From 3c779b6e343a3315fac1c32e8e678cbdbb75d2c8 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Tue, 16 Jun 2020 16:10:50 +0200 Subject: [PATCH 0001/1140] update channel preview --- lib/src/channel_name.dart | 1 + lib/src/channel_preview.dart | 25 ++++++++++++++++++------- lib/src/stream_chat_theme.dart | 2 +- 3 files changed, 20 insertions(+), 8 deletions(-) diff --git a/lib/src/channel_name.dart b/lib/src/channel_name.dart index ef7599b7..96a6a14a 100644 --- a/lib/src/channel_name.dart +++ b/lib/src/channel_name.dart @@ -42,6 +42,7 @@ class ChannelName extends StatelessWidget { return Text( title, style: textStyle, + overflow: TextOverflow.ellipsis, ); }, ); diff --git a/lib/src/channel_preview.dart b/lib/src/channel_preview.dart index 1e86f4fb..d9b69705 100644 --- a/lib/src/channel_preview.dart +++ b/lib/src/channel_preview.dart @@ -56,20 +56,31 @@ class ChannelPreview extends StatelessWidget { leading: ChannelImage( onTap: onImageTap, ), - title: ChannelName( - textStyle: StreamChatTheme.of(context).channelPreviewTheme.title, - ), - subtitle: _buildSubtitle(context), - trailing: Row( - mainAxisSize: MainAxisSize.min, + title: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - _buildDate(context), + Flexible( + child: ChannelName( + textStyle: StreamChatTheme.of(context).channelPreviewTheme.title, + ), + ), if (channel.state.unreadCount > 0) UnreadIndicator( channel: channel, ), ], ), + subtitle: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Flexible(child: _buildSubtitle(context)), + _buildDate(context), + ], + ), + trailing: Row( + mainAxisSize: MainAxisSize.min, + children: [], + ), ); } diff --git a/lib/src/stream_chat_theme.dart b/lib/src/stream_chat_theme.dart index e75d30c3..c1d44b9b 100644 --- a/lib/src/stream_chat_theme.dart +++ b/lib/src/stream_chat_theme.dart @@ -230,7 +230,7 @@ class StreamChatThemeData { color: isDark ? Colors.white : Colors.black, ), subtitle: TextStyle( - fontSize: 13, + fontSize: 12.5, color: isDark ? Colors.white : Colors.black, ), lastMessageAt: TextStyle( From 5b5c390c8295f6d067b2bcd038ca50f717155a2e Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Tue, 16 Jun 2020 17:22:26 +0200 Subject: [PATCH 0002/1140] update sending indicator --- example/lib/main.dart | 1 + lib/src/message_list_view.dart | 4 +++- lib/src/message_widget.dart | 35 ++++++++++------------------------ lib/src/sending_indicator.dart | 33 +++++++++----------------------- lib/src/stream_chat_theme.dart | 2 +- 5 files changed, 24 insertions(+), 51 deletions(-) diff --git a/example/lib/main.dart b/example/lib/main.dart index f81c61be..81322040 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -90,6 +90,7 @@ class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( +// debugShowMaterialGrid: true, theme: ThemeData.light(), darkTheme: ThemeData.dark(), themeMode: ThemeMode.system, diff --git a/lib/src/message_list_view.dart b/lib/src/message_list_view.dart index c4b5a390..121109c4 100644 --- a/lib/src/message_list_view.dart +++ b/lib/src/message_list_view.dart @@ -463,7 +463,9 @@ class _MessageListViewState extends State { topRight: Radius.circular(16), bottomRight: Radius.circular(16), ), - showUserAvatar: isNextUser ? DisplayWidget.hide : DisplayWidget.show, + showUserAvatar: isMyMessage + ? DisplayWidget.gone + : (isNextUser ? DisplayWidget.hide : DisplayWidget.show), 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 3294ab17..752c1b23 100644 --- a/lib/src/message_widget.dart +++ b/lib/src/message_widget.dart @@ -201,8 +201,8 @@ class _MessageWidgetState extends State { @override Widget build(BuildContext context) { var leftPadding = widget.showUserAvatar != DisplayWidget.gone - ? widget.messageTheme.avatarTheme.constraints.maxWidth + 23.0 - : 12.0; + ? widget.messageTheme.avatarTheme.constraints.maxWidth + 16.0 + : 6.0; if (widget.showSendingIndicator == DisplayWidget.gone) { leftPadding -= 7; } @@ -232,17 +232,6 @@ class _MessageWidgetState extends State { crossAxisAlignment: CrossAxisAlignment.end, mainAxisSize: MainAxisSize.min, children: [ - if (widget.showSendingIndicator == - DisplayWidget.show) - _buildSendingIndicator(), - SizedBox( - width: 2, - ), - if (widget.showSendingIndicator == - DisplayWidget.hide) - SizedBox( - width: 8, - ), if (widget.showUserAvatar == DisplayWidget.show) _buildUserAvatar(), SizedBox( @@ -389,12 +378,14 @@ class _MessageWidgetState extends State { if (widget.message.createdAt != null && widget.showTimestamp) TextSpan( text: Jiffy(widget.message.createdAt.toLocal()) - .format(' HH:mm'), + .format(' HH:mm'), ), ], ), ), ), + if (widget.showSendingIndicator == DisplayWidget.show) + _buildSendingIndicator(), if (widget.readList?.isNotEmpty == true) SizedBox.fromSize( size: Size((widget.readList.length * 10.0) + 10, 17), @@ -623,17 +614,11 @@ class _MessageWidgetState extends State { } Widget _buildSendingIndicator() { - return Transform.translate( - offset: Offset( - 0, - 4, - ), - child: Transform( - transform: Matrix4.rotationY(widget.reverse ? pi : 0), - alignment: Alignment.center, - child: SendingIndicator( - message: widget.message, - ), + return Transform( + transform: Matrix4.rotationY(widget.reverse ? pi : 0), + alignment: Alignment.center, + child: SendingIndicator( + message: widget.message, ), ); } diff --git a/lib/src/sending_indicator.dart b/lib/src/sending_indicator.dart index 81e7dfef..b51f07ae 100644 --- a/lib/src/sending_indicator.dart +++ b/lib/src/sending_indicator.dart @@ -13,39 +13,24 @@ class SendingIndicator extends StatelessWidget { @override Widget build(BuildContext context) { if (message.status == MessageSendingStatus.SENT || message.status == null) { - return CircleAvatar( - radius: 4, - backgroundColor: StreamChatTheme.of(context).accentColor, - child: Icon( - Icons.done, - color: Colors.white, - size: 4, - ), + return Icon( + Icons.done, + size: 8, ); } if (message.status == MessageSendingStatus.SENDING || message.status == MessageSendingStatus.UPDATING) { - return CircleAvatar( - radius: 4, - backgroundColor: Colors.grey, - child: Icon( - Icons.access_time, - size: 4, - color: Colors.white, - ), + return Icon( + Icons.access_time, + size: 8, ); } if (message.status == MessageSendingStatus.FAILED || message.status == MessageSendingStatus.FAILED_UPDATE || message.status == MessageSendingStatus.FAILED_DELETE) { - return CircleAvatar( - radius: 4, - backgroundColor: Color(0xffd0021B).withOpacity(.1), - child: Icon( - Icons.error_outline, - size: 4, - color: Colors.white, - ), + return Icon( + Icons.error_outline, + size: 8, ); } diff --git a/lib/src/stream_chat_theme.dart b/lib/src/stream_chat_theme.dart index c1d44b9b..c4a4fa45 100644 --- a/lib/src/stream_chat_theme.dart +++ b/lib/src/stream_chat_theme.dart @@ -287,7 +287,7 @@ class StreamChatThemeData { fontWeight: FontWeight.bold, fontSize: 12, ), - messageBackgroundColor: Color(0x33ebebeb), + messageBackgroundColor: Color(0xffE6E6E6), avatarTheme: AvatarTheme( borderRadius: BorderRadius.circular(20), constraints: BoxConstraints.tightFor( From 8fc314d942e8c5b1b5b9b99b354666225987aaaa Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Thu, 18 Jun 2020 11:03:28 +0200 Subject: [PATCH 0003/1140] update sending indicator --- lib/src/channel_list_view.dart | 1 - lib/src/channel_preview.dart | 24 ++++++++++++++++++++---- lib/src/message_list_view.dart | 9 +++++---- lib/src/message_widget.dart | 20 ++++++++++++-------- lib/src/sending_indicator.dart | 8 ++++++++ 5 files changed, 45 insertions(+), 17 deletions(-) diff --git a/lib/src/channel_list_view.dart b/lib/src/channel_list_view.dart index 782dd772..9b4cab61 100644 --- a/lib/src/channel_list_view.dart +++ b/lib/src/channel_list_view.dart @@ -329,7 +329,6 @@ class _ChannelListViewState extends State color: Theme.of(context).brightness == Brightness.dark ? Colors.white.withOpacity(0.1) : Colors.black.withOpacity(0.1), - margin: EdgeInsets.symmetric(horizontal: 16), ); } diff --git a/lib/src/channel_preview.dart b/lib/src/channel_preview.dart index d9b69705..40c2ee8e 100644 --- a/lib/src/channel_preview.dart +++ b/lib/src/channel_preview.dart @@ -74,13 +74,29 @@ class ChannelPreview extends StatelessWidget { mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Flexible(child: _buildSubtitle(context)), + Builder( + builder: (context) { + final lastMessage = channel.state.messages.last; + if (channel.state?.messages?.isNotEmpty == true && + lastMessage.user.id == StreamChat.of(context).user.id) { + return Padding( + padding: const EdgeInsets.only(right: 4.0), + child: SendingIndicator( + message: lastMessage, + allRead: channel.state.read + .where((element) => + element.lastRead.isAfter(lastMessage.createdAt)) + .length == + channel.memberCount - 1, + ), + ); + } + return SizedBox(); + }, + ), _buildDate(context), ], ), - trailing: Row( - mainAxisSize: MainAxisSize.min, - children: [], - ), ); } diff --git a/lib/src/message_list_view.dart b/lib/src/message_list_view.dart index 121109c4..d976896b 100644 --- a/lib/src/message_list_view.dart +++ b/lib/src/message_list_view.dart @@ -426,10 +426,8 @@ class _MessageListViewState extends State { final isNextUser = index - 1 >= 0 && message.user.id == messages[index - 1]?.user?.id; - final readList = StreamChannel.of(context) - .channel - .state - .read + var channel = StreamChannel.of(context).channel; + final readList = channel.state.read .where((element) => element.user.id != userId) .where((read) => read.lastRead.isAfter(message.createdAt) && @@ -437,6 +435,8 @@ class _MessageListViewState extends State { read.lastRead.isBefore(messages[index - 1].createdAt))) .toList(); + final allRead = readList.length == channel.memberCount - 1; + return MessageWidget( message: message, reverse: isMyMessage, @@ -470,6 +470,7 @@ class _MessageListViewState extends State { ? StreamChatTheme.of(context).ownMessageTheme : StreamChatTheme.of(context).otherMessageTheme, readList: readList, + allRead: allRead, ); } diff --git a/lib/src/message_widget.dart b/lib/src/message_widget.dart index 752c1b23..a833bb95 100644 --- a/lib/src/message_widget.dart +++ b/lib/src/message_widget.dart @@ -91,6 +91,8 @@ class MessageWidget extends StatefulWidget { /// If true the widget will show the reactions final bool showReactions; + final bool allRead; + /// If true the widget will show the reply indicator final bool showReplyIndicator; @@ -136,6 +138,7 @@ class MessageWidget extends StatefulWidget { this.padding, this.textPadding = const EdgeInsets.all(8.0), this.attachmentPadding = EdgeInsets.zero, + this.allRead = false, }) : attachmentBuilders = { 'image': (context, message, attachment) { return ImageAttachment( @@ -203,9 +206,6 @@ class _MessageWidgetState extends State { var leftPadding = widget.showUserAvatar != DisplayWidget.gone ? widget.messageTheme.avatarTheme.constraints.maxWidth + 16.0 : 6.0; - if (widget.showSendingIndicator == DisplayWidget.gone) { - leftPadding -= 7; - } return Portal( child: Padding( padding: widget.padding ?? EdgeInsets.all(8), @@ -614,11 +614,15 @@ class _MessageWidgetState extends State { } Widget _buildSendingIndicator() { - return Transform( - transform: Matrix4.rotationY(widget.reverse ? pi : 0), - alignment: Alignment.center, - child: SendingIndicator( - message: widget.message, + return Padding( + padding: const EdgeInsets.only(right: 4.0), + child: Transform( + transform: Matrix4.rotationY(widget.reverse ? pi : 0), + alignment: Alignment.center, + child: SendingIndicator( + message: widget.message, + allRead: widget.allRead, + ), ), ); } diff --git a/lib/src/sending_indicator.dart b/lib/src/sending_indicator.dart index b51f07ae..f92686c7 100644 --- a/lib/src/sending_indicator.dart +++ b/lib/src/sending_indicator.dart @@ -4,14 +4,22 @@ import 'package:stream_chat_flutter/stream_chat_flutter.dart'; /// Used to show the sending status of the message class SendingIndicator extends StatelessWidget { final Message message; + final bool allRead; const SendingIndicator({ Key key, this.message, + this.allRead = false, }) : super(key: key); @override Widget build(BuildContext context) { + if (allRead) { + return Icon( + Icons.done_all, + size: 8, + ); + } if (message.status == MessageSendingStatus.SENT || message.status == null) { return Icon( Icons.done, From 4e802f71bb708d6f68f356c3bdf4bfc1ed72fda7 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Thu, 18 Jun 2020 15:43:31 +0200 Subject: [PATCH 0004/1140] change message radius --- lib/src/message_list_view.dart | 9 +++---- lib/src/message_widget.dart | 47 ++++++++++++++++++++-------------- 2 files changed, 32 insertions(+), 24 deletions(-) diff --git a/lib/src/message_list_view.dart b/lib/src/message_list_view.dart index d976896b..306e830b 100644 --- a/lib/src/message_list_view.dart +++ b/lib/src/message_list_view.dart @@ -401,7 +401,7 @@ class _MessageListViewState extends State { bottomRight: Radius.circular(16), ), borderSide: isMyMessage ? BorderSide.none : null, - showUserAvatar: DisplayWidget.show, + showUserAvatar: isMyMessage ? DisplayWidget.gone : DisplayWidget.show, messageTheme: isMyMessage ? StreamChatTheme.of(context).ownMessageTheme : StreamChatTheme.of(context).otherMessageTheme, @@ -421,8 +421,6 @@ class _MessageListViewState extends State { final userId = StreamChat.of(context).user.id; final isMyMessage = message.user.id == userId; - final isLastUser = index + 1 < messages.length && - message.user.id == messages[index + 1]?.user?.id; final isNextUser = index - 1 >= 0 && message.user.id == messages[index - 1]?.user?.id; @@ -457,9 +455,10 @@ class _MessageListViewState extends State { borderSide: isMyMessage ? BorderSide.none : null, onThreadTap: _onThreadTap, attachmentBorderRadiusGeometry: BorderRadius.circular(16), + attachmentPadding: const EdgeInsets.all(2), borderRadiusGeometry: BorderRadius.only( - topLeft: Radius.circular(isLastUser ? 2 : 16), - bottomLeft: Radius.circular(2), + topLeft: Radius.circular(16), + bottomLeft: Radius.circular(!isNextUser ? 0 : 16), topRight: Radius.circular(16), bottomRight: Radius.circular(16), ), diff --git a/lib/src/message_widget.dart b/lib/src/message_widget.dart index a833bb95..07760235 100644 --- a/lib/src/message_widget.dart +++ b/lib/src/message_widget.dart @@ -136,7 +136,10 @@ class MessageWidget extends StatefulWidget { Map customAttachmentBuilders, this.readList, this.padding, - this.textPadding = const EdgeInsets.all(8.0), + this.textPadding = const EdgeInsets.symmetric( + horizontal: 16.0, + vertical: 8.0, + ), this.attachmentPadding = EdgeInsets.zero, this.allRead = false, }) : attachmentBuilders = { @@ -373,7 +376,10 @@ class _MessageWidgetState extends State { if (widget.showUsername) TextSpan( text: widget.message.user.name, - style: TextStyle(fontWeight: FontWeight.bold), + style: TextStyle( + fontWeight: FontWeight.bold, + color: widget.messageTheme.createdAt.color + .withOpacity(1)), ), if (widget.message.createdAt != null && widget.showTimestamp) TextSpan( @@ -550,23 +556,26 @@ class _MessageWidgetState extends State { ), child: Padding( padding: widget.attachmentPadding, - child: Transform( - transform: Matrix4.rotationY(widget.reverse ? pi : 0), - alignment: Alignment.center, - child: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.end, - children: [ - getFailedMessageWidget( - context, - padding: const EdgeInsets.all(8.0), - ), - attachmentBuilder( - context, - widget.message, - attachment, - ), - ], + child: ClipRRect( + borderRadius: BorderRadius.circular(6), + child: Transform( + transform: Matrix4.rotationY(widget.reverse ? pi : 0), + alignment: Alignment.center, + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.end, + children: [ + getFailedMessageWidget( + context, + padding: const EdgeInsets.all(8.0), + ), + attachmentBuilder( + context, + widget.message, + attachment, + ), + ], + ), ), ), ), From 0398908bd692c8ec89d39d89c9486753d03ec136 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Fri, 19 Jun 2020 11:45:45 +0200 Subject: [PATCH 0005/1140] update date divider --- lib/src/date_divider.dart | 57 +++++++++++++-------------------------- 1 file changed, 18 insertions(+), 39 deletions(-) diff --git a/lib/src/date_divider.dart b/lib/src/date_divider.dart index 102c6e14..13f755d7 100644 --- a/lib/src/date_divider.dart +++ b/lib/src/date_divider.dart @@ -12,16 +12,8 @@ class DateDivider extends StatelessWidget { @override Widget build(BuildContext context) { - final divider = Expanded( - child: Padding( - padding: const EdgeInsets.symmetric(horizontal: 8.0), - child: Divider(), - ), - ); - final createdAt = Jiffy(dateTime); final now = DateTime.now(); - final hourInfo = createdAt.format('h:mm a'); String dayInfo; if (Jiffy(createdAt).isSame(now, Units.DAY)) { @@ -38,42 +30,29 @@ class DateDivider extends StatelessWidget { Jiffy(now).subtract(years: 1), Units.DAY, )) { - dayInfo = createdAt.format('dd/MM').toUpperCase(); + dayInfo = createdAt.format('MMMM d').toUpperCase(); } else { - dayInfo = createdAt.format('dd/MM/yyyy').toUpperCase(); + dayInfo = createdAt.format('MMMM d').toUpperCase(); } - return Row( - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - divider, - Padding( - padding: const EdgeInsets.symmetric(horizontal: 32.0), - child: Text.rich( - TextSpan( - children: [ - TextSpan( - text: dayInfo, - style: TextStyle( - fontWeight: FontWeight.bold, - ), - ), - TextSpan(text: ' AT'), - TextSpan(text: ' $hourInfo'), - ], - style: TextStyle( - fontWeight: FontWeight.normal, - ), - ), - style: TextStyle( - fontSize: 10, - color: - Theme.of(context).textTheme.headline6.color.withOpacity(.5), - ), + return Center( + child: Container( + padding: const EdgeInsets.symmetric(horizontal: 8), + decoration: BoxDecoration( + color: Colors.black.withOpacity(0.5), + borderRadius: BorderRadius.circular( + 8, ), ), - divider, - ], + child: Text( + dayInfo, + style: TextStyle( + fontSize: 12, + color: Colors.white, + fontWeight: FontWeight.bold, + ), + ), + ), ); } } From 8b0bb0f3b2d979b6782187f79ba62a1e6b7f387a Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Wed, 8 Jul 2020 10:45:26 +0200 Subject: [PATCH 0006/1140] remove opacity difference for unread channels --- lib/src/channel_preview.dart | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/lib/src/channel_preview.dart b/lib/src/channel_preview.dart index 40c2ee8e..9b113ca8 100644 --- a/lib/src/channel_preview.dart +++ b/lib/src/channel_preview.dart @@ -130,21 +130,20 @@ class ChannelPreview extends StatelessWidget { } Widget _buildSubtitle(BuildContext context) { - final opacity = channel.state.unreadCount > 0 ? 1.0 : 0.5; return TypingIndicator( channel: channel, - alternativeWidget: _buildLastMessage(context, opacity), + alternativeWidget: _buildLastMessage(context), style: StreamChatTheme.of(context).channelPreviewTheme.subtitle.copyWith( color: StreamChatTheme.of(context) .channelPreviewTheme .subtitle .color - .withOpacity(opacity), + .withOpacity(0.5), ), ); } - Widget _buildLastMessage(BuildContext context, double opacity) { + Widget _buildLastMessage(BuildContext context) { return StreamBuilder>( stream: channel.state.messagesStream, initialData: channel.state.messages, @@ -189,7 +188,7 @@ class ChannelPreview extends StatelessWidget { .channelPreviewTheme .subtitle .color - .withOpacity(opacity), + .withOpacity(0.5), ), ); }, From 6256195b4b800d66da18c92b7234c92599856648 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Wed, 8 Jul 2020 10:45:43 +0200 Subject: [PATCH 0007/1140] change default unread color --- lib/src/stream_chat_theme.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/stream_chat_theme.dart b/lib/src/stream_chat_theme.dart index c4a4fa45..1a7677d6 100644 --- a/lib/src/stream_chat_theme.dart +++ b/lib/src/stream_chat_theme.dart @@ -217,7 +217,7 @@ class StreamChatThemeData { ), ), channelPreviewTheme: ChannelPreviewTheme( - unreadCounterColor: Color(0xffd0021B), + unreadCounterColor: Color(0xffff3742), avatarTheme: AvatarTheme( borderRadius: BorderRadius.circular(20), constraints: BoxConstraints.tightFor( From eb5517aca3607ee972dea48c5705d65dadd5129a Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Wed, 8 Jul 2020 10:45:50 +0200 Subject: [PATCH 0008/1140] update unread indicator --- lib/src/unread_indicator.dart | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/lib/src/unread_indicator.dart b/lib/src/unread_indicator.dart index 73f57d05..96bf0a00 100644 --- a/lib/src/unread_indicator.dart +++ b/lib/src/unread_indicator.dart @@ -17,10 +17,13 @@ class UnreadIndicator extends StatelessWidget { child: CircleAvatar( backgroundColor: StreamChatTheme.of(context).channelPreviewTheme.unreadCounterColor, - radius: 6, + radius: 8, child: Text( '${channel.state.unreadCount}', - style: TextStyle(fontSize: 8), + style: TextStyle( + fontSize: 11, + color: Colors.white, + ), ), ), ); From 28aeb1a1a48eb544af7bbedcb598b43fc1383779 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Wed, 8 Jul 2020 10:59:48 +0200 Subject: [PATCH 0009/1140] fix last message preview. it had a white space in front --- lib/src/channel_preview.dart | 28 ++++++++++++++-------------- lib/src/sending_indicator.dart | 1 + 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/lib/src/channel_preview.dart b/lib/src/channel_preview.dart index 9b113ca8..da244498 100644 --- a/lib/src/channel_preview.dart +++ b/lib/src/channel_preview.dart @@ -161,21 +161,21 @@ class ChannelPreview extends StatelessWidget { if (lastMessage.isDeleted) { text = 'This message was deleted.'; } else if (lastMessage.attachments != null) { - final prefix = lastMessage.attachments - .map((e) { - if (e.type == 'image') { - return '📷'; - } else if (e.type == 'video') { - return '🎬'; - } else if (e.type == 'giphy') { - return 'GIF'; - } - return null; - }) - .where((e) => e != null) - .join(' '); + final parts = [ + ...lastMessage.attachments.map((e) { + if (e.type == 'image') { + return '📷'; + } else if (e.type == 'video') { + return '🎬'; + } else if (e.type == 'giphy') { + return '[GIF]'; + } + return null; + }).where((e) => e != null), + lastMessage.text ?? '', + ]; - text = '$prefix ${lastMessage.text ?? ''}'; + text = parts.join(' '); } return Text( diff --git a/lib/src/sending_indicator.dart b/lib/src/sending_indicator.dart index f92686c7..e93984e2 100644 --- a/lib/src/sending_indicator.dart +++ b/lib/src/sending_indicator.dart @@ -24,6 +24,7 @@ class SendingIndicator extends StatelessWidget { return Icon( Icons.done, size: 8, + color: IconTheme.of(context).color.withOpacity(0.5), ); } if (message.status == MessageSendingStatus.SENDING || From 1f226f33c84b12d0bf5ceb31fa52aad06c0ec0a8 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Wed, 8 Jul 2020 14:52:39 +0200 Subject: [PATCH 0010/1140] add online indicator to useravatar --- lib/src/channel_image.dart | 27 ++++++++- lib/src/message_widget.dart | 2 + lib/src/user_avatar.dart | 107 +++++++++++++++++++++++------------- 3 files changed, 96 insertions(+), 40 deletions(-) diff --git a/lib/src/channel_image.dart b/lib/src/channel_image.dart index bef666db..d8401bdf 100644 --- a/lib/src/channel_image.dart +++ b/lib/src/channel_image.dart @@ -49,6 +49,7 @@ class ChannelImage extends StatelessWidget { this.channel, this.constraints, this.onTap, + this.showOnlineStatus = true, }) : super(key: key); /// The channel to show the image of @@ -60,9 +61,11 @@ class ChannelImage extends StatelessWidget { /// The function called when the image is tapped final VoidCallback onTap; + final bool showOnlineStatus; + @override Widget build(BuildContext context) { - final client = StreamChat.of(context); + final streamChat = StreamChat.of(context); final channel = this.channel ?? StreamChannel.of(context).channel; return StreamBuilder>( stream: channel.extraDataStream, @@ -73,8 +76,26 @@ class ChannelImage extends StatelessWidget { image = snapshot.data['image']; } else if (channel.state.members.length == 2) { final otherMember = channel.state.members - .firstWhere((member) => member.user.id != client.user.id); - image = otherMember.user.extraData['image']; + .firstWhere((member) => member.user.id != streamChat.user.id); + return StreamBuilder( + stream: streamChat.client.state.usersStream + .map((users) => users[otherMember.userId]), + initialData: otherMember.user, + builder: (context, snapshot) { + return UserAvatar( + user: snapshot.data ?? otherMember.user, + constraints: constraints ?? + StreamChatTheme.of(context) + .channelPreviewTheme + .avatarTheme + .constraints, + onTap: onTap != null + ? (_) { + onTap(); + } + : null, + ); + }); } return ClipRRect( diff --git a/lib/src/message_widget.dart b/lib/src/message_widget.dart index 07760235..3103d079 100644 --- a/lib/src/message_widget.dart +++ b/lib/src/message_widget.dart @@ -426,6 +426,7 @@ class _MessageWidgetState extends State { child: UserAvatar( user: e.user, constraints: BoxConstraints.loose(Size.fromRadius(16)), + showOnlineStatus: false, ), ), ), @@ -648,6 +649,7 @@ class _MessageWidgetState extends State { user: widget.message.user, onTap: widget.onUserAvatarTap, constraints: widget.messageTheme.avatarTheme.constraints, + showOnlineStatus: false, ), ), ), diff --git a/lib/src/user_avatar.dart b/lib/src/user_avatar.dart index 8ea9a525..33e8ab90 100644 --- a/lib/src/user_avatar.dart +++ b/lib/src/user_avatar.dart @@ -9,55 +9,88 @@ class UserAvatar extends StatelessWidget { Key key, @required this.user, this.constraints, + this.onlineIndicatorConstraints, this.onTap, + this.showOnlineStatus = true, }) : super(key: key); final User user; final BoxConstraints constraints; + final BoxConstraints onlineIndicatorConstraints; final void Function(User) onTap; + final bool showOnlineStatus; @override Widget build(BuildContext context) { return GestureDetector( - onTap: () { - if (onTap != null) { - onTap(user); - } - }, - child: ClipRRect( - borderRadius: StreamChatTheme.of(context) - .ownMessageTheme - .avatarTheme - .borderRadius, - child: Container( - constraints: constraints ?? - StreamChatTheme.of(context) - .ownMessageTheme - .avatarTheme - .constraints, - decoration: BoxDecoration( - color: StreamChatTheme.of(context).accentColor, + onTap: onTap != null + ? () { + if (onTap != null) { + onTap(user); + } + } + : null, + child: Stack( + children: [ + ClipRRect( + borderRadius: StreamChatTheme.of(context) + .ownMessageTheme + .avatarTheme + .borderRadius, + child: Container( + constraints: constraints ?? + StreamChatTheme.of(context) + .ownMessageTheme + .avatarTheme + .constraints, + decoration: BoxDecoration( + color: StreamChatTheme.of(context).accentColor, + ), + child: user.extraData?.containsKey('image') ?? false + ? CachedNetworkImage( + imageUrl: user.extraData['image'], + errorWidget: (_, __, ___) { + return Center( + child: Text( + user.extraData?.containsKey('name') ?? false + ? user.extraData['name'][0] + : '', + style: TextStyle( + color: Colors.white, + fontWeight: FontWeight.bold, + ), + ), + ); + }, + fit: BoxFit.cover, + ) + : StreamChatTheme.of(context).defaultUserImage(context, user), + ), ), - child: user.extraData?.containsKey('image') ?? false - ? CachedNetworkImage( - imageUrl: user.extraData['image'], - errorWidget: (_, __, ___) { - return Center( - child: Text( - user.extraData?.containsKey('name') ?? false - ? user.extraData['name'][0] - : '', - style: TextStyle( - color: Colors.white, - fontWeight: FontWeight.bold, + if (showOnlineStatus && user.online) + Positioned( + top: 0, + right: 0, + child: Material( + child: Center( + child: Container( + padding: const EdgeInsets.all(2.0), + constraints: onlineIndicatorConstraints ?? + BoxConstraints.tightFor( + width: 12, + height: 12, ), - ), - ); - }, - fit: BoxFit.cover, - ) - : StreamChatTheme.of(context).defaultUserImage(context, user), - ), + child: Material( + shape: CircleBorder(), + color: Color(0xff20E070), + ), + ), + ), + shape: CircleBorder(), + color: Colors.white, + ), + ), + ], ), ); } From 86ea7b7e28922c184b1fab2625a5972dfe49f6ef Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Wed, 8 Jul 2020 14:53:02 +0200 Subject: [PATCH 0011/1140] add presence to example app --- example/lib/main.dart | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/example/lib/main.dart b/example/lib/main.dart index 81322040..682601ef 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -67,7 +67,7 @@ void _initNotifications(Client client) { void main() async { final client = Client( 's2dxdhpxd94g', - logLevel: Level.INFO, + logLevel: Level.FINEST, showLocalNotification: Platform.isAndroid ? showLocalNotification : null, persistenceEnabled: true, ); @@ -91,6 +91,7 @@ class MyApp extends StatelessWidget { Widget build(BuildContext context) { return MaterialApp( // debugShowMaterialGrid: true, +// debugShowCheckedModeBanner: false, theme: ThemeData.light(), darkTheme: ThemeData.dark(), themeMode: ThemeMode.system, @@ -116,6 +117,9 @@ class ChannelListPage extends StatelessWidget { '\$in': [StreamChat.of(context).user.id], } }, + options: { + 'presence': true, + }, sort: [SortOption('last_message_at')], pagination: PaginationParams( limit: 20, From 446b051d0359456fbeab4845fffe7a608ab3e8f6 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Wed, 8 Jul 2020 15:10:17 +0200 Subject: [PATCH 0012/1140] show deleted and system messages in italic --- lib/src/channel_preview.dart | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/lib/src/channel_preview.dart b/lib/src/channel_preview.dart index da244498..c35071cb 100644 --- a/lib/src/channel_preview.dart +++ b/lib/src/channel_preview.dart @@ -76,16 +76,15 @@ class ChannelPreview extends StatelessWidget { Flexible(child: _buildSubtitle(context)), Builder( builder: (context) { - final lastMessage = channel.state.messages.last; - if (channel.state?.messages?.isNotEmpty == true && - lastMessage.user.id == StreamChat.of(context).user.id) { + if (channel.state.lastMessage?.user?.id == + StreamChat.of(context).user.id) { return Padding( padding: const EdgeInsets.only(right: 4.0), child: SendingIndicator( - message: lastMessage, + message: channel.state.lastMessage, allRead: channel.state.read - .where((element) => - element.lastRead.isAfter(lastMessage.createdAt)) + .where((element) => element.lastRead + .isAfter(channel.state.lastMessage.createdAt)) .length == channel.memberCount - 1, ), @@ -189,6 +188,9 @@ class ChannelPreview extends StatelessWidget { .subtitle .color .withOpacity(0.5), + fontStyle: (lastMessage.isSystem || lastMessage.isDeleted) + ? FontStyle.italic + : FontStyle.normal, ), ); }, From 995a6a8d3d6cd30d9272e4ff972b1b5d5fe9752a Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Wed, 8 Jul 2020 15:30:17 +0200 Subject: [PATCH 0013/1140] compose channel name from members if there is no name --- lib/src/channel_name.dart | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/lib/src/channel_name.dart b/lib/src/channel_name.dart index 96a6a14a..bc30a7f4 100644 --- a/lib/src/channel_name.dart +++ b/lib/src/channel_name.dart @@ -30,13 +30,19 @@ class ChannelName extends StatelessWidget { initialData: channel.extraData, builder: (context, snapshot) { String title; - if (snapshot.data['name'] == null && - channel.state.members.length == 2) { - final otherMember = channel.state.members - .firstWhere((member) => member.user.id != client.user.id); - title = otherMember.user.name; + if (snapshot.data['name'] == null) { + final otherMembers = channel.state.members + .where((member) => member.userId != client.user.id); + if (otherMembers.length > 0) { + final exceedingMembers = otherMembers.length - 5; + print('exceedingMembers: ${exceedingMembers}'); + title = + '${otherMembers.take(5).map((e) => e.user.name).join(', ')} ${exceedingMembers > 0 ? '+ $exceedingMembers' : ''}'; + } else { + title = channel.id; + } } else { - title = snapshot.data['name'] ?? channel.id; + title = snapshot.data['name']; } return Text( From bd012e0d2464f641ca50704de254fded474b21f8 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Wed, 8 Jul 2020 15:31:22 +0200 Subject: [PATCH 0014/1140] remove log --- lib/src/channel_name.dart | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/src/channel_name.dart b/lib/src/channel_name.dart index bc30a7f4..01abcb81 100644 --- a/lib/src/channel_name.dart +++ b/lib/src/channel_name.dart @@ -33,9 +33,8 @@ class ChannelName extends StatelessWidget { if (snapshot.data['name'] == null) { final otherMembers = channel.state.members .where((member) => member.userId != client.user.id); - if (otherMembers.length > 0) { + if (otherMembers.isNotEmpty) { final exceedingMembers = otherMembers.length - 5; - print('exceedingMembers: ${exceedingMembers}'); title = '${otherMembers.take(5).map((e) => e.user.name).join(', ')} ${exceedingMembers > 0 ? '+ $exceedingMembers' : ''}'; } else { From 3ab0815ae979a498132712694a0e1ae1369788e6 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Wed, 8 Jul 2020 16:33:00 +0200 Subject: [PATCH 0015/1140] add group image --- lib/src/channel_image.dart | 18 ++++++++ lib/src/group_image.dart | 85 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 103 insertions(+) create mode 100644 lib/src/group_image.dart diff --git a/lib/src/channel_image.dart b/lib/src/channel_image.dart index d8401bdf..113d6de0 100644 --- a/lib/src/channel_image.dart +++ b/lib/src/channel_image.dart @@ -1,6 +1,7 @@ import 'package:cached_network_image/cached_network_image.dart'; import 'package:flutter/material.dart'; import 'package:stream_chat/stream_chat.dart'; +import 'package:stream_chat_flutter/src/group_image.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; /// ![screenshot](https://raw.githubusercontent.com/GetStream/stream-chat-flutter/master/screenshots/channel_image.png) @@ -96,6 +97,23 @@ class ChannelImage extends StatelessWidget { : null, ); }); + } else { + final images = channel.state.members + .where((member) => + member.user.id != streamChat.user.id && + member.user.extraData['image'] != null) + .take(4) + .map((e) => e.user.extraData['image'] as String) + .toList(); + return GroupImage( + images: images, + constraints: constraints ?? + StreamChatTheme.of(context) + .channelPreviewTheme + .avatarTheme + .constraints, + onTap: onTap, + ); } return ClipRRect( diff --git a/lib/src/group_image.dart b/lib/src/group_image.dart new file mode 100644 index 00000000..1a3b7634 --- /dev/null +++ b/lib/src/group_image.dart @@ -0,0 +1,85 @@ +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:flutter/material.dart'; + +import '../stream_chat_flutter.dart'; + +class GroupImage extends StatelessWidget { + const GroupImage({ + Key key, + @required this.images, + this.constraints, + this.onTap, + }) : super(key: key); + + final List images; + final BoxConstraints constraints; + final VoidCallback onTap; + + @override + Widget build(BuildContext context) { + final secondRow = images + .skip(2) + .map((url) => Flexible( + child: CachedNetworkImage( + imageUrl: url, + fit: BoxFit.cover, + ), + )) + .toList(); + + return GestureDetector( + onTap: onTap, + child: ClipRRect( + borderRadius: StreamChatTheme.of(context) + .ownMessageTheme + .avatarTheme + .borderRadius, + child: Container( + constraints: constraints ?? + StreamChatTheme.of(context) + .ownMessageTheme + .avatarTheme + .constraints, + decoration: BoxDecoration( + color: StreamChatTheme.of(context).accentColor, + ), + child: Flex( + direction: Axis.vertical, + children: [ + Flexible( + child: Flex( + direction: Axis.horizontal, + children: images + .take(2) + .map((url) => Flexible( + fit: FlexFit.tight, + child: CachedNetworkImage( + imageUrl: url, + fit: BoxFit.cover, + ), + )) + .toList(), + ), + ), + Flexible( + child: Flex( + direction: Axis.horizontal, + children: images + .skip(2) + .map((url) => Flexible( + fit: FlexFit.tight, + child: CachedNetworkImage( + imageUrl: url, + fit: BoxFit.cover, + ), + )) + .toList(), + ), + ) + ], + ), + ), + ), + ); + } +} From 67dbac28570f5319f8178c30ea0ae2835a364c02 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Wed, 8 Jul 2020 16:48:28 +0200 Subject: [PATCH 0016/1140] fix group image for three people group --- lib/src/group_image.dart | 36 +++++++++++++++++++++--------------- 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/lib/src/group_image.dart b/lib/src/group_image.dart index 1a3b7634..91bdf7b0 100644 --- a/lib/src/group_image.dart +++ b/lib/src/group_image.dart @@ -45,10 +45,13 @@ class GroupImage extends StatelessWidget { ), child: Flex( direction: Axis.vertical, + crossAxisAlignment: CrossAxisAlignment.stretch, children: [ Flexible( + fit: FlexFit.tight, child: Flex( direction: Axis.horizontal, + crossAxisAlignment: CrossAxisAlignment.stretch, children: images .take(2) .map((url) => Flexible( @@ -61,21 +64,24 @@ class GroupImage extends StatelessWidget { .toList(), ), ), - Flexible( - child: Flex( - direction: Axis.horizontal, - children: images - .skip(2) - .map((url) => Flexible( - fit: FlexFit.tight, - child: CachedNetworkImage( - imageUrl: url, - fit: BoxFit.cover, - ), - )) - .toList(), - ), - ) + if (images.length > 2) + Flexible( + fit: FlexFit.tight, + child: Flex( + direction: Axis.horizontal, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: images + .skip(2) + .map((url) => Flexible( + fit: FlexFit.tight, + child: CachedNetworkImage( + imageUrl: url, + fit: BoxFit.cover, + ), + )) + .toList(), + ), + ) ], ), ), From a2a5b48928fc052ca5b6cfd2515f41bdea3b99fc Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Thu, 9 Jul 2020 11:15:06 +0200 Subject: [PATCH 0017/1140] add channel muted ui --- lib/src/channel_preview.dart | 140 +++++++++++++++++++-------------- lib/src/stream_chat_theme.dart | 2 +- 2 files changed, 83 insertions(+), 59 deletions(-) diff --git a/lib/src/channel_preview.dart b/lib/src/channel_preview.dart index c35071cb..ddf43239 100644 --- a/lib/src/channel_preview.dart +++ b/lib/src/channel_preview.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/widgets.dart'; import 'package:jiffy/jiffy.dart'; +import 'package:line_awesome_icons/line_awesome_icons.dart'; import 'package:stream_chat/stream_chat.dart'; import 'package:stream_chat_flutter/src/unread_indicator.dart'; @@ -42,59 +43,63 @@ class ChannelPreview extends StatelessWidget { @override Widget build(BuildContext context) { - return ListTile( - onTap: () { - if (onTap != null) { - onTap(channel); - } - }, - onLongPress: () { - if (onLongPress != null) { - onLongPress(channel); - } - }, - leading: ChannelImage( - onTap: onImageTap, - ), - title: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Flexible( - child: ChannelName( - textStyle: StreamChatTheme.of(context).channelPreviewTheme.title, + return Opacity( + opacity: channel.isMuted ? 0.5 : 1, + child: ListTile( + onTap: () { + if (onTap != null) { + onTap(channel); + } + }, + onLongPress: () { + if (onLongPress != null) { + onLongPress(channel); + } + }, + leading: ChannelImage( + onTap: onImageTap, + ), + title: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Flexible( + child: ChannelName( + textStyle: + StreamChatTheme.of(context).channelPreviewTheme.title, + ), ), - ), - if (channel.state.unreadCount > 0) - UnreadIndicator( - channel: channel, + if (channel.state.unreadCount > 0) + UnreadIndicator( + channel: channel, + ), + ], + ), + subtitle: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Flexible(child: _buildSubtitle(context)), + Builder( + builder: (context) { + if (channel.state.lastMessage?.user?.id == + StreamChat.of(context).user.id) { + return Padding( + padding: const EdgeInsets.only(right: 4.0), + child: SendingIndicator( + message: channel.state.lastMessage, + allRead: channel.state.read + .where((element) => element.lastRead + .isAfter(channel.state.lastMessage.createdAt)) + .length == + channel.memberCount - 1, + ), + ); + } + return SizedBox(); + }, ), - ], - ), - subtitle: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Flexible(child: _buildSubtitle(context)), - Builder( - builder: (context) { - if (channel.state.lastMessage?.user?.id == - StreamChat.of(context).user.id) { - return Padding( - padding: const EdgeInsets.only(right: 4.0), - child: SendingIndicator( - message: channel.state.lastMessage, - allRead: channel.state.read - .where((element) => element.lastRead - .isAfter(channel.state.lastMessage.createdAt)) - .length == - channel.memberCount - 1, - ), - ); - } - return SizedBox(); - }, - ), - _buildDate(context), - ], + _buildDate(context), + ], + ), ), ); } @@ -129,15 +134,35 @@ class ChannelPreview extends StatelessWidget { } Widget _buildSubtitle(BuildContext context) { + if (channel.isMuted) { + return Row( + crossAxisAlignment: CrossAxisAlignment.end, + children: [ + Icon( + LineAwesomeIcons.volume_off, + size: 15, + ), + Text( + 'Channel is muted', + style: StreamChatTheme.of(context) + .channelPreviewTheme + .subtitle + .copyWith( + color: StreamChatTheme.of(context) + .channelPreviewTheme + .subtitle + .color, + ), + ), + ], + ); + } return TypingIndicator( channel: channel, alternativeWidget: _buildLastMessage(context), style: StreamChatTheme.of(context).channelPreviewTheme.subtitle.copyWith( - color: StreamChatTheme.of(context) - .channelPreviewTheme - .subtitle - .color - .withOpacity(0.5), + color: + StreamChatTheme.of(context).channelPreviewTheme.subtitle.color, ), ); } @@ -186,8 +211,7 @@ class ChannelPreview extends StatelessWidget { color: StreamChatTheme.of(context) .channelPreviewTheme .subtitle - .color - .withOpacity(0.5), + .color, fontStyle: (lastMessage.isSystem || lastMessage.isDeleted) ? FontStyle.italic : FontStyle.normal, diff --git a/lib/src/stream_chat_theme.dart b/lib/src/stream_chat_theme.dart index 1a7677d6..7df9eb7c 100644 --- a/lib/src/stream_chat_theme.dart +++ b/lib/src/stream_chat_theme.dart @@ -231,7 +231,7 @@ class StreamChatThemeData { ), subtitle: TextStyle( fontSize: 12.5, - color: isDark ? Colors.white : Colors.black, + color: (isDark ? Colors.white : Colors.black).withOpacity(0.5), ), lastMessageAt: TextStyle( fontSize: 11, From c00ed3f2a280c63b5b4a8d350680e5d35aa865fd Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Wed, 15 Jul 2020 09:10:58 +0200 Subject: [PATCH 0018/1140] add icons dependency --- pubspec.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/pubspec.yaml b/pubspec.yaml index 0a55458d..dfc3fbcd 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -24,6 +24,7 @@ dependencies: stream_chat: ^0.2.0-alpha+20 mime: ^0.9.6+3 visibility_detector: ^0.1.5 + line_awesome_icons: ^1.0.4+2 http_parser: ^3.1.4 dev_dependencies: From 2541d5e4746066b707140f8b9d798e391c60e163 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Fri, 17 Jul 2020 16:48:12 +0200 Subject: [PATCH 0019/1140] add channel bottom sheet --- lib/src/channel_bottom_sheet.dart | 148 ++++++++++++++++++++++++++++++ lib/src/channel_header.dart | 26 ++---- lib/src/channel_image.dart | 14 ++- lib/src/channel_info.dart | 59 ++++++++++++ lib/src/channel_list_view.dart | 66 ++++++++++--- lib/src/channel_preview.dart | 118 +++++++++++++----------- lib/src/user_avatar.dart | 11 ++- 7 files changed, 346 insertions(+), 96 deletions(-) create mode 100644 lib/src/channel_bottom_sheet.dart create mode 100644 lib/src/channel_info.dart diff --git a/lib/src/channel_bottom_sheet.dart b/lib/src/channel_bottom_sheet.dart new file mode 100644 index 00000000..c3057d31 --- /dev/null +++ b/lib/src/channel_bottom_sheet.dart @@ -0,0 +1,148 @@ +import 'package:flutter/material.dart'; +import 'package:line_awesome_icons/line_awesome_icons.dart'; +import 'package:stream_chat/stream_chat.dart'; + +import 'channel_info.dart'; +import 'channel_name.dart'; +import 'stream_chat.dart'; +import 'stream_chat_theme.dart'; +import 'user_avatar.dart'; + +class ChannelBottomSheet extends StatelessWidget { + const ChannelBottomSheet({ + Key key, + @required this.channel, + }) : super(key: key); + + final Channel channel; + + @override + Widget build(BuildContext context) { + return SafeArea( + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Padding( + padding: const EdgeInsets.symmetric( + vertical: 2.0, + ), + child: Center( + child: ChannelName( + channel: channel, + textStyle: + StreamChatTheme.of(context).channelPreviewTheme.title, + ), + ), + ), + Padding( + padding: const EdgeInsets.symmetric( + vertical: 2.0, + ), + child: Center( + child: ChannelInfo( + channel: channel, + textStyle: + StreamChatTheme.of(context).channelPreviewTheme.subtitle, + ), + ), + ), + Padding( + padding: const EdgeInsets.symmetric( + vertical: 15.0, + ), + child: Center( + child: StreamBuilder>( + stream: channel.state.membersStream.map((event) => event + .where((m) => m.userId != StreamChat.of(context).user.id) + .toList()), + initialData: channel.state.members + .where((m) => m.userId != StreamChat.of(context).user.id) + .toList(), + builder: _buildMembers, + ), + ), + ), + Divider(), + StreamBuilder( + stream: channel.isMutedStream, + initialData: channel.isMuted, + builder: (context, snapshot) { + return SwitchListTile( + onChanged: (bool muted) async { + if (muted) { + await channel.mute(); + } else { + await channel.unmute(); + } + }, + value: snapshot.data, + title: Row( + children: [ + Padding( + padding: const EdgeInsets.only(right: 22.0), + child: Icon(LineAwesomeIcons.volume_off), + ), + Text('Mute'), + ], + ), + ); + }), + ], + ), + ), + ); + } + + Widget _buildMembers( + BuildContext context, + AsyncSnapshot> snapshot, + ) { + if (snapshot.data.isEmpty) { + return SizedBox(); + } + + return Container( + height: 83, + child: ListView( + padding: EdgeInsets.only( + left: (MediaQuery.of(context).size.width / 2) - 48, + ), + scrollDirection: Axis.horizontal, + children: snapshot.data.map((m) { + return Padding( + padding: const EdgeInsets.symmetric( + horizontal: 8.0, + ), + child: Column( + children: [ + UserAvatar( + showOnlineStatus: true, + user: m.user, + borderRadius: BorderRadius.circular(32), + constraints: BoxConstraints.tight( + Size.square(64), + ), + ), + Padding( + padding: const EdgeInsets.only(top: 5.0), + child: Text( + m.user.name?.split(' ')?.elementAt(0), + style: StreamChatTheme.of(context) + .channelPreviewTheme + .title + .copyWith( + fontSize: 12, + ), + ), + ), + ], + ), + ); + }).toList(), + ), + ); + } +} diff --git a/lib/src/channel_header.dart b/lib/src/channel_header.dart index 5a7a146c..e257fbbc 100644 --- a/lib/src/channel_header.dart +++ b/lib/src/channel_header.dart @@ -1,6 +1,6 @@ import 'package:flutter/material.dart'; -import 'package:jiffy/jiffy.dart'; import 'package:stream_chat/stream_chat.dart'; +import 'package:stream_chat_flutter/src/channel_info.dart'; import 'package:stream_chat_flutter/src/channel_name.dart'; import 'package:stream_chat_flutter/src/stream_chat_theme.dart'; @@ -107,7 +107,11 @@ class ChannelHeader extends StatelessWidget implements PreferredSizeWidget { .channelHeaderTheme .title, ), - _buildLastActive(context, channel), + ChannelInfo( + channel: channel, + textStyle: + StreamChatTheme.of(context).channelPreviewTheme.subtitle, + ), ], ), ), @@ -115,24 +119,6 @@ class ChannelHeader extends StatelessWidget implements PreferredSizeWidget { ); } - Widget _buildLastActive(BuildContext context, Channel channel) { - return StreamBuilder( - stream: channel.lastMessageAtStream, - initialData: channel.lastMessageAt, - builder: (context, snapshot) { - return (snapshot.data != null) - ? Text( - 'Active ${Jiffy(snapshot.data.toLocal()).fromNow()}', - style: StreamChatTheme.of(context) - .channelTheme - .channelHeaderTheme - .lastMessageAt, - ) - : SizedBox(); - }, - ); - } - Padding _buildBackButton(BuildContext context) { return Padding( padding: const EdgeInsets.all(14.0), diff --git a/lib/src/channel_image.dart b/lib/src/channel_image.dart index 113d6de0..3bdc3b2a 100644 --- a/lib/src/channel_image.dart +++ b/lib/src/channel_image.dart @@ -51,8 +51,11 @@ class ChannelImage extends StatelessWidget { this.constraints, this.onTap, this.showOnlineStatus = true, + this.borderRadius, }) : super(key: key); + final BorderRadius borderRadius; + /// The channel to show the image of final Channel channel; @@ -84,6 +87,7 @@ class ChannelImage extends StatelessWidget { initialData: otherMember.user, builder: (context, snapshot) { return UserAvatar( + borderRadius: borderRadius, user: snapshot.data ?? otherMember.user, constraints: constraints ?? StreamChatTheme.of(context) @@ -117,10 +121,11 @@ class ChannelImage extends StatelessWidget { } return ClipRRect( - borderRadius: StreamChatTheme.of(context) - .channelPreviewTheme - .avatarTheme - .borderRadius, + borderRadius: borderRadius ?? + StreamChatTheme.of(context) + .channelPreviewTheme + .avatarTheme + .borderRadius, child: Container( constraints: constraints ?? StreamChatTheme.of(context) @@ -131,7 +136,6 @@ class ChannelImage extends StatelessWidget { color: StreamChatTheme.of(context).accentColor, ), child: Stack( - fit: StackFit.expand, children: [ image != null ? CachedNetworkImage( diff --git a/lib/src/channel_info.dart b/lib/src/channel_info.dart new file mode 100644 index 00000000..af1915a3 --- /dev/null +++ b/lib/src/channel_info.dart @@ -0,0 +1,59 @@ +import 'package:flutter/material.dart'; +import 'package:jiffy/jiffy.dart'; +import 'package:stream_chat_flutter/stream_chat_flutter.dart'; + +class ChannelInfo extends StatelessWidget { + final Channel channel; + + /// The style of the text displayed + final TextStyle textStyle; + + const ChannelInfo({ + Key key, + @required this.channel, + this.textStyle, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + if (channel.memberCount > 2) { + return Text( + '${channel.memberCount} Members, ${channel.state.watcherCount} Online', + style: StreamChatTheme.of(context) + .channelTheme + .channelHeaderTheme + .lastMessageAt, + ); + } else { + return StreamBuilder>( + stream: channel.state.membersStream, + initialData: channel.state.members, + builder: (context, snapshot) { + final otherMember = snapshot.data.firstWhere( + (element) => element.userId != StreamChat.of(context).user.id, + orElse: () => null, + ); + + if (otherMember == null) { + return SizedBox(); + } + + if (otherMember.user.online) { + return Text( + 'Online', + style: StreamChatTheme.of(context) + .channelTheme + .channelHeaderTheme + .lastMessageAt, + ); + } + + return Text( + 'Last seen ${Jiffy(otherMember.user.lastActive).fromNow()}', + style: textStyle, + ); + }, + ); + } + } +} diff --git a/lib/src/channel_list_view.dart b/lib/src/channel_list_view.dart index 9b4cab61..3329382f 100644 --- a/lib/src/channel_list_view.dart +++ b/lib/src/channel_list_view.dart @@ -1,8 +1,10 @@ import 'package:flutter/material.dart'; +import 'package:flutter_slidable/flutter_slidable.dart'; import 'package:stream_chat/stream_chat.dart'; import 'package:stream_chat_flutter/src/channels_bloc.dart'; import '../stream_chat_flutter.dart'; +import 'channel_bottom_sheet.dart'; import 'channel_preview.dart'; import 'stream_channel.dart'; import 'stream_chat.dart'; @@ -60,11 +62,15 @@ class ChannelListView extends StatefulWidget { this.channelPreviewBuilder, this.errorBuilder, this.onImageTap, + this.swipeToAction = false, }) : super(key: key); /// The builder that will be used in case of error final Widget Function(Error error) errorBuilder; + /// If true a default swipe to action behaviour will be added to this widget + final bool swipeToAction; + /// The query filters to use. /// You can query on any of the custom fields you've defined on the [Channel]. /// You can also filter other built-in channel fields. @@ -274,17 +280,55 @@ class _ChannelListViewState extends State ], ); } else { - child = ChannelPreview( - onLongPress: widget.onChannelLongPress, - channel: channel, - onImageTap: widget.onImageTap != null - ? () { - widget.onImageTap(channel); - } - : null, - onTap: (channel) { - onTap(channel, widget.channelWidget); - }, + child = Slidable( + enabled: widget.swipeToAction, + actionPane: SlidableBehindActionPane(), + actionExtentRatio: 0.12, + closeOnScroll: true, + secondaryActions: [ + IconSlideAction( + color: Color(0xffEBEBEB), + icon: Icons.more_horiz, + onTap: () { + showModalBottomSheet( + clipBehavior: Clip.hardEdge, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.only( + topLeft: Radius.circular(32), + topRight: Radius.circular(32), + ), + ), + context: context, + builder: (context) { + return ChannelBottomSheet(channel: channel); + }, + ); + }, + ), + IconSlideAction( + color: Color(0xffEBEBEB), + icon: Icons.notifications_none, + ), + IconSlideAction( + color: Color(0xffEBEBEB), + icon: Icons.delete, + ), + ], + child: Container( + color: StreamChatTheme.of(context).backgroundColor, + child: ChannelPreview( + onLongPress: widget.onChannelLongPress, + channel: channel, + onImageTap: widget.onImageTap != null + ? () { + widget.onImageTap(channel); + } + : null, + onTap: (channel) { + onTap(channel, widget.channelWidget); + }, + ), + ), ); } return child; diff --git a/lib/src/channel_preview.dart b/lib/src/channel_preview.dart index 31a986ce..de6c8222 100644 --- a/lib/src/channel_preview.dart +++ b/lib/src/channel_preview.dart @@ -43,65 +43,71 @@ class ChannelPreview extends StatelessWidget { @override Widget build(BuildContext context) { - return Opacity( - opacity: channel.isMuted ? 0.5 : 1, - child: ListTile( - onTap: () { - if (onTap != null) { - onTap(channel); - } - }, - onLongPress: () { - if (onLongPress != null) { - onLongPress(channel); - } - }, - leading: ChannelImage( - onTap: onImageTap, - ), - title: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Flexible( - child: ChannelName( - textStyle: - StreamChatTheme.of(context).channelPreviewTheme.title, - ), - ), - if (channel.state.unreadCount > 0) - UnreadIndicator( - channel: channel, - ), - ], - ), - subtitle: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Flexible(child: _buildSubtitle(context)), - Builder( - builder: (context) { - if (channel.state.lastMessage?.user?.id == - StreamChat.of(context).user.id) { - return Padding( - padding: const EdgeInsets.only(right: 4.0), - child: SendingIndicator( - message: channel.state.lastMessage, - allRead: channel.state.read - .where((element) => element.lastRead - .isAfter(channel.state.lastMessage.createdAt)) - .length == - channel.memberCount - 1, - ), - ); + return StreamBuilder( + stream: channel.isMutedStream, + initialData: channel.isMuted, + builder: (context, snapshot) { + return Opacity( + opacity: snapshot.data ? 0.5 : 1, + child: ListTile( + onTap: () { + if (onTap != null) { + onTap(channel); } - return SizedBox(); }, + onLongPress: () { + if (onLongPress != null) { + onLongPress(channel); + } + }, + leading: ChannelImage( + onTap: onImageTap, + ), + title: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Flexible( + child: ChannelName( + textStyle: + StreamChatTheme.of(context).channelPreviewTheme.title, + ), + ), + if (channel.state.unreadCount > 0) + UnreadIndicator( + channel: channel, + ), + ], + ), + subtitle: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Flexible(child: _buildSubtitle(context)), + Builder( + builder: (context) { + if (channel.state.lastMessage?.user?.id == + StreamChat.of(context).user.id) { + return Padding( + padding: const EdgeInsets.only(right: 4.0), + child: SendingIndicator( + message: channel.state.lastMessage, + allRead: channel.state.read + .where((element) => element.lastRead + .isAfter(channel + .state.lastMessage.createdAt)) + .length == + channel.memberCount - 1, + ), + ); + } + return SizedBox(); + }, + ), + _buildDate(context), + ], + ), ), - _buildDate(context), - ], - ), - ), - ); + ); + }); } Widget _buildDate(BuildContext context) { diff --git a/lib/src/user_avatar.dart b/lib/src/user_avatar.dart index 33e8ab90..a3d5b6f5 100644 --- a/lib/src/user_avatar.dart +++ b/lib/src/user_avatar.dart @@ -12,10 +12,12 @@ class UserAvatar extends StatelessWidget { this.onlineIndicatorConstraints, this.onTap, this.showOnlineStatus = true, + this.borderRadius, }) : super(key: key); final User user; final BoxConstraints constraints; + final BorderRadius borderRadius; final BoxConstraints onlineIndicatorConstraints; final void Function(User) onTap; final bool showOnlineStatus; @@ -33,10 +35,11 @@ class UserAvatar extends StatelessWidget { child: Stack( children: [ ClipRRect( - borderRadius: StreamChatTheme.of(context) - .ownMessageTheme - .avatarTheme - .borderRadius, + borderRadius: borderRadius ?? + StreamChatTheme.of(context) + .ownMessageTheme + .avatarTheme + .borderRadius, child: Container( constraints: constraints ?? StreamChatTheme.of(context) From d99afe7e63ef664730c9ac2c3508e2084677aa3e Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Mon, 20 Jul 2020 15:33:21 +0200 Subject: [PATCH 0020/1140] add mute and delete channel --- assets/icon_user_minus.svg | 5 ++ lib/src/channel_bottom_sheet.dart | 85 ++++++++++++++++++++++++------- lib/src/channel_list_view.dart | 56 ++++++++++++++++++-- lib/src/utils.dart | 30 +++++++++++ 4 files changed, 154 insertions(+), 22 deletions(-) create mode 100644 assets/icon_user_minus.svg diff --git a/assets/icon_user_minus.svg b/assets/icon_user_minus.svg new file mode 100644 index 00000000..47210701 --- /dev/null +++ b/assets/icon_user_minus.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/lib/src/channel_bottom_sheet.dart b/lib/src/channel_bottom_sheet.dart index c3057d31..a2f124fc 100644 --- a/lib/src/channel_bottom_sheet.dart +++ b/lib/src/channel_bottom_sheet.dart @@ -1,6 +1,9 @@ +import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_svg/flutter_svg.dart'; import 'package:line_awesome_icons/line_awesome_icons.dart'; import 'package:stream_chat/stream_chat.dart'; +import 'package:stream_chat_flutter/src/utils.dart'; import 'channel_info.dart'; import 'channel_name.dart'; @@ -70,26 +73,74 @@ class ChannelBottomSheet extends StatelessWidget { stream: channel.isMutedStream, initialData: channel.isMuted, builder: (context, snapshot) { - return SwitchListTile( - onChanged: (bool muted) async { - if (muted) { - await channel.mute(); - } else { - await channel.unmute(); - } - }, - value: snapshot.data, - title: Row( - children: [ - Padding( - padding: const EdgeInsets.only(right: 22.0), - child: Icon(LineAwesomeIcons.volume_off), - ), - Text('Mute'), - ], + return ListTile( + leading: Icon( + LineAwesomeIcons.volume_off, + size: 22, + color: StreamChatTheme.of(context).primaryIconTheme.color, + ), + title: Text('Mute ${channel.isGroup ? 'group' : 'user'}'), + trailing: Switch( + onChanged: (bool muted) async { + if (muted) { + await channel.mute(); + } else { + await channel.unmute(); + } + }, + value: snapshot.data, ), ); }), + Divider(), + if (channel.isGroup && !channel.isDistinct) + ListTile( + leading: SvgPicture.asset( + 'assets/icon_user_minus.svg', + package: 'stream_chat_flutter', + width: 22, + ), + title: Text('Leave Group'), + onTap: () async { + final confirm = await showConfirmationDialog( + context, + 'Do you want to leave the group?', + ); + if (confirm == true) { + await channel.removeMembers(channel.state.members + .where((element) => + element.userId == StreamChat.of(context).user.id) + .toList()); + Navigator.pop(context); + } + }, + ), + if (!channel.isGroup && !channel.isDistinct) + ListTile( + leading: Icon( + Icons.delete_outline, + color: Color(0xFFFF3742), + ), + title: Text( + 'Delete chat', + style: TextStyle( + color: Color(0xFFFF3742), + ), + ), + onTap: () async { + final confirm = await showConfirmationDialog( + context, + 'Do you want to delete the chat?', + ); + if (confirm == true) { + await channel.removeMembers(channel.state.members + .where((element) => + element.userId == StreamChat.of(context).user.id) + .toList()); + Navigator.pop(context); + } + }, + ), ], ), ), diff --git a/lib/src/channel_list_view.dart b/lib/src/channel_list_view.dart index 3329382f..4b77f784 100644 --- a/lib/src/channel_list_view.dart +++ b/lib/src/channel_list_view.dart @@ -1,7 +1,10 @@ import 'package:flutter/material.dart'; import 'package:flutter_slidable/flutter_slidable.dart'; +import 'package:flutter_svg/flutter_svg.dart'; +import 'package:line_awesome_icons/line_awesome_icons.dart'; import 'package:stream_chat/stream_chat.dart'; import 'package:stream_chat_flutter/src/channels_bloc.dart'; +import 'package:stream_chat_flutter/src/utils.dart'; import '../stream_chat_flutter.dart'; import 'channel_bottom_sheet.dart'; @@ -307,12 +310,55 @@ class _ChannelListViewState extends State ), IconSlideAction( color: Color(0xffEBEBEB), - icon: Icons.notifications_none, - ), - IconSlideAction( - color: Color(0xffEBEBEB), - icon: Icons.delete, + icon: LineAwesomeIcons.volume_off, + onTap: () async { + if (!channel.isMuted) { + await channel.mute(); + } else { + await channel.unmute(); + } + }, ), + if (channel.isGroup && !channel.isDistinct) + IconSlideAction( + color: Color(0xffEBEBEB), + iconWidget: SvgPicture.asset( + 'assets/icon_user_minus.svg', + package: 'stream_chat_flutter', + width: 22, + ), + onTap: () async { + final confirm = await showConfirmationDialog( + context, + 'Do you want to leave the group?', + ); + if (confirm == true) { + await channel.removeMembers(channel.state.members + .where((element) => + element.userId == + StreamChat.of(context).user.id) + .toList()); + } + }, + ), + if (!channel.isGroup && !channel.isDistinct) + IconSlideAction( + color: Color(0xffEBEBEB), + icon: Icons.delete_outline, + onTap: () async { + final confirm = await showConfirmationDialog( + context, + 'Do you want to delete the chat?', + ); + if (confirm == true) { + await channel.removeMembers(channel.state.members + .where((element) => + element.userId == + StreamChat.of(context).user.id) + .toList()); + } + }, + ), ], child: Container( color: StreamChatTheme.of(context).backgroundColor, diff --git a/lib/src/utils.dart b/lib/src/utils.dart index c427099b..b20e5f59 100644 --- a/lib/src/utils.dart +++ b/lib/src/utils.dart @@ -12,3 +12,33 @@ Future launchURL(BuildContext context, String url) async { ); } } + +Future showConfirmationDialog( + BuildContext context, + String question, +) { + return showDialog( + context: context, + builder: (context) { + return AlertDialog( + title: Text(question), + actions: [ + FlatButton( + child: Text('Ok'), + onPressed: () => Navigator.pop( + context, + true, + ), + ), + FlatButton( + child: Text('Cancel'), + onPressed: () => Navigator.pop( + context, + false, + ), + ), + ], + ); + }, + ); +} From 39551e7cda7e5cc1cb0bb9c23f15cb7cad1105df Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Mon, 20 Jul 2020 16:18:58 +0200 Subject: [PATCH 0021/1140] update actions --- .github/workflows/main.yml | 82 +++++++++++++++++++++++++------------- 1 file changed, 55 insertions(+), 27 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 6e56f2be..622f5eb0 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -10,7 +10,7 @@ on: release: types: - created - + env: flutter_version: "1.12.13+hotfix.5" @@ -18,29 +18,57 @@ jobs: test: runs-on: [ubuntu-latest] steps: - - uses: actions/checkout@v2 - - name: Cache Flutter dependencies - id: cache - uses: actions/cache@v1 - with: - path: /opt/hostedtoolcache/flutter - key: ${{ runner.OS }}-flutter-install-cache-${{ env.flutter_version }} - - name: Flutter action - uses: subosito/flutter-action@v1.1.1 - with: - flutter-version: ${{ env.flutter_version }} - - name: Get dependencies - run: flutter pub get - - name: Coverage fix - run: | - file=test/coverage_helper_test.dart - echo "// Helper file to make coverage work for all dart files\n" > $file - echo "// ignore_for_file: unused_import" >> $file - find lib -name '*.dart' | grep -e '[^g]\.dart' | grep -v '_html.dart' | cut -c4- | awk -v package=stream_chat_flutter '{printf "import '\''package:%s%s'\'';\n", package, $1}' >> $file - echo "" >> $file - echo "void main(){}" >> $file - cat $file - - name: Run tests - run: flutter test --coverage - - name: Codecov - run: bash <(curl -s https://codecov.io/bash) -c -t ${{ secrets.CODECOV_TOKEN }} -f coverage/lcov.info -F flutter_tool + - uses: actions/checkout@v2 + - name: Cache Flutter dependencies + id: cache + uses: actions/cache@v1 + with: + path: /opt/hostedtoolcache/flutter + key: ${{ runner.OS }}-flutter-install-cache-${{ env.flutter_version }} + - name: Flutter action + uses: subosito/flutter-action@v1.1.1 + with: + flutter-version: ${{ env.flutter_version }} + - name: Get dependencies + run: flutter pub get + - name: Coverage fix + run: | + file=test/coverage_helper_test.dart + echo "// Helper file to make coverage work for all dart files\n" > $file + echo "// ignore_for_file: unused_import" >> $file + find lib -name '*.dart' | grep -e '[^g]\.dart' | grep -v '_html.dart' | cut -c4- | awk -v package=stream_chat_flutter '{printf "import '\''package:%s%s'\'';\n", package, $1}' >> $file + echo "" >> $file + echo "void main(){}" >> $file + cat $file + - name: Run tests + run: flutter test --coverage + - name: Codecov + run: bash <(curl -s https://codecov.io/bash) -c -t ${{ secrets.CODECOV_TOKEN }} -f coverage/lcov.info -F flutter_tool + build_and_deploy: + name: Build + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: actions/checkout@v1 + - uses: actions/setup-java@v1 + with: + java-version: '12.x' + - uses: subosito/flutter-action@v1.1.1 + with: + flutter-version: ${{ env.flutter_version }} + - run: flutter pub get + - name: Build + run: flutter build apk + - name: Upload + uses: actions/upload-artifact@master + with: + name: apk-build + path: example/build/app/outputs/bundle/release + - name: Deploy + #if: github.base_ref == 'master' + uses: wzieba/Firebase-Distribution-Github-Action@v1.2.1 + with: + appId: ${{secrets.FIREBASE_ANDROID_APPID}} + token: ${{secrets.FIREBASE_TOKEN}} + groups: stream-testers + file: example/build/app/outputs/apk/release/app-release.apk From 07cdec83058a5e08a94ad05a3f3498c4d607d590 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Mon, 20 Jul 2020 17:24:22 +0200 Subject: [PATCH 0022/1140] update actions --- .github/workflows/main.yml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 622f5eb0..da511672 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -2,14 +2,14 @@ name: CI on: push: - branches: - - master - pull_request: - branches: - - master - release: - types: - - created +# branches: +# - master +# pull_request: +# branches: +# - master +# release: +# types: +# - created env: flutter_version: "1.12.13+hotfix.5" From 89069b4bfa266665a849ab725d560eefca65539c Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Mon, 20 Jul 2020 17:28:07 +0200 Subject: [PATCH 0023/1140] update actions --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index da511672..77271796 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -12,7 +12,7 @@ on: # - created env: - flutter_version: "1.12.13+hotfix.5" + flutter_version: "1.17.5" jobs: test: From 0bb4a866fb9496f64d8303efd886a7abf26df6c8 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Mon, 20 Jul 2020 17:30:06 +0200 Subject: [PATCH 0024/1140] update actions --- .github/workflows/main.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 77271796..2f60dc8f 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -26,7 +26,7 @@ jobs: path: /opt/hostedtoolcache/flutter key: ${{ runner.OS }}-flutter-install-cache-${{ env.flutter_version }} - name: Flutter action - uses: subosito/flutter-action@v1.1.1 + uses: subosito/flutter-action@v1.3.2 with: flutter-version: ${{ env.flutter_version }} - name: Get dependencies @@ -53,7 +53,7 @@ jobs: - uses: actions/setup-java@v1 with: java-version: '12.x' - - uses: subosito/flutter-action@v1.1.1 + - uses: subosito/flutter-action@v1.3.2 with: flutter-version: ${{ env.flutter_version }} - run: flutter pub get From 1a8edea24e2c1a2bb347e61cdae84e4e03c7da7c Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Mon, 20 Jul 2020 17:33:23 +0200 Subject: [PATCH 0025/1140] update actions --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 2f60dc8f..723f4613 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -24,7 +24,7 @@ jobs: uses: actions/cache@v1 with: path: /opt/hostedtoolcache/flutter - key: ${{ runner.OS }}-flutter-install-cache-${{ env.flutter_version }} + key: ${{ runner.OS }}-flutter-cache-${{ env.flutter_version }} - name: Flutter action uses: subosito/flutter-action@v1.3.2 with: From 8d52681069d1de4a2a72b77c6afd45d772e00959 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Mon, 20 Jul 2020 17:37:04 +0200 Subject: [PATCH 0026/1140] update actions --- .github/workflows/main.yml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 723f4613..48980157 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -56,9 +56,13 @@ jobs: - uses: subosito/flutter-action@v1.3.2 with: flutter-version: ${{ env.flutter_version }} - - run: flutter pub get + - run: | + cd example + flutter pub get - name: Build - run: flutter build apk + run: | + cd example + flutter build apk - name: Upload uses: actions/upload-artifact@master with: From 5598fbc0f7269d4935969681acd389bb987cab49 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Mon, 20 Jul 2020 17:52:24 +0200 Subject: [PATCH 0027/1140] update dependencies --- example/lib/main.dart | 3 ++- pubspec.yaml | 8 +++++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/example/lib/main.dart b/example/lib/main.dart index 682601ef..a8d4f813 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -67,7 +67,7 @@ void _initNotifications(Client client) { void main() async { final client = Client( 's2dxdhpxd94g', - logLevel: Level.FINEST, + logLevel: Level.ALL, showLocalNotification: Platform.isAndroid ? showLocalNotification : null, persistenceEnabled: true, ); @@ -112,6 +112,7 @@ class ChannelListPage extends StatelessWidget { return Scaffold( body: ChannelsBloc( child: ChannelListView( + swipeToAction: true, filter: { 'members': { '\$in': [StreamChat.of(context).user.id], diff --git a/pubspec.yaml b/pubspec.yaml index 50af3113..bb45e910 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -23,11 +23,17 @@ dependencies: file_picker: ^1.12.0 image_picker: ^0.6.7+2 flutter_keyboard_visibility: ^3.2.1 - stream_chat: ^0.2.0+2 + stream_chat: ^0.2.1 + flutter_svg: ^0.17.0 mime: ^0.9.6+3 visibility_detector: ^0.1.5 line_awesome_icons: ^1.0.4+2 http_parser: ^3.1.4 + flutter_slidable: ^0.5.4 + +flutter: + assets: + - assets/ dev_dependencies: pedantic: ^1.9.0 From a5cf2c5875fc4210cf523468b46bdea00077c2ad Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Tue, 21 Jul 2020 09:45:01 +0200 Subject: [PATCH 0028/1140] add google-services.json to git --- .gitignore | 3 +- example/android/app/google-services.json | 235 +++++++++++++++++++++++ 2 files changed, 236 insertions(+), 2 deletions(-) create mode 100644 example/android/app/google-services.json diff --git a/.gitignore b/.gitignore index 457042a0..28b825a6 100644 --- a/.gitignore +++ b/.gitignore @@ -59,5 +59,4 @@ doc/api/ *.js.deps *.js.map -fvm -google-services.json \ No newline at end of file +fvm \ No newline at end of file diff --git a/example/android/app/google-services.json b/example/android/app/google-services.json new file mode 100644 index 00000000..fa5842bf --- /dev/null +++ b/example/android/app/google-services.json @@ -0,0 +1,235 @@ +{ + "project_info": { + "project_number": "674907137625", + "firebase_url": "https://stream-chat-internal.firebaseio.com", + "project_id": "stream-chat-internal", + "storage_bucket": "stream-chat-internal.appspot.com" + }, + "client": [ + { + "client_info": { + "mobilesdk_app_id": "1:674907137625:android:e55b74fd5747e39ad7f348", + "android_client_info": { + "package_name": "com.example.example" + } + }, + "oauth_client": [ + { + "client_id": "674907137625-o5iqvv6dtmljtn069b5djv19ad9a7js0.apps.googleusercontent.com", + "client_type": 3 + } + ], + "api_key": [ + { + "current_key": "AIzaSyBArS4RH7lUn3xbD-jhzWl5hVWZhliRgY0" + } + ], + "services": { + "appinvite_service": { + "other_platform_oauth_client": [ + { + "client_id": "674907137625-o5iqvv6dtmljtn069b5djv19ad9a7js0.apps.googleusercontent.com", + "client_type": 3 + }, + { + "client_id": "674907137625-flarfn9cefu4lermgpbc4b8rm8l15ian.apps.googleusercontent.com", + "client_type": 2, + "ios_info": { + "bundle_id": "io.getstream.flutter" + } + } + ] + } + } + }, + { + "client_info": { + "mobilesdk_app_id": "1:674907137625:android:05257db0ea1f2505d7f348", + "android_client_info": { + "package_name": "io.getstream.chat.android.client.sample" + } + }, + "oauth_client": [ + { + "client_id": "674907137625-o5iqvv6dtmljtn069b5djv19ad9a7js0.apps.googleusercontent.com", + "client_type": 3 + } + ], + "api_key": [ + { + "current_key": "AIzaSyBArS4RH7lUn3xbD-jhzWl5hVWZhliRgY0" + } + ], + "services": { + "appinvite_service": { + "other_platform_oauth_client": [ + { + "client_id": "674907137625-o5iqvv6dtmljtn069b5djv19ad9a7js0.apps.googleusercontent.com", + "client_type": 3 + }, + { + "client_id": "674907137625-flarfn9cefu4lermgpbc4b8rm8l15ian.apps.googleusercontent.com", + "client_type": 2, + "ios_info": { + "bundle_id": "io.getstream.flutter" + } + } + ] + } + } + }, + { + "client_info": { + "mobilesdk_app_id": "1:674907137625:android:c41e48c4c799aee8d7f348", + "android_client_info": { + "package_name": "io.getstream.chat.example" + } + }, + "oauth_client": [ + { + "client_id": "674907137625-o5iqvv6dtmljtn069b5djv19ad9a7js0.apps.googleusercontent.com", + "client_type": 3 + } + ], + "api_key": [ + { + "current_key": "AIzaSyBArS4RH7lUn3xbD-jhzWl5hVWZhliRgY0" + } + ], + "services": { + "appinvite_service": { + "other_platform_oauth_client": [ + { + "client_id": "674907137625-o5iqvv6dtmljtn069b5djv19ad9a7js0.apps.googleusercontent.com", + "client_type": 3 + }, + { + "client_id": "674907137625-flarfn9cefu4lermgpbc4b8rm8l15ian.apps.googleusercontent.com", + "client_type": 2, + "ios_info": { + "bundle_id": "io.getstream.flutter" + } + } + ] + } + } + }, + { + "client_info": { + "mobilesdk_app_id": "1:674907137625:android:c36d6f4ab7491192d7f348", + "android_client_info": { + "package_name": "io.getstream.chat.sample" + } + }, + "oauth_client": [ + { + "client_id": "674907137625-o5iqvv6dtmljtn069b5djv19ad9a7js0.apps.googleusercontent.com", + "client_type": 3 + } + ], + "api_key": [ + { + "current_key": "AIzaSyBArS4RH7lUn3xbD-jhzWl5hVWZhliRgY0" + } + ], + "services": { + "appinvite_service": { + "other_platform_oauth_client": [ + { + "client_id": "674907137625-o5iqvv6dtmljtn069b5djv19ad9a7js0.apps.googleusercontent.com", + "client_type": 3 + }, + { + "client_id": "674907137625-flarfn9cefu4lermgpbc4b8rm8l15ian.apps.googleusercontent.com", + "client_type": 2, + "ios_info": { + "bundle_id": "io.getstream.flutter" + } + } + ] + } + } + }, + { + "client_info": { + "mobilesdk_app_id": "1:674907137625:android:d91b4d966e372431d7f348", + "android_client_info": { + "package_name": "io.getstream.chat.sample.debug" + } + }, + "oauth_client": [ + { + "client_id": "674907137625-o5iqvv6dtmljtn069b5djv19ad9a7js0.apps.googleusercontent.com", + "client_type": 3 + } + ], + "api_key": [ + { + "current_key": "AIzaSyBArS4RH7lUn3xbD-jhzWl5hVWZhliRgY0" + } + ], + "services": { + "appinvite_service": { + "other_platform_oauth_client": [ + { + "client_id": "674907137625-o5iqvv6dtmljtn069b5djv19ad9a7js0.apps.googleusercontent.com", + "client_type": 3 + }, + { + "client_id": "674907137625-flarfn9cefu4lermgpbc4b8rm8l15ian.apps.googleusercontent.com", + "client_type": 2, + "ios_info": { + "bundle_id": "io.getstream.flutter" + } + } + ] + } + } + }, + { + "client_info": { + "mobilesdk_app_id": "1:674907137625:android:ff6593c705df1c43d7f348", + "android_client_info": { + "package_name": "io.getstream.chat.sdk" + } + }, + "oauth_client": [ + { + "client_id": "674907137625-khntpmmm3s1756v4jugnhcifgjlqrmd0.apps.googleusercontent.com", + "client_type": 1, + "android_info": { + "package_name": "io.getstream.chat.sdk", + "certificate_hash": "38f7d663a2ed58ae8990d365c41bd82df62185dc" + } + }, + { + "client_id": "674907137625-o5iqvv6dtmljtn069b5djv19ad9a7js0.apps.googleusercontent.com", + "client_type": 3 + } + ], + "api_key": [ + { + "current_key": "AIzaSyBArS4RH7lUn3xbD-jhzWl5hVWZhliRgY0" + } + ], + "services": { + "appinvite_service": { + "other_platform_oauth_client": [ + { + "client_id": "674907137625-o5iqvv6dtmljtn069b5djv19ad9a7js0.apps.googleusercontent.com", + "client_type": 3 + }, + { + "client_id": "674907137625-flarfn9cefu4lermgpbc4b8rm8l15ian.apps.googleusercontent.com", + "client_type": 2, + "ios_info": { + "bundle_id": "io.getstream.flutter" + } + } + ] + } + } + } + ], + "configuration_version": "1" +} \ No newline at end of file From 3367a4f890ff7031a8dc3ba7c4873e5f1312649d Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Tue, 21 Jul 2020 10:18:59 +0200 Subject: [PATCH 0029/1140] fix dark ui messages --- lib/src/channel_list_view.dart | 14 ++++++++++---- lib/src/date_divider.dart | 5 ++++- lib/src/stream_chat_theme.dart | 2 +- 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/lib/src/channel_list_view.dart b/lib/src/channel_list_view.dart index 4b77f784..11f4b402 100644 --- a/lib/src/channel_list_view.dart +++ b/lib/src/channel_list_view.dart @@ -283,6 +283,10 @@ class _ChannelListViewState extends State ], ); } else { + final backgroundColor = + Theme.of(context).brightness == Brightness.light + ? Color(0xffEBEBEB) + : Color(0xff141414); child = Slidable( enabled: widget.swipeToAction, actionPane: SlidableBehindActionPane(), @@ -290,7 +294,7 @@ class _ChannelListViewState extends State closeOnScroll: true, secondaryActions: [ IconSlideAction( - color: Color(0xffEBEBEB), + color: backgroundColor, icon: Icons.more_horiz, onTap: () { showModalBottomSheet( @@ -309,7 +313,7 @@ class _ChannelListViewState extends State }, ), IconSlideAction( - color: Color(0xffEBEBEB), + color: backgroundColor, icon: LineAwesomeIcons.volume_off, onTap: () async { if (!channel.isMuted) { @@ -321,10 +325,12 @@ class _ChannelListViewState extends State ), if (channel.isGroup && !channel.isDistinct) IconSlideAction( - color: Color(0xffEBEBEB), + color: backgroundColor, iconWidget: SvgPicture.asset( 'assets/icon_user_minus.svg', package: 'stream_chat_flutter', + color: + StreamChatTheme.of(context).primaryIconTheme.color, width: 22, ), onTap: () async { @@ -343,7 +349,7 @@ class _ChannelListViewState extends State ), if (!channel.isGroup && !channel.isDistinct) IconSlideAction( - color: Color(0xffEBEBEB), + color: backgroundColor, icon: Icons.delete_outline, onTap: () async { final confirm = await showConfirmationDialog( diff --git a/lib/src/date_divider.dart b/lib/src/date_divider.dart index 13f755d7..8fbe5f77 100644 --- a/lib/src/date_divider.dart +++ b/lib/src/date_divider.dart @@ -39,7 +39,10 @@ class DateDivider extends StatelessWidget { child: Container( padding: const EdgeInsets.symmetric(horizontal: 8), decoration: BoxDecoration( - color: Colors.black.withOpacity(0.5), + color: (Theme.of(context).brightness == Brightness.light + ? Colors.black + : Colors.white) + .withOpacity(0.5), borderRadius: BorderRadius.circular( 8, ), diff --git a/lib/src/stream_chat_theme.dart b/lib/src/stream_chat_theme.dart index 7df9eb7c..23dfa90a 100644 --- a/lib/src/stream_chat_theme.dart +++ b/lib/src/stream_chat_theme.dart @@ -287,7 +287,7 @@ class StreamChatThemeData { fontWeight: FontWeight.bold, fontSize: 12, ), - messageBackgroundColor: Color(0xffE6E6E6), + messageBackgroundColor: isDark ? Color(0xff191919) : Color(0xffE6E6E6), avatarTheme: AvatarTheme( borderRadius: BorderRadius.circular(20), constraints: BoxConstraints.tightFor( From d60ed9afd2cb87c198670fad538c1c50b70cc98f Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Tue, 21 Jul 2020 13:10:59 +0200 Subject: [PATCH 0030/1140] fix single channel image --- lib/src/channel_image.dart | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/src/channel_image.dart b/lib/src/channel_image.dart index 3bdc3b2a..f18f7a0a 100644 --- a/lib/src/channel_image.dart +++ b/lib/src/channel_image.dart @@ -136,6 +136,8 @@ class ChannelImage extends StatelessWidget { color: StreamChatTheme.of(context).accentColor, ), child: Stack( + alignment: Alignment.center, + fit: StackFit.expand, children: [ image != null ? CachedNetworkImage( From 900e634ca8c2e1013ec016342b60640d734077fe Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Tue, 21 Jul 2020 14:22:01 +0200 Subject: [PATCH 0031/1140] bump version using git hook --- example/pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 266926c8..e2edfdf7 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -1,7 +1,7 @@ name: example description: A new Flutter project. -version: 1.0.0+1 +version: 1.0.1+3 environment: sdk: ">=2.2.2 <3.0.0" From d03a70e39a980883c990fd60cf2970346c708c70 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Tue, 21 Jul 2020 15:25:04 +0200 Subject: [PATCH 0032/1140] update ios config --- example/ios/Podfile.lock | 24 ++++++++++++++++--- example/ios/Runner.xcodeproj/project.pbxproj | 12 +++++----- .../xcshareddata/WorkspaceSettings.xcsettings | 8 +++++++ example/pubspec.yaml | 2 +- 4 files changed, 36 insertions(+), 10 deletions(-) create mode 100644 example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock index a3821dbf..3afa0479 100644 --- a/example/ios/Podfile.lock +++ b/example/ios/Podfile.lock @@ -89,7 +89,7 @@ PODS: - Flutter (1.0.0) - flutter_apns (0.0.1): - Flutter - - flutter_keyboard_visibility (0.7.0): + - flutter_keyboard_visibility (0.0.1): - Flutter - flutter_local_notifications (0.0.1): - Flutter @@ -138,6 +138,8 @@ PODS: - nanopb/encode (0.3.9011) - path_provider (0.0.1): - Flutter + - path_provider_linux (0.0.1): + - Flutter - path_provider_macos (0.0.1): - Flutter - PromisesObjC (1.2.8) @@ -151,6 +153,8 @@ PODS: - SDWebImage/Core (~> 5.6) - shared_preferences (0.0.1): - Flutter + - shared_preferences_linux (0.0.1): + - Flutter - shared_preferences_macos (0.0.1): - Flutter - shared_preferences_web (0.0.1): @@ -165,6 +169,8 @@ PODS: - Starscream (~> 3.1) - url_launcher (0.0.1): - Flutter + - url_launcher_linux (0.0.1): + - Flutter - url_launcher_macos (0.0.1): - Flutter - url_launcher_web (0.0.1): @@ -187,13 +193,16 @@ DEPENDENCIES: - image_picker (from `.symlinks/plugins/image_picker/ios`) - moor_ffi (from `.symlinks/plugins/moor_ffi/ios`) - path_provider (from `.symlinks/plugins/path_provider/ios`) + - path_provider_linux (from `.symlinks/plugins/path_provider_linux/ios`) - path_provider_macos (from `.symlinks/plugins/path_provider_macos/ios`) - shared_preferences (from `.symlinks/plugins/shared_preferences/ios`) + - shared_preferences_linux (from `.symlinks/plugins/shared_preferences_linux/ios`) - shared_preferences_macos (from `.symlinks/plugins/shared_preferences_macos/ios`) - shared_preferences_web (from `.symlinks/plugins/shared_preferences_web/ios`) - sqflite (from `.symlinks/plugins/sqflite/ios`) - StreamChatClient - url_launcher (from `.symlinks/plugins/url_launcher/ios`) + - url_launcher_linux (from `.symlinks/plugins/url_launcher_linux/ios`) - url_launcher_macos (from `.symlinks/plugins/url_launcher_macos/ios`) - url_launcher_web (from `.symlinks/plugins/url_launcher_web/ios`) - video_player (from `.symlinks/plugins/video_player/ios`) @@ -250,10 +259,14 @@ EXTERNAL SOURCES: :path: ".symlinks/plugins/moor_ffi/ios" path_provider: :path: ".symlinks/plugins/path_provider/ios" + path_provider_linux: + :path: ".symlinks/plugins/path_provider_linux/ios" path_provider_macos: :path: ".symlinks/plugins/path_provider_macos/ios" shared_preferences: :path: ".symlinks/plugins/shared_preferences/ios" + shared_preferences_linux: + :path: ".symlinks/plugins/shared_preferences_linux/ios" shared_preferences_macos: :path: ".symlinks/plugins/shared_preferences_macos/ios" shared_preferences_web: @@ -262,6 +275,8 @@ EXTERNAL SOURCES: :path: ".symlinks/plugins/sqflite/ios" url_launcher: :path: ".symlinks/plugins/url_launcher/ios" + url_launcher_linux: + :path: ".symlinks/plugins/url_launcher_linux/ios" url_launcher_macos: :path: ".symlinks/plugins/url_launcher_macos/ios" url_launcher_web: @@ -290,7 +305,7 @@ SPEC CHECKSUMS: FLAnimatedImage: 4a0b56255d9b05f18b6dd7ee06871be5d3b89e31 Flutter: 0e3d915762c693b495b44d77113d4970485de6ec flutter_apns: f516b118e423fe7c0a38771180549c4d6cb67c2f - flutter_keyboard_visibility: 6195387fb6d8f46e5cd6dda4a4154e41f800f545 + flutter_keyboard_visibility: 0339d06371254c3eb25eeb90ba8d17dca8f9c069 flutter_local_notifications: 9e4738ce2471c5af910d961a6b7eadcf57c50186 flutter_plugin_android_lifecycle: dc0b544e129eebb77a6bfb1239d4d1c673a60a35 FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a @@ -299,10 +314,11 @@ SPEC CHECKSUMS: GoogleDataTransportCCTSupport: 32f75fbe904c82772fcbb6b6bd4525bfb6f2a862 GoogleUtilities: ad0f3b691c67909d03a3327cc205222ab8f42e0e GzipSwift: 893f3e48e597a1a4f62fafcb6514220fcf8287fa - image_picker: 66aa71bc96850a90590a35d4c4a2907b0d823109 + image_picker: 9c3312491f862b28d21ecd8fdf0ee14e601b3f09 moor_ffi: d66c9470c18e9cb333423bbcb493c105c6c774c6 nanopb: 18003b5e52dab79db540fe93fe9579f399bd1ccd path_provider: abfe2b5c733d04e238b0d8691db0cfd63a27a93c + path_provider_linux: 4d630dc393e1f20364f3e3b4a2ff41d9674a84e4 path_provider_macos: f760a3c5b04357c380e2fddb6f9db6f3015897e0 PromisesObjC: c119f3cd559f50b7ae681fa59dc1acd19173b7e6 Protobuf: 176220c526ad8bd09ab1fb40a978eac3fef665f7 @@ -310,12 +326,14 @@ SPEC CHECKSUMS: SDWebImage: 84000f962cbfa70c07f19d2234cbfcf5d779b5dc SDWebImageFLPlugin: 6c2295fb1242d44467c6c87dc5db6b0a13228fd8 shared_preferences: af6bfa751691cdc24be3045c43ec037377ada40d + shared_preferences_linux: afefbfe8d921e207f01ede8b60373d9e3b566b78 shared_preferences_macos: f3f29b71ccbb56bf40c9dd6396c9acf15e214087 shared_preferences_web: 141cce0c3ed1a1c5bf2a0e44f52d31eeb66e5ea9 sqflite: 4001a31ff81d210346b500c55b17f4d6c7589dd0 Starscream: 4bb2f9942274833f7b4d296a55504dcfc7edb7b0 StreamChatClient: 91b0f585e7dc92ade58e657daffafb16d485b2a6 url_launcher: 6fef411d543ceb26efce54b05a0a40bfd74cbbef + url_launcher_linux: ac237cb7a8058736e4aae38bdbcc748a4b394cc0 url_launcher_macos: fd7894421cd39320dce5f292fc99ea9270b2a313 url_launcher_web: e5527357f037c87560776e36436bf2b0288b965c video_player: 9cc823b1d9da7e8427ee591e8438bfbcde500e6e diff --git a/example/ios/Runner.xcodeproj/project.pbxproj b/example/ios/Runner.xcodeproj/project.pbxproj index 456c5e1f..6083a722 100644 --- a/example/ios/Runner.xcodeproj/project.pbxproj +++ b/example/ios/Runner.xcodeproj/project.pbxproj @@ -546,7 +546,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; - CODE_SIGN_IDENTITY = "iPhone Developer"; + CODE_SIGN_IDENTITY = "iPhone Distribution"; CODE_SIGN_STYLE = Manual; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; DEVELOPMENT_TEAM = EHV7XZLAHA; @@ -564,7 +564,7 @@ ); PRODUCT_BUNDLE_IDENTIFIER = io.getstream.flutter; PRODUCT_NAME = "$(TARGET_NAME)"; - PROVISIONING_PROFILE_SPECIFIER = "flutter app example"; + PROVISIONING_PROFILE_SPECIFIER = "flutter example"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_VERSION = 5.0; VERSIONING_SYSTEM = "apple-generic"; @@ -687,7 +687,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; - CODE_SIGN_IDENTITY = "iPhone Developer"; + CODE_SIGN_IDENTITY = "iPhone Distribution"; CODE_SIGN_STYLE = Manual; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; DEVELOPMENT_TEAM = EHV7XZLAHA; @@ -705,7 +705,7 @@ ); PRODUCT_BUNDLE_IDENTIFIER = io.getstream.flutter; PRODUCT_NAME = "$(TARGET_NAME)"; - PROVISIONING_PROFILE_SPECIFIER = "flutter app example"; + PROVISIONING_PROFILE_SPECIFIER = "flutter example"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 5.0; @@ -721,7 +721,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; - CODE_SIGN_IDENTITY = "iPhone Developer"; + CODE_SIGN_IDENTITY = "iPhone Distribution"; CODE_SIGN_STYLE = Manual; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; DEVELOPMENT_TEAM = EHV7XZLAHA; @@ -739,7 +739,7 @@ ); PRODUCT_BUNDLE_IDENTIFIER = io.getstream.flutter; PRODUCT_NAME = "$(TARGET_NAME)"; - PROVISIONING_PROFILE_SPECIFIER = "flutter app example"; + PROVISIONING_PROFILE_SPECIFIER = "flutter example"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_VERSION = 5.0; VERSIONING_SYSTEM = "apple-generic"; diff --git a/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 00000000..f9b0d7c5 --- /dev/null +++ b/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + PreviewsEnabled + + + diff --git a/example/pubspec.yaml b/example/pubspec.yaml index e2edfdf7..37be1464 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -1,7 +1,7 @@ name: example description: A new Flutter project. -version: 1.0.1+3 +version: 1.0.2+4 environment: sdk: ">=2.2.2 <3.0.0" From 02a3642894f3d24d06276c83b255d026bae2982c Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Thu, 23 Jul 2020 11:02:46 +0200 Subject: [PATCH 0033/1140] add image group --- lib/src/group_image.dart | 12 +--- lib/src/image_attachment.dart | 6 +- lib/src/image_group.dart | 99 ++++++++++++++++++++++++++ lib/src/message_widget.dart | 130 +++++++++++++++++++++------------- 4 files changed, 183 insertions(+), 64 deletions(-) create mode 100644 lib/src/image_group.dart diff --git a/lib/src/group_image.dart b/lib/src/group_image.dart index 91bdf7b0..2385007d 100644 --- a/lib/src/group_image.dart +++ b/lib/src/group_image.dart @@ -17,16 +17,6 @@ class GroupImage extends StatelessWidget { @override Widget build(BuildContext context) { - final secondRow = images - .skip(2) - .map((url) => Flexible( - child: CachedNetworkImage( - imageUrl: url, - fit: BoxFit.cover, - ), - )) - .toList(); - return GestureDetector( onTap: onTap, child: ClipRRect( @@ -81,7 +71,7 @@ class GroupImage extends StatelessWidget { )) .toList(), ), - ) + ), ], ), ), diff --git a/lib/src/image_attachment.dart b/lib/src/image_attachment.dart index a4bd1a0f..e05f401b 100644 --- a/lib/src/image_attachment.dart +++ b/lib/src/image_attachment.dart @@ -17,8 +17,8 @@ class ImageAttachment extends StatelessWidget { Key key, @required this.attachment, @required this.message, + @required this.size, this.messageTheme, - this.size, }) : super(key: key); @override @@ -30,8 +30,8 @@ class ImageAttachment extends StatelessWidget { attachment: attachment, ); } - return SizedBox.fromSize( - size: size, + return ConstrainedBox( + constraints: BoxConstraints.loose(size), child: Stack( children: [ Column( diff --git a/lib/src/image_group.dart b/lib/src/image_group.dart new file mode 100644 index 00000000..70acca23 --- /dev/null +++ b/lib/src/image_group.dart @@ -0,0 +1,99 @@ +import 'package:flutter/material.dart'; +import 'package:stream_chat/stream_chat.dart'; +import 'package:stream_chat_flutter/src/message_widget.dart'; + +class ImageGroup extends StatelessWidget { + const ImageGroup({ + Key key, + @required this.imageBuilder, + @required this.images, + @required this.message, + this.size, + }) : super(key: key); + + final AttachmentBuilder imageBuilder; + final List images; + final Message message; + final Size size; + + @override + Widget build(BuildContext context) { + return ConstrainedBox( + constraints: BoxConstraints.loose(size), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + FittedBox( + fit: BoxFit.cover, + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + imageBuilder( + context, + message, + images[0], + ), + Padding( + padding: const EdgeInsets.only(left: 4.0), + child: imageBuilder( + context, + message, + images[1], + ), + ), + ], + ), + ), + if (images.length >= 3) + Padding( + padding: const EdgeInsets.only(top: 2.0), + child: FittedBox( + fit: BoxFit.cover, + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + imageBuilder( + context, + message, + images[2], + ), + if (images.length >= 4) + Padding( + padding: const EdgeInsets.only(left: 4.0), + child: Stack( + children: [ + imageBuilder( + context, + message, + images[3], + ), + if (images.length > 4) + Positioned.fill( + child: Material( + color: Colors.black38, + child: InkWell( + onTap: () {}, + child: Center( + child: Text( + '${images.length - 4} +', + style: TextStyle( + color: Colors.white, + fontSize: 28, + ), + ), + ), + ), + ), + ), + ], + ), + ), + ], + ), + ), + ), + ], + ), + ); + } +} diff --git a/lib/src/message_widget.dart b/lib/src/message_widget.dart index 3103d079..09d9dc13 100644 --- a/lib/src/message_widget.dart +++ b/lib/src/message_widget.dart @@ -8,6 +8,7 @@ import 'package:flutter_portal/flutter_portal.dart'; import 'package:jiffy/jiffy.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; +import 'image_group.dart'; import 'message_actions_bottom_sheet.dart'; import 'message_text.dart'; @@ -272,6 +273,7 @@ class _MessageWidgetState extends State { : Column( crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, children: [ ..._parseAttachments(context), if (widget.message.text @@ -523,6 +525,30 @@ class _MessageWidgetState extends State { } List _parseAttachments(BuildContext context) { + final images = widget.message.attachments + .where((element) => element.type == 'image') + .toList(); + + if (images.length > 1) { + final imageBuilder = widget.attachmentBuilders['image']; + return [ + wrapAttachmentWidget( + context, + Material( + color: widget.messageTheme.messageBackgroundColor, + child: ImageGroup( + size: Size.fromWidth( + MediaQuery.of(context).size.width * 0.8, + ), + imageBuilder: imageBuilder, + images: images, + message: widget.message, + ), + ), + ), + ]; + } + return widget.message.attachments?.map((attachment) { final attachmentBuilder = widget.attachmentBuilders[attachment.type]; @@ -530,61 +556,65 @@ class _MessageWidgetState extends State { return SizedBox(); } - return Padding( - padding: EdgeInsets.only( - bottom: 4, - ), - child: GestureDetector( - onTap: () => retryMessage(context), - onLongPress: () => onLongPress(context), - child: Material( - color: _getBackgroundColor(), - clipBehavior: Clip.hardEdge, - shape: widget.attachmentShape ?? - widget.shape ?? - ContinuousRectangleBorder( - side: widget.attachmentBorderSide ?? - widget.borderSide ?? - BorderSide( - color: - Theme.of(context).brightness == Brightness.dark - ? Colors.white.withAlpha(24) - : Colors.black.withAlpha(24), - ), - borderRadius: widget.attachmentBorderRadiusGeometry ?? - widget.borderRadiusGeometry ?? - BorderRadius.zero, + final attachmentWidget = attachmentBuilder( + context, + widget.message, + attachment, + ); + return wrapAttachmentWidget(context, attachmentWidget); + })?.toList() ?? + []; + } + + Padding wrapAttachmentWidget(BuildContext context, Widget attachmentWidget) { + return Padding( + padding: EdgeInsets.only( + bottom: 4, + ), + child: GestureDetector( + onTap: () => retryMessage(context), + onLongPress: () => onLongPress(context), + child: Material( + color: _getBackgroundColor(), + clipBehavior: Clip.hardEdge, + shape: widget.attachmentShape ?? + widget.shape ?? + ContinuousRectangleBorder( + side: widget.attachmentBorderSide ?? + widget.borderSide ?? + BorderSide( + color: Theme.of(context).brightness == Brightness.dark + ? Colors.white.withAlpha(24) + : Colors.black.withAlpha(24), ), - child: Padding( - padding: widget.attachmentPadding, - child: ClipRRect( - borderRadius: BorderRadius.circular(6), - child: Transform( - transform: Matrix4.rotationY(widget.reverse ? pi : 0), - alignment: Alignment.center, - child: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.end, - children: [ - getFailedMessageWidget( - context, - padding: const EdgeInsets.all(8.0), - ), - attachmentBuilder( - context, - widget.message, - attachment, - ), - ], - ), + borderRadius: widget.attachmentBorderRadiusGeometry ?? + widget.borderRadiusGeometry ?? + BorderRadius.zero, + ), + child: Padding( + padding: widget.attachmentPadding, + child: ClipRRect( + borderRadius: BorderRadius.circular(6), + child: Transform( + transform: Matrix4.rotationY(widget.reverse ? pi : 0), + alignment: Alignment.center, + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.end, + children: [ + getFailedMessageWidget( + context, + padding: const EdgeInsets.all(8.0), ), - ), + attachmentWidget, + ], ), ), ), - ); - })?.toList() ?? - []; + ), + ), + ), + ); } void onLongPress(BuildContext context) { From 808cc223a10f3e0bedfe71312e274fe051a7a742 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Thu, 23 Jul 2020 13:57:16 +0200 Subject: [PATCH 0034/1140] add carousel on tap --- lib/src/full_screen_image.dart | 14 ++- lib/src/image_attachment.dart | 19 ++-- lib/src/image_group.dart | 161 ++++++++++++++++++++++----------- lib/src/message_widget.dart | 5 +- pubspec.yaml | 1 + 5 files changed, 130 insertions(+), 70 deletions(-) diff --git a/lib/src/full_screen_image.dart b/lib/src/full_screen_image.dart index c6f5804f..cc6a244a 100644 --- a/lib/src/full_screen_image.dart +++ b/lib/src/full_screen_image.dart @@ -15,14 +15,12 @@ class FullScreenImage extends StatelessWidget { @override Widget build(BuildContext context) { - return Container( - child: PhotoView( - imageProvider: CachedNetworkImageProvider(url), - maxScale: PhotoViewComputedScale.covered, - minScale: PhotoViewComputedScale.contained, - heroAttributes: PhotoViewHeroAttributes( - tag: url, - ), + return PhotoView( + imageProvider: CachedNetworkImageProvider(url), + maxScale: PhotoViewComputedScale.covered, + minScale: PhotoViewComputedScale.contained, + heroAttributes: PhotoViewHeroAttributes( + tag: url, ), ); } diff --git a/lib/src/image_attachment.dart b/lib/src/image_attachment.dart index e05f401b..ba11252a 100644 --- a/lib/src/image_attachment.dart +++ b/lib/src/image_attachment.dart @@ -39,13 +39,18 @@ class ImageAttachment extends StatelessWidget { Expanded( child: GestureDetector( onTap: () { - Navigator.push(context, MaterialPageRoute(builder: (_) { - return FullScreenImage( - url: attachment.imageUrl ?? - attachment.assetUrl ?? - attachment.thumbUrl, - ); - })); + Navigator.push( + context, + MaterialPageRoute( + builder: (_) { + return FullScreenImage( + url: attachment.imageUrl ?? + attachment.assetUrl ?? + attachment.thumbUrl, + ); + }, + ), + ); }, child: CachedNetworkImage( height: size?.height, diff --git a/lib/src/image_group.dart b/lib/src/image_group.dart index 70acca23..51b7be80 100644 --- a/lib/src/image_group.dart +++ b/lib/src/image_group.dart @@ -1,17 +1,18 @@ +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:carousel_slider/carousel_options.dart'; +import 'package:carousel_slider/carousel_slider.dart'; import 'package:flutter/material.dart'; import 'package:stream_chat/stream_chat.dart'; -import 'package:stream_chat_flutter/src/message_widget.dart'; +import 'package:stream_chat_flutter/src/full_screen_image.dart'; class ImageGroup extends StatelessWidget { const ImageGroup({ Key key, - @required this.imageBuilder, @required this.images, @required this.message, this.size, }) : super(key: key); - final AttachmentBuilder imageBuilder; final List images; final Message message; final Size size; @@ -20,72 +21,77 @@ class ImageGroup extends StatelessWidget { Widget build(BuildContext context) { return ConstrainedBox( constraints: BoxConstraints.loose(size), - child: Column( - mainAxisSize: MainAxisSize.min, + child: Flex( + direction: Axis.vertical, children: [ - FittedBox( - fit: BoxFit.cover, - child: Row( - mainAxisSize: MainAxisSize.min, + Flexible( + flex: 1, + fit: FlexFit.tight, + child: Flex( + crossAxisAlignment: CrossAxisAlignment.stretch, + direction: Axis.horizontal, children: [ - imageBuilder( - context, - message, - images[0], + Flexible( + flex: 1, + fit: FlexFit.tight, + child: _buildImage(context, 0), ), - Padding( - padding: const EdgeInsets.only(left: 4.0), - child: imageBuilder( - context, - message, - images[1], + Flexible( + flex: 1, + fit: FlexFit.tight, + child: Padding( + padding: const EdgeInsets.only(left: 2.0), + child: _buildImage(context, 1), ), ), ], ), ), if (images.length >= 3) - Padding( - padding: const EdgeInsets.only(top: 2.0), - child: FittedBox( - fit: BoxFit.cover, - child: Row( - mainAxisSize: MainAxisSize.min, + Flexible( + fit: FlexFit.tight, + flex: 1, + child: Padding( + padding: const EdgeInsets.only(top: 2.0), + child: Flex( + direction: Axis.horizontal, + crossAxisAlignment: CrossAxisAlignment.stretch, children: [ - imageBuilder( - context, - message, - images[2], + Flexible( + fit: FlexFit.tight, + flex: 1, + child: _buildImage(context, 2), ), if (images.length >= 4) - Padding( - padding: const EdgeInsets.only(left: 4.0), - child: Stack( - children: [ - imageBuilder( - context, - message, - images[3], - ), - if (images.length > 4) - Positioned.fill( - child: Material( - color: Colors.black38, - child: InkWell( - onTap: () {}, - child: Center( - child: Text( - '${images.length - 4} +', - style: TextStyle( - color: Colors.white, - fontSize: 28, + Flexible( + fit: FlexFit.tight, + flex: 1, + child: Padding( + padding: const EdgeInsets.only(left: 2.0), + child: Stack( + fit: StackFit.expand, + children: [ + _buildImage(context, 3), + if (images.length > 4) + Positioned.fill( + child: GestureDetector( + onTap: () => _onTap(context, 3), + child: Material( + color: Colors.black38, + child: Center( + child: Text( + '${images.length - 4} +', + style: TextStyle( + color: Colors.white, + fontSize: 28, + ), ), ), ), ), ), - ), - ], + ], + ), ), ), ], @@ -96,4 +102,55 @@ class ImageGroup extends StatelessWidget { ), ); } + + void _onTap( + BuildContext context, [ + int index, + ]) { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) { + return Scaffold( + appBar: AppBar( + backgroundColor: Colors.transparent, + iconTheme: IconThemeData( + color: Colors.white, + ), + ), + backgroundColor: Colors.black, + body: SizedBox.expand( + child: CarouselSlider( + items: images + .map((image) => FullScreenImage( + url: image.imageUrl ?? + image.thumbUrl ?? + image.assetUrl, + )) + .toList(), + options: CarouselOptions( + initialPage: index ?? 0, + enableInfiniteScroll: false, + viewportFraction: 0.95, + height: MediaQuery.of(context).size.height, + ), + ), + ), + ); + }, + ), + ); + } + + Widget _buildImage(BuildContext context, int index) { + return GestureDetector( + onTap: () => _onTap(context, index), + child: CachedNetworkImage( + imageUrl: images[index].imageUrl ?? + images[index].thumbUrl ?? + images[index].assetUrl, + fit: BoxFit.cover, + ), + ); + } } diff --git a/lib/src/message_widget.dart b/lib/src/message_widget.dart index 09d9dc13..2fc448ad 100644 --- a/lib/src/message_widget.dart +++ b/lib/src/message_widget.dart @@ -530,17 +530,16 @@ class _MessageWidgetState extends State { .toList(); if (images.length > 1) { - final imageBuilder = widget.attachmentBuilders['image']; return [ wrapAttachmentWidget( context, Material( color: widget.messageTheme.messageBackgroundColor, child: ImageGroup( - size: Size.fromWidth( + size: Size( MediaQuery.of(context).size.width * 0.8, + MediaQuery.of(context).size.height * 0.3, ), - imageBuilder: imageBuilder, images: images, message: widget.message, ), diff --git a/pubspec.yaml b/pubspec.yaml index b221a83b..8c25ab28 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -30,6 +30,7 @@ dependencies: line_awesome_icons: ^1.0.4+2 http_parser: ^3.1.4 flutter_slidable: ^0.5.4 + carousel_slider: ^2.2.1 flutter: assets: From e4e05a857b6639a7b3dd54ddbcf054e4b1df6e40 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Thu, 23 Jul 2020 14:29:14 +0200 Subject: [PATCH 0035/1140] Update main.yml --- .github/workflows/main.yml | 49 +++++++++++++++++++++++++++++++++++--- 1 file changed, 46 insertions(+), 3 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 48980157..086f58b5 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -44,8 +44,51 @@ jobs: run: flutter test --coverage - name: Codecov run: bash <(curl -s https://codecov.io/bash) -c -t ${{ secrets.CODECOV_TOKEN }} -f coverage/lcov.info -F flutter_tool - build_and_deploy: - name: Build + build_ios: + name: Build iOS + runs-on: macOS-latest + steps: + - uses: actions/checkout@v1 + - uses: actions/setup-java@v1 + with: + java-version: '12.x' + - uses: subosito/flutter-action@v1.3.2 + with: + flutter-version: ${{ env.flutter_version }} + - run: | + cd example + flutter pub get + flutter clean + flutter build ios --release --no-codesign + - name: Upload iPA + uses: actions/upload-artifact@v2 + with: + name: ios-build + path: example/build/ios/iphoneos + + deploy ios: + name: Upload iOS to Firebase App Distribution + needs: [build_ios] + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v1 + - name: set up JDK 1.8 + uses: actions/setup-java@v1 + with: + java-version: 1.8 + - name: Download Artifact + uses: actions/download-artifact@v2 + with: + name: ios-build + - name: Upload IPA + uses: wzieba/Firebase-Distribution-Github-Action@v1.0.0 + with: + appId: io.getstream.ChatExample + token: ${{secrets.FIREBASE_TOKEN}} + group: ios-stream-testers + file: Runner.ipa + build_and_deploy_android: + name: Build and deploy android runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 @@ -64,7 +107,7 @@ jobs: cd example flutter build apk - name: Upload - uses: actions/upload-artifact@master + uses: actions/upload-artifact@v2 with: name: apk-build path: example/build/app/outputs/bundle/release From 55b9ec295082391773343e7b65bf66173b5bf4a0 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Thu, 23 Jul 2020 14:34:27 +0200 Subject: [PATCH 0036/1140] Update main.yml --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 086f58b5..9b0dc5a0 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -66,7 +66,7 @@ jobs: name: ios-build path: example/build/ios/iphoneos - deploy ios: + deploy_ios: name: Upload iOS to Firebase App Distribution needs: [build_ios] runs-on: ubuntu-latest From ecdb5cb6829181290ff3a774ee65b34b641ae95c Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Thu, 23 Jul 2020 14:47:19 +0200 Subject: [PATCH 0037/1140] Update main.yml --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 9b0dc5a0..89afa416 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -85,7 +85,7 @@ jobs: with: appId: io.getstream.ChatExample token: ${{secrets.FIREBASE_TOKEN}} - group: ios-stream-testers + groups: ios-stream-testers file: Runner.ipa build_and_deploy_android: name: Build and deploy android From 410945a8a4fd90c6cff3157e638a3a91dff75f63 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Thu, 23 Jul 2020 15:01:25 +0200 Subject: [PATCH 0038/1140] Update main.yml --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 89afa416..7fa13a5a 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -83,7 +83,7 @@ jobs: - name: Upload IPA uses: wzieba/Firebase-Distribution-Github-Action@v1.0.0 with: - appId: io.getstream.ChatExample + appId: "1:674907137625:ios:cafb9fb076a453c4d7f348" token: ${{secrets.FIREBASE_TOKEN}} groups: ios-stream-testers file: Runner.ipa From 2e8511138668c7def20046c3f544dcab3663c576 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Thu, 23 Jul 2020 15:25:37 +0200 Subject: [PATCH 0039/1140] update firebase deploy action version --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 7fa13a5a..a940cdeb 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -81,7 +81,7 @@ jobs: with: name: ios-build - name: Upload IPA - uses: wzieba/Firebase-Distribution-Github-Action@v1.0.0 + uses: wzieba/Firebase-Distribution-Github-Action@v1.2.1 with: appId: "1:674907137625:ios:cafb9fb076a453c4d7f348" token: ${{secrets.FIREBASE_TOKEN}} From 01bef02b73c5fc437037a3f22dd2569ea7ebd127 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Thu, 23 Jul 2020 15:45:48 +0200 Subject: [PATCH 0040/1140] debug release ios --- .github/workflows/main.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index a940cdeb..a78d0f17 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -87,6 +87,7 @@ jobs: token: ${{secrets.FIREBASE_TOKEN}} groups: ios-stream-testers file: Runner.ipa + debug: true build_and_deploy_android: name: Build and deploy android runs-on: ubuntu-latest From 495fcc89b586cfbdf5c1fa4b8948cfa5ad62c697 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Thu, 23 Jul 2020 16:05:39 +0200 Subject: [PATCH 0041/1140] add debug commands --- .github/workflows/main.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index a78d0f17..2ddecf1d 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -80,6 +80,9 @@ jobs: uses: actions/download-artifact@v2 with: name: ios-build + - run: | + ls -l /home/runner/work/stream-chat-flutter/stream-chat-flutter + ls -l . - name: Upload IPA uses: wzieba/Firebase-Distribution-Github-Action@v1.2.1 with: From bc3245ccd0e12215d821e7f883c66ef8efc8cfc7 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Thu, 23 Jul 2020 16:20:11 +0200 Subject: [PATCH 0042/1140] Update main.yml --- .github/workflows/main.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 2ddecf1d..5b1ad171 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -61,10 +61,10 @@ jobs: flutter clean flutter build ios --release --no-codesign - name: Upload iPA - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v2.1.0 with: name: ios-build - path: example/build/ios/iphoneos + path: ./example/build/ios/iphoneos/ deploy_ios: name: Upload iOS to Firebase App Distribution From eaad42b4dae8e3f4cf9eed0f701a3bd00dbdd9c2 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Thu, 23 Jul 2020 17:10:32 +0200 Subject: [PATCH 0043/1140] Update main.yml --- .github/workflows/main.yml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 5b1ad171..8b0a6630 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -60,11 +60,16 @@ jobs: flutter pub get flutter clean flutter build ios --release --no-codesign + cd ios + xcodebuild -workspace Runner.xcworkspace -scheme Runner -sdk iphoneos -configuration Release archive -archivePath $PWD/build/Runner.xcarchive + xcodebuild -exportArchive -archivePath $PWD/build/Runner.xcarchive -exportOptionsPlist exportOptions.plist -exportPath $PWD/build/Runner.ipa + cd .. + - name: Upload iPA uses: actions/upload-artifact@v2.1.0 with: name: ios-build - path: ./example/build/ios/iphoneos/ + path: ios/build/Runner.ipa/Runner.ipa deploy_ios: name: Upload iOS to Firebase App Distribution From 0aa25ec3d05ed8d9d41d9dc617e959c6401de47d Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Fri, 24 Jul 2020 10:22:30 +0200 Subject: [PATCH 0044/1140] Update main.yml --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 8b0a6630..7cde01df 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -59,7 +59,7 @@ jobs: cd example flutter pub get flutter clean - flutter build ios --release --no-codesign + flutter build ios --release cd ios xcodebuild -workspace Runner.xcworkspace -scheme Runner -sdk iphoneos -configuration Release archive -archivePath $PWD/build/Runner.xcarchive xcodebuild -exportArchive -archivePath $PWD/build/Runner.xcarchive -exportOptionsPlist exportOptions.plist -exportPath $PWD/build/Runner.ipa From 836acf69434c5d056073055bb1b2f280801f1157 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Tue, 28 Jul 2020 14:07:16 +0200 Subject: [PATCH 0045/1140] add fastlane + github actions for ios --- .github/workflows/main.yml | 31 ++- .gitignore | 3 +- example/ios/Gemfile | 6 + example/ios/Gemfile.lock | 180 +++++++++++++++ example/ios/Podfile | 2 +- example/ios/Podfile.lock | 208 ++++++++---------- .../xcschemes/Notifications.xcscheme | 96 ++++++++ .../xcshareddata/xcschemes/Runner.xcscheme | 8 +- example/ios/fastlane/Appfile | 6 + example/ios/fastlane/Fastfile | 46 ++++ example/ios/fastlane/MatchFile | 15 ++ example/ios/fastlane/Pluginfile | 5 + example/ios/fastlane/README.md | 37 ++++ .../fastlane/beta_gym_export_options.plist | 15 ++ example/ios/fastlane/report.xml | 48 ++++ example/pubspec.yaml | 2 +- 16 files changed, 585 insertions(+), 123 deletions(-) create mode 100644 example/ios/Gemfile create mode 100644 example/ios/Gemfile.lock create mode 100644 example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Notifications.xcscheme create mode 100644 example/ios/fastlane/Appfile create mode 100644 example/ios/fastlane/Fastfile create mode 100644 example/ios/fastlane/MatchFile create mode 100644 example/ios/fastlane/Pluginfile create mode 100644 example/ios/fastlane/README.md create mode 100644 example/ios/fastlane/beta_gym_export_options.plist create mode 100644 example/ios/fastlane/report.xml diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 48980157..5e854f10 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -44,7 +44,35 @@ jobs: run: flutter test --coverage - name: Codecov run: bash <(curl -s https://codecov.io/bash) -c -t ${{ secrets.CODECOV_TOKEN }} -f coverage/lcov.info -F flutter_tool - build_and_deploy: + build_and_deploy_ios: + steps: + - uses: actions/checkout@v1 + - name: Cache RubyGems + uses: actions/cache@v1 + id: rubygem-cache + with: + path: vendor/bundle + key: ${{ runner.os }}-gem-${{ hashFiles('**/Gemfile.lock') }} + restore-keys: ${{ runner.os }}-gem- + - name: Install RubyGems + if: steps.rubygem-cache.outputs.cache-hit != 'true' + run: bundle install + - uses: subosito/flutter-action@v1.3.2 + with: + flutter-version: ${{ env.flutter_version }} + - name: Flutter setup + run: | + flutter pub get + flutter build ios --release --no-codesign + - name: Build + env: + MATCH_PASSWORD: ${{ secrets.MATCH_PASSWORD }} + MATCH_GIT_BASIC_AUTHORIZATION: ${{ secrets.MATCH_GIT_BASIC_AUTHORIZATION }} + FIREBASE_TOKEN: ${{ secrets.FIREBASE_TOKEN }} + run: | + cd ios + bundle exec fastlane deploy_to_firebase + build_and_deploy_android: name: Build runs-on: ubuntu-latest steps: @@ -69,7 +97,6 @@ jobs: name: apk-build path: example/build/app/outputs/bundle/release - name: Deploy - #if: github.base_ref == 'master' uses: wzieba/Firebase-Distribution-Github-Action@v1.2.1 with: appId: ${{secrets.FIREBASE_ANDROID_APPID}} diff --git a/.gitignore b/.gitignore index 28b825a6..fe7ca994 100644 --- a/.gitignore +++ b/.gitignore @@ -59,4 +59,5 @@ doc/api/ *.js.deps *.js.map -fvm \ No newline at end of file +fvm +example/ios/dist \ No newline at end of file diff --git a/example/ios/Gemfile b/example/ios/Gemfile new file mode 100644 index 00000000..cdd3a6b3 --- /dev/null +++ b/example/ios/Gemfile @@ -0,0 +1,6 @@ +source "https://rubygems.org" + +gem "fastlane" + +plugins_path = File.join(File.dirname(__FILE__), 'fastlane', 'Pluginfile') +eval_gemfile(plugins_path) if File.exist?(plugins_path) diff --git a/example/ios/Gemfile.lock b/example/ios/Gemfile.lock new file mode 100644 index 00000000..cc4bf5f3 --- /dev/null +++ b/example/ios/Gemfile.lock @@ -0,0 +1,180 @@ +GEM + remote: https://rubygems.org/ + specs: + CFPropertyList (3.0.2) + addressable (2.7.0) + public_suffix (>= 2.0.2, < 5.0) + atomos (0.1.3) + aws-eventstream (1.1.0) + aws-partitions (1.345.0) + aws-sdk-core (3.104.3) + aws-eventstream (~> 1, >= 1.0.2) + aws-partitions (~> 1, >= 1.239.0) + aws-sigv4 (~> 1.1) + jmespath (~> 1.0) + aws-sdk-kms (1.36.0) + aws-sdk-core (~> 3, >= 3.99.0) + aws-sigv4 (~> 1.1) + aws-sdk-s3 (1.75.0) + aws-sdk-core (~> 3, >= 3.104.1) + aws-sdk-kms (~> 1) + aws-sigv4 (~> 1.1) + aws-sigv4 (1.2.1) + aws-eventstream (~> 1, >= 1.0.2) + babosa (1.0.3) + claide (1.0.3) + colored (1.2) + colored2 (3.1.2) + commander-fastlane (4.4.6) + highline (~> 1.7.2) + declarative (0.0.20) + declarative-option (0.1.0) + digest-crc (0.6.1) + rake (~> 13.0) + domain_name (0.5.20190701) + unf (>= 0.0.5, < 1.0.0) + dotenv (2.7.6) + emoji_regex (3.0.0) + excon (0.75.0) + faraday (1.0.1) + multipart-post (>= 1.2, < 3) + faraday-cookie_jar (0.0.6) + faraday (>= 0.7.4) + http-cookie (~> 1.0.0) + faraday_middleware (1.0.0) + faraday (~> 1.0) + fastimage (2.2.0) + fastlane (2.153.1) + CFPropertyList (>= 2.3, < 4.0.0) + addressable (>= 2.3, < 3.0.0) + aws-sdk-s3 (~> 1.0) + babosa (>= 1.0.3, < 2.0.0) + bundler (>= 1.12.0, < 3.0.0) + colored + commander-fastlane (>= 4.4.6, < 5.0.0) + dotenv (>= 2.1.1, < 3.0.0) + emoji_regex (>= 0.1, < 4.0) + excon (>= 0.71.0, < 1.0.0) + faraday (~> 1.0) + faraday-cookie_jar (~> 0.0.6) + faraday_middleware (~> 1.0) + fastimage (>= 2.1.0, < 3.0.0) + gh_inspector (>= 1.1.2, < 2.0.0) + google-api-client (>= 0.37.0, < 0.39.0) + google-cloud-storage (>= 1.15.0, < 2.0.0) + highline (>= 1.7.2, < 2.0.0) + json (< 3.0.0) + jwt (>= 2.1.0, < 3) + mini_magick (>= 4.9.4, < 5.0.0) + multipart-post (~> 2.0.0) + plist (>= 3.1.0, < 4.0.0) + rubyzip (>= 2.0.0, < 3.0.0) + security (= 0.1.3) + simctl (~> 1.6.3) + slack-notifier (>= 2.0.0, < 3.0.0) + terminal-notifier (>= 2.0.0, < 3.0.0) + terminal-table (>= 1.4.5, < 2.0.0) + tty-screen (>= 0.6.3, < 1.0.0) + tty-spinner (>= 0.8.0, < 1.0.0) + word_wrap (~> 1.0.0) + xcodeproj (>= 1.13.0, < 2.0.0) + xcpretty (~> 0.3.0) + xcpretty-travis-formatter (>= 0.0.3) + fastlane-plugin-firebase_app_distribution (0.1.4) + gh_inspector (1.1.3) + google-api-client (0.38.0) + addressable (~> 2.5, >= 2.5.1) + googleauth (~> 0.9) + httpclient (>= 2.8.1, < 3.0) + mini_mime (~> 1.0) + representable (~> 3.0) + retriable (>= 2.0, < 4.0) + signet (~> 0.12) + google-cloud-core (1.5.0) + google-cloud-env (~> 1.0) + google-cloud-errors (~> 1.0) + google-cloud-env (1.3.3) + faraday (>= 0.17.3, < 2.0) + google-cloud-errors (1.0.1) + google-cloud-storage (1.26.2) + addressable (~> 2.5) + digest-crc (~> 0.4) + google-api-client (~> 0.33) + google-cloud-core (~> 1.2) + googleauth (~> 0.9) + mini_mime (~> 1.0) + googleauth (0.13.0) + faraday (>= 0.17.3, < 2.0) + jwt (>= 1.4, < 3.0) + memoist (~> 0.16) + multi_json (~> 1.11) + os (>= 0.9, < 2.0) + signet (~> 0.14) + highline (1.7.10) + http-cookie (1.0.3) + domain_name (~> 0.5) + httpclient (2.8.3) + jmespath (1.4.0) + json (2.3.1) + jwt (2.2.1) + memoist (0.16.2) + mini_magick (4.10.1) + mini_mime (1.0.2) + multi_json (1.15.0) + multipart-post (2.0.0) + nanaimo (0.3.0) + naturally (2.2.0) + os (1.1.0) + plist (3.5.0) + public_suffix (4.0.5) + rake (13.0.1) + representable (3.0.4) + declarative (< 0.1.0) + declarative-option (< 0.2.0) + uber (< 0.2.0) + retriable (3.1.2) + rouge (2.0.7) + rubyzip (2.3.0) + security (0.1.3) + signet (0.14.0) + addressable (~> 2.3) + faraday (>= 0.17.3, < 2.0) + jwt (>= 1.5, < 3.0) + multi_json (~> 1.10) + simctl (1.6.8) + CFPropertyList + naturally + slack-notifier (2.3.2) + terminal-notifier (2.0.0) + terminal-table (1.8.0) + unicode-display_width (~> 1.1, >= 1.1.1) + tty-cursor (0.7.1) + tty-screen (0.8.1) + tty-spinner (0.9.3) + tty-cursor (~> 0.7) + uber (0.1.0) + unf (0.1.4) + unf_ext + unf_ext (0.0.7.7) + unicode-display_width (1.7.0) + word_wrap (1.0.0) + xcodeproj (1.17.1) + CFPropertyList (>= 2.3.3, < 4.0) + atomos (~> 0.1.3) + claide (>= 1.0.2, < 2.0) + colored2 (~> 3.1) + nanaimo (~> 0.3.0) + xcpretty (0.3.0) + rouge (~> 2.0.7) + xcpretty-travis-formatter (1.0.0) + xcpretty (~> 0.2, >= 0.0.7) + +PLATFORMS + ruby + +DEPENDENCIES + fastlane + fastlane-plugin-firebase_app_distribution + +BUNDLED WITH + 2.0.2 diff --git a/example/ios/Podfile b/example/ios/Podfile index ad84eb7b..9e328189 100644 --- a/example/ios/Podfile +++ b/example/ios/Podfile @@ -63,7 +63,7 @@ target 'Runner' do # Keep pod path relative so it can be checked into Podfile.lock. pod 'Flutter', :path => 'Flutter' - pod 'StreamChatClient' + pod 'StreamChatClient', '~> 2.0.0' # Plugin Pods # Prepare symlinks folder. We use symlinks to avoid having Podfile.lock diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock index 3afa0479..de801ca0 100644 --- a/example/ios/Podfile.lock +++ b/example/ios/Podfile.lock @@ -1,91 +1,86 @@ PODS: - - DKImagePickerController/Core (4.2.2): + - DKImagePickerController/Core (4.3.2): - DKImagePickerController/ImageDataManager - DKImagePickerController/Resource - - DKImagePickerController/ImageDataManager (4.2.2) - - DKImagePickerController/PhotoGallery (4.2.2): + - DKImagePickerController/ImageDataManager (4.3.2) + - DKImagePickerController/PhotoGallery (4.3.2): - DKImagePickerController/Core - DKPhotoGallery - - DKImagePickerController/Resource (4.2.2) - - DKPhotoGallery (0.0.14): - - DKPhotoGallery/Core (= 0.0.14) - - DKPhotoGallery/Model (= 0.0.14) - - DKPhotoGallery/Preview (= 0.0.14) - - DKPhotoGallery/Resource (= 0.0.14) + - DKImagePickerController/Resource (4.3.2) + - DKPhotoGallery (0.0.17): + - DKPhotoGallery/Core (= 0.0.17) + - DKPhotoGallery/Model (= 0.0.17) + - DKPhotoGallery/Preview (= 0.0.17) + - DKPhotoGallery/Resource (= 0.0.17) - SDWebImage - - SDWebImageFLPlugin - - DKPhotoGallery/Core (0.0.14): + - SwiftyGif + - DKPhotoGallery/Core (0.0.17): - DKPhotoGallery/Model - DKPhotoGallery/Preview - SDWebImage - - SDWebImageFLPlugin - - DKPhotoGallery/Model (0.0.14): + - SwiftyGif + - DKPhotoGallery/Model (0.0.17): - SDWebImage - - SDWebImageFLPlugin - - DKPhotoGallery/Preview (0.0.14): + - SwiftyGif + - DKPhotoGallery/Preview (0.0.17): - DKPhotoGallery/Model - DKPhotoGallery/Resource - SDWebImage - - SDWebImageFLPlugin - - DKPhotoGallery/Resource (0.0.14): + - SwiftyGif + - DKPhotoGallery/Resource (0.0.17): - SDWebImage - - SDWebImageFLPlugin + - SwiftyGif - file_picker (0.0.1): - DKImagePickerController/PhotoGallery - Flutter - - Firebase/Core (6.20.0): + - Firebase/Core (6.28.1): - Firebase/CoreOnly - - FirebaseAnalytics (= 6.3.1) - - Firebase/CoreOnly (6.20.0): - - FirebaseCore (= 6.6.4) - - Firebase/Messaging (6.20.0): + - FirebaseAnalytics (= 6.6.2) + - Firebase/CoreOnly (6.28.1): + - FirebaseCore (= 6.9.1) + - Firebase/Messaging (6.28.1): - Firebase/CoreOnly - - FirebaseMessaging (~> 4.3.0) + - FirebaseMessaging (~> 4.6.0) - firebase_messaging (0.0.1): - Firebase/Core - Firebase/Messaging - Flutter - - FirebaseAnalytics (6.3.1): - - FirebaseCore (~> 6.6) - - FirebaseInstallations (~> 1.1) - - GoogleAppMeasurement (= 6.3.1) + - FirebaseAnalytics (6.6.2): + - FirebaseCore (~> 6.8) + - FirebaseInstallations (~> 1.4) + - GoogleAppMeasurement (= 6.6.2) - GoogleUtilities/AppDelegateSwizzler (~> 6.0) - GoogleUtilities/MethodSwizzler (~> 6.0) - GoogleUtilities/Network (~> 6.0) - "GoogleUtilities/NSData+zlib (~> 6.0)" - - nanopb (= 0.3.9011) - - FirebaseAnalyticsInterop (1.5.0) - - FirebaseCore (6.6.4): - - FirebaseCoreDiagnostics (~> 1.2) - - FirebaseCoreDiagnosticsInterop (~> 1.2) - - GoogleUtilities/Environment (~> 6.5) - - GoogleUtilities/Logger (~> 6.5) - - FirebaseCoreDiagnostics (1.2.2): - - FirebaseCoreDiagnosticsInterop (~> 1.2) - - GoogleDataTransportCCTSupport (~> 2.0) - - GoogleUtilities/Environment (~> 6.5) - - GoogleUtilities/Logger (~> 6.5) - - nanopb (~> 0.3.901) - - FirebaseCoreDiagnosticsInterop (1.2.0) - - FirebaseInstallations (1.1.0): - - FirebaseCore (~> 6.6) - - GoogleUtilities/UserDefaults (~> 6.5) + - nanopb (~> 1.30905.0) + - FirebaseCore (6.9.1): + - FirebaseCoreDiagnostics (~> 1.3) + - GoogleUtilities/Environment (~> 6.7) + - GoogleUtilities/Logger (~> 6.7) + - FirebaseCoreDiagnostics (1.5.0): + - GoogleDataTransport (~> 7.0) + - GoogleUtilities/Environment (~> 6.7) + - GoogleUtilities/Logger (~> 6.7) + - nanopb (~> 1.30905.0) + - FirebaseInstallations (1.5.0): + - FirebaseCore (~> 6.8) + - GoogleUtilities/Environment (~> 6.7) + - GoogleUtilities/UserDefaults (~> 6.7) - PromisesObjC (~> 1.2) - - FirebaseInstanceID (4.3.2): - - FirebaseCore (~> 6.6) + - FirebaseInstanceID (4.5.0): + - FirebaseCore (~> 6.8) - FirebaseInstallations (~> 1.0) - - GoogleUtilities/Environment (~> 6.5) - - GoogleUtilities/UserDefaults (~> 6.5) - - FirebaseMessaging (4.3.0): - - FirebaseAnalyticsInterop (~> 1.5) - - FirebaseCore (~> 6.6) + - GoogleUtilities/Environment (~> 6.7) + - GoogleUtilities/UserDefaults (~> 6.7) + - FirebaseMessaging (4.6.0): + - FirebaseCore (~> 6.8) - FirebaseInstanceID (~> 4.3) - - GoogleUtilities/AppDelegateSwizzler (~> 6.5) - - GoogleUtilities/Environment (~> 6.5) - - GoogleUtilities/Reachability (~> 6.5) - - GoogleUtilities/UserDefaults (~> 6.5) + - GoogleUtilities/AppDelegateSwizzler (~> 6.7) + - GoogleUtilities/Environment (~> 6.7) + - GoogleUtilities/Reachability (~> 6.7) + - GoogleUtilities/UserDefaults (~> 6.7) - Protobuf (>= 3.9.2, ~> 3.9) - - FLAnimatedImage (1.0.12) - Flutter (1.0.0) - flutter_apns (0.0.1): - Flutter @@ -98,59 +93,55 @@ PODS: - FMDB (2.7.5): - FMDB/standard (= 2.7.5) - FMDB/standard (2.7.5) - - GoogleAppMeasurement (6.3.1): + - GoogleAppMeasurement (6.6.2): - GoogleUtilities/AppDelegateSwizzler (~> 6.0) - GoogleUtilities/MethodSwizzler (~> 6.0) - GoogleUtilities/Network (~> 6.0) - "GoogleUtilities/NSData+zlib (~> 6.0)" - - nanopb (= 0.3.9011) - - GoogleDataTransport (5.0.0) - - GoogleDataTransportCCTSupport (2.0.0): - - GoogleDataTransport (~> 5.0) - - nanopb (~> 0.3.901) - - GoogleUtilities/AppDelegateSwizzler (6.5.2): + - nanopb (~> 1.30905.0) + - GoogleDataTransport (7.0.0): + - nanopb (~> 1.30905.0) + - GoogleUtilities/AppDelegateSwizzler (6.7.1): - GoogleUtilities/Environment - GoogleUtilities/Logger - GoogleUtilities/Network - - GoogleUtilities/Environment (6.5.2) - - GoogleUtilities/Logger (6.5.2): + - GoogleUtilities/Environment (6.7.1): + - PromisesObjC (~> 1.2) + - GoogleUtilities/Logger (6.7.1): - GoogleUtilities/Environment - - GoogleUtilities/MethodSwizzler (6.5.2): + - GoogleUtilities/MethodSwizzler (6.7.1): - GoogleUtilities/Logger - - GoogleUtilities/Network (6.5.2): + - GoogleUtilities/Network (6.7.1): - GoogleUtilities/Logger - "GoogleUtilities/NSData+zlib" - GoogleUtilities/Reachability - - "GoogleUtilities/NSData+zlib (6.5.2)" - - GoogleUtilities/Reachability (6.5.2): + - "GoogleUtilities/NSData+zlib (6.7.1)" + - GoogleUtilities/Reachability (6.7.1): - GoogleUtilities/Logger - - GoogleUtilities/UserDefaults (6.5.2): + - GoogleUtilities/UserDefaults (6.7.1): - GoogleUtilities/Logger - GzipSwift (5.1.1) - image_picker (0.0.1): - Flutter - moor_ffi (0.0.1): - Flutter - - nanopb (0.3.9011): - - nanopb/decode (= 0.3.9011) - - nanopb/encode (= 0.3.9011) - - nanopb/decode (0.3.9011) - - nanopb/encode (0.3.9011) + - nanopb (1.30905.0): + - nanopb/decode (= 1.30905.0) + - nanopb/encode (= 1.30905.0) + - nanopb/decode (1.30905.0) + - nanopb/encode (1.30905.0) - path_provider (0.0.1): - Flutter - path_provider_linux (0.0.1): - Flutter - path_provider_macos (0.0.1): - Flutter - - PromisesObjC (1.2.8) - - Protobuf (3.11.4) + - PromisesObjC (1.2.9) + - Protobuf (3.12.0) - ReachabilitySwift (5.0.0) - - SDWebImage (5.8.0): - - SDWebImage/Core (= 5.8.0) - - SDWebImage/Core (5.8.0) - - SDWebImageFLPlugin (0.4.0): - - FLAnimatedImage (>= 1.0.11) - - SDWebImage/Core (~> 5.6) + - SDWebImage (5.8.4): + - SDWebImage/Core (= 5.8.4) + - SDWebImage/Core (5.8.4) - shared_preferences (0.0.1): - Flutter - shared_preferences_linux (0.0.1): @@ -167,6 +158,7 @@ PODS: - GzipSwift (~> 5.1) - ReachabilitySwift (~> 5.0) - Starscream (~> 3.1) + - SwiftyGif (5.3.0) - url_launcher (0.0.1): - Flutter - url_launcher_linux (0.0.1): @@ -200,7 +192,7 @@ DEPENDENCIES: - shared_preferences_macos (from `.symlinks/plugins/shared_preferences_macos/ios`) - shared_preferences_web (from `.symlinks/plugins/shared_preferences_web/ios`) - sqflite (from `.symlinks/plugins/sqflite/ios`) - - StreamChatClient + - StreamChatClient (~> 2.0.0) - url_launcher (from `.symlinks/plugins/url_launcher/ios`) - url_launcher_linux (from `.symlinks/plugins/url_launcher_linux/ios`) - url_launcher_macos (from `.symlinks/plugins/url_launcher_macos/ios`) @@ -215,18 +207,14 @@ SPEC REPOS: - DKPhotoGallery - Firebase - FirebaseAnalytics - - FirebaseAnalyticsInterop - FirebaseCore - FirebaseCoreDiagnostics - - FirebaseCoreDiagnosticsInterop - FirebaseInstallations - FirebaseInstanceID - FirebaseMessaging - - FLAnimatedImage - FMDB - GoogleAppMeasurement - GoogleDataTransport - - GoogleDataTransportCCTSupport - GoogleUtilities - GzipSwift - nanopb @@ -234,9 +222,9 @@ SPEC REPOS: - Protobuf - ReachabilitySwift - SDWebImage - - SDWebImageFLPlugin - Starscream - StreamChatClient + - SwiftyGif EXTERNAL SOURCES: file_picker: @@ -289,42 +277,37 @@ EXTERNAL SOURCES: :path: ".symlinks/plugins/wakelock/ios" SPEC CHECKSUMS: - DKImagePickerController: 4a3e7948a848c4348e600b3fe5ce41478835fa10 - DKPhotoGallery: 0290d32343574f06eaa4c26f8f2f8a1035e916be + DKImagePickerController: b5eb7f7a388e4643264105d648d01f727110fc3d + DKPhotoGallery: fdfad5125a9fdda9cc57df834d49df790dbb4179 file_picker: 3e6c3790de664ccf9b882732d9db5eaf6b8d4eb1 - Firebase: fe7f74012742ab403451dd283e6909b8f1fb348a + Firebase: ed042590caa0029392257529a8003c25ee82bc18 firebase_messaging: 21344b3b3a7d9d325d63a70e3750c0c798fe1e03 - FirebaseAnalytics: 572e467f3d977825266e8ccd52674aa3e6f47eac - FirebaseAnalyticsInterop: 3f86269c38ae41f47afeb43ebf32a001f58fcdae - FirebaseCore: ed0a24c758a57c2b88c5efa8e6a8195e868af589 - FirebaseCoreDiagnostics: e9b4cd8ba60dee0f2d13347332e4b7898cca5b61 - FirebaseCoreDiagnosticsInterop: 296e2c5f5314500a850ad0b83e9e7c10b011a850 - FirebaseInstallations: 575cd32f2aec0feeb0e44f5d0110a09e5e60b47b - FirebaseInstanceID: 7ee0d6777013bb952f377b41965bf132b6a075be - FirebaseMessaging: 4ec33842d36b3319e062e51fb8b35a74f726950d - FLAnimatedImage: 4a0b56255d9b05f18b6dd7ee06871be5d3b89e31 + FirebaseAnalytics: 5fa308e1b13f838d0f6dc74719ac2a72e8c5afc4 + FirebaseCore: 687b8e6a0a4337b898a6326d68254c2f80c143af + FirebaseCoreDiagnostics: 7535fe695737f8c5b350584292a70b7f8ff0357b + FirebaseInstallations: 3c520c951305cbf9ca54eb891ff9e6d1fd384881 + FirebaseInstanceID: 358d5cb393d2750a745569ede06827c35aea530b + FirebaseMessaging: bdd4d573eab37ebee29bad4e7c4b0ef18fa1a952 Flutter: 0e3d915762c693b495b44d77113d4970485de6ec flutter_apns: f516b118e423fe7c0a38771180549c4d6cb67c2f flutter_keyboard_visibility: 0339d06371254c3eb25eeb90ba8d17dca8f9c069 flutter_local_notifications: 9e4738ce2471c5af910d961a6b7eadcf57c50186 flutter_plugin_android_lifecycle: dc0b544e129eebb77a6bfb1239d4d1c673a60a35 FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a - GoogleAppMeasurement: c29d405ff76e18551b5d158eaba6753fda8c7542 - GoogleDataTransport: a857c6a002d201b524dd4bc2ed7e7355ed07e785 - GoogleDataTransportCCTSupport: 32f75fbe904c82772fcbb6b6bd4525bfb6f2a862 - GoogleUtilities: ad0f3b691c67909d03a3327cc205222ab8f42e0e + GoogleAppMeasurement: 8cd1f289d60e629cf16ab03363b9e89c776b9651 + GoogleDataTransport: 8a40cb194ad242b6f6dfe72c14fe40fc67c4dcd7 + GoogleUtilities: e121a3867449ce16b0e35ddf1797ea7a389ffdf2 GzipSwift: 893f3e48e597a1a4f62fafcb6514220fcf8287fa image_picker: 9c3312491f862b28d21ecd8fdf0ee14e601b3f09 moor_ffi: d66c9470c18e9cb333423bbcb493c105c6c774c6 - nanopb: 18003b5e52dab79db540fe93fe9579f399bd1ccd + nanopb: c43f40fadfe79e8b8db116583945847910cbabc9 path_provider: abfe2b5c733d04e238b0d8691db0cfd63a27a93c path_provider_linux: 4d630dc393e1f20364f3e3b4a2ff41d9674a84e4 path_provider_macos: f760a3c5b04357c380e2fddb6f9db6f3015897e0 - PromisesObjC: c119f3cd559f50b7ae681fa59dc1acd19173b7e6 - Protobuf: 176220c526ad8bd09ab1fb40a978eac3fef665f7 + PromisesObjC: b48e0338dbbac2207e611750777895f7a5811b75 + Protobuf: 2793fcd0622a00b546c60e7cbbcc493e043e9bb9 ReachabilitySwift: 985039c6f7b23a1da463388634119492ff86c825 - SDWebImage: 84000f962cbfa70c07f19d2234cbfcf5d779b5dc - SDWebImageFLPlugin: 6c2295fb1242d44467c6c87dc5db6b0a13228fd8 + SDWebImage: cf6922231e95550934da2ada0f20f2becf2ceba9 shared_preferences: af6bfa751691cdc24be3045c43ec037377ada40d shared_preferences_linux: afefbfe8d921e207f01ede8b60373d9e3b566b78 shared_preferences_macos: f3f29b71ccbb56bf40c9dd6396c9acf15e214087 @@ -332,6 +315,7 @@ SPEC CHECKSUMS: sqflite: 4001a31ff81d210346b500c55b17f4d6c7589dd0 Starscream: 4bb2f9942274833f7b4d296a55504dcfc7edb7b0 StreamChatClient: 91b0f585e7dc92ade58e657daffafb16d485b2a6 + SwiftyGif: e466e86c660d343357ab944a819a101c4127cb40 url_launcher: 6fef411d543ceb26efce54b05a0a40bfd74cbbef url_launcher_linux: ac237cb7a8058736e4aae38bdbcc748a4b394cc0 url_launcher_macos: fd7894421cd39320dce5f292fc99ea9270b2a313 @@ -340,6 +324,6 @@ SPEC CHECKSUMS: video_player_web: da8cadb8274ed4f8dbee8d7171b420dedd437ce7 wakelock: 0d4a70faf8950410735e3f61fb15d517c8a6efc4 -PODFILE CHECKSUM: 5cc7e2f1316491ee530029e2e8391f4100d41fbd +PODFILE CHECKSUM: aaaddd91b568e9a010ff3278737eb06bc017bd6e COCOAPODS: 1.8.4 diff --git a/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Notifications.xcscheme b/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Notifications.xcscheme new file mode 100644 index 00000000..9387f0d0 --- /dev/null +++ b/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Notifications.xcscheme @@ -0,0 +1,96 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index a28140cf..fb2dffc4 100644 --- a/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -27,8 +27,6 @@ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" shouldUseLaunchSchemeArgsEnv = "YES"> - - - - + + - - + + + + iCloudContainerEnvironment + Development + provisioningProfiles + + io.getstream.flutter + flutter example + io.getstream.flutter.Notifications + flutter example notifications + + + \ No newline at end of file diff --git a/example/ios/fastlane/report.xml b/example/ios/fastlane/report.xml new file mode 100644 index 00000000..e26cb644 --- /dev/null +++ b/example/ios/fastlane/report.xml @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 37be1464..86ab5a62 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -1,7 +1,7 @@ name: example description: A new Flutter project. -version: 1.0.2+4 +version: 1.0.3+5 environment: sdk: ">=2.2.2 <3.0.0" From 57d3c62bf75c5a33f61da38b5918c38e02b8fd34 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Tue, 28 Jul 2020 14:11:06 +0200 Subject: [PATCH 0046/1140] Update main.yml --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 12c0485c..0381af9a 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -45,7 +45,7 @@ jobs: - name: Codecov run: bash <(curl -s https://codecov.io/bash) -c -t ${{ secrets.CODECOV_TOKEN }} -f coverage/lcov.info -F flutter_tool build_and_deploy_ios: - runs-on: [macos-latest] + runs-on: [macos-latest] steps: - uses: actions/checkout@v1 - name: Cache RubyGems From d3eef802b881f2195f9c96d257e9b594d9f06eac Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Tue, 28 Jul 2020 14:16:50 +0200 Subject: [PATCH 0047/1140] Update main.yml --- .github/workflows/main.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 0381af9a..ed814646 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -57,7 +57,9 @@ jobs: restore-keys: ${{ runner.os }}-gem- - name: Install RubyGems if: steps.rubygem-cache.outputs.cache-hit != 'true' - run: bundle install + run: | + cd ios + bundle install - uses: subosito/flutter-action@v1.3.2 with: flutter-version: ${{ env.flutter_version }} From 81628730552539a6c4cbc2b186d1680a1648264c Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Tue, 28 Jul 2020 14:23:27 +0200 Subject: [PATCH 0048/1140] Update main.yml --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index ed814646..64c27fcc 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -58,7 +58,7 @@ jobs: - name: Install RubyGems if: steps.rubygem-cache.outputs.cache-hit != 'true' run: | - cd ios + cd example/ios bundle install - uses: subosito/flutter-action@v1.3.2 with: From 0e508fb1efa5559f2e231a6b8678f879d0c3f210 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Tue, 28 Jul 2020 14:29:47 +0200 Subject: [PATCH 0049/1140] Update main.yml --- .github/workflows/main.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 64c27fcc..bb51f319 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -65,6 +65,7 @@ jobs: flutter-version: ${{ env.flutter_version }} - name: Flutter setup run: | + cd example flutter pub get flutter build ios --release --no-codesign - name: Build From 8a44a02e502105a89a31a6d554f65ed7f20af162 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Tue, 28 Jul 2020 14:49:18 +0200 Subject: [PATCH 0050/1140] Update main.yml --- .github/workflows/main.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index bb51f319..5ba77776 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -68,13 +68,13 @@ jobs: cd example flutter pub get flutter build ios --release --no-codesign - - name: Build + - name: Build and release env: MATCH_PASSWORD: ${{ secrets.MATCH_PASSWORD }} MATCH_GIT_BASIC_AUTHORIZATION: ${{ secrets.MATCH_GIT_BASIC_AUTHORIZATION }} FIREBASE_TOKEN: ${{ secrets.FIREBASE_TOKEN }} run: | - cd ios + cd example/ios bundle exec fastlane deploy_to_firebase build_and_deploy_android: runs-on: ubuntu-latest From 9b01585faddd676d2ccf0e3370234ec530160c61 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Tue, 28 Jul 2020 15:25:10 +0200 Subject: [PATCH 0051/1140] update github username --- example/ios/fastlane/MatchFile | 2 +- example/lib/split_view.dart | 132 +++++++++++++++++++++++++++++++++ example/pubspec.yaml | 2 +- 3 files changed, 134 insertions(+), 2 deletions(-) create mode 100644 example/lib/split_view.dart diff --git a/example/ios/fastlane/MatchFile b/example/ios/fastlane/MatchFile index 21b0863c..3d0ce2c0 100644 --- a/example/ios/fastlane/MatchFile +++ b/example/ios/fastlane/MatchFile @@ -2,7 +2,7 @@ git_url("https://github.com/GetStream/ios-certificates") storage_mode("git") -username("salvatore@getstream.io") +username("imtoori") team_id("EHV7XZLAHA") diff --git a/example/lib/split_view.dart b/example/lib/split_view.dart new file mode 100644 index 00000000..cbfd8798 --- /dev/null +++ b/example/lib/split_view.dart @@ -0,0 +1,132 @@ +import 'package:flutter/material.dart'; +import 'package:stream_chat_flutter/stream_chat_flutter.dart'; + +void main() async { + final client = Client( + 's2dxdhpxd94g', + logLevel: Level.INFO, + ); + + await client.setUser( + User(id: 'super-band-9'), + 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoic3VwZXItYmFuZC05In0.0L6lGoeLwkz0aZRUcpZKsvaXtNEDHBcezVTZ0oPq40A', + ); + + runApp(MyApp(client)); +} + +class MyApp extends StatelessWidget { + final Client client; + + MyApp(this.client); + + @override + Widget build(BuildContext context) { + return MaterialApp( + builder: (context, child) => StreamChat( + child: child, + client: client, + ), + home: SplitView(), + ); + } +} + +class SplitView extends StatefulWidget { + @override + _SplitViewState createState() => _SplitViewState(); +} + +class _SplitViewState extends State { + Channel selectedChannel; + + @override + Widget build(BuildContext context) { + return Flex( + direction: Axis.horizontal, + children: [ + Flexible( + child: ChannelListPage( + onTap: (channel) { + setState(() { + selectedChannel = channel; + }); + }, + ), + flex: 1, + ), + Flexible( + child: selectedChannel != null + ? StreamChannel( + key: ValueKey(selectedChannel.cid), + child: ChannelPage(), + channel: selectedChannel, + ) + : Scaffold( + body: Center( + child: Text( + 'Pick a channel to show the messages 💬', + style: Theme.of(context).textTheme.headline, + ), + ), + ), + flex: 2, + ), + ], + ); + } +} + +class ChannelListPage extends StatelessWidget { + final void Function(Channel) onTap; + + ChannelListPage({this.onTap}); + + @override + Widget build(BuildContext context) { + return Scaffold( + body: ChannelsBloc( + child: ChannelListView( + onChannelTap: onTap != null + ? (channel, _) { + onTap(channel); + } + : null, + filter: { + 'members': { + '\$in': [StreamChat.of(context).user.id], + } + }, + sort: [SortOption('last_message_at')], + pagination: PaginationParams( + limit: 20, + ), + channelWidget: ChannelPage(), + ), + ), + ); + } +} + +class ChannelPage extends StatelessWidget { + const ChannelPage({ + Key key, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: ChannelHeader( + showBackButton: false, + ), + body: Column( + children: [ + Expanded( + child: MessageListView(), + ), + MessageInput(), + ], + ), + ); + } +} diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 86ab5a62..607913b7 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -1,7 +1,7 @@ name: example description: A new Flutter project. -version: 1.0.3+5 +version: 1.0.4+6 environment: sdk: ">=2.2.2 <3.0.0" From 1bc5982d725c5661973fa0af1dd9f0b4b82fdcdc Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Tue, 28 Jul 2020 15:38:32 +0200 Subject: [PATCH 0052/1140] update matchfile --- example/ios/fastlane/{MatchFile => Matchfile} | 4 +++- example/pubspec.yaml | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) rename example/ios/fastlane/{MatchFile => Matchfile} (89%) diff --git a/example/ios/fastlane/MatchFile b/example/ios/fastlane/Matchfile similarity index 89% rename from example/ios/fastlane/MatchFile rename to example/ios/fastlane/Matchfile index 3d0ce2c0..26e1dda3 100644 --- a/example/ios/fastlane/MatchFile +++ b/example/ios/fastlane/Matchfile @@ -2,7 +2,9 @@ git_url("https://github.com/GetStream/ios-certificates") storage_mode("git") -username("imtoori") +username("salvatore@getstream.io") + +type("adhoc") team_id("EHV7XZLAHA") diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 607913b7..e19a0e9f 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -1,7 +1,7 @@ name: example description: A new Flutter project. -version: 1.0.4+6 +version: 1.0.5+7 environment: sdk: ">=2.2.2 <3.0.0" From f28e1cb914d7a46d7389e8c375de61f23258ef8d Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Tue, 28 Jul 2020 15:49:25 +0200 Subject: [PATCH 0053/1140] update matchfile --- example/ios/fastlane/Matchfile | 2 -- example/pubspec.yaml | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/example/ios/fastlane/Matchfile b/example/ios/fastlane/Matchfile index 26e1dda3..21b0863c 100644 --- a/example/ios/fastlane/Matchfile +++ b/example/ios/fastlane/Matchfile @@ -4,8 +4,6 @@ storage_mode("git") username("salvatore@getstream.io") -type("adhoc") - team_id("EHV7XZLAHA") # app_identifier(["tools.fastlane.app", "tools.fastlane.app2"]) diff --git a/example/pubspec.yaml b/example/pubspec.yaml index e19a0e9f..580de824 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -1,7 +1,7 @@ name: example description: A new Flutter project. -version: 1.0.5+7 +version: 1.0.6+8 environment: sdk: ">=2.2.2 <3.0.0" From 5d1d695911b798d26fc812357ee14d325bdd652e Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Tue, 28 Jul 2020 16:52:40 +0200 Subject: [PATCH 0054/1140] add setup_ci --- example/ios/fastlane/Fastfile | 6 ++++++ example/pubspec.yaml | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/example/ios/fastlane/Fastfile b/example/ios/fastlane/Fastfile index f2eb8c56..575e5dd7 100644 --- a/example/ios/fastlane/Fastfile +++ b/example/ios/fastlane/Fastfile @@ -1,6 +1,12 @@ fastlane_version "2.68.0" default_platform :ios +before_all do + if is_ci + setup_ci() + end +end + desc "Installs all Certs and Profiles necessary for development and ad-hoc" lane :match_me do match( diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 580de824..fb730eff 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -1,7 +1,7 @@ name: example description: A new Flutter project. -version: 1.0.6+8 +version: 1.0.7+9 environment: sdk: ">=2.2.2 <3.0.0" From 79505b2254987b138bf7c589a073c45ebb18ab22 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Wed, 29 Jul 2020 11:22:44 +0200 Subject: [PATCH 0055/1140] update provisioning profiles --- .../fastlane/beta_gym_export_options.plist | 4 ++-- example/ios/fastlane/report.xml | 21 ++++++++++++------- example/pubspec.yaml | 2 +- 3 files changed, 16 insertions(+), 11 deletions(-) diff --git a/example/ios/fastlane/beta_gym_export_options.plist b/example/ios/fastlane/beta_gym_export_options.plist index 986bb5e6..7889dd5a 100644 --- a/example/ios/fastlane/beta_gym_export_options.plist +++ b/example/ios/fastlane/beta_gym_export_options.plist @@ -7,9 +7,9 @@ provisioningProfiles io.getstream.flutter - flutter example + match Development io.getstream.flutter io.getstream.flutter.Notifications - flutter example notifications + match Development io.getstream.flutter.Notifications \ No newline at end of file diff --git a/example/ios/fastlane/report.xml b/example/ios/fastlane/report.xml index e26cb644..51cbc75b 100644 --- a/example/ios/fastlane/report.xml +++ b/example/ios/fastlane/report.xml @@ -5,42 +5,47 @@ - + - + - + - + - + - + - + - + + + + + + diff --git a/example/pubspec.yaml b/example/pubspec.yaml index fb730eff..9bb4e4d7 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -1,7 +1,7 @@ name: example description: A new Flutter project. -version: 1.0.7+9 +version: 1.0.8+10 environment: sdk: ">=2.2.2 <3.0.0" From 65c18b57a1d72ccdc6f1c06fbda3ae4fa1773775 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Wed, 29 Jul 2020 11:38:13 +0200 Subject: [PATCH 0056/1140] update provisioning profiles --- example/ios/fastlane/beta_gym_export_options.plist | 4 ++-- example/pubspec.yaml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/example/ios/fastlane/beta_gym_export_options.plist b/example/ios/fastlane/beta_gym_export_options.plist index 7889dd5a..53c74098 100644 --- a/example/ios/fastlane/beta_gym_export_options.plist +++ b/example/ios/fastlane/beta_gym_export_options.plist @@ -7,9 +7,9 @@ provisioningProfiles io.getstream.flutter - match Development io.getstream.flutter + match AdHoc io.getstream.flutter io.getstream.flutter.Notifications - match Development io.getstream.flutter.Notifications + match AdHoc io.getstream.flutter.Notifications \ No newline at end of file diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 9bb4e4d7..fdd63a9e 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -1,7 +1,7 @@ name: example description: A new Flutter project. -version: 1.0.8+10 +version: 1.0.9+11 environment: sdk: ">=2.2.2 <3.0.0" From bdac79505976a595cbb94fde75cbff53e6b206f8 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Wed, 29 Jul 2020 11:59:38 +0200 Subject: [PATCH 0057/1140] update provisioning profiles --- example/ios/Runner.xcodeproj/project.pbxproj | 12 ++++++------ example/pubspec.yaml | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/example/ios/Runner.xcodeproj/project.pbxproj b/example/ios/Runner.xcodeproj/project.pbxproj index 6083a722..5405840a 100644 --- a/example/ios/Runner.xcodeproj/project.pbxproj +++ b/example/ios/Runner.xcodeproj/project.pbxproj @@ -424,7 +424,7 @@ MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = io.getstream.flutter.Notifications; PRODUCT_NAME = "$(TARGET_NAME)"; - PROVISIONING_PROFILE_SPECIFIER = "flutter example notifications"; + PROVISIONING_PROFILE_SPECIFIER = "match AdHoc io.getstream.flutter.Notifications"; SKIP_INSTALL = YES; SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; @@ -453,7 +453,7 @@ MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = io.getstream.flutter.Notifications; PRODUCT_NAME = "$(TARGET_NAME)"; - PROVISIONING_PROFILE_SPECIFIER = "flutter example notifications"; + PROVISIONING_PROFILE_SPECIFIER = "match AdHoc io.getstream.flutter.Notifications"; SKIP_INSTALL = YES; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; @@ -480,7 +480,7 @@ MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = io.getstream.flutter.Notifications; PRODUCT_NAME = "$(TARGET_NAME)"; - PROVISIONING_PROFILE_SPECIFIER = "flutter example notifications"; + PROVISIONING_PROFILE_SPECIFIER = "match AdHoc io.getstream.flutter.Notifications"; SKIP_INSTALL = YES; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; @@ -564,7 +564,7 @@ ); PRODUCT_BUNDLE_IDENTIFIER = io.getstream.flutter; PRODUCT_NAME = "$(TARGET_NAME)"; - PROVISIONING_PROFILE_SPECIFIER = "flutter example"; + PROVISIONING_PROFILE_SPECIFIER = "match AdHoc io.getstream.flutter"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_VERSION = 5.0; VERSIONING_SYSTEM = "apple-generic"; @@ -705,7 +705,7 @@ ); PRODUCT_BUNDLE_IDENTIFIER = io.getstream.flutter; PRODUCT_NAME = "$(TARGET_NAME)"; - PROVISIONING_PROFILE_SPECIFIER = "flutter example"; + PROVISIONING_PROFILE_SPECIFIER = "match AdHoc io.getstream.flutter"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 5.0; @@ -739,7 +739,7 @@ ); PRODUCT_BUNDLE_IDENTIFIER = io.getstream.flutter; PRODUCT_NAME = "$(TARGET_NAME)"; - PROVISIONING_PROFILE_SPECIFIER = "flutter example"; + PROVISIONING_PROFILE_SPECIFIER = "match AdHoc io.getstream.flutter"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_VERSION = 5.0; VERSIONING_SYSTEM = "apple-generic"; diff --git a/example/pubspec.yaml b/example/pubspec.yaml index fdd63a9e..5d9c539d 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -1,7 +1,7 @@ name: example description: A new Flutter project. -version: 1.0.9+11 +version: 1.0.10+12 environment: sdk: ">=2.2.2 <3.0.0" From e1aaa63ac7a042b53825b6ceca14c80d508c474d Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Wed, 29 Jul 2020 12:22:37 +0200 Subject: [PATCH 0058/1140] fix firebase in fastlane --- example/ios/fastlane/Fastfile | 2 +- example/pubspec.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/example/ios/fastlane/Fastfile b/example/ios/fastlane/Fastfile index 575e5dd7..8e0393af 100644 --- a/example/ios/fastlane/Fastfile +++ b/example/ios/fastlane/Fastfile @@ -46,7 +46,7 @@ platform :ios do firebase_app_distribution( app: "1:674907137625:ios:cafb9fb076a453c4d7f348", - groups: "ios-stream-testers", + groups: "ios-stream-testers" ) end end \ No newline at end of file diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 5d9c539d..fe8266eb 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -1,7 +1,7 @@ name: example description: A new Flutter project. -version: 1.0.10+12 +version: 1.0.11+13 environment: sdk: ">=2.2.2 <3.0.0" From 5e2d61c00e5cf3ec7ee264c8b873bb6fe20d9c5a Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Wed, 29 Jul 2020 12:45:59 +0200 Subject: [PATCH 0059/1140] add firebase tools --- .github/workflows/main.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 5ba77776..85157d7c 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -63,6 +63,8 @@ jobs: - uses: subosito/flutter-action@v1.3.2 with: flutter-version: ${{ env.flutter_version }} + - name: Install firebase-tools + run: npm install -g firebase-tools - name: Flutter setup run: | cd example From 882b57aca2ae121c86cb999d4a8535f8b817b9fd Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Wed, 29 Jul 2020 14:06:43 +0200 Subject: [PATCH 0060/1140] update main.yml --- .github/workflows/main.yml | 46 +++----------------------------------- 1 file changed, 3 insertions(+), 43 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 85157d7c..e6c393ba 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -1,49 +1,14 @@ name: CI on: - push: -# branches: -# - master -# pull_request: -# branches: -# - master -# release: -# types: -# - created + release: + types: + - created env: flutter_version: "1.17.5" jobs: - test: - runs-on: [ubuntu-latest] - steps: - - uses: actions/checkout@v2 - - name: Cache Flutter dependencies - id: cache - uses: actions/cache@v1 - with: - path: /opt/hostedtoolcache/flutter - key: ${{ runner.OS }}-flutter-cache-${{ env.flutter_version }} - - name: Flutter action - uses: subosito/flutter-action@v1.3.2 - with: - flutter-version: ${{ env.flutter_version }} - - name: Get dependencies - run: flutter pub get - - name: Coverage fix - run: | - file=test/coverage_helper_test.dart - echo "// Helper file to make coverage work for all dart files\n" > $file - echo "// ignore_for_file: unused_import" >> $file - find lib -name '*.dart' | grep -e '[^g]\.dart' | grep -v '_html.dart' | cut -c4- | awk -v package=stream_chat_flutter '{printf "import '\''package:%s%s'\'';\n", package, $1}' >> $file - echo "" >> $file - echo "void main(){}" >> $file - cat $file - - name: Run tests - run: flutter test --coverage - - name: Codecov - run: bash <(curl -s https://codecov.io/bash) -c -t ${{ secrets.CODECOV_TOKEN }} -f coverage/lcov.info -F flutter_tool build_and_deploy_ios: runs-on: [macos-latest] steps: @@ -96,11 +61,6 @@ jobs: run: | cd example flutter build apk - - name: Upload - uses: actions/upload-artifact@v2 - with: - name: apk-build - path: example/build/app/outputs/bundle/release - name: Deploy uses: wzieba/Firebase-Distribution-Github-Action@v1.2.1 with: From d008bc01acf88e42c2567b2943ba558facb79719 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Mon, 3 Aug 2020 10:45:59 +0200 Subject: [PATCH 0061/1140] update image group sizing --- lib/src/image_group.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/image_group.dart b/lib/src/image_group.dart index 51b7be80..1a7144d8 100644 --- a/lib/src/image_group.dart +++ b/lib/src/image_group.dart @@ -10,7 +10,7 @@ class ImageGroup extends StatelessWidget { Key key, @required this.images, @required this.message, - this.size, + @required this.size, }) : super(key: key); final List images; From b95efa0ea5849e6feb493fcdc7bdb8760ebe3226 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Mon, 3 Aug 2020 15:56:00 +0200 Subject: [PATCH 0062/1140] update components for splitview --- example/lib/split_view.dart | 53 +++++----- example/pubspec.yaml | 2 +- lib/src/message_widget.dart | 198 ++++++++++++++++++------------------ 3 files changed, 128 insertions(+), 125 deletions(-) diff --git a/example/lib/split_view.dart b/example/lib/split_view.dart index cbfd8798..f99e69fc 100644 --- a/example/lib/split_view.dart +++ b/example/lib/split_view.dart @@ -56,20 +56,20 @@ class _SplitViewState extends State { flex: 1, ), Flexible( - child: selectedChannel != null - ? StreamChannel( - key: ValueKey(selectedChannel.cid), - child: ChannelPage(), - channel: selectedChannel, - ) - : Scaffold( - body: Center( + child: Scaffold( + body: selectedChannel != null + ? StreamChannel( + key: ValueKey(selectedChannel.cid), + child: ChannelPage(), + channel: selectedChannel, + ) + : Center( child: Text( 'Pick a channel to show the messages 💬', - style: Theme.of(context).textTheme.headline, + style: Theme.of(context).textTheme.headline5, ), ), - ), + ), flex: 2, ), ], @@ -101,7 +101,6 @@ class ChannelListPage extends StatelessWidget { pagination: PaginationParams( limit: 20, ), - channelWidget: ChannelPage(), ), ), ); @@ -115,18 +114,26 @@ class ChannelPage extends StatelessWidget { @override Widget build(BuildContext context) { - return Scaffold( - appBar: ChannelHeader( - showBackButton: false, - ), - body: Column( - children: [ - Expanded( - child: MessageListView(), - ), - MessageInput(), - ], - ), + return Navigator( + onGenerateRoute: (settings) { + return MaterialPageRoute( + builder: (context) { + return Scaffold( + appBar: ChannelHeader( + showBackButton: false, + ), + body: Column( + children: [ + Expanded( + child: MessageListView(), + ), + MessageInput(), + ], + ), + ); + }, + ); + }, ); } } diff --git a/example/pubspec.yaml b/example/pubspec.yaml index fe8266eb..0e512cf6 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -1,7 +1,7 @@ name: example description: A new Flutter project. -version: 1.0.11+13 +version: 1.0.12+14 environment: sdk: ">=2.2.2 <3.0.0" diff --git a/lib/src/message_widget.dart b/lib/src/message_widget.dart index 2fc448ad..a2020726 100644 --- a/lib/src/message_widget.dart +++ b/lib/src/message_widget.dart @@ -216,90 +216,83 @@ class _MessageWidgetState extends State { child: Transform( alignment: Alignment.center, transform: Matrix4.rotationY(widget.reverse ? pi : 0), - child: Container( + child: FractionallySizedBox( alignment: Alignment.centerLeft, - child: Container( - constraints: BoxConstraints.loose( - Size.fromWidth(MediaQuery.of(context).size.width * 0.8), - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisSize: MainAxisSize.min, - children: [ - IntrinsicWidth( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, + widthFactor: 0.75, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.end, mainAxisSize: MainAxisSize.min, children: [ - Row( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.end, - mainAxisSize: MainAxisSize.min, - children: [ - if (widget.showUserAvatar == DisplayWidget.show) - _buildUserAvatar(), - SizedBox( - width: 6, + if (widget.showUserAvatar == DisplayWidget.show) + _buildUserAvatar(), + SizedBox( + width: 6, + ), + if (widget.showUserAvatar == DisplayWidget.hide) + SizedBox( + width: widget.messageTheme.avatarTheme.constraints + .maxWidth + + 8, + ), + Flexible( + child: Padding( + padding: widget.showReactions + ? EdgeInsets.only( + top: _reactionPadding, + ) + : EdgeInsets.zero, + child: PortalEntry( + portalAnchor: Alignment(0, 1), + childAnchor: Alignment.topRight, + portal: _buildReactionIndicator(context), + child: (widget.message.isDeleted && + widget.message.status != + MessageSendingStatus.FAILED_DELETE) + ? Transform( + alignment: Alignment.center, + transform: Matrix4.rotationY( + widget.reverse ? pi : 0), + child: DeletedMessage( + messageTheme: widget.messageTheme, + ), + ) + : Column( + crossAxisAlignment: + CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + ..._parseAttachments(context), + if (widget.message.text + .trim() + .isNotEmpty) + _buildTextBubble(context), + ], + ), ), - if (widget.showUserAvatar == DisplayWidget.hide) - SizedBox( - width: widget.messageTheme.avatarTheme - .constraints.maxWidth + - 8, - ), - Flexible( - child: Padding( - padding: widget.showReactions - ? EdgeInsets.only( - top: _reactionPadding, - ) - : EdgeInsets.zero, - child: PortalEntry( - portalAnchor: Alignment(0, 1), - childAnchor: Alignment.topRight, - portal: _buildReactionIndicator(context), - child: (widget.message.isDeleted && - widget.message.status != - MessageSendingStatus - .FAILED_DELETE) - ? Transform( - alignment: Alignment.center, - transform: Matrix4.rotationY( - widget.reverse ? pi : 0), - child: DeletedMessage( - messageTheme: widget.messageTheme, - ), - ) - : Column( - crossAxisAlignment: - CrossAxisAlignment.start, - mainAxisSize: MainAxisSize.min, - children: [ - ..._parseAttachments(context), - if (widget.message.text - .trim() - .isNotEmpty) - _buildTextBubble(context), - ], - ), - ), - ), - ), - ], + ), ), - if (widget.showReplyIndicator && - widget.message.replyCount > 0) - _buildReplyIndicator(leftPadding), ], ), - ), - if ((widget.message.createdAt != null && - widget.showTimestamp) || - widget.showUsername || - widget.readList?.isNotEmpty == true) - _buildBottomRow(leftPadding), - ], - ), + if (widget.showReplyIndicator && + widget.message.replyCount > 0) + _buildReplyIndicator(leftPadding), + ], + ), + if ((widget.message.createdAt != null && + widget.showTimestamp) || + widget.showUsername || + widget.readList?.isNotEmpty == true) + _buildBottomRow(leftPadding), + ], ), ), ), @@ -447,32 +440,35 @@ class _MessageWidgetState extends State { ? Container( child: GestureDetector( onTap: () => onLongPress(context), - child: Container( - width: MediaQuery.of(context).size.width * 0.3, - padding: const EdgeInsets.only( - bottom: 4.0, - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisSize: MainAxisSize.min, - children: [ - Transform( - transform: Matrix4.rotationY(widget.reverse ? pi : 0), - alignment: Alignment.center, - child: Container( - padding: const EdgeInsets.all(8), - decoration: BoxDecoration( - color: - Theme.of(context).brightness == Brightness.dark - ? Colors.white - : Colors.black, - borderRadius: BorderRadius.all(Radius.circular(14)), + child: FractionallySizedBox( + widthFactor: 0.3, + child: Padding( + padding: const EdgeInsets.only( + bottom: 4.0, + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisSize: MainAxisSize.min, + children: [ + Transform( + transform: Matrix4.rotationY(widget.reverse ? pi : 0), + alignment: Alignment.center, + child: Container( + padding: const EdgeInsets.all(8), + decoration: BoxDecoration( + color: Theme.of(context).brightness == + Brightness.dark + ? Colors.white + : Colors.black, + borderRadius: + BorderRadius.all(Radius.circular(14)), + ), + child: _buildReactionsText(context), ), - child: _buildReactionsText(context), ), - ), - _buildReactionsTail(context), - ], + _buildReactionsTail(context), + ], + ), ), ), ), From bab5565964706936a5c73808ae6fa8d215684fc7 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Fri, 7 Aug 2020 16:53:58 +0200 Subject: [PATCH 0063/1140] merge master --- CHANGELOG.md | 14 ++++++++++++ lib/src/channel_bottom_sheet.dart | 12 ++++------ lib/src/channel_list_view.dart | 15 ++++-------- lib/src/channels_bloc.dart | 38 ++++++++++++++++++++++++++----- lib/src/message_widget.dart | 13 +++++++++-- pubspec.yaml | 6 ++--- 6 files changed, 69 insertions(+), 29 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0db3a916..911e4ba3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,17 @@ +## 0.2.3 + +- Add `lockChannelsOrder` parameter to `ChannelsBloc` + +## 0.2.2+3 + +- Fix `ChannelListView` channel hidden behaviour + +- Refresh `ChannelListView` on new message from hidden channel + +## 0.2.2+1 + +- Fix some components to implement a splitview example + ## 0.2.2 - Add `messageLinks` property to `MessageTheme` to customize links color diff --git a/lib/src/channel_bottom_sheet.dart b/lib/src/channel_bottom_sheet.dart index a2f124fc..5d32b80c 100644 --- a/lib/src/channel_bottom_sheet.dart +++ b/lib/src/channel_bottom_sheet.dart @@ -107,10 +107,8 @@ class ChannelBottomSheet extends StatelessWidget { 'Do you want to leave the group?', ); if (confirm == true) { - await channel.removeMembers(channel.state.members - .where((element) => - element.userId == StreamChat.of(context).user.id) - .toList()); + await channel + .removeMembers([StreamChat.of(context).user.id]); Navigator.pop(context); } }, @@ -133,10 +131,8 @@ class ChannelBottomSheet extends StatelessWidget { 'Do you want to delete the chat?', ); if (confirm == true) { - await channel.removeMembers(channel.state.members - .where((element) => - element.userId == StreamChat.of(context).user.id) - .toList()); + await channel + .removeMembers([StreamChat.of(context).user.id]); Navigator.pop(context); } }, diff --git a/lib/src/channel_list_view.dart b/lib/src/channel_list_view.dart index 11f4b402..fd60eb95 100644 --- a/lib/src/channel_list_view.dart +++ b/lib/src/channel_list_view.dart @@ -339,11 +339,8 @@ class _ChannelListViewState extends State 'Do you want to leave the group?', ); if (confirm == true) { - await channel.removeMembers(channel.state.members - .where((element) => - element.userId == - StreamChat.of(context).user.id) - .toList()); + await channel + .removeMembers([StreamChat.of(context).user.id]); } }, ), @@ -357,11 +354,8 @@ class _ChannelListViewState extends State 'Do you want to delete the chat?', ); if (confirm == true) { - await channel.removeMembers(channel.state.members - .where((element) => - element.userId == - StreamChat.of(context).user.id) - .toList()); + await channel + .removeMembers([StreamChat.of(context).user.id]); } }, ), @@ -472,6 +466,7 @@ class _ChannelListViewState extends State .on( EventType.connectionRecovered, EventType.notificationAddedToChannel, + EventType.notificationMessageNew, EventType.channelVisible, ) .listen((event) { diff --git a/lib/src/channels_bloc.dart b/lib/src/channels_bloc.dart index b38c6030..e2cf9cd9 100644 --- a/lib/src/channels_bloc.dart +++ b/lib/src/channels_bloc.dart @@ -4,16 +4,21 @@ import 'package:flutter/material.dart'; import 'package:rxdart/rxdart.dart'; import 'package:stream_chat/stream_chat.dart'; import 'package:stream_chat_flutter/src/stream_chat.dart'; +import 'package:stream_chat_flutter/stream_chat_flutter.dart'; /// Widget dedicated to the management of a channel list with pagination class ChannelsBloc extends StatefulWidget { /// The widget child final Widget child; + /// Set this to false to prevent channels to be brought to the top of the list when a new message arrives + final bool lockChannelsOrder; + /// Instantiate a new ChannelsBloc const ChannelsBloc({ Key key, this.child, + this.lockChannelsOrder = false, }) : super(key: key); @override @@ -58,6 +63,8 @@ class ChannelsBlocState extends State Stream get queryChannelsLoading => _queryChannelsLoadingController.stream; + final List _hiddenChannels = []; + /// Calls [client.queryChannels] updating [queryChannelsLoading] stream Future queryChannels({ Map filter, @@ -112,12 +119,31 @@ class ChannelsBlocState extends State final client = StreamChat.of(context).client; - _subscriptions.add(client.on(EventType.messageNew).listen((e) { - final newChannels = List.from(channels ?? []); - final index = newChannels.indexWhere((c) => c.cid == e.cid); - if (index > 0) { - final channel = newChannels.removeAt(index); - newChannels.insert(0, channel); + if (!widget.lockChannelsOrder) { + _subscriptions.add(client.on(EventType.messageNew).listen((e) { + final newChannels = List.from(channels ?? []); + final index = newChannels.indexWhere((c) => c.cid == e.cid); + if (index > 0) { + final channel = newChannels.removeAt(index); + newChannels.insert(0, channel); + _channelsController.add(newChannels); + } else { + final hiddenIndex = _hiddenChannels.indexWhere((c) => c.cid == e.cid); + if (hiddenIndex > -1) { + newChannels.insert(0, _hiddenChannels[hiddenIndex]); + _hiddenChannels.removeAt(hiddenIndex); + _channelsController.add(newChannels); + } + } + })); + } + + _subscriptions.add(client.on(EventType.channelHidden).listen((event) async { + final newChannels = List.from(channels); + final channelIndex = newChannels.indexWhere((c) => c.cid == event.cid); + if (channelIndex > -1) { + final channel = newChannels.removeAt(channelIndex); + _hiddenChannels.add(channel); _channelsController.add(newChannels); } })); diff --git a/lib/src/message_widget.dart b/lib/src/message_widget.dart index a2020726..663e682a 100644 --- a/lib/src/message_widget.dart +++ b/lib/src/message_widget.dart @@ -208,8 +208,8 @@ class _MessageWidgetState extends State { @override Widget build(BuildContext context) { var leftPadding = widget.showUserAvatar != DisplayWidget.gone - ? widget.messageTheme.avatarTheme.constraints.maxWidth + 16.0 - : 6.0; + ? widget.messageTheme.avatarTheme.constraints.maxWidth + 24.0 + : 16.0; return Portal( child: Padding( padding: widget.padding ?? EdgeInsets.all(8), @@ -232,6 +232,15 @@ class _MessageWidgetState extends State { crossAxisAlignment: CrossAxisAlignment.end, mainAxisSize: MainAxisSize.min, children: [ + if (widget.showSendingIndicator == DisplayWidget.show) + _buildSendingIndicator(), + SizedBox( + width: 2, + ), + if (widget.showSendingIndicator == DisplayWidget.hide) + SizedBox( + width: 8, + ), if (widget.showUserAvatar == DisplayWidget.show) _buildUserAvatar(), SizedBox( diff --git a/pubspec.yaml b/pubspec.yaml index 8c25ab28..6eb7a7d8 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: stream_chat_flutter homepage: https://github.com/GetStream/stream-chat-flutter description: Stream Chat official Flutter SDK. Build your own chat experience using Dart and Flutter. -version: 0.2.2 +version: 0.2.3 repository: https://github.com/GetStream/stream-chat-flutter issue_tracker: https://github.com/GetStream/stream-chat-flutter/issues @@ -23,8 +23,8 @@ dependencies: file_picker: ^1.12.0 image_picker: ^0.6.7+2 flutter_keyboard_visibility: ^3.2.1 - stream_chat: ^0.2.1 - flutter_svg: ^0.17.0 + flutter_svg: ^0.18.0 + stream_chat: ^0.2.2 mime: ^0.9.6+3 visibility_detector: ^0.1.5 line_awesome_icons: ^1.0.4+2 From bd4eb3d7e9d5ff57dfdd6580ff5182d26a0cf32f Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Mon, 17 Aug 2020 14:42:40 +0200 Subject: [PATCH 0064/1140] fix sending indicator --- lib/src/message_widget.dart | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/lib/src/message_widget.dart b/lib/src/message_widget.dart index 663e682a..a2020726 100644 --- a/lib/src/message_widget.dart +++ b/lib/src/message_widget.dart @@ -208,8 +208,8 @@ class _MessageWidgetState extends State { @override Widget build(BuildContext context) { var leftPadding = widget.showUserAvatar != DisplayWidget.gone - ? widget.messageTheme.avatarTheme.constraints.maxWidth + 24.0 - : 16.0; + ? widget.messageTheme.avatarTheme.constraints.maxWidth + 16.0 + : 6.0; return Portal( child: Padding( padding: widget.padding ?? EdgeInsets.all(8), @@ -232,15 +232,6 @@ class _MessageWidgetState extends State { crossAxisAlignment: CrossAxisAlignment.end, mainAxisSize: MainAxisSize.min, children: [ - if (widget.showSendingIndicator == DisplayWidget.show) - _buildSendingIndicator(), - SizedBox( - width: 2, - ), - if (widget.showSendingIndicator == DisplayWidget.hide) - SizedBox( - width: 8, - ), if (widget.showUserAvatar == DisplayWidget.show) _buildUserAvatar(), SizedBox( From cd1af89fc0112861e226a587c27a7c82e8af278c Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Mon, 24 Aug 2020 11:07:32 +0200 Subject: [PATCH 0065/1140] implement didUpdateWidget in ChannelListView to react to setState --- lib/src/channel_list_view.dart | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/lib/src/channel_list_view.dart b/lib/src/channel_list_view.dart index fd60eb95..c3f31e56 100644 --- a/lib/src/channel_list_view.dart +++ b/lib/src/channel_list_view.dart @@ -441,10 +441,9 @@ class _ChannelListViewState extends State void initState() { super.initState(); - final channelsBloc = ChannelsBloc.of(context); - WidgetsBinding.instance.addObserver(this); + final channelsBloc = ChannelsBloc.of(context); channelsBloc.queryChannels( filter: widget.filter, sortOptions: widget.sort, @@ -479,6 +478,24 @@ class _ChannelListViewState extends State }); } + @override + void didUpdateWidget(ChannelListView oldWidget) { + super.didUpdateWidget(oldWidget); + + if (widget.filter != oldWidget.filter || + widget.sort != oldWidget.sort || + widget.pagination != oldWidget.pagination || + widget.options != oldWidget.options) { + final channelsBloc = ChannelsBloc.of(context); + channelsBloc.queryChannels( + filter: widget.filter, + sortOptions: widget.sort, + paginationParams: widget.pagination, + options: widget.options, + ); + } + } + @override void dispose() { WidgetsBinding.instance.removeObserver(this); From 0997867944b5c4a055e2506df887795ac4c0492e Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Thu, 27 Aug 2020 16:22:22 +0200 Subject: [PATCH 0066/1140] add message_actions_modal.dart --- assets/icon_edit.svg | 3 + lib/src/message_actions_modal.dart | 278 +++++++++++++++++++++++++++++ lib/src/message_widget.dart | 48 ++--- lib/src/reaction_picker.dart | 2 +- 4 files changed, 306 insertions(+), 25 deletions(-) create mode 100644 assets/icon_edit.svg create mode 100644 lib/src/message_actions_modal.dart diff --git a/assets/icon_edit.svg b/assets/icon_edit.svg new file mode 100644 index 00000000..6979c575 --- /dev/null +++ b/assets/icon_edit.svg @@ -0,0 +1,3 @@ + + + diff --git a/lib/src/message_actions_modal.dart b/lib/src/message_actions_modal.dart new file mode 100644 index 00000000..5a089786 --- /dev/null +++ b/lib/src/message_actions_modal.dart @@ -0,0 +1,278 @@ +import 'dart:ui'; + +import 'package:flutter/material.dart'; +import 'package:flutter_svg/flutter_svg.dart'; +import 'package:stream_chat/stream_chat.dart'; +import 'package:stream_chat_flutter/src/reaction_picker.dart'; +import 'package:stream_chat_flutter/src/stream_channel.dart'; + +import '../stream_chat_flutter.dart'; +import 'message_input.dart'; +import 'stream_chat.dart'; + +class MessageActionsModal extends StatelessWidget { + final Widget Function(BuildContext, Message) editMessageInputBuilder; + final void Function(Message) onThreadTap; + final Message message; + final MessageTheme messageTheme; + final bool showReactions; + final bool showDeleteMessage; + final bool showEditMessage; + final bool showReply; + final bool reverse; + final ShapeBorder messageShape; + final Map reactionToEmoji = const { + 'love': '❤️️', + 'haha': '😂', + 'like': '👍', + 'sad': '😕', + 'angry': '😡', + 'wow': '😲', + }; + + const MessageActionsModal({ + Key key, + @required this.message, + @required this.messageTheme, + this.showReactions, + this.showDeleteMessage, + this.showEditMessage, + this.onThreadTap, + this.showReply, + this.editMessageInputBuilder, + this.messageShape, + this.reverse, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + final channel = StreamChannel.of(context).channel; + 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, + ), + ), + ), + ), + Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + if (showReactions && + (message.status == MessageSendingStatus.SENT || + message.status == null)) + ReactionPicker( + channel: channel, + reactionToEmoji: reactionToEmoji, + message: message, + ), + AbsorbPointer( + child: MessageWidget( + reverse: reverse, + message: message, + 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( + context: context, + tiles: [ + if (showEditMessage) _buildEditMessage(context), + if (showReply && + (message.status == MessageSendingStatus.SENT || + message.status == null) && + message.parentId == null) + _buildReplyButton(context), + if (showDeleteMessage) _buildDeleteButton(context), + ], + ).toList(), + ), + ), + ) + ], + ), + ], + ); + } + + Widget _buildDeleteButton(BuildContext context) { + return ListTile( + title: Text( + 'Delete message', + style: + Theme.of(context).textTheme.headline6.copyWith(color: Colors.red), + ), + leading: Icon( + Icons.delete_outline, + color: Colors.red, + ), + onTap: () { + Navigator.pop(context); + StreamChat.of(context).client.deleteMessage( + message, + StreamChannel.of(context).channel.cid, + ); + }, + ); + } + + Widget _buildEditMessage(BuildContext context) { + return ListTile( + title: Text( + 'Edit message', + style: Theme.of(context).textTheme.headline6, + ), + leading: SvgPicture.asset( + 'assets/icon_edit.svg', + alignment: Alignment.center, + package: 'stream_chat_flutter', + color: StreamChatTheme.of(context).primaryIconTheme.color, + width: 17, + ), + onTap: () async { + Navigator.pop(context); + _showEditBottomSheet(context); + }, + ); + } + + void _showEditBottomSheet(BuildContext context) { + final channel = StreamChannel.of(context).channel; + showModalBottomSheet( + context: context, + elevation: 2, + clipBehavior: Clip.hardEdge, + isScrollControlled: true, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.only( + topLeft: Radius.circular(32), + topRight: Radius.circular(32), + ), + ), + builder: (context) { + return StreamChannel( + channel: channel, + child: Flex( + direction: Axis.vertical, + mainAxisAlignment: MainAxisAlignment.end, + mainAxisSize: MainAxisSize.min, + children: [ + Padding( + padding: const EdgeInsets.only( + top: 16.0, + left: 16.0, + right: 16.0, + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + 'Edit message', + style: Theme.of(context).textTheme.headline6, + ), + Container( + height: 30, + padding: const EdgeInsets.all(2.0), + child: AspectRatio( + aspectRatio: 1, + child: RawMaterialButton( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(4), + ), + elevation: 0, + highlightElevation: 0, + focusElevation: 0, + disabledElevation: 0, + hoverElevation: 0, + onPressed: () { + Navigator.of(context).pop(); + }, + fillColor: + Theme.of(context).brightness == Brightness.dark + ? Colors.white.withOpacity(.1) + : Colors.black.withOpacity(.1), + padding: EdgeInsets.all(4), + child: Icon( + Icons.close, + size: 15, + color: StreamChatTheme.of(context) + .primaryIconTheme + .color, + ), + ), + ), + ), + ], + ), + ), + Padding( + padding: EdgeInsets.only( + bottom: MediaQuery.of(context).viewInsets.bottom, + ), + child: editMessageInputBuilder != null + ? editMessageInputBuilder(context, message) + : MessageInput( + editMessage: message, + onMessageSent: (_) { + FocusScope.of(context).unfocus(); + Navigator.pop(context); + }, + ), + ), + ], + ), + ); + }, + ); + } + + Widget _buildReplyButton(BuildContext context) { + return ListTile( + title: Text( + 'Start a thread', + style: Theme.of(context).textTheme.headline6, + ), + leading: Icon( + Icons.reply, + color: StreamChatTheme.of(context).primaryIconTheme.color, + ), + onTap: () { + Navigator.pop(context); + if (onThreadTap != null) { + onThreadTap(message); + } + }, + ); + } +} diff --git a/lib/src/message_widget.dart b/lib/src/message_widget.dart index a2020726..c8160c06 100644 --- a/lib/src/message_widget.dart +++ b/lib/src/message_widget.dart @@ -6,10 +6,10 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_portal/flutter_portal.dart'; import 'package:jiffy/jiffy.dart'; +import 'package:stream_chat_flutter/src/message_actions_modal.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; import 'image_group.dart'; -import 'message_actions_bottom_sheet.dart'; import 'message_text.dart'; typedef AttachmentBuilder = Widget Function(BuildContext, Message, Attachment); @@ -492,21 +492,17 @@ class _MessageWidgetState extends State { ); } - void _showMessageBottomSheet(BuildContext context) { + void _showMessageModalBottomSheet(BuildContext context) { final channel = StreamChannel.of(context).channel; - showModalBottomSheet( - clipBehavior: Clip.hardEdge, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.only( - topLeft: Radius.circular(32), - topRight: Radius.circular(32), - ), - ), + showDialog( context: context, builder: (context) { return StreamChannel( channel: channel, - child: MessageActionsBottomSheet( + child: MessageActionsModal( + messageTheme: widget.messageTheme, + messageShape: widget.shape ?? _getDefaultShape(context), + reverse: widget.reverse, showDeleteMessage: widget.showDeleteMessage, message: widget.message, editMessageInputBuilder: widget.editMessageInputBuilder, @@ -520,6 +516,21 @@ class _MessageWidgetState extends State { }); } + ContinuousRectangleBorder _getDefaultShape(BuildContext context) { + return ContinuousRectangleBorder( + side: widget.attachmentBorderSide ?? + widget.borderSide ?? + BorderSide( + color: Theme.of(context).brightness == Brightness.dark + ? Colors.white.withAlpha(24) + : Colors.black.withAlpha(24), + ), + borderRadius: widget.attachmentBorderRadiusGeometry ?? + widget.borderRadiusGeometry ?? + BorderRadius.zero, + ); + } + List _parseAttachments(BuildContext context) { final images = widget.message.attachments .where((element) => element.type == 'image') @@ -574,18 +585,7 @@ class _MessageWidgetState extends State { clipBehavior: Clip.hardEdge, shape: widget.attachmentShape ?? widget.shape ?? - ContinuousRectangleBorder( - side: widget.attachmentBorderSide ?? - widget.borderSide ?? - BorderSide( - color: Theme.of(context).brightness == Brightness.dark - ? Colors.white.withAlpha(24) - : Colors.black.withAlpha(24), - ), - borderRadius: widget.attachmentBorderRadiusGeometry ?? - widget.borderRadiusGeometry ?? - BorderRadius.zero, - ), + _getDefaultShape(context), child: Padding( padding: widget.attachmentPadding, child: ClipRRect( @@ -621,7 +621,7 @@ class _MessageWidgetState extends State { if (widget.onMessageActions != null) { widget.onMessageActions(context, widget.message); } else { - _showMessageBottomSheet(context); + _showMessageModalBottomSheet(context); } return; } diff --git a/lib/src/reaction_picker.dart b/lib/src/reaction_picker.dart index 56127476..885d937a 100644 --- a/lib/src/reaction_picker.dart +++ b/lib/src/reaction_picker.dart @@ -24,7 +24,7 @@ class ReactionPicker extends StatelessWidget { @override Widget build(BuildContext context) { - return Container( + return Material( color: Colors.black87, child: Row( crossAxisAlignment: CrossAxisAlignment.start, From 8c17b268aee77925fbb2260311dec4c025c6648b Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Tue, 1 Sep 2020 15:09:47 +0200 Subject: [PATCH 0067/1140] add reaction picker --- assets/Icon_LOL_reaction.svg | 5 + assets/Icon_love_reaction.svg | 3 + assets/Icon_thumbs_down_reaction.svg | 3 + assets/Icon_thumbs_up_reaction.svg | 3 + assets/Icon_wut_reaction.svg | 3 + assets/icon_edit.svg | 4 +- lib/src/message_actions_bottom_sheet.dart | 209 ---------------------- lib/src/message_actions_modal.dart | 23 +-- lib/src/message_widget.dart | 158 ++++++++++++---- lib/src/reaction_asset.dart | 11 ++ lib/src/reaction_picker.dart | 73 ++++---- lib/src/stream_chat_theme.dart | 51 +++++- pubspec.yaml | 2 +- 13 files changed, 247 insertions(+), 301 deletions(-) create mode 100644 assets/Icon_LOL_reaction.svg create mode 100644 assets/Icon_love_reaction.svg create mode 100644 assets/Icon_thumbs_down_reaction.svg create mode 100644 assets/Icon_thumbs_up_reaction.svg create mode 100644 assets/Icon_wut_reaction.svg delete mode 100644 lib/src/message_actions_bottom_sheet.dart create mode 100644 lib/src/reaction_asset.dart diff --git a/assets/Icon_LOL_reaction.svg b/assets/Icon_LOL_reaction.svg new file mode 100644 index 00000000..301fe02c --- /dev/null +++ b/assets/Icon_LOL_reaction.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/assets/Icon_love_reaction.svg b/assets/Icon_love_reaction.svg new file mode 100644 index 00000000..76b09fd3 --- /dev/null +++ b/assets/Icon_love_reaction.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/Icon_thumbs_down_reaction.svg b/assets/Icon_thumbs_down_reaction.svg new file mode 100644 index 00000000..0d55ad2a --- /dev/null +++ b/assets/Icon_thumbs_down_reaction.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/Icon_thumbs_up_reaction.svg b/assets/Icon_thumbs_up_reaction.svg new file mode 100644 index 00000000..ff4dcc72 --- /dev/null +++ b/assets/Icon_thumbs_up_reaction.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/Icon_wut_reaction.svg b/assets/Icon_wut_reaction.svg new file mode 100644 index 00000000..c150b264 --- /dev/null +++ b/assets/Icon_wut_reaction.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/icon_edit.svg b/assets/icon_edit.svg index 6979c575..32f9cea7 100644 --- a/assets/icon_edit.svg +++ b/assets/icon_edit.svg @@ -1,3 +1,3 @@ - - + + diff --git a/lib/src/message_actions_bottom_sheet.dart b/lib/src/message_actions_bottom_sheet.dart deleted file mode 100644 index 1e81900f..00000000 --- a/lib/src/message_actions_bottom_sheet.dart +++ /dev/null @@ -1,209 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:stream_chat/stream_chat.dart'; -import 'package:stream_chat_flutter/src/reaction_picker.dart'; -import 'package:stream_chat_flutter/src/stream_channel.dart'; - -import '../stream_chat_flutter.dart'; -import 'message_input.dart'; -import 'stream_chat.dart'; - -class MessageActionsBottomSheet extends StatelessWidget { - final Widget Function(BuildContext, Message) editMessageInputBuilder; - final void Function(Message) onThreadTap; - final Message message; - final bool showReactions; - final bool showDeleteMessage; - final bool showEditMessage; - final bool showReply; - final Map reactionToEmoji = const { - 'love': '❤️️', - 'haha': '😂', - 'like': '👍', - 'sad': '😕', - 'angry': '😡', - 'wow': '😲', - }; - - const MessageActionsBottomSheet({ - Key key, - this.message, - this.showReactions, - this.showDeleteMessage, - this.showEditMessage, - this.onThreadTap, - this.showReply, - this.editMessageInputBuilder, - }) : super(key: key); - - @override - Widget build(BuildContext context) { - final channel = StreamChannel.of(context).channel; - return SafeArea( - child: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - if (showReactions && - (message.status == MessageSendingStatus.SENT || - message.status == null)) - ReactionPicker( - channel: channel, - reactionToEmoji: reactionToEmoji, - message: message, - ), - if (showDeleteMessage) _buildDeleteButton(context), - if (showEditMessage) _buildEditMessage(context), - if (showReply && - (message.status == MessageSendingStatus.SENT || - message.status == null) && - message.parentId == null) - _buildReplyButton(context), - ], - ), - ); - } - - FlatButton _buildDeleteButton(BuildContext context) { - return FlatButton( - child: Padding( - padding: const EdgeInsets.all(16.0), - child: Text( - 'Delete message', - style: - Theme.of(context).textTheme.headline5.copyWith(color: Colors.red), - ), - ), - onPressed: () { - Navigator.pop(context); - StreamChat.of(context).client.deleteMessage( - message, - StreamChannel.of(context).channel.cid, - ); - }, - ); - } - - FlatButton _buildEditMessage(BuildContext context) { - return FlatButton( - child: Padding( - padding: const EdgeInsets.all(16.0), - child: Text( - 'Edit message', - style: Theme.of(context).textTheme.headline5, - ), - ), - onPressed: () async { - Navigator.pop(context); - _showEditBottomSheet(context); - }, - ); - } - - void _showEditBottomSheet(BuildContext context) { - final channel = StreamChannel.of(context).channel; - showModalBottomSheet( - context: context, - elevation: 2, - clipBehavior: Clip.hardEdge, - isScrollControlled: true, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.only( - topLeft: Radius.circular(32), - topRight: Radius.circular(32), - ), - ), - builder: (context) { - return StreamChannel( - channel: channel, - child: Flex( - direction: Axis.vertical, - mainAxisAlignment: MainAxisAlignment.end, - mainAxisSize: MainAxisSize.min, - children: [ - Padding( - padding: const EdgeInsets.only( - top: 16.0, - left: 16.0, - right: 16.0, - ), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text( - 'Edit message', - style: Theme.of(context).textTheme.headline6, - ), - Container( - height: 30, - padding: const EdgeInsets.all(2.0), - child: AspectRatio( - aspectRatio: 1, - child: RawMaterialButton( - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(4), - ), - elevation: 0, - highlightElevation: 0, - focusElevation: 0, - disabledElevation: 0, - hoverElevation: 0, - onPressed: () { - Navigator.of(context).pop(); - }, - fillColor: - Theme.of(context).brightness == Brightness.dark - ? Colors.white.withOpacity(.1) - : Colors.black.withOpacity(.1), - padding: EdgeInsets.all(4), - child: Icon( - Icons.close, - size: 15, - color: StreamChatTheme.of(context) - .primaryIconTheme - .color, - ), - ), - ), - ), - ], - ), - ), - Padding( - padding: EdgeInsets.only( - bottom: MediaQuery.of(context).viewInsets.bottom, - ), - child: editMessageInputBuilder != null - ? editMessageInputBuilder(context, message) - : MessageInput( - editMessage: message, - onMessageSent: (_) { - FocusScope.of(context).unfocus(); - Navigator.pop(context); - }, - ), - ), - ], - ), - ); - }, - ); - } - - FlatButton _buildReplyButton(BuildContext context) { - return FlatButton( - child: Padding( - padding: const EdgeInsets.all(16.0), - child: Text( - 'Start a thread', - style: Theme.of(context).textTheme.headline5, - ), - ), - onPressed: () { - Navigator.pop(context); - if (onThreadTap != null) { - onThreadTap(message); - } - }, - ); - } -} diff --git a/lib/src/message_actions_modal.dart b/lib/src/message_actions_modal.dart index 5a089786..683f250b 100644 --- a/lib/src/message_actions_modal.dart +++ b/lib/src/message_actions_modal.dart @@ -6,9 +6,10 @@ import 'package:stream_chat/stream_chat.dart'; import 'package:stream_chat_flutter/src/reaction_picker.dart'; import 'package:stream_chat_flutter/src/stream_channel.dart'; -import '../stream_chat_flutter.dart'; import 'message_input.dart'; +import 'message_widget.dart'; import 'stream_chat.dart'; +import 'stream_chat_theme.dart'; class MessageActionsModal extends StatelessWidget { final Widget Function(BuildContext, Message) editMessageInputBuilder; @@ -21,14 +22,6 @@ class MessageActionsModal extends StatelessWidget { final bool showReply; final bool reverse; final ShapeBorder messageShape; - final Map reactionToEmoji = const { - 'love': '❤️️', - 'haha': '😂', - 'like': '👍', - 'sad': '😕', - 'angry': '😡', - 'wow': '😲', - }; const MessageActionsModal({ Key key, @@ -73,10 +66,12 @@ class MessageActionsModal extends StatelessWidget { if (showReactions && (message.status == MessageSendingStatus.SENT || message.status == null)) - ReactionPicker( - channel: channel, - reactionToEmoji: reactionToEmoji, - message: message, + Center( + child: ReactionPicker( + channel: channel, + message: message, + messageTheme: messageTheme, + ), ), AbsorbPointer( child: MessageWidget( @@ -158,7 +153,7 @@ class MessageActionsModal extends StatelessWidget { alignment: Alignment.center, package: 'stream_chat_flutter', color: StreamChatTheme.of(context).primaryIconTheme.color, - width: 17, + width: 24, ), onTap: () async { Navigator.pop(context); diff --git a/lib/src/message_widget.dart b/lib/src/message_widget.dart index c8160c06..5fea9fa0 100644 --- a/lib/src/message_widget.dart +++ b/lib/src/message_widget.dart @@ -5,6 +5,7 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_portal/flutter_portal.dart'; +import 'package:flutter_svg/flutter_svg.dart'; import 'package:jiffy/jiffy.dart'; import 'package:stream_chat_flutter/src/message_actions_modal.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; @@ -193,15 +194,6 @@ class MessageWidget extends StatefulWidget { } class _MessageWidgetState extends State { - final Map _reactionToEmoji = { - 'love': '❤️️', - 'haha': '😂', - 'like': '👍', - 'sad': '😕', - 'angry': '😡', - 'wow': '😲', - }; - final GlobalKey _reactionPickerKey = GlobalKey(); double _reactionPadding = 0; @@ -341,9 +333,9 @@ class _MessageWidgetState extends State { offset: Offset(4, 0), child: CustomPaint( painter: ReactionBubblePainter( - Theme.of(context).brightness == Brightness.dark - ? Colors.white - : Colors.black, + widget.messageTheme.reactionsBackgroundColor, + widget.messageTheme.reactionsBorderColor, + widget.message.reactionCounts.length, ), ), ) @@ -456,14 +448,23 @@ class _MessageWidgetState extends State { child: Container( padding: const EdgeInsets.all(8), decoration: BoxDecoration( - color: Theme.of(context).brightness == - Brightness.dark - ? Colors.white - : Colors.black, + border: widget.messageTheme + .reactionsBackgroundColor == + StreamChatTheme.of(context) + .backgroundColor + ? Border.all( + color: Theme.of(context).brightness == + Brightness.dark + ? Colors.white.withAlpha(24) + : Colors.black.withAlpha(24), + ) + : null, + color: + widget.messageTheme.reactionsBackgroundColor, borderRadius: BorderRadius.all(Radius.circular(14)), ), - child: _buildReactionsText(context), + child: _buildReactions(context), ), ), _buildReactionsTail(context), @@ -477,18 +478,33 @@ class _MessageWidgetState extends State { ); } - Text _buildReactionsText(BuildContext context) { - return Text( - widget.message.reactionCounts.keys.map((reactionType) { - return _reactionToEmoji[reactionType] ?? '?'; - }).join(' ') + - ' ${widget.message.reactionCounts.values.fold(0, (t, v) => v + t).toString()}', - style: TextStyle( - color: Theme.of(context).brightness == Brightness.dark - ? Colors.black - : Colors.white, - ), - textAlign: TextAlign.justify, + Widget _buildReactions(BuildContext context) { + final reactionAssets = StreamChatTheme.of(context).reactionAssets; + return Row( + mainAxisSize: MainAxisSize.min, + children: [ + ...widget.message.reactionCounts.keys.map((reactionType) { + final reactionAsset = reactionAssets.firstWhere( + (reactionAsset) => reactionAsset.type == reactionType, + orElse: () => null, + ); + if (reactionAsset == null) { + return Text( + '?', + style: TextStyle( + color: StreamChatTheme.of(context).accentColor, + ), + ); + } + + return SvgPicture.asset( + reactionAsset.svgAsset, + package: reactionAsset.package, + height: 16, + color: StreamChatTheme.of(context).accentColor, + ); + }).toList(), + ], ); } @@ -807,17 +823,89 @@ class _MessageWidgetState extends State { class ReactionBubblePainter extends CustomPainter { final Color color; + final Color borderColor; + final int reactionsCount; - ReactionBubblePainter(this.color); + ReactionBubblePainter( + this.color, + this.borderColor, + this.reactionsCount, + ); @override void paint(Canvas canvas, Size size) { - final paint = Paint()..color = color; + _drawArc(size, canvas); + + _drawBorder(size, canvas); + + _drawOval(size, canvas); + + _drawOvalBorder(size, canvas); + } + + void _drawOvalBorder(Size size, Canvas canvas) { + final paint = Paint() + ..color = borderColor + ..strokeWidth = 1 + ..style = PaintingStyle.stroke; + final path = Path(); - path.lineTo(-2, -6); - path.lineTo(0, 10); - path.lineTo(10, -6); - path.lineTo(-2, -6); + path.addOval( + Rect.fromCircle( + center: Offset(0, 3), + radius: 2, + ), + ); + canvas.drawPath(path, paint); + } + + void _drawOval(Size size, Canvas canvas) { + final paint = Paint() + ..color = color + ..strokeWidth = 1; + + final path = Path(); + path.addOval(Rect.fromCircle( + center: Offset(0, 3), + radius: 2, + )); + canvas.drawPath(path, paint); + } + + void _drawBorder(Size size, Canvas canvas) { + final paint = Paint() + ..color = borderColor + ..strokeWidth = 1 + ..style = PaintingStyle.stroke; + + final dy = reactionsCount > 1 ? -2.0 : -3.0; + final path = Path(); + path.addArc( + Rect.fromCircle( + center: Offset(-4, dy), + radius: 4, + ), + -pi * 1.15, + -pi / 1.4, + ); + canvas.drawPath(path, paint); + } + + void _drawArc(Size size, Canvas canvas) { + final paint = Paint() + ..color = color + ..strokeWidth = 1; + + final dy = reactionsCount > 1 ? -2.0 : -3.0; + final path = Path(); + path.addArc( + Rect.fromCircle( + center: Offset(-4, dy), + radius: 4, + ), + -pi, + -pi, + ); canvas.drawPath(path, paint); } diff --git a/lib/src/reaction_asset.dart b/lib/src/reaction_asset.dart new file mode 100644 index 00000000..d33bbf26 --- /dev/null +++ b/lib/src/reaction_asset.dart @@ -0,0 +1,11 @@ +class ReactionAsset { + final String type; + final String svgAsset; + final String package; + + ReactionAsset({ + this.type, + this.svgAsset, + this.package, + }); +} diff --git a/lib/src/reaction_picker.dart b/lib/src/reaction_picker.dart index 885d937a..af9d36da 100644 --- a/lib/src/reaction_picker.dart +++ b/lib/src/reaction_picker.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:flutter_svg/flutter_svg.dart'; import '../stream_chat_flutter.dart'; @@ -11,60 +12,54 @@ import '../stream_chat_flutter.dart'; class ReactionPicker extends StatelessWidget { const ReactionPicker({ Key key, - @required this.reactionToEmoji, @required this.message, @required this.channel, - this.size = 30, + @required this.messageTheme, }) : super(key: key); - final Map reactionToEmoji; final Message message; - final double size; + final MessageTheme messageTheme; final Channel channel; @override Widget build(BuildContext context) { + final reactionAssets = StreamChatTheme.of(context).reactionAssets; return Material( - color: Colors.black87, + color: messageTheme.reactionsBackgroundColor, + clipBehavior: Clip.hardEdge, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(24), + ), child: Row( crossAxisAlignment: CrossAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.center, mainAxisSize: MainAxisSize.min, - children: reactionToEmoji.keys.map((reactionType) { - final ownReactionIndex = message.ownReactions - ?.indexWhere((reaction) => reaction.type == reactionType) ?? + children: reactionAssets.map((reactionAsset) { + final ownReactionIndex = message.ownReactions?.indexWhere( + (reaction) => reaction.type == reactionAsset.type) ?? -1; - return Column( - mainAxisSize: MainAxisSize.min, - mainAxisAlignment: MainAxisAlignment.start, - children: [ - IconButton( - iconSize: size, - icon: Text( - reactionToEmoji[reactionType], - style: TextStyle( - fontSize: size - 10, - ), - ), - onPressed: () { - if (ownReactionIndex != -1) { - removeReaction( - context, message.ownReactions[ownReactionIndex]); - } else { - sendReaction(context, reactionType); - } - }, - ), - ownReactionIndex != -1 - ? Padding( - padding: const EdgeInsets.only(bottom: 4.0), - child: Text( - message.ownReactions[ownReactionIndex].score.toString(), - style: TextStyle(color: Colors.white), - ), - ) - : SizedBox(), - ], + return IconButton( + iconSize: 24, + icon: SvgPicture.asset( + reactionAsset.svgAsset, + package: reactionAsset.package, + color: ownReactionIndex != -1 + ? StreamChatTheme.of(context).accentColor + : Colors.black, + ), + onPressed: () { + if (ownReactionIndex != -1) { + removeReaction( + context, + message.ownReactions[ownReactionIndex], + ); + } else { + sendReaction( + context, + reactionAsset.type, + ); + } + }, ); }).toList(), ), diff --git a/lib/src/stream_chat_theme.dart b/lib/src/stream_chat_theme.dart index 57aeec53..b208c035 100644 --- a/lib/src/stream_chat_theme.dart +++ b/lib/src/stream_chat_theme.dart @@ -4,6 +4,8 @@ import 'package:stream_chat_flutter/src/channel_header.dart'; import 'package:stream_chat_flutter/src/channel_preview.dart'; import 'package:stream_chat_flutter/src/message_input.dart'; +import 'reaction_asset.dart'; + /// Inherited widget providing the [StreamChatThemeData] to the widget tree class StreamChatTheme extends InheritedWidget { final StreamChatThemeData data; @@ -72,6 +74,9 @@ class StreamChatThemeData { /// Primary icon theme final IconThemeData primaryIconTheme; + /// Assets used for rendering reactions + final List reactionAssets; + /// Create a theme from scratch StreamChatThemeData({ this.primaryColor, @@ -85,6 +90,7 @@ class StreamChatThemeData { this.defaultChannelImage, this.defaultUserImage, this.primaryIconTheme, + this.reactionAssets, }); /// Create a theme from a Material [Theme] @@ -135,6 +141,7 @@ class StreamChatThemeData { Widget Function(BuildContext, Channel) defaultChannelImage, Widget Function(BuildContext, User) defaultUserImage, IconThemeData primaryIconTheme, + List reactionAssets, }) => StreamChatThemeData( primaryColor: primaryColor ?? this.primaryColor, @@ -203,6 +210,7 @@ class StreamChatThemeData { this.otherMessageTheme.avatarTheme, ) ?? this.otherMessageTheme, + reactionAssets: reactionAssets ?? this.reactionAssets, ); /// Get the default Stream Chat theme @@ -293,7 +301,9 @@ class StreamChatThemeData { fontWeight: FontWeight.bold, fontSize: 12, ), - messageBackgroundColor: isDark ? Color(0xff191919) : Color(0xffE6E6E6), + messageBackgroundColor: 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( @@ -306,6 +316,9 @@ class StreamChatThemeData { ), ), otherMessageTheme: MessageTheme( + reactionsBackgroundColor: + isDark ? Color(0xff191919) : Color(0xffEAEAEA), + reactionsBorderColor: theme.scaffoldBackgroundColor, messageText: TextStyle( fontSize: 15, color: isDark ? Colors.white : Colors.black, @@ -333,6 +346,33 @@ class StreamChatThemeData { ), ), ), + reactionAssets: [ + ReactionAsset( + type: 'love', + svgAsset: 'assets/Icon_love_reaction.svg', + package: 'stream_chat_flutter', + ), + ReactionAsset( + type: 'thumbs_up', + svgAsset: 'assets/Icon_thumbs_up_reaction.svg', + package: 'stream_chat_flutter', + ), + ReactionAsset( + type: 'thumbs_down', + svgAsset: 'assets/Icon_thumbs_down_reaction.svg', + package: 'stream_chat_flutter', + ), + ReactionAsset( + type: 'lol', + svgAsset: 'assets/Icon_LOL_reaction.svg', + package: 'stream_chat_flutter', + ), + ReactionAsset( + type: 'wut', + svgAsset: 'assets/Icon_wut_reaction.svg', + package: 'stream_chat_flutter', + ), + ], ); } } @@ -415,6 +455,8 @@ class MessageTheme { final TextStyle createdAt; final TextStyle replies; final Color messageBackgroundColor; + final Color reactionsBackgroundColor; + final Color reactionsBorderColor; final AvatarTheme avatarTheme; const MessageTheme({ @@ -423,6 +465,8 @@ class MessageTheme { this.messageAuthor, this.messageLinks, this.messageBackgroundColor, + this.reactionsBackgroundColor, + this.reactionsBorderColor, this.avatarTheme, this.createdAt, }); @@ -436,6 +480,8 @@ class MessageTheme { Color messageBackgroundColor, Color otherMessageBackgroundColor, AvatarTheme avatarTheme, + Color reactionsBackgroundColor, + Color reactionsBorderColor, }) => MessageTheme( messageText: messageText ?? this.messageText, @@ -446,6 +492,9 @@ class MessageTheme { messageBackgroundColor ?? this.messageBackgroundColor, avatarTheme: avatarTheme ?? this.avatarTheme, replies: replies ?? this.replies, + reactionsBackgroundColor: + reactionsBackgroundColor ?? this.reactionsBackgroundColor, + reactionsBorderColor: reactionsBorderColor ?? this.reactionsBorderColor, ); } diff --git a/pubspec.yaml b/pubspec.yaml index c3dfbe4c..7012f360 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -24,7 +24,7 @@ dependencies: image_picker: ^0.6.7+2 flutter_keyboard_visibility: ^3.2.1 flutter_svg: ^0.18.0 - stream_chat: ^0.2.3 + stream_chat: ^0.2.3+3 mime: ^0.9.6+3 visibility_detector: ^0.1.5 line_awesome_icons: ^1.0.4+2 From 867d242e28c5c8746e36c286def0b49609ccbd50 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Tue, 1 Sep 2020 15:13:16 +0200 Subject: [PATCH 0068/1140] update github actions --- .github/workflows/main.yml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index e6c393ba..d1858708 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -1,9 +1,10 @@ name: CI on: - release: - types: - - created + push: + branches: + - master + - feature/new-ui env: flutter_version: "1.17.5" From 396ab171cda70bc1ab0337f267002b3aba8b0853 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Tue, 1 Sep 2020 15:17:19 +0200 Subject: [PATCH 0069/1140] update flutter version --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index d1858708..9f5ca809 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -7,7 +7,7 @@ on: - feature/new-ui env: - flutter_version: "1.17.5" + flutter_version: "1.20.2" jobs: build_and_deploy_ios: From f5ac9c08c868a1baaa8ed5603e087813cbf0548c Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Mon, 5 Oct 2020 10:50:52 +0200 Subject: [PATCH 0070/1140] remove caching in ci --- .github/workflows/main.yml | 8 -------- 1 file changed, 8 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index ec65f282..d938ce03 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -11,15 +11,7 @@ jobs: runs-on: [macos-latest] steps: - uses: actions/checkout@v1 - - name: Cache RubyGems - uses: actions/cache@v1 - id: rubygem-cache - with: - path: vendor/bundle - key: ${{ runner.os }}-gem-${{ hashFiles('**/Gemfile.lock') }} - restore-keys: ${{ runner.os }}-gem- - name: Install RubyGems - if: steps.rubygem-cache.outputs.cache-hit != 'true' run: | cd example/ios bundle install From 5786df1ef511df02e6f35e01a0dc858750eadf58 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Mon, 5 Oct 2020 11:04:21 +0200 Subject: [PATCH 0071/1140] update test --- test/src/channel_preview_test.dart | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/test/src/channel_preview_test.dart b/test/src/channel_preview_test.dart index f5e0fbd0..122e2283 100644 --- a/test/src/channel_preview_test.dart +++ b/test/src/channel_preview_test.dart @@ -5,6 +5,8 @@ import 'package:stream_chat_flutter/stream_chat_flutter.dart'; class MockClient extends Mock implements Client {} +class MockClientState extends Mock implements ClientState {} + class MockChannel extends Mock implements Channel {} class MockChannelState extends Mock implements ChannelClientState {} @@ -14,18 +16,28 @@ void main() { 'it should show basic channel information', (WidgetTester tester) async { final client = MockClient(); + final clientState = MockClientState(); final channel = MockChannel(); final channelState = MockChannelState(); final lastMessageAt = DateTime.parse('2020-06-22 12:00:00'); + when(client.state).thenReturn(clientState); + when(clientState.user).thenReturn(OwnUser(id: 'user-id')); when(channel.lastMessageAt).thenReturn(lastMessageAt); when(channel.state).thenReturn(channelState); + when(channel.isMuted).thenReturn(false); + when(channel.isMutedStream).thenAnswer((i) => Stream.value(false)); + when(channel.extraDataStream).thenAnswer((i) => Stream.value({ + 'name': 'test name', + })); when(channel.extraData).thenReturn({ 'name': 'test name', }); when(channelState.unreadCount).thenReturn(1); + when(channelState.members).thenReturn([]); when(channelState.lastMessage).thenReturn(Message( text: 'hello', + user: User(id: 'other-user'), )); await tester.pumpWidget(MaterialApp( From f81013dd9bb54bc36544df0798f3619692aed3c6 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Mon, 5 Oct 2020 11:16:55 +0200 Subject: [PATCH 0072/1140] update ci --- .github/workflows/main.yml | 72 ++++++++++++++++++++++++++------------ 1 file changed, 50 insertions(+), 22 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index d938ce03..b476bb73 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -10,7 +10,7 @@ jobs: build_and_deploy_ios: runs-on: [macos-latest] steps: - - uses: actions/checkout@v1 + - uses: actions/checkout@v2 - name: Install RubyGems run: | cd example/ios @@ -24,35 +24,63 @@ jobs: run: | cd example flutter pub get - flutter build ios --release --no-codesign + - name: Coverage fix + run: | + file=test/coverage_helper_test.dart + echo "// Helper file to make coverage work for all dart files\n" > $file + echo "// ignore_for_file: unused_import" >> $file + find lib -name '*.dart' | grep -e '[^g]\.dart' | grep -v '_html.dart' | cut -c4- | awk -v package=stream_chat_flutter '{printf "import '\''package:%s%s'\'';\n", package, $1}' >> $file + echo "" >> $file + echo "void main(){}" >> $file + cat $file + - name: Run tests + run: flutter test --coverage + - name: Codecov + run: bash <(curl -s https://codecov.io/bash) -c -t ${{ secrets.CODECOV_TOKEN }} -f coverage/lcov.info -F flutter_tool - name: Build and release env: MATCH_PASSWORD: ${{ secrets.MATCH_PASSWORD }} MATCH_GIT_BASIC_AUTHORIZATION: ${{ secrets.MATCH_GIT_BASIC_AUTHORIZATION }} FIREBASE_TOKEN: ${{ secrets.FIREBASE_TOKEN }} run: | + cd example + flutter build ios --release --no-codesign cd example/ios bundle exec fastlane deploy_to_firebase build_and_deploy_android: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 - - name: Flutter action - uses: subosito/flutter-action@v1.3.2 - with: - channel: 'stable' - - name: Get dependencies - run: flutter pub get - - name: Coverage fix - run: | - file=test/coverage_helper_test.dart - echo "// Helper file to make coverage work for all dart files\n" > $file - echo "// ignore_for_file: unused_import" >> $file - find lib -name '*.dart' | grep -e '[^g]\.dart' | grep -v '_html.dart' | cut -c4- | awk -v package=stream_chat_flutter '{printf "import '\''package:%s%s'\'';\n", package, $1}' >> $file - echo "" >> $file - echo "void main(){}" >> $file - cat $file - - name: Run tests - run: flutter test --coverage - - name: Codecov - run: bash <(curl -s https://codecov.io/bash) -c -t ${{ secrets.CODECOV_TOKEN }} -f coverage/lcov.info -F flutter_tool + - uses: actions/checkout@v2 + - uses: actions/setup-java@v1 + with: + java-version: '12.x' + - uses: subosito/flutter-action@v1.3.2 + with: + channel: 'stable' + - run: | + cd example + flutter pub get + - name: Coverage fix + run: | + file=test/coverage_helper_test.dart + echo "// Helper file to make coverage work for all dart files\n" > $file + echo "// ignore_for_file: unused_import" >> $file + find lib -name '*.dart' | grep -e '[^g]\.dart' | grep -v '_html.dart' | cut -c4- | awk -v package=stream_chat_flutter '{printf "import '\''package:%s%s'\'';\n", package, $1}' >> $file + echo "" >> $file + echo "void main(){}" >> $file + cat $file + - name: Run tests + run: flutter test --coverage + - name: Codecov + run: bash <(curl -s https://codecov.io/bash) -c -t ${{ secrets.CODECOV_TOKEN }} -f coverage/lcov.info -F flutter_tool + - name: Build + run: | + cd example + flutter build apk + - name: Deploy + uses: wzieba/Firebase-Distribution-Github-Action@v1.2.1 + with: + appId: ${{secrets.FIREBASE_ANDROID_APPID}} + token: ${{secrets.FIREBASE_TOKEN}} + groups: stream-testers + file: example/build/app/outputs/apk/release/app-release.apk From 12c3258198137f1518f5738d90332f11ceec4f55 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Mon, 5 Oct 2020 11:17:38 +0200 Subject: [PATCH 0073/1140] Update main.yml --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index b476bb73..0778e5a8 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -25,7 +25,7 @@ jobs: cd example flutter pub get - name: Coverage fix - run: | + run: | file=test/coverage_helper_test.dart echo "// Helper file to make coverage work for all dart files\n" > $file echo "// ignore_for_file: unused_import" >> $file From c20371cd16396f431d31622611bf91f8ba25ba7f Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Mon, 5 Oct 2020 11:18:02 +0200 Subject: [PATCH 0074/1140] Update main.yml --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 0778e5a8..41c5cd7d 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -61,7 +61,7 @@ jobs: cd example flutter pub get - name: Coverage fix - run: | + run: | file=test/coverage_helper_test.dart echo "// Helper file to make coverage work for all dart files\n" > $file echo "// ignore_for_file: unused_import" >> $file From 70ce7712655cdca93fe0189646f57c631d81644c Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Mon, 5 Oct 2020 11:37:29 +0200 Subject: [PATCH 0075/1140] update ci --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 41c5cd7d..ca43c066 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -45,7 +45,7 @@ jobs: run: | cd example flutter build ios --release --no-codesign - cd example/ios + cd ios bundle exec fastlane deploy_to_firebase build_and_deploy_android: runs-on: ubuntu-latest From 6efb0ebbc1a0172e626a850a910f11c4bcb428ce Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Mon, 5 Oct 2020 12:44:19 +0200 Subject: [PATCH 0076/1140] update fastlane plugins --- example/ios/Gemfile.lock | 2 +- example/pubspec.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/example/ios/Gemfile.lock b/example/ios/Gemfile.lock index cc4bf5f3..cd71d005 100644 --- a/example/ios/Gemfile.lock +++ b/example/ios/Gemfile.lock @@ -80,7 +80,7 @@ GEM xcodeproj (>= 1.13.0, < 2.0.0) xcpretty (~> 0.3.0) xcpretty-travis-formatter (>= 0.0.3) - fastlane-plugin-firebase_app_distribution (0.1.4) + fastlane-plugin-firebase_app_distribution (0.2.3) gh_inspector (1.1.3) google-api-client (0.38.0) addressable (~> 2.5, >= 2.5.1) diff --git a/example/pubspec.yaml b/example/pubspec.yaml index d6a7d76f..0faf2ed7 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -1,7 +1,7 @@ name: example description: A new Flutter project. -version: 1.0.15+17 +version: 1.0.16+18 environment: sdk: ">=2.2.2 <3.0.0" From 1e96e4be441c61db6deeef3ac30a42ef7d718e63 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Mon, 5 Oct 2020 13:51:32 +0200 Subject: [PATCH 0077/1140] update fastlane --- example/ios/fastlane/report.xml | 30 ++++++------------------------ example/pubspec.yaml | 2 +- 2 files changed, 7 insertions(+), 25 deletions(-) diff --git a/example/ios/fastlane/report.xml b/example/ios/fastlane/report.xml index 51cbc75b..9f26a224 100644 --- a/example/ios/fastlane/report.xml +++ b/example/ios/fastlane/report.xml @@ -5,47 +5,29 @@ - + - + - + - + - + - - - - - - - - - - - - - - - - - - - + diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 0faf2ed7..90a1c7f1 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -1,7 +1,7 @@ name: example description: A new Flutter project. -version: 1.0.16+18 +version: 1.0.17+19 environment: sdk: ">=2.2.2 <3.0.0" From 88e5a2eb2cba06670b6efcb23b4868466fe368f6 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Mon, 5 Oct 2020 14:20:32 +0200 Subject: [PATCH 0078/1140] trigger ci --- example/ios/fastlane/Matchfile | 1 + example/pubspec.yaml | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/example/ios/fastlane/Matchfile b/example/ios/fastlane/Matchfile index 21b0863c..cc976de1 100644 --- a/example/ios/fastlane/Matchfile +++ b/example/ios/fastlane/Matchfile @@ -7,6 +7,7 @@ username("salvatore@getstream.io") team_id("EHV7XZLAHA") # app_identifier(["tools.fastlane.app", "tools.fastlane.app2"]) + # username("user@fastlane.tools") # Your Apple Developer Portal username # For all available options run `fastlane match --help` diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 90a1c7f1..b186e1af 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -1,7 +1,7 @@ name: example description: A new Flutter project. -version: 1.0.17+19 +version: 1.0.18+20 environment: sdk: ">=2.2.2 <3.0.0" From 2e0ac9a82c97453658d619bc1be0973a35a870b0 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Mon, 5 Oct 2020 15:05:53 +0200 Subject: [PATCH 0079/1140] update groupid --- example/ios/Notifications/NotificationService.swift | 2 +- example/ios/Notifications/Notifications.entitlements | 2 +- example/ios/Runner/AppDelegate.swift | 2 +- example/ios/Runner/Runner.entitlements | 2 +- example/pubspec.yaml | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/example/ios/Notifications/NotificationService.swift b/example/ios/Notifications/NotificationService.swift index 60e44390..976e8d6a 100644 --- a/example/ios/Notifications/NotificationService.swift +++ b/example/ios/Notifications/NotificationService.swift @@ -18,7 +18,7 @@ final class NotificationService: UNNotificationServiceExtension { self.contentHandler = contentHandler bestAttemptContent = (request.content.mutableCopy() as? UNMutableNotificationContent) - guard let sharedDefaults = UserDefaults(suiteName: "group.io.stream.flutter"), + guard let sharedDefaults = UserDefaults(suiteName: "group.io.getstream.flutter"), let apiKey = sharedDefaults.string(forKey: "KEY_API_KEY"), let userId = sharedDefaults.string(forKey: "KEY_USER_ID"), let token = sharedDefaults.string(forKey: "KEY_TOKEN"), diff --git a/example/ios/Notifications/Notifications.entitlements b/example/ios/Notifications/Notifications.entitlements index 00390120..e5b71890 100644 --- a/example/ios/Notifications/Notifications.entitlements +++ b/example/ios/Notifications/Notifications.entitlements @@ -4,7 +4,7 @@ com.apple.security.application-groups - group.io.stream.flutter + group.io.getstream.flutter diff --git a/example/ios/Runner/AppDelegate.swift b/example/ios/Runner/AppDelegate.swift index 3f549155..69a7daf4 100644 --- a/example/ios/Runner/AppDelegate.swift +++ b/example/ios/Runner/AppDelegate.swift @@ -3,7 +3,7 @@ import Flutter @UIApplicationMain @objc class AppDelegate: FlutterAppDelegate { - let sharedDefaults = UserDefaults(suiteName: "group.io.stream.flutter") + let sharedDefaults = UserDefaults(suiteName: "group.io.getstream.flutter") override func application( _ application: UIApplication, diff --git a/example/ios/Runner/Runner.entitlements b/example/ios/Runner/Runner.entitlements index 967ba7f2..433bdfe0 100644 --- a/example/ios/Runner/Runner.entitlements +++ b/example/ios/Runner/Runner.entitlements @@ -6,7 +6,7 @@ development com.apple.security.application-groups - group.io.stream.flutter + group.io.getstream.flutter diff --git a/example/pubspec.yaml b/example/pubspec.yaml index b186e1af..ac562d41 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -1,7 +1,7 @@ name: example description: A new Flutter project. -version: 1.0.18+20 +version: 1.0.20+22 environment: sdk: ">=2.2.2 <3.0.0" From ff3d74ceece2bb66ab95763615dbf4e13b3fde27 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Mon, 5 Oct 2020 15:39:01 +0200 Subject: [PATCH 0080/1140] update ci --- example/ios/Flutter/.last_build_id | 2 +- example/ios/fastlane/report.xml | 30 ++++++++++++++++++++++++------ example/pubspec.yaml | 2 +- 3 files changed, 26 insertions(+), 8 deletions(-) diff --git a/example/ios/Flutter/.last_build_id b/example/ios/Flutter/.last_build_id index ab2c77bd..e3266027 100644 --- a/example/ios/Flutter/.last_build_id +++ b/example/ios/Flutter/.last_build_id @@ -1 +1 @@ -13ecb9b157bb3e3d1ca2efb15c813a88 \ No newline at end of file +06fe8d0d3d89937a6d33b1033e75ae96 \ No newline at end of file diff --git a/example/ios/fastlane/report.xml b/example/ios/fastlane/report.xml index 9f26a224..a04d8d30 100644 --- a/example/ios/fastlane/report.xml +++ b/example/ios/fastlane/report.xml @@ -5,29 +5,47 @@ - + - + - + - + - + - + + + + + + + + + + + + + + + + + + + diff --git a/example/pubspec.yaml b/example/pubspec.yaml index ac562d41..89903370 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -1,7 +1,7 @@ name: example description: A new Flutter project. -version: 1.0.20+22 +version: 1.0.21+23 environment: sdk: ">=2.2.2 <3.0.0" From e165beea4de6ff8206e161145cd07dfd56bbce07 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Mon, 5 Oct 2020 17:33:18 +0200 Subject: [PATCH 0081/1140] update ci --- example/ios/fastlane/report.xml | 18 +++++++++--------- example/pubspec.yaml | 2 +- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/example/ios/fastlane/report.xml b/example/ios/fastlane/report.xml index a04d8d30..6038c98b 100644 --- a/example/ios/fastlane/report.xml +++ b/example/ios/fastlane/report.xml @@ -5,47 +5,47 @@ - + - + - + - + - + - + - + - + - + diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 89903370..5b561f77 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -1,7 +1,7 @@ name: example description: A new Flutter project. -version: 1.0.21+23 +version: 1.0.22+24 environment: sdk: ">=2.2.2 <3.0.0" From 504df27822b5161f8656689fd3ec3a27434aadcd Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Tue, 6 Oct 2020 09:11:26 +0200 Subject: [PATCH 0082/1140] add readonly to match_me --- example/ios/fastlane/Fastfile | 6 ++++-- example/pubspec.yaml | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/example/ios/fastlane/Fastfile b/example/ios/fastlane/Fastfile index 8e0393af..8bc6fb4e 100644 --- a/example/ios/fastlane/Fastfile +++ b/example/ios/fastlane/Fastfile @@ -14,7 +14,8 @@ lane :match_me do app_identifier: [ "io.getstream.flutter", "io.getstream.flutter.Notifications" - ] + ], + readonly: true ) match( @@ -22,7 +23,8 @@ lane :match_me do app_identifier: [ "io.getstream.flutter", "io.getstream.flutter.Notifications" - ] + ], + readonly: true ) end diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 5b561f77..88635d95 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -1,7 +1,7 @@ name: example description: A new Flutter project. -version: 1.0.22+24 +version: 1.0.23+25 environment: sdk: ">=2.2.2 <3.0.0" From fc5c3b7e0e808e54fe2a47e103d4fb76110ff269 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Tue, 6 Oct 2020 09:38:49 +0200 Subject: [PATCH 0083/1140] update fastlane --- example/ios/fastlane/Fastfile | 9 --------- example/pubspec.yaml | 2 +- 2 files changed, 1 insertion(+), 10 deletions(-) diff --git a/example/ios/fastlane/Fastfile b/example/ios/fastlane/Fastfile index 8bc6fb4e..2701bdce 100644 --- a/example/ios/fastlane/Fastfile +++ b/example/ios/fastlane/Fastfile @@ -9,15 +9,6 @@ end desc "Installs all Certs and Profiles necessary for development and ad-hoc" lane :match_me do - match( - type: "development", - app_identifier: [ - "io.getstream.flutter", - "io.getstream.flutter.Notifications" - ], - readonly: true - ) - match( type: "adhoc", app_identifier: [ diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 88635d95..6b71e3a2 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -1,7 +1,7 @@ name: example description: A new Flutter project. -version: 1.0.23+25 +version: 1.0.24+26 environment: sdk: ">=2.2.2 <3.0.0" From ca226a3021ecb8ff3a13d50d799570d914a42f48 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Tue, 6 Oct 2020 09:59:27 +0200 Subject: [PATCH 0084/1140] update fastlane --- example/ios/fastlane/Fastfile | 3 ++- example/ios/fastlane/report.xml | 21 ++++++++------------- example/pubspec.yaml | 2 +- 3 files changed, 11 insertions(+), 15 deletions(-) diff --git a/example/ios/fastlane/Fastfile b/example/ios/fastlane/Fastfile index 2701bdce..9f6065be 100644 --- a/example/ios/fastlane/Fastfile +++ b/example/ios/fastlane/Fastfile @@ -15,7 +15,8 @@ lane :match_me do "io.getstream.flutter", "io.getstream.flutter.Notifications" ], - readonly: true + readonly: is_ci, + force_for_new_devices: true ) end diff --git a/example/ios/fastlane/report.xml b/example/ios/fastlane/report.xml index 6038c98b..4c8743d0 100644 --- a/example/ios/fastlane/report.xml +++ b/example/ios/fastlane/report.xml @@ -5,47 +5,42 @@ - + - + - + - + - + - + - + - - - - - - + diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 6b71e3a2..4a08d0d7 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -1,7 +1,7 @@ name: example description: A new Flutter project. -version: 1.0.24+26 +version: 1.0.25+27 environment: sdk: ">=2.2.2 <3.0.0" From 63879f49c56235ec979c1d04bc5c4931ab1cde67 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Tue, 6 Oct 2020 10:20:15 +0200 Subject: [PATCH 0085/1140] update fastlane --- example/ios/Gemfile.lock | 34 ++++++++++++++++----------------- example/ios/fastlane/Fastfile | 2 +- example/ios/fastlane/report.xml | 21 ++++++++++++-------- example/pubspec.yaml | 2 +- 4 files changed, 32 insertions(+), 27 deletions(-) diff --git a/example/ios/Gemfile.lock b/example/ios/Gemfile.lock index cd71d005..dc0ee04f 100644 --- a/example/ios/Gemfile.lock +++ b/example/ios/Gemfile.lock @@ -6,20 +6,20 @@ GEM public_suffix (>= 2.0.2, < 5.0) atomos (0.1.3) aws-eventstream (1.1.0) - aws-partitions (1.345.0) - aws-sdk-core (3.104.3) + aws-partitions (1.380.0) + aws-sdk-core (3.109.1) aws-eventstream (~> 1, >= 1.0.2) aws-partitions (~> 1, >= 1.239.0) aws-sigv4 (~> 1.1) jmespath (~> 1.0) - aws-sdk-kms (1.36.0) - aws-sdk-core (~> 3, >= 3.99.0) + aws-sdk-kms (1.39.0) + aws-sdk-core (~> 3, >= 3.109.0) aws-sigv4 (~> 1.1) - aws-sdk-s3 (1.75.0) - aws-sdk-core (~> 3, >= 3.104.1) + aws-sdk-s3 (1.83.0) + aws-sdk-core (~> 3, >= 3.109.0) aws-sdk-kms (~> 1) aws-sigv4 (~> 1.1) - aws-sigv4 (1.2.1) + aws-sigv4 (1.2.2) aws-eventstream (~> 1, >= 1.0.2) babosa (1.0.3) claide (1.0.3) @@ -35,16 +35,16 @@ GEM unf (>= 0.0.5, < 1.0.0) dotenv (2.7.6) emoji_regex (3.0.0) - excon (0.75.0) + excon (0.76.0) faraday (1.0.1) multipart-post (>= 1.2, < 3) - faraday-cookie_jar (0.0.6) - faraday (>= 0.7.4) + faraday-cookie_jar (0.0.7) + faraday (>= 0.8.0) http-cookie (~> 1.0.0) faraday_middleware (1.0.0) faraday (~> 1.0) fastimage (2.2.0) - fastlane (2.153.1) + fastlane (2.162.0) CFPropertyList (>= 2.3, < 4.0.0) addressable (>= 2.3, < 3.0.0) aws-sdk-s3 (~> 1.0) @@ -96,14 +96,14 @@ GEM google-cloud-env (1.3.3) faraday (>= 0.17.3, < 2.0) google-cloud-errors (1.0.1) - google-cloud-storage (1.26.2) + google-cloud-storage (1.29.1) addressable (~> 2.5) digest-crc (~> 0.4) google-api-client (~> 0.33) google-cloud-core (~> 1.2) googleauth (~> 0.9) mini_mime (~> 1.0) - googleauth (0.13.0) + googleauth (0.13.1) faraday (>= 0.17.3, < 2.0) jwt (>= 1.4, < 3.0) memoist (~> 0.16) @@ -116,7 +116,7 @@ GEM httpclient (2.8.3) jmespath (1.4.0) json (2.3.1) - jwt (2.2.1) + jwt (2.2.2) memoist (0.16.2) mini_magick (4.10.1) mini_mime (1.0.2) @@ -124,9 +124,9 @@ GEM multipart-post (2.0.0) nanaimo (0.3.0) naturally (2.2.0) - os (1.1.0) + os (1.1.1) plist (3.5.0) - public_suffix (4.0.5) + public_suffix (4.0.6) rake (13.0.1) representable (3.0.4) declarative (< 0.1.0) @@ -158,7 +158,7 @@ GEM unf_ext (0.0.7.7) unicode-display_width (1.7.0) word_wrap (1.0.0) - xcodeproj (1.17.1) + xcodeproj (1.18.0) CFPropertyList (>= 2.3.3, < 4.0) atomos (~> 0.1.3) claide (>= 1.0.2, < 2.0) diff --git a/example/ios/fastlane/Fastfile b/example/ios/fastlane/Fastfile index 9f6065be..ec2adc81 100644 --- a/example/ios/fastlane/Fastfile +++ b/example/ios/fastlane/Fastfile @@ -1,4 +1,4 @@ -fastlane_version "2.68.0" +fastlane_version "2.162.0" default_platform :ios before_all do diff --git a/example/ios/fastlane/report.xml b/example/ios/fastlane/report.xml index 4c8743d0..5f117a83 100644 --- a/example/ios/fastlane/report.xml +++ b/example/ios/fastlane/report.xml @@ -5,42 +5,47 @@ - + - + - + - + - + - + - + - + + + + + + diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 4a08d0d7..623893de 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -1,7 +1,7 @@ name: example description: A new Flutter project. -version: 1.0.25+27 +version: 1.0.26+28 environment: sdk: ">=2.2.2 <3.0.0" From 9ff4c156f5e21ab765d24366e68a637baa0d5804 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Tue, 6 Oct 2020 10:46:00 +0200 Subject: [PATCH 0086/1140] update fastlane --- example/ios/fastlane/report.xml | 24 ++++++++---------------- example/pubspec.yaml | 2 +- 2 files changed, 9 insertions(+), 17 deletions(-) diff --git a/example/ios/fastlane/report.xml b/example/ios/fastlane/report.xml index 5f117a83..d6fdf2d7 100644 --- a/example/ios/fastlane/report.xml +++ b/example/ios/fastlane/report.xml @@ -5,47 +5,39 @@ - + - + - + - + - + - + - + - - - - - - - - - + diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 623893de..04049e82 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -1,7 +1,7 @@ name: example description: A new Flutter project. -version: 1.0.26+28 +version: 1.0.27+29 environment: sdk: ">=2.2.2 <3.0.0" From 069f1a8ee4c7dcee3e6b6105f1e3bfe42f395b53 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Thu, 15 Oct 2020 10:37:22 +0200 Subject: [PATCH 0087/1140] fix reaction bubble ui --- lib/src/message_widget.dart | 286 ++++++++------------------------- lib/src/reaction_bubble.dart | 193 ++++++++++++++++++++++ lib/src/reaction_picker.dart | 6 +- lib/src/stream_channel.dart | 4 +- lib/src/stream_chat.dart | 16 ++ lib/src/stream_chat_theme.dart | 45 ++++-- pubspec.yaml | 2 +- 7 files changed, 313 insertions(+), 239 deletions(-) create mode 100644 lib/src/reaction_bubble.dart diff --git a/lib/src/message_widget.dart b/lib/src/message_widget.dart index 841a2b26..f4f141bf 100644 --- a/lib/src/message_widget.dart +++ b/lib/src/message_widget.dart @@ -2,12 +2,13 @@ import 'dart:math'; import 'dart:ui'; import 'package:flutter/cupertino.dart'; +import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_portal/flutter_portal.dart'; -import 'package:flutter_svg/flutter_svg.dart'; import 'package:jiffy/jiffy.dart'; import 'package:stream_chat_flutter/src/message_actions_modal.dart'; +import 'package:stream_chat_flutter/src/reaction_bubble.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; import 'image_group.dart'; @@ -198,9 +199,6 @@ class MessageWidget extends StatefulWidget { } class _MessageWidgetState extends State { - final GlobalKey _reactionPickerKey = GlobalKey(); - double _reactionPadding = 0; - @override Widget build(BuildContext context) { var leftPadding = widget.showUserAvatar != DisplayWidget.gone @@ -243,11 +241,15 @@ class _MessageWidgetState extends State { child: Padding( padding: widget.showReactions ? EdgeInsets.only( - top: _reactionPadding, + top: widget.message.reactionCounts + ?.isNotEmpty == + true + ? 16 + : 0, ) : EdgeInsets.zero, child: PortalEntry( - portalAnchor: Alignment(0, 1), + portalAnchor: Alignment(-0.81, 0), childAnchor: Alignment.topRight, portal: _buildReactionIndicator(context), child: (widget.message.isDeleted && @@ -296,57 +298,6 @@ class _MessageWidgetState extends State { ); } - @override - void didUpdateWidget(MessageWidget oldWidget) { - super.didUpdateWidget(oldWidget); - _updateReactionPadding(); - } - - @override - void initState() { - super.initState(); - _updateReactionPadding(); - } - - void _updateReactionPadding() { - WidgetsBinding.instance.addPostFrameCallback((timeStamp) { - if (!mounted) { - return; - } - if (_reactionPickerKey.currentContext != null && - widget.message.reactionCounts != null && - widget.message.reactionCounts.values - .where((element) => element > 0) - .isNotEmpty) { - setState(() { - _reactionPadding = _reactionPickerKey.currentContext.size.height; - }); - } else { - setState(() { - _reactionPadding = 0; - }); - } - }); - } - - Widget _buildReactionsTail(BuildContext context) { - return AnimatedSwitcher( - duration: Duration(milliseconds: 300), - child: widget.message.reactionCounts?.isNotEmpty == true - ? Transform.translate( - offset: Offset(4, 0), - child: CustomPaint( - painter: ReactionBubblePainter( - widget.messageTheme.reactionsBackgroundColor, - widget.messageTheme.reactionsBorderColor, - widget.message.reactionCounts.length, - ), - ), - ) - : SizedBox(), - ); - } - Padding _buildBottomRow(double leftPadding) { return Padding( padding: EdgeInsets.only( @@ -427,53 +378,72 @@ class _MessageWidgetState extends State { } Widget _buildReactionIndicator(BuildContext context) { + final otherReactions = widget.message.latestReactions + ?.where( + (element) => element.user.id != StreamChat.of(context).user.id) + ?.toList() ?? + []; + + 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( - key: _reactionPickerKey, duration: Duration(milliseconds: 300), child: (widget.showReactions && - widget.message.reactionCounts?.isNotEmpty == true && + (widget.message.reactionCounts?.isNotEmpty == true || + otherReactions.isNotEmpty) && !widget.message.isDeleted) ? Container( child: GestureDetector( onTap: () => onLongPress(context), child: FractionallySizedBox( - widthFactor: 0.3, - child: Padding( - padding: const EdgeInsets.only( - bottom: 4.0, - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisSize: MainAxisSize.min, - children: [ - Transform( - transform: Matrix4.rotationY(widget.reverse ? pi : 0), - alignment: Alignment.center, - child: Container( - padding: const EdgeInsets.all(8), - decoration: BoxDecoration( - border: widget.messageTheme - .reactionsBackgroundColor == - StreamChatTheme.of(context) - .backgroundColor - ? Border.all( - color: Theme.of(context).brightness == - Brightness.dark - ? Colors.white.withAlpha(24) - : Colors.black.withAlpha(24), - ) - : null, - color: - widget.messageTheme.reactionsBackgroundColor, - borderRadius: - BorderRadius.all(Radius.circular(14)), - ), - child: _buildReactions(context), - ), - ), - _buildReactionsTail(context), - ], - ), + widthFactor: 0.5, + child: Row( + mainAxisAlignment: MainAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: rowChildren, ), ), ), @@ -482,36 +452,6 @@ class _MessageWidgetState extends State { ); } - Widget _buildReactions(BuildContext context) { - final reactionAssets = StreamChatTheme.of(context).reactionAssets; - return Row( - mainAxisSize: MainAxisSize.min, - children: [ - ...widget.message.reactionCounts.keys.map((reactionType) { - final reactionAsset = reactionAssets.firstWhere( - (reactionAsset) => reactionAsset.type == reactionType, - orElse: () => null, - ); - if (reactionAsset == null) { - return Text( - '?', - style: TextStyle( - color: StreamChatTheme.of(context).accentColor, - ), - ); - } - - return SvgPicture.asset( - reactionAsset.svgAsset, - package: reactionAsset.package, - height: 16, - color: StreamChatTheme.of(context).accentColor, - ); - }).toList(), - ], - ); - } - void _showMessageModalBottomSheet(BuildContext context) { final channel = StreamChannel.of(context).channel; showDialog( @@ -825,97 +765,3 @@ class _MessageWidgetState extends State { ); } } - -class ReactionBubblePainter extends CustomPainter { - final Color color; - final Color borderColor; - final int reactionsCount; - - ReactionBubblePainter( - this.color, - this.borderColor, - this.reactionsCount, - ); - - @override - void paint(Canvas canvas, Size size) { - _drawArc(size, canvas); - - _drawBorder(size, canvas); - - _drawOval(size, canvas); - - _drawOvalBorder(size, canvas); - } - - void _drawOvalBorder(Size size, Canvas canvas) { - final paint = Paint() - ..color = borderColor - ..strokeWidth = 1 - ..style = PaintingStyle.stroke; - - final path = Path(); - path.addOval( - Rect.fromCircle( - center: Offset(0, 3), - radius: 2, - ), - ); - canvas.drawPath(path, paint); - } - - void _drawOval(Size size, Canvas canvas) { - final paint = Paint() - ..color = color - ..strokeWidth = 1; - - final path = Path(); - path.addOval(Rect.fromCircle( - center: Offset(0, 3), - radius: 2, - )); - canvas.drawPath(path, paint); - } - - void _drawBorder(Size size, Canvas canvas) { - final paint = Paint() - ..color = borderColor - ..strokeWidth = 1 - ..style = PaintingStyle.stroke; - - final dy = reactionsCount > 1 ? -2.0 : -3.0; - final path = Path(); - path.addArc( - Rect.fromCircle( - center: Offset(-4, dy), - radius: 4, - ), - -pi * 1.15, - -pi / 1.4, - ); - canvas.drawPath(path, paint); - } - - void _drawArc(Size size, Canvas canvas) { - final paint = Paint() - ..color = color - ..strokeWidth = 1; - - final dy = reactionsCount > 1 ? -2.0 : -3.0; - final path = Path(); - path.addArc( - Rect.fromCircle( - center: Offset(-4, dy), - radius: 4, - ), - -pi, - -pi, - ); - canvas.drawPath(path, paint); - } - - @override - bool shouldRepaint(CustomPainter oldDelegate) { - return true; - } -} diff --git a/lib/src/reaction_bubble.dart b/lib/src/reaction_bubble.dart new file mode 100644 index 00000000..46c2b238 --- /dev/null +++ b/lib/src/reaction_bubble.dart @@ -0,0 +1,193 @@ +import 'dart:math'; + +import 'package:flutter/material.dart'; +import 'package:flutter_svg/svg.dart'; +import 'package:stream_chat_flutter/stream_chat_flutter.dart'; + +class ReactionBubble extends StatelessWidget { + const ReactionBubble({ + Key key, + @required this.reactions, + @required this.borderColor, + @required this.backgroundColor, + this.reverse = false, + this.flipTail = false, + }) : super(key: key); + + final List reactions; + final Color borderColor; + final Color backgroundColor; + final bool reverse; + final bool flipTail; + + @override + Widget build(BuildContext context) { + final reactionAssets = StreamChatTheme.of(context).reactionAssets; + return Transform( + transform: Matrix4.rotationY(reverse ? pi : 0), + alignment: Alignment.center, + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisSize: MainAxisSize.min, + children: [ + Container( + padding: const EdgeInsets.all(4), + decoration: BoxDecoration( + border: Border.all( + color: borderColor, + ), + color: backgroundColor, + borderRadius: BorderRadius.all(Radius.circular(14)), + ), + child: Wrap( + children: [ + ...reactions.map((reaction) { + final reactionAsset = reactionAssets.firstWhere( + (reactionAsset) => reactionAsset.type == reaction.type, + orElse: () => null, + ); + if (reactionAsset == null) { + return Text( + '?', + style: TextStyle( + color: StreamChatTheme.of(context).accentColor, + ), + ); + } + + return SvgPicture.asset( + reactionAsset.svgAsset, + package: reactionAsset.package, + height: 16, + color: StreamChatTheme.of(context).accentColor, + ); + }).toList(), + ], + ), + ), + _buildReactionsTail(context), + ], + ), + ); + } + + Widget _buildReactionsTail(BuildContext context) { + final tail = Transform.translate( + offset: Offset(4, 0), + child: CustomPaint( + painter: ReactionBubblePainter( + backgroundColor, + borderColor, + reactions.length, + ), + ), + ); + + if (!flipTail) { + return tail; + } else { + return Transform( + transform: Matrix4.rotationY(pi), + alignment: Alignment.center, + child: tail, + ); + } + } +} + +class ReactionBubblePainter extends CustomPainter { + final Color color; + final Color borderColor; + final int reactionsCount; + + ReactionBubblePainter( + this.color, + this.borderColor, + this.reactionsCount, + ); + + @override + void paint(Canvas canvas, Size size) { + _drawOval(size, canvas); + + _drawOvalBorder(size, canvas); + + _drawArc(size, canvas); + + _drawBorder(size, canvas); + } + + void _drawOvalBorder(Size size, Canvas canvas) { + final paint = Paint() + ..color = borderColor + ..strokeWidth = 1 + ..style = PaintingStyle.stroke; + + final path = Path(); + path.addOval( + Rect.fromCircle( + center: Offset(6, 2), + radius: 2, + ), + ); + canvas.drawPath(path, paint); + } + + void _drawOval(Size size, Canvas canvas) { + final paint = Paint() + ..color = color + ..strokeWidth = 1; + + final path = Path(); + path.addOval(Rect.fromCircle( + center: Offset(6, 2), + radius: 2, + )); + canvas.drawPath(path, paint); + } + + void _drawBorder(Size size, Canvas canvas) { + final paint = Paint() + ..color = borderColor + ..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 ? 1.18 : 1.1; + final path = Path(); + path.addArc( + Rect.fromCircle( + center: Offset(0, dy), + radius: 4, + ), + -pi * startAngle, + -pi / sweepAngle, + ); + canvas.drawPath(path, paint); + } + + void _drawArc(Size size, Canvas canvas) { + final paint = Paint() + ..color = color + ..strokeWidth = 1; + + final dy = reactionsCount > 1 ? -2.0 : -3.0; + final startAngle = reactionsCount > 1 ? 1.05 : 1.16; + final path = Path(); + path.addArc( + Rect.fromCircle( + center: Offset(0, dy), + radius: 4, + ), + -pi * startAngle, + -pi, + ); + canvas.drawPath(path, paint); + } + + @override + bool shouldRepaint(CustomPainter oldDelegate) { + return true; + } +} diff --git a/lib/src/reaction_picker.dart b/lib/src/reaction_picker.dart index 6d9d2a64..c07c32cb 100644 --- a/lib/src/reaction_picker.dart +++ b/lib/src/reaction_picker.dart @@ -25,7 +25,7 @@ class ReactionPicker extends StatelessWidget { Widget build(BuildContext context) { final reactionAssets = StreamChatTheme.of(context).reactionAssets; return Material( - color: messageTheme.reactionsBackgroundColor, + color: messageTheme.ownReactionsBackgroundColor, clipBehavior: Clip.hardEdge, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(24), @@ -35,7 +35,7 @@ class ReactionPicker extends StatelessWidget { mainAxisAlignment: MainAxisAlignment.center, mainAxisSize: MainAxisSize.min, children: reactionAssets.map((reactionAsset) { - final ownReactionIndex = message.latestReactions?.indexWhere( + final ownReactionIndex = message.ownReactions?.indexWhere( (reaction) => reaction.type == reactionAsset.type) ?? -1; return IconButton( @@ -45,7 +45,7 @@ class ReactionPicker extends StatelessWidget { package: reactionAsset.package, color: ownReactionIndex != -1 ? StreamChatTheme.of(context).accentColor - : Colors.black, + : Theme.of(context).iconTheme.color, ), onPressed: () { if (ownReactionIndex != -1) { diff --git a/lib/src/stream_channel.dart b/lib/src/stream_channel.dart index 21ee99f3..ce19b261 100644 --- a/lib/src/stream_channel.dart +++ b/lib/src/stream_channel.dart @@ -81,7 +81,9 @@ class StreamChannelState extends State { } _queryMessageController.add(false); }).catchError((e, stack) { - _queryMessageController.addError(e, stack); + if (!_queryMessageController.isClosed) { + _queryMessageController.addError(e, stack); + } }); } diff --git a/lib/src/stream_chat.dart b/lib/src/stream_chat.dart index dfc6095b..b22c257c 100644 --- a/lib/src/stream_chat.dart +++ b/lib/src/stream_chat.dart @@ -129,6 +129,14 @@ 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, ), otherMessageTheme: defaultTheme.otherMessageTheme.copyWith( replies: themeData?.otherMessageTheme?.replies, @@ -142,6 +150,14 @@ 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, ), accentColor: themeData?.accentColor, secondaryColor: themeData?.secondaryColor, diff --git a/lib/src/stream_chat_theme.dart b/lib/src/stream_chat_theme.dart index b208c035..0f92a294 100644 --- a/lib/src/stream_chat_theme.dart +++ b/lib/src/stream_chat_theme.dart @@ -302,8 +302,12 @@ class StreamChatThemeData { fontSize: 12, ), messageBackgroundColor: isDark ? Color(0xff191919) : Color(0xffEAEAEA), - reactionsBackgroundColor: isDark ? Colors.black : Colors.white, - reactionsBorderColor: 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), avatarTheme: AvatarTheme( borderRadius: BorderRadius.circular(20), constraints: BoxConstraints.tightFor( @@ -316,9 +320,12 @@ class StreamChatThemeData { ), ), otherMessageTheme: MessageTheme( - reactionsBackgroundColor: + ownReactionsBackgroundColor: + isDark ? Color(0xff191919) : Color(0xffEAEAEA), + ownReactionsBorderColor: isDark ? Colors.black : Colors.white, + otherReactionsBackgroundColor: isDark ? Colors.black : Colors.white, + otherReactionsBorderColor: isDark ? Color(0xff191919) : Color(0xffEAEAEA), - reactionsBorderColor: theme.scaffoldBackgroundColor, messageText: TextStyle( fontSize: 15, color: isDark ? Colors.white : Colors.black, @@ -455,8 +462,10 @@ class MessageTheme { final TextStyle createdAt; final TextStyle replies; final Color messageBackgroundColor; - final Color reactionsBackgroundColor; - final Color reactionsBorderColor; + final Color ownReactionsBackgroundColor; + final Color ownReactionsBorderColor; + final Color otherReactionsBackgroundColor; + final Color otherReactionsBorderColor; final AvatarTheme avatarTheme; const MessageTheme({ @@ -465,8 +474,10 @@ class MessageTheme { this.messageAuthor, this.messageLinks, this.messageBackgroundColor, - this.reactionsBackgroundColor, - this.reactionsBorderColor, + this.ownReactionsBackgroundColor, + this.ownReactionsBorderColor, + this.otherReactionsBackgroundColor, + this.otherReactionsBorderColor, this.avatarTheme, this.createdAt, }); @@ -478,10 +489,11 @@ class MessageTheme { TextStyle createdAt, TextStyle replies, Color messageBackgroundColor, - Color otherMessageBackgroundColor, AvatarTheme avatarTheme, - Color reactionsBackgroundColor, - Color reactionsBorderColor, + Color ownReactionsBackgroundColor, + Color ownReactionsBorderColor, + Color otherReactionsBackgroundColor, + Color otherReactionsBorderColor, }) => MessageTheme( messageText: messageText ?? this.messageText, @@ -492,9 +504,14 @@ class MessageTheme { messageBackgroundColor ?? this.messageBackgroundColor, avatarTheme: avatarTheme ?? this.avatarTheme, replies: replies ?? this.replies, - reactionsBackgroundColor: - reactionsBackgroundColor ?? this.reactionsBackgroundColor, - reactionsBorderColor: reactionsBorderColor ?? this.reactionsBorderColor, + ownReactionsBackgroundColor: + ownReactionsBackgroundColor ?? this.ownReactionsBackgroundColor, + ownReactionsBorderColor: + ownReactionsBorderColor ?? this.ownReactionsBorderColor, + otherReactionsBackgroundColor: + otherReactionsBackgroundColor ?? this.otherReactionsBackgroundColor, + otherReactionsBorderColor: + otherReactionsBorderColor ?? this.otherReactionsBorderColor, ); } diff --git a/pubspec.yaml b/pubspec.yaml index 4ac8ef33..ecbeabe7 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -24,7 +24,7 @@ dependencies: image_picker: ^0.6.7+2 flutter_keyboard_visibility: ^3.2.1 flutter_svg: ^0.18.0 - stream_chat: ^0.2.7+1 + stream_chat: ^0.2.8 mime: ^0.9.6+3 visibility_detector: ^0.1.5 line_awesome_icons: ^1.0.4+2 From 24d9b244f2517a53dcf11c389893cc8c1b83520b Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Thu, 15 Oct 2020 11:43:07 +0200 Subject: [PATCH 0088/1140] check if channel.membercount is null --- lib/src/channel_info.dart | 2 +- lib/src/message_list_view.dart | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/src/channel_info.dart b/lib/src/channel_info.dart index af1915a3..a4f0272e 100644 --- a/lib/src/channel_info.dart +++ b/lib/src/channel_info.dart @@ -16,7 +16,7 @@ class ChannelInfo extends StatelessWidget { @override Widget build(BuildContext context) { - if (channel.memberCount > 2) { + if (channel.memberCount != null && channel.memberCount > 2) { return Text( '${channel.memberCount} Members, ${channel.state.watcherCount} Online', style: StreamChatTheme.of(context) diff --git a/lib/src/message_list_view.dart b/lib/src/message_list_view.dart index 081ca004..85fba5a8 100644 --- a/lib/src/message_list_view.dart +++ b/lib/src/message_list_view.dart @@ -446,7 +446,7 @@ class _MessageListViewState extends State { read.lastRead.isBefore(messages[index - 1].createdAt))) ?.toList(); - final allRead = readList.length == channel.memberCount - 1; + final allRead = readList.length >= (channel.memberCount ?? 0) - 1; return MessageWidget( message: message, From bf538b41934287461d6b68dcbad2821f9ada2904 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Fri, 16 Oct 2020 15:20:35 +0530 Subject: [PATCH 0089/1140] feat: wip message input --- lib/src/message_input.dart | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 5334b82b..c2d7506e 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -184,7 +184,7 @@ class MessageInputState extends State { child: Stack( clipBehavior: Clip.none, children: [ - _buildBorder(context), + //_buildBorder(context), Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ @@ -281,7 +281,7 @@ class MessageInputState extends State { decoration: InputDecoration( hintText: 'Write a message', prefixText: ' ', - border: InputBorder.none, + border: OutlineInputBorder(), ), textCapitalization: TextCapitalization.sentences, ), @@ -613,8 +613,11 @@ class MessageInputState extends State { onPressed: () { showAttachmentModal(); }, - icon: Icon( - Icons.add_circle_outline, + icon: Transform.rotate( + child: Icon( + Icons.attach_file_sharp, + ), + angle: - 0.3, ), ), ); From 95214873f979219ae56f2a181299eaf74ce8234d Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Fri, 16 Oct 2020 15:45:00 +0530 Subject: [PATCH 0090/1140] feat: wip message input --- lib/src/message_input.dart | 34 +++++++++++++++++++++++++++++----- 1 file changed, 29 insertions(+), 5 deletions(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index c2d7506e..8ad19388 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -222,7 +222,7 @@ class MessageInputState extends State { ? CrossFadeState.showFirst : CrossFadeState.showSecond, firstChild: _buildSendButton(context), - secondChild: SizedBox(), + secondChild: _buildIdleSendButton(context), duration: Duration(milliseconds: 300), alignment: Alignment.center, ); @@ -617,7 +617,7 @@ class MessageInputState extends State { child: Icon( Icons.attach_file_sharp, ), - angle: - 0.3, + angle: 0.4, ), ), ); @@ -835,6 +835,30 @@ class MessageInputState extends State { return res.file; } + Widget _buildIdleSendButton(BuildContext context) { + return IconTheme( + data: + StreamChatTheme.of(context).channelTheme.messageInputButtonIconTheme, + child: Material( + clipBehavior: Clip.hardEdge, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(32), + ), + color: Colors.grey, + child: IconButton( + key: Key('sendButton'), + onPressed: () { + sendMessage(); + }, + icon: Icon( + Icons.arrow_forward, + color: Colors.white, + ), + ), + ), + ); + } + Widget _buildSendButton(BuildContext context) { return IconTheme( data: @@ -844,15 +868,15 @@ class MessageInputState extends State { shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(32), ), - color: Colors.transparent, + color: StreamChatTheme.of(context).accentColor, child: IconButton( key: Key('sendButton'), onPressed: () { sendMessage(); }, icon: Icon( - Icons.send, - color: StreamChatTheme.of(context).accentColor, + Icons.arrow_upward, + color: Colors.white, ), ), ), From 6ab3e99ffa52f1a1c3cea731d27738c50ab3da19 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Fri, 16 Oct 2020 15:56:09 +0530 Subject: [PATCH 0091/1140] feat: wip message input --- lib/src/message_input.dart | 66 ++++++++++++++++++++++---------------- 1 file changed, 38 insertions(+), 28 deletions(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 8ad19388..6e0b8b90 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -839,20 +839,25 @@ class MessageInputState extends State { return IconTheme( data: StreamChatTheme.of(context).channelTheme.messageInputButtonIconTheme, - child: Material( - clipBehavior: Clip.hardEdge, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(32), - ), - color: Colors.grey, - child: IconButton( - key: Key('sendButton'), - onPressed: () { - sendMessage(); - }, - icon: Icon( - Icons.arrow_forward, - color: Colors.white, + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Center( + child: Material( + clipBehavior: Clip.hardEdge, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(24), + ), + color: Colors.grey, + child: IconButton( + key: Key('sendButton'), + onPressed: () { + sendMessage(); + }, + icon: Icon( + Icons.arrow_forward, + color: Colors.white, + ), + ), ), ), ), @@ -863,20 +868,25 @@ class MessageInputState extends State { return IconTheme( data: StreamChatTheme.of(context).channelTheme.messageInputButtonIconTheme, - child: Material( - clipBehavior: Clip.hardEdge, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(32), - ), - color: StreamChatTheme.of(context).accentColor, - child: IconButton( - key: Key('sendButton'), - onPressed: () { - sendMessage(); - }, - icon: Icon( - Icons.arrow_upward, - color: Colors.white, + child: Center( + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Material( + clipBehavior: Clip.hardEdge, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(24), + ), + color: StreamChatTheme.of(context).accentColor, + child: IconButton( + key: Key('sendButton'), + onPressed: () { + sendMessage(); + }, + icon: Icon( + Icons.arrow_upward, + color: Colors.white, + ), + ), ), ), ), From 550c47ae90a54574578e980e8fbb4528c1bc5e3e Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Fri, 16 Oct 2020 16:01:40 +0530 Subject: [PATCH 0092/1140] feat: wip message input --- lib/src/message_input.dart | 138 +++++++++++++++++++------------------ 1 file changed, 72 insertions(+), 66 deletions(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 6e0b8b90..217ef438 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -230,60 +230,62 @@ class MessageInputState extends State { Expanded _buildTextInput(BuildContext context) { return Expanded( - child: LimitedBox( - maxHeight: widget.maxHeight, - child: TextField( - key: Key('messageInputText'), - enabled: _inputEnabled, - minLines: null, - maxLines: null, - onSubmitted: (_) { - sendMessage(); - }, - keyboardType: widget.keyboardType, - controller: textEditingController, - focusNode: _focusNode, - onChanged: (s) { - StreamChannel.of(context).channel.keyStroke(); + child: Center( + child: LimitedBox( + maxHeight: widget.maxHeight, + child: TextField( + key: Key('messageInputText'), + enabled: _inputEnabled, + minLines: null, + maxLines: null, + onSubmitted: (_) { + sendMessage(); + }, + keyboardType: widget.keyboardType, + controller: textEditingController, + focusNode: _focusNode, + onChanged: (s) { + StreamChannel.of(context).channel.keyStroke(); - setState(() { - _messageIsPresent = s.trim().isNotEmpty; - }); + setState(() { + _messageIsPresent = s.trim().isNotEmpty; + }); - _commandsOverlay?.remove(); - _commandsOverlay = null; - _mentionsOverlay?.remove(); - _mentionsOverlay = null; + _commandsOverlay?.remove(); + _commandsOverlay = null; + _mentionsOverlay?.remove(); + _mentionsOverlay = null; - if (s.startsWith('/')) { - _commandsOverlay = _buildCommandsOverlayEntry(); - Overlay.of(context).insert(_commandsOverlay); - } + if (s.startsWith('/')) { + _commandsOverlay = _buildCommandsOverlayEntry(); + Overlay.of(context).insert(_commandsOverlay); + } - if (textEditingController.selection.isCollapsed && - (s[textEditingController.selection.start - 1] == '@' || - textEditingController.text - .substring(0, textEditingController.selection.start) - .split(' ') - .last - .contains('@'))) { - _mentionsOverlay = _buildMentionsOverlayEntry(); - Overlay.of(context).insert(_mentionsOverlay); - } - }, - onTap: () { - setState(() { - _typingStarted = true; - }); - }, - style: Theme.of(context).textTheme.bodyText2, - autofocus: false, - decoration: InputDecoration( - hintText: 'Write a message', - prefixText: ' ', - border: OutlineInputBorder(), + if (textEditingController.selection.isCollapsed && + (s[textEditingController.selection.start - 1] == '@' || + textEditingController.text + .substring(0, textEditingController.selection.start) + .split(' ') + .last + .contains('@'))) { + _mentionsOverlay = _buildMentionsOverlayEntry(); + Overlay.of(context).insert(_mentionsOverlay); + } + }, + onTap: () { + setState(() { + _typingStarted = true; + }); + }, + style: Theme.of(context).textTheme.bodyText2, + autofocus: false, + decoration: InputDecoration( + hintText: 'Write a message', + prefixText: ' ', + border: OutlineInputBorder(), + ), + textCapitalization: TextCapitalization.sentences, ), - textCapitalization: TextCapitalization.sentences, ), ), ); @@ -602,22 +604,24 @@ class MessageInputState extends State { } } - Material _buildAttachmentButton() { - return Material( - clipBehavior: Clip.hardEdge, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(32), - ), - color: Colors.transparent, - child: IconButton( - onPressed: () { - showAttachmentModal(); - }, - icon: Transform.rotate( - child: Icon( - Icons.attach_file_sharp, + Widget _buildAttachmentButton() { + return Center( + child: Material( + clipBehavior: Clip.hardEdge, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(32), + ), + color: Colors.transparent, + child: IconButton( + onPressed: () { + showAttachmentModal(); + }, + icon: Transform.rotate( + child: Icon( + Icons.attach_file_sharp, + ), + angle: 0.4, ), - angle: 0.4, ), ), ); @@ -845,7 +849,7 @@ class MessageInputState extends State { child: Material( clipBehavior: Clip.hardEdge, shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(24), + borderRadius: BorderRadius.circular(32), ), color: Colors.grey, child: IconButton( @@ -856,6 +860,7 @@ class MessageInputState extends State { icon: Icon( Icons.arrow_forward, color: Colors.white, + size: 18.0, ), ), ), @@ -874,7 +879,7 @@ class MessageInputState extends State { child: Material( clipBehavior: Clip.hardEdge, shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(24), + borderRadius: BorderRadius.circular(32), ), color: StreamChatTheme.of(context).accentColor, child: IconButton( @@ -885,6 +890,7 @@ class MessageInputState extends State { icon: Icon( Icons.arrow_upward, color: Colors.white, + size: 18.0, ), ), ), From d7624721b8a0feba8f96e92b7119c3e86db18b10 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Fri, 16 Oct 2020 12:38:07 +0200 Subject: [PATCH 0093/1140] use stream icons --- assets/Icon_LOL_reaction.svg | 5 - assets/Icon_love_reaction.svg | 3 - assets/Icon_thumbs_down_reaction.svg | 3 - assets/Icon_thumbs_up_reaction.svg | 3 - assets/Icon_wut_reaction.svg | 3 - assets/icon_edit.svg | 3 - assets/icon_user_minus.svg | 5 - fonts/stream-icons.ttf | Bin 0 -> 52056 bytes lib/src/channel_bottom_sheet.dart | 13 +- lib/src/channel_list_view.dart | 12 +- lib/src/channel_preview.dart | 7 +- lib/src/message_actions_modal.dart | 15 +- lib/src/reaction_asset.dart | 14 +- lib/src/reaction_bubble.dart | 10 +- lib/src/reaction_picker.dart | 14 +- lib/src/stream_chat_theme.dart | 36 +- lib/src/stream_icons.dart | 1189 ++++++++++++++++++++++++++ lib/stream_chat_flutter.dart | 1 + pubspec.yaml | 8 +- 19 files changed, 1244 insertions(+), 100 deletions(-) delete mode 100644 assets/Icon_LOL_reaction.svg delete mode 100644 assets/Icon_love_reaction.svg delete mode 100644 assets/Icon_thumbs_down_reaction.svg delete mode 100644 assets/Icon_thumbs_up_reaction.svg delete mode 100644 assets/Icon_wut_reaction.svg delete mode 100644 assets/icon_edit.svg delete mode 100644 assets/icon_user_minus.svg create mode 100644 fonts/stream-icons.ttf create mode 100644 lib/src/stream_icons.dart diff --git a/assets/Icon_LOL_reaction.svg b/assets/Icon_LOL_reaction.svg deleted file mode 100644 index 301fe02c..00000000 --- a/assets/Icon_LOL_reaction.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/assets/Icon_love_reaction.svg b/assets/Icon_love_reaction.svg deleted file mode 100644 index 76b09fd3..00000000 --- a/assets/Icon_love_reaction.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/assets/Icon_thumbs_down_reaction.svg b/assets/Icon_thumbs_down_reaction.svg deleted file mode 100644 index 0d55ad2a..00000000 --- a/assets/Icon_thumbs_down_reaction.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/assets/Icon_thumbs_up_reaction.svg b/assets/Icon_thumbs_up_reaction.svg deleted file mode 100644 index ff4dcc72..00000000 --- a/assets/Icon_thumbs_up_reaction.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/assets/Icon_wut_reaction.svg b/assets/Icon_wut_reaction.svg deleted file mode 100644 index c150b264..00000000 --- a/assets/Icon_wut_reaction.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/assets/icon_edit.svg b/assets/icon_edit.svg deleted file mode 100644 index 32f9cea7..00000000 --- a/assets/icon_edit.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/assets/icon_user_minus.svg b/assets/icon_user_minus.svg deleted file mode 100644 index 47210701..00000000 --- a/assets/icon_user_minus.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/fonts/stream-icons.ttf b/fonts/stream-icons.ttf new file mode 100644 index 0000000000000000000000000000000000000000..2e4d854086f4e1e0258f7e509df0df139b8dc9da GIT binary patch literal 52056 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

tJawn`}K6L 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 O`TB9h ), IconSlideAction( color: backgroundColor, - icon: LineAwesomeIcons.volume_off, + icon: StreamIcons.mute, onTap: () async { if (!channel.isMuted) { await channel.mute(); @@ -374,13 +372,7 @@ class _ChannelListViewState extends State if (channel.isGroup && !channel.isDistinct) IconSlideAction( color: backgroundColor, - iconWidget: SvgPicture.asset( - 'assets/icon_user_minus.svg', - package: 'stream_chat_flutter', - color: - StreamChatTheme.of(context).primaryIconTheme.color, - width: 22, - ), + icon: StreamIcons.user_minus, onTap: () async { final confirm = await showConfirmationDialog( context, diff --git a/lib/src/channel_preview.dart b/lib/src/channel_preview.dart index de6c8222..de1daab8 100644 --- a/lib/src/channel_preview.dart +++ b/lib/src/channel_preview.dart @@ -1,7 +1,6 @@ import 'package:flutter/material.dart'; import 'package:flutter/widgets.dart'; import 'package:jiffy/jiffy.dart'; -import 'package:line_awesome_icons/line_awesome_icons.dart'; import 'package:stream_chat/stream_chat.dart'; import 'package:stream_chat_flutter/src/unread_indicator.dart'; @@ -145,11 +144,11 @@ class ChannelPreview extends StatelessWidget { crossAxisAlignment: CrossAxisAlignment.end, children: [ Icon( - LineAwesomeIcons.volume_off, - size: 15, + StreamIcons.mute, + size: 16, ), Text( - 'Channel is muted', + ' Channel is muted', style: StreamChatTheme.of(context) .channelPreviewTheme .subtitle diff --git a/lib/src/message_actions_modal.dart b/lib/src/message_actions_modal.dart index 683f250b..31086885 100644 --- a/lib/src/message_actions_modal.dart +++ b/lib/src/message_actions_modal.dart @@ -1,10 +1,10 @@ import 'dart:ui'; import 'package:flutter/material.dart'; -import 'package:flutter_svg/flutter_svg.dart'; import 'package:stream_chat/stream_chat.dart'; import 'package:stream_chat_flutter/src/reaction_picker.dart'; import 'package:stream_chat_flutter/src/stream_channel.dart'; +import 'package:stream_chat_flutter/src/stream_icons.dart'; import 'message_input.dart'; import 'message_widget.dart'; @@ -129,7 +129,7 @@ class MessageActionsModal extends StatelessWidget { Theme.of(context).textTheme.headline6.copyWith(color: Colors.red), ), leading: Icon( - Icons.delete_outline, + StreamIcons.delete, color: Colors.red, ), onTap: () { @@ -148,12 +148,9 @@ class MessageActionsModal extends StatelessWidget { 'Edit message', style: Theme.of(context).textTheme.headline6, ), - leading: SvgPicture.asset( - 'assets/icon_edit.svg', - alignment: Alignment.center, - package: 'stream_chat_flutter', + leading: Icon( + StreamIcons.edit, color: StreamChatTheme.of(context).primaryIconTheme.color, - width: 24, ), onTap: () async { Navigator.pop(context); @@ -255,11 +252,11 @@ class MessageActionsModal extends StatelessWidget { Widget _buildReplyButton(BuildContext context) { return ListTile( title: Text( - 'Start a thread', + 'Thread reply', style: Theme.of(context).textTheme.headline6, ), leading: Icon( - Icons.reply, + StreamIcons.Thread_Reply, color: StreamChatTheme.of(context).primaryIconTheme.color, ), onTap: () { diff --git a/lib/src/reaction_asset.dart b/lib/src/reaction_asset.dart index d33bbf26..5f885643 100644 --- a/lib/src/reaction_asset.dart +++ b/lib/src/reaction_asset.dart @@ -1,11 +1,11 @@ -class ReactionAsset { - final String type; - final String svgAsset; - final String package; +import 'package:flutter/material.dart'; - ReactionAsset({ +class ReactionIcon { + final String type; + final IconData iconData; + + ReactionIcon({ this.type, - this.svgAsset, - this.package, + this.iconData, }); } diff --git a/lib/src/reaction_bubble.dart b/lib/src/reaction_bubble.dart index 46c2b238..c9768c8d 100644 --- a/lib/src/reaction_bubble.dart +++ b/lib/src/reaction_bubble.dart @@ -1,7 +1,6 @@ import 'dart:math'; import 'package:flutter/material.dart'; -import 'package:flutter_svg/svg.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; class ReactionBubble extends StatelessWidget { @@ -22,7 +21,7 @@ class ReactionBubble extends StatelessWidget { @override Widget build(BuildContext context) { - final reactionAssets = StreamChatTheme.of(context).reactionAssets; + final reactionAssets = StreamChatTheme.of(context).reactionIcons; return Transform( transform: Matrix4.rotationY(reverse ? pi : 0), alignment: Alignment.center, @@ -55,10 +54,9 @@ class ReactionBubble extends StatelessWidget { ); } - return SvgPicture.asset( - reactionAsset.svgAsset, - package: reactionAsset.package, - height: 16, + return Icon( + reactionAsset.iconData, + size: 16, color: StreamChatTheme.of(context).accentColor, ); }).toList(), diff --git a/lib/src/reaction_picker.dart b/lib/src/reaction_picker.dart index c07c32cb..3b890230 100644 --- a/lib/src/reaction_picker.dart +++ b/lib/src/reaction_picker.dart @@ -1,5 +1,4 @@ import 'package:flutter/material.dart'; -import 'package:flutter_svg/flutter_svg.dart'; import '../stream_chat_flutter.dart'; @@ -23,7 +22,7 @@ class ReactionPicker extends StatelessWidget { @override Widget build(BuildContext context) { - final reactionAssets = StreamChatTheme.of(context).reactionAssets; + final reactionAssets = StreamChatTheme.of(context).reactionIcons; return Material( color: messageTheme.ownReactionsBackgroundColor, clipBehavior: Clip.hardEdge, @@ -34,15 +33,14 @@ class ReactionPicker extends StatelessWidget { crossAxisAlignment: CrossAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.center, mainAxisSize: MainAxisSize.min, - children: reactionAssets.map((reactionAsset) { + children: reactionAssets.map((reactionIcon) { final ownReactionIndex = message.ownReactions?.indexWhere( - (reaction) => reaction.type == reactionAsset.type) ?? + (reaction) => reaction.type == reactionIcon.type) ?? -1; return IconButton( iconSize: 24, - icon: SvgPicture.asset( - reactionAsset.svgAsset, - package: reactionAsset.package, + icon: Icon( + reactionIcon.iconData, color: ownReactionIndex != -1 ? StreamChatTheme.of(context).accentColor : Theme.of(context).iconTheme.color, @@ -56,7 +54,7 @@ class ReactionPicker extends StatelessWidget { } else { sendReaction( context, - reactionAsset.type, + reactionIcon.type, ); } }, diff --git a/lib/src/stream_chat_theme.dart b/lib/src/stream_chat_theme.dart index 0f92a294..56f71a93 100644 --- a/lib/src/stream_chat_theme.dart +++ b/lib/src/stream_chat_theme.dart @@ -3,6 +3,7 @@ import 'package:stream_chat/stream_chat.dart'; import 'package:stream_chat_flutter/src/channel_header.dart'; import 'package:stream_chat_flutter/src/channel_preview.dart'; import 'package:stream_chat_flutter/src/message_input.dart'; +import 'package:stream_chat_flutter/src/stream_icons.dart'; import 'reaction_asset.dart'; @@ -75,7 +76,7 @@ class StreamChatThemeData { final IconThemeData primaryIconTheme; /// Assets used for rendering reactions - final List reactionAssets; + final List reactionIcons; /// Create a theme from scratch StreamChatThemeData({ @@ -90,7 +91,7 @@ class StreamChatThemeData { this.defaultChannelImage, this.defaultUserImage, this.primaryIconTheme, - this.reactionAssets, + this.reactionIcons, }); /// Create a theme from a Material [Theme] @@ -141,7 +142,7 @@ class StreamChatThemeData { Widget Function(BuildContext, Channel) defaultChannelImage, Widget Function(BuildContext, User) defaultUserImage, IconThemeData primaryIconTheme, - List reactionAssets, + List reactionAssets, }) => StreamChatThemeData( primaryColor: primaryColor ?? this.primaryColor, @@ -210,7 +211,7 @@ class StreamChatThemeData { this.otherMessageTheme.avatarTheme, ) ?? this.otherMessageTheme, - reactionAssets: reactionAssets ?? this.reactionAssets, + reactionIcons: reactionAssets ?? this.reactionIcons, ); /// Get the default Stream Chat theme @@ -353,31 +354,26 @@ class StreamChatThemeData { ), ), ), - reactionAssets: [ - ReactionAsset( + reactionIcons: [ + ReactionIcon( type: 'love', - svgAsset: 'assets/Icon_love_reaction.svg', - package: 'stream_chat_flutter', + iconData: StreamIcons.love_reaction, ), - ReactionAsset( + ReactionIcon( type: 'thumbs_up', - svgAsset: 'assets/Icon_thumbs_up_reaction.svg', - package: 'stream_chat_flutter', + iconData: StreamIcons.thumbs_up_reaction, ), - ReactionAsset( + ReactionIcon( type: 'thumbs_down', - svgAsset: 'assets/Icon_thumbs_down_reaction.svg', - package: 'stream_chat_flutter', + iconData: StreamIcons.thumbs_up_reaction_1, ), - ReactionAsset( + ReactionIcon( type: 'lol', - svgAsset: 'assets/Icon_LOL_reaction.svg', - package: 'stream_chat_flutter', + iconData: StreamIcons.LOL_reaction, ), - ReactionAsset( + ReactionIcon( type: 'wut', - svgAsset: 'assets/Icon_wut_reaction.svg', - package: 'stream_chat_flutter', + iconData: StreamIcons.wut_reaction, ), ], ); diff --git a/lib/src/stream_icons.dart b/lib/src/stream_icons.dart new file mode 100644 index 00000000..73d1e5c0 --- /dev/null +++ b/lib/src/stream_icons.dart @@ -0,0 +1,1189 @@ +import 'package:flutter/widgets.dart'; + +class StreamIcons { + StreamIcons._(); + + static const String _fontFamily = 'stream-icons'; + static const String _fontPackage = 'stream_chat_flutter'; + + static const IconData ambulance_car = IconData( + 0xe900, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData ambulance_signal = IconData( + 0xe901, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData ambulance = IconData( + 0xe902, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData apps = IconData( + 0xe903, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData archive = IconData( + 0xe904, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData arrow_down_left = IconData( + 0xe905, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData arrow_down = IconData( + 0xe906, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData arrow_drop_down = IconData( + 0xe907, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData arrow_drop_up = IconData( + 0xe908, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData arrow_left_up = IconData( + 0xe909, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData arrow_left = IconData( + 0xe90a, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData arrow_right_down = IconData( + 0xe90b, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData arrow_right = IconData( + 0xe90c, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData arrow_up_right = IconData( + 0xe90d, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData arrow_up = IconData( + 0xe90e, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData at_mention = IconData( + 0xe90f, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData atom = IconData( + 0xe910, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData attach = IconData( + 0xe911, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData attention = IconData( + 0xe912, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData basket = IconData( + 0xe913, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData blank_empty = IconData( + 0xe914, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData blank = IconData( + 0xe915, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData blood_add = IconData( + 0xe916, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData blood_delete = IconData( + 0xe917, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData brain = IconData( + 0xe918, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData building = IconData( + 0xe919, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData calculator = IconData( + 0xe91a, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData calendar = IconData( + 0xe91b, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData call_in = IconData( + 0xe91c, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData call_out = IconData( + 0xe91d, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData call = IconData( + 0xe91e, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData camera = IconData( + 0xe91f, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData car = IconData( + 0xe920, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData card = IconData( + 0xe921, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData cards = IconData( + 0xe922, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData cash = IconData( + 0xe923, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData chart_line = IconData( + 0xe924, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData chart = IconData( + 0xe925, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData check_all = IconData( + 0xe926, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData check_send = IconData( + 0xe927, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData check = IconData( + 0xe928, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData chemical = IconData( + 0xe929, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData circle_down = IconData( + 0xe92a, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData circle_left = IconData( + 0xe92b, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData circle_right = IconData( + 0xe92c, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData circle_up = IconData( + 0xe92d, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData close_circle = IconData( + 0xe92e, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData close = IconData( + 0xe92f, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData closed = IconData( + 0xe930, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData coin = IconData( + 0xe931, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData command_runner_rocket = IconData( + 0xe932, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData compass = IconData( + 0xe933, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData copy = IconData( + 0xe934, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData couch = IconData( + 0xe935, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData curve_left_down = IconData( + 0xe936, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData curve_line_down_left = IconData( + 0xe937, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData curve_line_down_right = IconData( + 0xe938, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData curve_line_left_up = IconData( + 0xe939, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData curve_line_right_up = IconData( + 0xe93a, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData curve_line_up_left = IconData( + 0xe93b, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData curve_line_up_right = IconData( + 0xe93c, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData curve_right_down = IconData( + 0xe93d, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData daily_planner = IconData( + 0xe93e, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData date = IconData( + 0xe93f, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData delete = IconData( + 0xe940, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData desktop = IconData( + 0xe941, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData disabled = IconData( + 0xe942, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData dna = IconData( + 0xe943, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData doc = IconData( + 0xe944, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData documents = IconData( + 0xe945, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData down = IconData( + 0xe946, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData download_1 = IconData( + 0xe947, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData download = IconData( + 0xe948, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData edit = IconData( + 0xe949, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData emergency_call_add = IconData( + 0xe94a, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData emergency_call = IconData( + 0xe94b, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData emergency = IconData( + 0xe94c, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData error = IconData( + 0xe94d, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData exit = IconData( + 0xe94e, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData experiment = IconData( + 0xe94f, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData eye_off = IconData( + 0xe950, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData eye = IconData( + 0xe951, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData face = IconData( + 0xe952, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData female = IconData( + 0xe953, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData filter_hor = IconData( + 0xe954, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData filter = IconData( + 0xe955, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData first_aid = IconData( + 0xe956, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData flag = IconData( + 0xe957, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData flash = IconData( + 0xe958, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData folder = IconData( + 0xe959, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData form_edit = IconData( + 0xe95a, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData grey600 = IconData( + 0xe95b, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData grid = IconData( + 0xe95c, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData heart_outline_add = IconData( + 0xe95d, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData heart_outline_delete = IconData( + 0xe95e, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData heart_pill = IconData( + 0xe95f, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData heart_1 = IconData( + 0xe960, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData heart = IconData( + 0xe961, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData help = IconData( + 0xe962, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData home_1 = IconData( + 0xe963, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData home = IconData( + 0xe964, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData hospital = IconData( + 0xe965, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData hourglass_empty = IconData( + 0xe966, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData hourglass_full_1 = IconData( + 0xe967, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData hourglass_full = IconData( + 0xe968, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData hourglass = IconData( + 0xe969, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData insurance_outline = IconData( + 0xe96a, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData insurance = IconData( + 0xe96b, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData left_right = IconData( + 0xe96c, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData left = IconData( + 0xe96d, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData light = IconData( + 0xe96e, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData lightning = IconData( + 0xe96f, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData link = IconData( + 0xe970, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData location_map = IconData( + 0xe971, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData location = IconData( + 0xe972, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData LOL_reaction = IconData( + 0xe973, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData love_reaction = IconData( + 0xe974, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData love = IconData( + 0xe975, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData lungs = IconData( + 0xe976, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData mail_open = IconData( + 0xe977, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData mail = IconData( + 0xe978, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData male = IconData( + 0xe979, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData medical_bed = IconData( + 0xe97a, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData medical_blank = IconData( + 0xe97b, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData medical_card_add = IconData( + 0xe97c, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData medical_card = IconData( + 0xe97d, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData medical_cross = IconData( + 0xe97e, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData medical_load = IconData( + 0xe97f, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData menu_point_v = IconData( + 0xe980, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData menu_point_1 = IconData( + 0xe981, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData menu_point = IconData( + 0xe982, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData menu = IconData( + 0xe983, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData message = IconData( + 0xe984, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData mic = IconData( + 0xe985, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData minus_circle = IconData( + 0xe986, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData minus = IconData( + 0xe987, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData molecule = IconData( + 0xe988, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData money = IconData( + 0xe989, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData multiply_circle = IconData( + 0xe98a, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData mute = IconData( + 0xe98b, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData notification_off = IconData( + 0xe98c, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData notification = IconData( + 0xe98d, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData nurse = IconData( + 0xe98e, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData open = IconData( + 0xe98f, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData patch = IconData( + 0xe990, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData payment = IconData( + 0xe991, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData pc_graph = IconData( + 0xe992, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData pen_write = IconData( + 0xe993, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData photo = IconData( + 0xe994, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData picture = IconData( + 0xe995, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData pie_chart_empty = IconData( + 0xe996, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData pie_chart_line = IconData( + 0xe997, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData pie_chart = IconData( + 0xe998, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData pill = IconData( + 0xe999, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData pin = IconData( + 0xe99a, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData plus_circle = IconData( + 0xe99b, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData plus = IconData( + 0xe99c, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData podium = IconData( + 0xe99d, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData pointer_leftright = IconData( + 0xe99e, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData pointer = IconData( + 0xe99f, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData potion_circle = IconData( + 0xe9a0, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData potion_health = IconData( + 0xe9a1, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData potion = IconData( + 0xe9a2, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData print = IconData( + 0xe9a3, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData pulse = IconData( + 0xe9a4, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData pyramid = IconData( + 0xe9a5, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData radiation = IconData( + 0xe9a6, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData rating = IconData( + 0xe9a7, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData record = IconData( + 0xe9a8, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData refresh_back = IconData( + 0xe9a9, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData refresh = IconData( + 0xe9aa, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData reload_vert = IconData( + 0xe9ab, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData reload = IconData( + 0xe9ac, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData right = IconData( + 0xe9ad, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData roll = IconData( + 0xe9ae, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData sale = IconData( + 0xe9af, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData save_check = IconData( + 0xe9b0, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData save_1 = IconData( + 0xe9b1, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData save = IconData( + 0xe9b2, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData schedule_square = IconData( + 0xe9b3, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData schedule = IconData( + 0xe9b4, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData scissors = IconData( + 0xe9b5, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData search = IconData( + 0xe9b6, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData send_message = IconData( + 0xe9b7, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData settings = IconData( + 0xe9b8, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData share_1 = IconData( + 0xe9b9, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData share = IconData( + 0xe9ba, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData signboard = IconData( + 0xe9bb, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData smile_sad = IconData( + 0xe9bc, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData smile = IconData( + 0xe9bd, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData sorting_down = IconData( + 0xe9be, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData sorting_up = IconData( + 0xe9bf, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData sorting = IconData( + 0xe9c0, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData square_down = IconData( + 0xe9c1, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData square_left = IconData( + 0xe9c2, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData square_right = IconData( + 0xe9c3, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData square_up = IconData( + 0xe9c4, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData stand = IconData( + 0xe9c5, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData star = IconData( + 0xe9c6, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData stats = IconData( + 0xe9c7, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData stethoscope = IconData( + 0xe9c8, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData sticker = IconData( + 0xe9c9, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData storage = IconData( + 0xe9ca, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData strl_down = IconData( + 0xe9cb, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData strl_left = IconData( + 0xe9cc, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData strl_right = IconData( + 0xe9cd, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData strl_up = IconData( + 0xe9ce, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData syringe = IconData( + 0xe9cf, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData tablet = IconData( + 0xe9d0, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData target = IconData( + 0xe9d1, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData test_tube = IconData( + 0xe9d2, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData Thread_Reply = IconData( + 0xe9d3, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData thumbs_up_reaction_1 = IconData( + 0xe9d4, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData thumbs_up_reaction = IconData( + 0xe9d5, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData time_wait = IconData( + 0xe9d6, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData time_1 = IconData( + 0xe9d7, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData time = IconData( + 0xe9d8, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData tooth = IconData( + 0xe9d9, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData tube_full = IconData( + 0xe9da, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData tv_check = IconData( + 0xe9db, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData tv_rating = IconData( + 0xe9dc, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData unfold_less_h = IconData( + 0xe9dd, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData unfold_less = IconData( + 0xe9de, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData unfold_more_h = IconData( + 0xe9df, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData unfold_more = IconData( + 0xe9e0, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData unread = IconData( + 0xe9e1, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData up_down = IconData( + 0xe9e2, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData up = IconData( + 0xe9e3, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData upload = IconData( + 0xe9e4, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData user_add = IconData( + 0xe9e5, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData user_delete = IconData( + 0xe9e6, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData user_minus = IconData( + 0xe9e7, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData user = IconData( + 0xe9e8, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData voice = IconData( + 0xe9e9, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData world = IconData( + 0xe9ea, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); + static const IconData wut_reaction = IconData( + 0xe9eb, + fontFamily: _fontFamily, + fontPackage: _fontPackage, + ); +} diff --git a/lib/stream_chat_flutter.dart b/lib/stream_chat_flutter.dart index dffbd154..4c5760bf 100644 --- a/lib/stream_chat_flutter.dart +++ b/lib/stream_chat_flutter.dart @@ -23,6 +23,7 @@ export 'src/sending_indicator.dart'; export 'src/stream_channel.dart'; export 'src/stream_chat.dart'; export 'src/stream_chat_theme.dart'; +export 'src/stream_icons.dart'; export 'src/system_message.dart'; export 'src/thread_header.dart'; export 'src/typing_indicator.dart'; diff --git a/pubspec.yaml b/pubspec.yaml index ecbeabe7..3fb1b5ff 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -23,18 +23,18 @@ dependencies: file_picker: ^2.0.0 image_picker: ^0.6.7+2 flutter_keyboard_visibility: ^3.2.1 - flutter_svg: ^0.18.0 stream_chat: ^0.2.8 mime: ^0.9.6+3 visibility_detector: ^0.1.5 - line_awesome_icons: ^1.0.4+2 http_parser: ^3.1.4 flutter_slidable: ^0.5.4 carousel_slider: ^2.2.1 flutter: - assets: - - assets/ + fonts: + - family: stream-icons + fonts: + - asset: fonts/stream-icons.ttf dev_dependencies: pedantic: ^1.9.0 From 8e98816ee3ff2b3741ff4960eecd3606369c544b Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Fri, 16 Oct 2020 16:09:25 +0530 Subject: [PATCH 0094/1140] feat: wip message input --- lib/src/message_input.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 217ef438..af0413f8 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -202,7 +202,7 @@ class MessageInputState extends State { Flex _buildTextField(BuildContext context) { return Flex( direction: Axis.horizontal, - crossAxisAlignment: CrossAxisAlignment.end, + crossAxisAlignment: CrossAxisAlignment.center, children: [ if (!widget.disableAttachments) _buildAttachmentButton(), if (widget.actionsLocation == ActionsLocation.left) From dba8e90b3785b52cf52830578b4673c169bd2ce5 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Thu, 15 Oct 2020 12:01:10 +0200 Subject: [PATCH 0095/1140] fix reaction bubble ui position --- lib/src/reaction_bubble.dart | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/lib/src/reaction_bubble.dart b/lib/src/reaction_bubble.dart index c9768c8d..7c36cdf3 100644 --- a/lib/src/reaction_bubble.dart +++ b/lib/src/reaction_bubble.dart @@ -26,7 +26,8 @@ class ReactionBubble extends StatelessWidget { transform: Matrix4.rotationY(reverse ? pi : 0), alignment: Alignment.center, child: Column( - crossAxisAlignment: CrossAxisAlignment.center, + crossAxisAlignment: + flipTail ? CrossAxisAlignment.start : CrossAxisAlignment.end, mainAxisSize: MainAxisSize.min, children: [ Container( @@ -71,7 +72,7 @@ class ReactionBubble extends StatelessWidget { Widget _buildReactionsTail(BuildContext context) { final tail = Transform.translate( - offset: Offset(4, 0), + offset: Offset(reactions.length > 1 ? -9 : -9, 0), child: CustomPaint( painter: ReactionBubblePainter( backgroundColor, @@ -152,7 +153,7 @@ class ReactionBubblePainter extends CustomPainter { final dy = reactionsCount > 1 ? -2.0 : -3.0; final startAngle = reactionsCount > 1 ? 1.08 : 1.16; - final sweepAngle = reactionsCount > 1 ? 1.18 : 1.1; + final sweepAngle = reactionsCount > 1 ? 0.95 : 1.1; final path = Path(); path.addArc( Rect.fromCircle( @@ -171,7 +172,8 @@ class ReactionBubblePainter extends CustomPainter { ..strokeWidth = 1; final dy = reactionsCount > 1 ? -2.0 : -3.0; - final startAngle = reactionsCount > 1 ? 1.05 : 1.16; + final startAngle = reactionsCount > 1 ? 1 : 1.16; + final sweepAngle = reactionsCount > 1 ? 1.2 : 1; final path = Path(); path.addArc( Rect.fromCircle( @@ -179,7 +181,7 @@ class ReactionBubblePainter extends CustomPainter { radius: 4, ), -pi * startAngle, - -pi, + -pi * sweepAngle, ); canvas.drawPath(path, paint); } From ab1e855cfe6c4278c33820cfe4b43a7e3cba66d2 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Thu, 15 Oct 2020 12:57:54 +0200 Subject: [PATCH 0096/1140] fix message padding --- 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 f4f141bf..13b31f21 100644 --- a/lib/src/message_widget.dart +++ b/lib/src/message_widget.dart @@ -244,7 +244,7 @@ class _MessageWidgetState extends State { top: widget.message.reactionCounts ?.isNotEmpty == true - ? 16 + ? 12 : 0, ) : EdgeInsets.zero, From c4a890d0697a5a0960b6096b1eafa18b5186d6bc Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Thu, 15 Oct 2020 13:34:59 +0200 Subject: [PATCH 0097/1140] add reactions modal --- example/lib/main.dart | 4 +- example/pubspec.yaml | 2 +- lib/src/message_reactions_modal.dart | 165 +++++++++++++++++++++++++++ lib/src/message_widget.dart | 31 ++++- 4 files changed, 197 insertions(+), 5 deletions(-) create mode 100644 lib/src/message_reactions_modal.dart diff --git a/example/lib/main.dart b/example/lib/main.dart index ed474701..89ed9381 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -75,7 +75,9 @@ void main() async { ); await client.setUser( - User(id: 'super-band-9'), + User(id: 'super-band-9', extraData: { + 'name': 'John Doe', + }), 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoic3VwZXItYmFuZC05In0.0L6lGoeLwkz0aZRUcpZKsvaXtNEDHBcezVTZ0oPq40A', ); diff --git a/example/pubspec.yaml b/example/pubspec.yaml index c3ab3b46..457e72e4 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -1,7 +1,7 @@ name: example description: A new Flutter project. -version: 1.0.28+30 +version: 1.0.29+31 environment: sdk: ">=2.2.2 <3.0.0" diff --git a/lib/src/message_reactions_modal.dart b/lib/src/message_reactions_modal.dart new file mode 100644 index 00000000..538fbd92 --- /dev/null +++ b/lib/src/message_reactions_modal.dart @@ -0,0 +1,165 @@ +import 'dart:ui'; + +import 'package:flutter/material.dart'; +import 'package:stream_chat/stream_chat.dart'; +import 'package:stream_chat_flutter/src/reaction_bubble.dart'; +import 'package:stream_chat_flutter/src/reaction_picker.dart'; +import 'package:stream_chat_flutter/src/stream_channel.dart'; +import 'package:stream_chat_flutter/src/stream_chat.dart'; +import 'package:stream_chat_flutter/src/user_avatar.dart'; + +import 'message_widget.dart'; +import 'stream_chat_theme.dart'; + +class MessageReactionsModal extends StatelessWidget { + final Widget Function(BuildContext, Message) editMessageInputBuilder; + final void Function(Message) onThreadTap; + final Message message; + final MessageTheme messageTheme; + final bool showReactions; + final bool showDeleteMessage; + final bool showEditMessage; + final bool showReply; + final bool reverse; + final ShapeBorder messageShape; + + const MessageReactionsModal({ + Key key, + @required this.message, + @required this.messageTheme, + this.showReactions, + this.showDeleteMessage, + this.showEditMessage, + this.onThreadTap, + this.showReply, + this.editMessageInputBuilder, + this.messageShape, + this.reverse, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + final channel = StreamChannel.of(context).channel; + 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, + ), + ), + ), + ), + Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + if (showReactions && + (message.status == MessageSendingStatus.SENT || + message.status == null)) + Center( + child: ReactionPicker( + channel: channel, + message: message, + messageTheme: messageTheme, + ), + ), + AbsorbPointer( + child: MessageWidget( + reverse: reverse, + message: message, + messageTheme: messageTheme, + showReactions: false, + showUsername: false, + showReplyIndicator: false, + showTimestamp: false, + showSendingIndicator: DisplayWidget.gone, + shape: messageShape, + ), + ), + SizedBox( + height: 8, + ), + if (message.latestReactions.isNotEmpty) + Padding( + padding: const EdgeInsets.symmetric( + horizontal: 8.0, + ), + child: Card( + clipBehavior: Clip.hardEdge, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(16), + ), + child: GridView.builder( + shrinkWrap: true, + padding: const EdgeInsets.all(16.0), + gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: 4, + crossAxisSpacing: 16, + childAspectRatio: 0.8, + mainAxisSpacing: 22, + ), + itemCount: message.latestReactions.length, + itemBuilder: (context, i) { + final reaction = message.latestReactions[i]; + final isCurrentUser = + reaction.user.id == StreamChat.of(context).user.id; + return Column( + mainAxisSize: MainAxisSize.min, + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Stack( + children: [ + UserAvatar( + user: reaction.user, + constraints: BoxConstraints.tightFor( + height: 64, + width: 64, + ), + borderRadius: BorderRadius.circular(32), + ), + 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, + ), + ], + ), + Text( + reaction.user.name, + style: Theme.of(context).textTheme.subtitle2, + textAlign: TextAlign.center, + ), + ], + ); + }, + ), + ), + ) + ], + ), + ], + ); + } +} diff --git a/lib/src/message_widget.dart b/lib/src/message_widget.dart index 13b31f21..fccaa1e4 100644 --- a/lib/src/message_widget.dart +++ b/lib/src/message_widget.dart @@ -8,6 +8,7 @@ import 'package:flutter/rendering.dart'; import 'package:flutter_portal/flutter_portal.dart'; import 'package:jiffy/jiffy.dart'; import 'package:stream_chat_flutter/src/message_actions_modal.dart'; +import 'package:stream_chat_flutter/src/message_reactions_modal.dart'; import 'package:stream_chat_flutter/src/reaction_bubble.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; @@ -437,7 +438,7 @@ class _MessageWidgetState extends State { !widget.message.isDeleted) ? Container( child: GestureDetector( - onTap: () => onLongPress(context), + onTap: () => _showMessageReactionsModalBottomSheet(context), child: FractionallySizedBox( widthFactor: 0.5, child: Row( @@ -452,7 +453,7 @@ class _MessageWidgetState extends State { ); } - void _showMessageModalBottomSheet(BuildContext context) { + void _showMessageActionModalBottomSheet(BuildContext context) { final channel = StreamChannel.of(context).channel; showDialog( context: context, @@ -476,6 +477,30 @@ class _MessageWidgetState extends State { }); } + void _showMessageReactionsModalBottomSheet(BuildContext context) { + final channel = StreamChannel.of(context).channel; + showDialog( + context: context, + builder: (context) { + return StreamChannel( + channel: channel, + child: MessageReactionsModal( + messageTheme: widget.messageTheme, + messageShape: widget.shape ?? _getDefaultShape(context), + reverse: widget.reverse, + showDeleteMessage: widget.showDeleteMessage, + message: widget.message, + editMessageInputBuilder: widget.editMessageInputBuilder, + onThreadTap: widget.onThreadTap, + showEditMessage: widget.showEditMessage, + showReactions: widget.showReactions, + showReply: + widget.showReplyIndicator && widget.onThreadTap != null, + ), + ); + }); + } + ContinuousRectangleBorder _getDefaultShape(BuildContext context) { return ContinuousRectangleBorder( side: widget.attachmentBorderSide ?? @@ -581,7 +606,7 @@ class _MessageWidgetState extends State { if (widget.onMessageActions != null) { widget.onMessageActions(context, widget.message); } else { - _showMessageModalBottomSheet(context); + _showMessageActionModalBottomSheet(context); } return; } From d36e2e564509c1f75ac8d0506ae7db0ef03a0034 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Fri, 16 Oct 2020 16:20:18 +0530 Subject: [PATCH 0098/1140] feat: wip message input --- lib/src/message_input.dart | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index af0413f8..10225e6b 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -282,7 +282,9 @@ class MessageInputState extends State { decoration: InputDecoration( hintText: 'Write a message', prefixText: ' ', - border: OutlineInputBorder(), + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(32), + ), ), textCapitalization: TextCapitalization.sentences, ), @@ -860,7 +862,7 @@ class MessageInputState extends State { icon: Icon( Icons.arrow_forward, color: Colors.white, - size: 18.0, + size: 16.0, ), ), ), @@ -890,7 +892,11 @@ class MessageInputState extends State { icon: Icon( Icons.arrow_upward, color: Colors.white, - size: 18.0, + size: 16.0, + ), + constraints: BoxConstraints( + maxWidth: 24.0, + maxHeight: 24.0, ), ), ), From b0ad9c673e79a3025da278b569f301659a1f1f6b Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Fri, 16 Oct 2020 12:03:04 +0200 Subject: [PATCH 0099/1140] fix reaction modal ui --- example/ios/Flutter/.last_build_id | 2 +- example/ios/Podfile.lock | 8 +- example/pubspec.yaml | 2 +- lib/src/channel_bottom_sheet.dart | 2 +- lib/src/message_actions_modal.dart | 1 + lib/src/message_reactions_modal.dart | 178 +++++++++++++++++---------- lib/src/message_widget.dart | 1 + lib/src/reaction_picker.dart | 93 ++++++++------ 8 files changed, 175 insertions(+), 112 deletions(-) diff --git a/example/ios/Flutter/.last_build_id b/example/ios/Flutter/.last_build_id index e3266027..171fde31 100644 --- a/example/ios/Flutter/.last_build_id +++ b/example/ios/Flutter/.last_build_id @@ -1 +1 @@ -06fe8d0d3d89937a6d33b1033e75ae96 \ No newline at end of file +0289cdadbd29bab804f275e3c5907d07 \ No newline at end of file diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock index f289e1b7..23f0045b 100644 --- a/example/ios/Podfile.lock +++ b/example/ios/Podfile.lock @@ -38,10 +38,10 @@ PODS: - Firebase/Messaging (6.26.0): - Firebase/CoreOnly - FirebaseMessaging (~> 4.4.1) - - firebase_core (0.5.0): + - firebase_core (0.5.0-1): - Firebase/CoreOnly (~> 6.26.0) - Flutter - - firebase_messaging (7.0.2): + - firebase_messaging (7.0.3): - Firebase/CoreOnly (~> 6.26.0) - Firebase/Messaging (~> 6.26.0) - firebase_core @@ -233,8 +233,8 @@ SPEC CHECKSUMS: DKPhotoGallery: fdfad5125a9fdda9cc57df834d49df790dbb4179 file_picker: 3e6c3790de664ccf9b882732d9db5eaf6b8d4eb1 Firebase: 7cf5f9c67f03cb3b606d1d6535286e1080e57eb6 - firebase_core: 3134fe79d257d430f163b558caf52a10a87efe8a - firebase_messaging: 2844c37f9ce87c0904b38fe435223161b1a71528 + firebase_core: 00e54a4744164a6b5a250b96dd1ad5afaba7a342 + firebase_messaging: 666d9994651b1ecf8c582b52dd913f3fa58c17ef FirebaseAnalyticsInterop: 3f86269c38ae41f47afeb43ebf32a001f58fcdae FirebaseCore: f42e5e5f382cdcf6b617ed737bf6c871a6947b17 FirebaseCoreDiagnostics: 770ac5958e1372ce67959ae4b4f31d8e127c3ac1 diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 457e72e4..a5a2f73f 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -1,7 +1,7 @@ name: example description: A new Flutter project. -version: 1.0.29+31 +version: 1.0.30+32 environment: sdk: ">=2.2.2 <3.0.0" diff --git a/lib/src/channel_bottom_sheet.dart b/lib/src/channel_bottom_sheet.dart index 187fc6a9..0de24270 100644 --- a/lib/src/channel_bottom_sheet.dart +++ b/lib/src/channel_bottom_sheet.dart @@ -154,7 +154,7 @@ class ChannelBottomSheet extends StatelessWidget { height: 83, child: ListView( padding: EdgeInsets.only( - left: (MediaQuery.of(context).size.width / 2) - 48, + left: (MediaQuery.of(context).size.width / 2) - 80, ), scrollDirection: Axis.horizontal, children: snapshot.data.map((m) { diff --git a/lib/src/message_actions_modal.dart b/lib/src/message_actions_modal.dart index 31086885..012a2c9f 100644 --- a/lib/src/message_actions_modal.dart +++ b/lib/src/message_actions_modal.dart @@ -1,5 +1,6 @@ import 'dart:ui'; +import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:stream_chat/stream_chat.dart'; import 'package:stream_chat_flutter/src/reaction_picker.dart'; diff --git a/lib/src/message_reactions_modal.dart b/lib/src/message_reactions_modal.dart index 538fbd92..90e1fb97 100644 --- a/lib/src/message_reactions_modal.dart +++ b/lib/src/message_reactions_modal.dart @@ -22,6 +22,7 @@ class MessageReactionsModal extends StatelessWidget { final bool showReply; final bool reverse; final ShapeBorder messageShape; + final void Function(User) onUserAvatarTap; const MessageReactionsModal({ Key key, @@ -35,6 +36,7 @@ class MessageReactionsModal extends StatelessWidget { this.editMessageInputBuilder, this.messageShape, this.reverse, + this.onUserAvatarTap, }) : super(key: key); @override @@ -87,79 +89,119 @@ class MessageReactionsModal extends StatelessWidget { ), ), SizedBox( - height: 8, + height: 16, ), if (message.latestReactions.isNotEmpty) - Padding( - padding: const EdgeInsets.symmetric( - horizontal: 8.0, - ), - child: Card( - clipBehavior: Clip.hardEdge, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(16), - ), - child: GridView.builder( - shrinkWrap: true, - padding: const EdgeInsets.all(16.0), - gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( - crossAxisCount: 4, - crossAxisSpacing: 16, - childAspectRatio: 0.8, - mainAxisSpacing: 22, - ), - itemCount: message.latestReactions.length, - itemBuilder: (context, i) { - final reaction = message.latestReactions[i]; - final isCurrentUser = - reaction.user.id == StreamChat.of(context).user.id; - return Column( - mainAxisSize: MainAxisSize.min, - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Stack( - children: [ - UserAvatar( - user: reaction.user, - constraints: BoxConstraints.tightFor( - height: 64, - width: 64, - ), - borderRadius: BorderRadius.circular(32), - ), - 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, - ), - ], - ), - Text( - reaction.user.name, - style: Theme.of(context).textTheme.subtitle2, - textAlign: TextAlign.center, - ), - ], - ); - }, - ), - ), - ) + Container( + constraints: BoxConstraints.loose(Size.fromHeight(400)), + child: _buildReactionCard(context), + ), ], ), ], ); } + + Padding _buildReactionCard(BuildContext context) { + final currentUser = StreamChat.of(context).user; + return Padding( + padding: const EdgeInsets.symmetric( + horizontal: 8.0, + ), + child: Card( + clipBehavior: Clip.hardEdge, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(16), + ), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Padding( + padding: const EdgeInsets.all(16.0), + child: Text( + 'Message Reactions', + style: Theme.of(context).textTheme.headline6, + ), + ), + 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, + ), + itemCount: message.latestReactions.length, + itemBuilder: (context, i) { + final reaction = message.latestReactions[i]; + + return _buildReaction( + reaction, + currentUser, + context, + ); + }, + ), + ), + ), + ], + ), + ), + ); + } + + Column _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, + ), + borderRadius: BorderRadius.circular(32), + ), + 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, + ), + ], + ), + Text( + reaction.user.name, + style: Theme.of(context).textTheme.subtitle2, + textAlign: TextAlign.center, + ), + ], + ); + } } diff --git a/lib/src/message_widget.dart b/lib/src/message_widget.dart index fccaa1e4..ef4eba2d 100644 --- a/lib/src/message_widget.dart +++ b/lib/src/message_widget.dart @@ -485,6 +485,7 @@ class _MessageWidgetState extends State { return StreamChannel( channel: channel, child: MessageReactionsModal( + onUserAvatarTap: widget.onUserAvatarTap, messageTheme: widget.messageTheme, messageShape: widget.shape ?? _getDefaultShape(context), reverse: widget.reverse, diff --git a/lib/src/reaction_picker.dart b/lib/src/reaction_picker.dart index 3b890230..ddeb6ad5 100644 --- a/lib/src/reaction_picker.dart +++ b/lib/src/reaction_picker.dart @@ -1,4 +1,7 @@ +import 'dart:math'; + import 'package:flutter/material.dart'; +import 'package:stream_chat_flutter/src/reaction_bubble.dart'; import '../stream_chat_flutter.dart'; @@ -23,44 +26,60 @@ class ReactionPicker extends StatelessWidget { @override Widget build(BuildContext context) { final reactionAssets = StreamChatTheme.of(context).reactionIcons; - return Material( - color: messageTheme.ownReactionsBackgroundColor, - clipBehavior: Clip.hardEdge, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(24), - ), - child: Row( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: MainAxisAlignment.center, - mainAxisSize: MainAxisSize.min, - children: reactionAssets.map((reactionIcon) { - final ownReactionIndex = message.ownReactions?.indexWhere( - (reaction) => reaction.type == reactionIcon.type) ?? - -1; - return IconButton( - iconSize: 24, - icon: Icon( - reactionIcon.iconData, - color: ownReactionIndex != -1 - ? StreamChatTheme.of(context).accentColor - : Theme.of(context).iconTheme.color, + return Stack( + fit: StackFit.passthrough, + children: [ + Material( + color: messageTheme.ownReactionsBackgroundColor, + clipBehavior: Clip.hardEdge, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(24), + ), + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.center, + mainAxisSize: MainAxisSize.min, + children: reactionAssets.map((reactionIcon) { + final ownReactionIndex = message.ownReactions?.indexWhere( + (reaction) => reaction.type == reactionIcon.type) ?? + -1; + return IconButton( + iconSize: 24, + icon: Icon( + reactionIcon.iconData, + color: ownReactionIndex != -1 + ? StreamChatTheme.of(context).accentColor + : Theme.of(context).iconTheme.color, + ), + onPressed: () { + if (ownReactionIndex != -1) { + removeReaction( + context, + message.ownReactions[ownReactionIndex], + ); + } else { + sendReaction( + context, + reactionIcon.type, + ); + } + }, + ); + }).toList(), + ), + ), + Positioned( + right: 14, + bottom: 0, + child: CustomPaint( + painter: ReactionBubblePainter( + messageTheme.ownReactionsBackgroundColor, + messageTheme.ownReactionsBorderColor, + 2, ), - onPressed: () { - if (ownReactionIndex != -1) { - removeReaction( - context, - message.ownReactions[ownReactionIndex], - ); - } else { - sendReaction( - context, - reactionIcon.type, - ); - } - }, - ); - }).toList(), - ), + ), + ), + ], ); } From 404aafbfce5329fede8f3858ec5790b978fb1720 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Fri, 16 Oct 2020 16:33:53 +0530 Subject: [PATCH 0100/1140] feat: wip message input --- lib/src/message_input.dart | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 10225e6b..130a9bf2 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -447,7 +447,9 @@ class MessageInputState extends State { leading: UserAvatar( user: m.user, ), - title: Text('${m.user.name}'), + title: Text('${m.user.name}', style: TextStyle(fontWeight: FontWeight.bold),), + subtitle: Text('${m.userId}'), + trailing: Icon(Icons.alternate_email, color: StreamChatTheme.of(context).primaryColor,), onTap: () { _mentionedUsers.add(m.user); @@ -894,10 +896,6 @@ class MessageInputState extends State { color: Colors.white, size: 16.0, ), - constraints: BoxConstraints( - maxWidth: 24.0, - maxHeight: 24.0, - ), ), ), ), From 6a7e0885ddc53e11340b88d4e5ed07f6d8afbda6 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Fri, 16 Oct 2020 16:39:06 +0530 Subject: [PATCH 0101/1140] feat: wip message input --- lib/src/message_input.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 130a9bf2..3fb4d592 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -449,7 +449,7 @@ class MessageInputState extends State { ), title: Text('${m.user.name}', style: TextStyle(fontWeight: FontWeight.bold),), subtitle: Text('${m.userId}'), - trailing: Icon(Icons.alternate_email, color: StreamChatTheme.of(context).primaryColor,), + trailing: Icon(Icons.alternate_email, color: StreamChatTheme.of(context).accentColor,), onTap: () { _mentionedUsers.add(m.user); From d571d7856abafb35ca28c2b9e3fb5111aee96156 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Fri, 16 Oct 2020 15:20:35 +0530 Subject: [PATCH 0102/1140] feat: wip message input --- lib/src/message_input.dart | 204 +++++++++++++++---------------------- 1 file changed, 80 insertions(+), 124 deletions(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 3fb4d592..c2d7506e 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -202,7 +202,7 @@ class MessageInputState extends State { Flex _buildTextField(BuildContext context) { return Flex( direction: Axis.horizontal, - crossAxisAlignment: CrossAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.end, children: [ if (!widget.disableAttachments) _buildAttachmentButton(), if (widget.actionsLocation == ActionsLocation.left) @@ -222,7 +222,7 @@ class MessageInputState extends State { ? CrossFadeState.showFirst : CrossFadeState.showSecond, firstChild: _buildSendButton(context), - secondChild: _buildIdleSendButton(context), + secondChild: SizedBox(), duration: Duration(milliseconds: 300), alignment: Alignment.center, ); @@ -230,64 +230,60 @@ class MessageInputState extends State { Expanded _buildTextInput(BuildContext context) { return Expanded( - child: Center( - child: LimitedBox( - maxHeight: widget.maxHeight, - child: TextField( - key: Key('messageInputText'), - enabled: _inputEnabled, - minLines: null, - maxLines: null, - onSubmitted: (_) { - sendMessage(); - }, - keyboardType: widget.keyboardType, - controller: textEditingController, - focusNode: _focusNode, - onChanged: (s) { - StreamChannel.of(context).channel.keyStroke(); + child: LimitedBox( + maxHeight: widget.maxHeight, + child: TextField( + key: Key('messageInputText'), + enabled: _inputEnabled, + minLines: null, + maxLines: null, + onSubmitted: (_) { + sendMessage(); + }, + keyboardType: widget.keyboardType, + controller: textEditingController, + focusNode: _focusNode, + onChanged: (s) { + StreamChannel.of(context).channel.keyStroke(); - setState(() { - _messageIsPresent = s.trim().isNotEmpty; - }); + setState(() { + _messageIsPresent = s.trim().isNotEmpty; + }); - _commandsOverlay?.remove(); - _commandsOverlay = null; - _mentionsOverlay?.remove(); - _mentionsOverlay = null; + _commandsOverlay?.remove(); + _commandsOverlay = null; + _mentionsOverlay?.remove(); + _mentionsOverlay = null; - if (s.startsWith('/')) { - _commandsOverlay = _buildCommandsOverlayEntry(); - Overlay.of(context).insert(_commandsOverlay); - } + if (s.startsWith('/')) { + _commandsOverlay = _buildCommandsOverlayEntry(); + Overlay.of(context).insert(_commandsOverlay); + } - if (textEditingController.selection.isCollapsed && - (s[textEditingController.selection.start - 1] == '@' || - textEditingController.text - .substring(0, textEditingController.selection.start) - .split(' ') - .last - .contains('@'))) { - _mentionsOverlay = _buildMentionsOverlayEntry(); - Overlay.of(context).insert(_mentionsOverlay); - } - }, - onTap: () { - setState(() { - _typingStarted = true; - }); - }, - style: Theme.of(context).textTheme.bodyText2, - autofocus: false, - decoration: InputDecoration( - hintText: 'Write a message', - prefixText: ' ', - border: OutlineInputBorder( - borderRadius: BorderRadius.circular(32), - ), - ), - textCapitalization: TextCapitalization.sentences, + if (textEditingController.selection.isCollapsed && + (s[textEditingController.selection.start - 1] == '@' || + textEditingController.text + .substring(0, textEditingController.selection.start) + .split(' ') + .last + .contains('@'))) { + _mentionsOverlay = _buildMentionsOverlayEntry(); + Overlay.of(context).insert(_mentionsOverlay); + } + }, + onTap: () { + setState(() { + _typingStarted = true; + }); + }, + style: Theme.of(context).textTheme.bodyText2, + autofocus: false, + decoration: InputDecoration( + hintText: 'Write a message', + prefixText: ' ', + border: OutlineInputBorder(), ), + textCapitalization: TextCapitalization.sentences, ), ), ); @@ -447,9 +443,7 @@ class MessageInputState extends State { leading: UserAvatar( user: m.user, ), - title: Text('${m.user.name}', style: TextStyle(fontWeight: FontWeight.bold),), - subtitle: Text('${m.userId}'), - trailing: Icon(Icons.alternate_email, color: StreamChatTheme.of(context).accentColor,), + title: Text('${m.user.name}'), onTap: () { _mentionedUsers.add(m.user); @@ -608,24 +602,22 @@ class MessageInputState extends State { } } - Widget _buildAttachmentButton() { - return Center( - child: Material( - clipBehavior: Clip.hardEdge, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(32), - ), - color: Colors.transparent, - child: IconButton( - onPressed: () { - showAttachmentModal(); - }, - icon: Transform.rotate( - child: Icon( - Icons.attach_file_sharp, - ), - angle: 0.4, + Material _buildAttachmentButton() { + return Material( + clipBehavior: Clip.hardEdge, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(32), + ), + color: Colors.transparent, + child: IconButton( + onPressed: () { + showAttachmentModal(); + }, + icon: Transform.rotate( + child: Icon( + Icons.attach_file_sharp, ), + angle: - 0.3, ), ), ); @@ -843,60 +835,24 @@ class MessageInputState extends State { return res.file; } - Widget _buildIdleSendButton(BuildContext context) { - return IconTheme( - data: - StreamChatTheme.of(context).channelTheme.messageInputButtonIconTheme, - child: Padding( - padding: const EdgeInsets.all(8.0), - child: Center( - child: Material( - clipBehavior: Clip.hardEdge, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(32), - ), - color: Colors.grey, - child: IconButton( - key: Key('sendButton'), - onPressed: () { - sendMessage(); - }, - icon: Icon( - Icons.arrow_forward, - color: Colors.white, - size: 16.0, - ), - ), - ), - ), - ), - ); - } - Widget _buildSendButton(BuildContext context) { return IconTheme( data: StreamChatTheme.of(context).channelTheme.messageInputButtonIconTheme, - child: Center( - child: Padding( - padding: const EdgeInsets.all(8.0), - child: Material( - clipBehavior: Clip.hardEdge, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(32), - ), + child: Material( + clipBehavior: Clip.hardEdge, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(32), + ), + color: Colors.transparent, + child: IconButton( + key: Key('sendButton'), + onPressed: () { + sendMessage(); + }, + icon: Icon( + Icons.send, color: StreamChatTheme.of(context).accentColor, - child: IconButton( - key: Key('sendButton'), - onPressed: () { - sendMessage(); - }, - icon: Icon( - Icons.arrow_upward, - color: Colors.white, - size: 16.0, - ), - ), ), ), ), From 9c532ce333af8f6fc52314fcd02cd9841e081465 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Fri, 16 Oct 2020 15:45:00 +0530 Subject: [PATCH 0103/1140] feat: wip message input --- lib/src/message_input.dart | 34 +++++++++++++++++++++++++++++----- 1 file changed, 29 insertions(+), 5 deletions(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index c2d7506e..8ad19388 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -222,7 +222,7 @@ class MessageInputState extends State { ? CrossFadeState.showFirst : CrossFadeState.showSecond, firstChild: _buildSendButton(context), - secondChild: SizedBox(), + secondChild: _buildIdleSendButton(context), duration: Duration(milliseconds: 300), alignment: Alignment.center, ); @@ -617,7 +617,7 @@ class MessageInputState extends State { child: Icon( Icons.attach_file_sharp, ), - angle: - 0.3, + angle: 0.4, ), ), ); @@ -835,6 +835,30 @@ class MessageInputState extends State { return res.file; } + Widget _buildIdleSendButton(BuildContext context) { + return IconTheme( + data: + StreamChatTheme.of(context).channelTheme.messageInputButtonIconTheme, + child: Material( + clipBehavior: Clip.hardEdge, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(32), + ), + color: Colors.grey, + child: IconButton( + key: Key('sendButton'), + onPressed: () { + sendMessage(); + }, + icon: Icon( + Icons.arrow_forward, + color: Colors.white, + ), + ), + ), + ); + } + Widget _buildSendButton(BuildContext context) { return IconTheme( data: @@ -844,15 +868,15 @@ class MessageInputState extends State { shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(32), ), - color: Colors.transparent, + color: StreamChatTheme.of(context).accentColor, child: IconButton( key: Key('sendButton'), onPressed: () { sendMessage(); }, icon: Icon( - Icons.send, - color: StreamChatTheme.of(context).accentColor, + Icons.arrow_upward, + color: Colors.white, ), ), ), From f137c5b917447415cecbc464d30828d88a349d70 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Fri, 16 Oct 2020 15:56:09 +0530 Subject: [PATCH 0104/1140] feat: wip message input --- lib/src/message_input.dart | 66 ++++++++++++++++++++++---------------- 1 file changed, 38 insertions(+), 28 deletions(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 8ad19388..6e0b8b90 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -839,20 +839,25 @@ class MessageInputState extends State { return IconTheme( data: StreamChatTheme.of(context).channelTheme.messageInputButtonIconTheme, - child: Material( - clipBehavior: Clip.hardEdge, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(32), - ), - color: Colors.grey, - child: IconButton( - key: Key('sendButton'), - onPressed: () { - sendMessage(); - }, - icon: Icon( - Icons.arrow_forward, - color: Colors.white, + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Center( + child: Material( + clipBehavior: Clip.hardEdge, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(24), + ), + color: Colors.grey, + child: IconButton( + key: Key('sendButton'), + onPressed: () { + sendMessage(); + }, + icon: Icon( + Icons.arrow_forward, + color: Colors.white, + ), + ), ), ), ), @@ -863,20 +868,25 @@ class MessageInputState extends State { return IconTheme( data: StreamChatTheme.of(context).channelTheme.messageInputButtonIconTheme, - child: Material( - clipBehavior: Clip.hardEdge, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(32), - ), - color: StreamChatTheme.of(context).accentColor, - child: IconButton( - key: Key('sendButton'), - onPressed: () { - sendMessage(); - }, - icon: Icon( - Icons.arrow_upward, - color: Colors.white, + child: Center( + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Material( + clipBehavior: Clip.hardEdge, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(24), + ), + color: StreamChatTheme.of(context).accentColor, + child: IconButton( + key: Key('sendButton'), + onPressed: () { + sendMessage(); + }, + icon: Icon( + Icons.arrow_upward, + color: Colors.white, + ), + ), ), ), ), From a7fd484443ced29569c3f9fb5738a4c5ccb76566 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Fri, 16 Oct 2020 16:01:40 +0530 Subject: [PATCH 0105/1140] feat: wip message input --- lib/src/message_input.dart | 138 +++++++++++++++++++------------------ 1 file changed, 72 insertions(+), 66 deletions(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 6e0b8b90..217ef438 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -230,60 +230,62 @@ class MessageInputState extends State { Expanded _buildTextInput(BuildContext context) { return Expanded( - child: LimitedBox( - maxHeight: widget.maxHeight, - child: TextField( - key: Key('messageInputText'), - enabled: _inputEnabled, - minLines: null, - maxLines: null, - onSubmitted: (_) { - sendMessage(); - }, - keyboardType: widget.keyboardType, - controller: textEditingController, - focusNode: _focusNode, - onChanged: (s) { - StreamChannel.of(context).channel.keyStroke(); + child: Center( + child: LimitedBox( + maxHeight: widget.maxHeight, + child: TextField( + key: Key('messageInputText'), + enabled: _inputEnabled, + minLines: null, + maxLines: null, + onSubmitted: (_) { + sendMessage(); + }, + keyboardType: widget.keyboardType, + controller: textEditingController, + focusNode: _focusNode, + onChanged: (s) { + StreamChannel.of(context).channel.keyStroke(); - setState(() { - _messageIsPresent = s.trim().isNotEmpty; - }); + setState(() { + _messageIsPresent = s.trim().isNotEmpty; + }); - _commandsOverlay?.remove(); - _commandsOverlay = null; - _mentionsOverlay?.remove(); - _mentionsOverlay = null; + _commandsOverlay?.remove(); + _commandsOverlay = null; + _mentionsOverlay?.remove(); + _mentionsOverlay = null; - if (s.startsWith('/')) { - _commandsOverlay = _buildCommandsOverlayEntry(); - Overlay.of(context).insert(_commandsOverlay); - } + if (s.startsWith('/')) { + _commandsOverlay = _buildCommandsOverlayEntry(); + Overlay.of(context).insert(_commandsOverlay); + } - if (textEditingController.selection.isCollapsed && - (s[textEditingController.selection.start - 1] == '@' || - textEditingController.text - .substring(0, textEditingController.selection.start) - .split(' ') - .last - .contains('@'))) { - _mentionsOverlay = _buildMentionsOverlayEntry(); - Overlay.of(context).insert(_mentionsOverlay); - } - }, - onTap: () { - setState(() { - _typingStarted = true; - }); - }, - style: Theme.of(context).textTheme.bodyText2, - autofocus: false, - decoration: InputDecoration( - hintText: 'Write a message', - prefixText: ' ', - border: OutlineInputBorder(), + if (textEditingController.selection.isCollapsed && + (s[textEditingController.selection.start - 1] == '@' || + textEditingController.text + .substring(0, textEditingController.selection.start) + .split(' ') + .last + .contains('@'))) { + _mentionsOverlay = _buildMentionsOverlayEntry(); + Overlay.of(context).insert(_mentionsOverlay); + } + }, + onTap: () { + setState(() { + _typingStarted = true; + }); + }, + style: Theme.of(context).textTheme.bodyText2, + autofocus: false, + decoration: InputDecoration( + hintText: 'Write a message', + prefixText: ' ', + border: OutlineInputBorder(), + ), + textCapitalization: TextCapitalization.sentences, ), - textCapitalization: TextCapitalization.sentences, ), ), ); @@ -602,22 +604,24 @@ class MessageInputState extends State { } } - Material _buildAttachmentButton() { - return Material( - clipBehavior: Clip.hardEdge, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(32), - ), - color: Colors.transparent, - child: IconButton( - onPressed: () { - showAttachmentModal(); - }, - icon: Transform.rotate( - child: Icon( - Icons.attach_file_sharp, + Widget _buildAttachmentButton() { + return Center( + child: Material( + clipBehavior: Clip.hardEdge, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(32), + ), + color: Colors.transparent, + child: IconButton( + onPressed: () { + showAttachmentModal(); + }, + icon: Transform.rotate( + child: Icon( + Icons.attach_file_sharp, + ), + angle: 0.4, ), - angle: 0.4, ), ), ); @@ -845,7 +849,7 @@ class MessageInputState extends State { child: Material( clipBehavior: Clip.hardEdge, shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(24), + borderRadius: BorderRadius.circular(32), ), color: Colors.grey, child: IconButton( @@ -856,6 +860,7 @@ class MessageInputState extends State { icon: Icon( Icons.arrow_forward, color: Colors.white, + size: 18.0, ), ), ), @@ -874,7 +879,7 @@ class MessageInputState extends State { child: Material( clipBehavior: Clip.hardEdge, shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(24), + borderRadius: BorderRadius.circular(32), ), color: StreamChatTheme.of(context).accentColor, child: IconButton( @@ -885,6 +890,7 @@ class MessageInputState extends State { icon: Icon( Icons.arrow_upward, color: Colors.white, + size: 18.0, ), ), ), From 20b92f6a17a4137d4a13ac4c3c03b74de37a1c24 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Fri, 16 Oct 2020 16:09:25 +0530 Subject: [PATCH 0106/1140] feat: wip message input --- lib/src/message_input.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 217ef438..af0413f8 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -202,7 +202,7 @@ class MessageInputState extends State { Flex _buildTextField(BuildContext context) { return Flex( direction: Axis.horizontal, - crossAxisAlignment: CrossAxisAlignment.end, + crossAxisAlignment: CrossAxisAlignment.center, children: [ if (!widget.disableAttachments) _buildAttachmentButton(), if (widget.actionsLocation == ActionsLocation.left) From 1c933ff385f25302cbf4865ebf4bc62ac6db268e Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Fri, 16 Oct 2020 16:20:18 +0530 Subject: [PATCH 0107/1140] feat: wip message input --- lib/src/message_input.dart | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index af0413f8..10225e6b 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -282,7 +282,9 @@ class MessageInputState extends State { decoration: InputDecoration( hintText: 'Write a message', prefixText: ' ', - border: OutlineInputBorder(), + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(32), + ), ), textCapitalization: TextCapitalization.sentences, ), @@ -860,7 +862,7 @@ class MessageInputState extends State { icon: Icon( Icons.arrow_forward, color: Colors.white, - size: 18.0, + size: 16.0, ), ), ), @@ -890,7 +892,11 @@ class MessageInputState extends State { icon: Icon( Icons.arrow_upward, color: Colors.white, - size: 18.0, + size: 16.0, + ), + constraints: BoxConstraints( + maxWidth: 24.0, + maxHeight: 24.0, ), ), ), From 7338956c7659cdaadb3abf2d636826fd5e7523fc Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Fri, 16 Oct 2020 16:33:53 +0530 Subject: [PATCH 0108/1140] feat: wip message input --- lib/src/message_input.dart | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 10225e6b..130a9bf2 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -447,7 +447,9 @@ class MessageInputState extends State { leading: UserAvatar( user: m.user, ), - title: Text('${m.user.name}'), + title: Text('${m.user.name}', style: TextStyle(fontWeight: FontWeight.bold),), + subtitle: Text('${m.userId}'), + trailing: Icon(Icons.alternate_email, color: StreamChatTheme.of(context).primaryColor,), onTap: () { _mentionedUsers.add(m.user); @@ -894,10 +896,6 @@ class MessageInputState extends State { color: Colors.white, size: 16.0, ), - constraints: BoxConstraints( - maxWidth: 24.0, - maxHeight: 24.0, - ), ), ), ), From e048d32817c66bd462e5683e726b46973ecb3d02 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Fri, 16 Oct 2020 16:39:06 +0530 Subject: [PATCH 0109/1140] feat: wip message input --- lib/src/message_input.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 130a9bf2..3fb4d592 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -449,7 +449,7 @@ class MessageInputState extends State { ), title: Text('${m.user.name}', style: TextStyle(fontWeight: FontWeight.bold),), subtitle: Text('${m.userId}'), - trailing: Icon(Icons.alternate_email, color: StreamChatTheme.of(context).primaryColor,), + trailing: Icon(Icons.alternate_email, color: StreamChatTheme.of(context).accentColor,), onTap: () { _mentionedUsers.add(m.user); From 71301d988f0a3f977ec6cb3181e3f2efa453e9af Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Fri, 16 Oct 2020 16:20:18 +0530 Subject: [PATCH 0110/1140] feat: wip message input --- lib/src/message_input.dart | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 3fb4d592..10225e6b 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -447,9 +447,7 @@ class MessageInputState extends State { leading: UserAvatar( user: m.user, ), - title: Text('${m.user.name}', style: TextStyle(fontWeight: FontWeight.bold),), - subtitle: Text('${m.userId}'), - trailing: Icon(Icons.alternate_email, color: StreamChatTheme.of(context).accentColor,), + title: Text('${m.user.name}'), onTap: () { _mentionedUsers.add(m.user); @@ -896,6 +894,10 @@ class MessageInputState extends State { color: Colors.white, size: 16.0, ), + constraints: BoxConstraints( + maxWidth: 24.0, + maxHeight: 24.0, + ), ), ), ), From 5f80489812ae422767b40e87d7eb1d70872b3e77 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Fri, 16 Oct 2020 16:33:53 +0530 Subject: [PATCH 0111/1140] feat: wip message input --- lib/src/message_input.dart | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 10225e6b..130a9bf2 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -447,7 +447,9 @@ class MessageInputState extends State { leading: UserAvatar( user: m.user, ), - title: Text('${m.user.name}'), + title: Text('${m.user.name}', style: TextStyle(fontWeight: FontWeight.bold),), + subtitle: Text('${m.userId}'), + trailing: Icon(Icons.alternate_email, color: StreamChatTheme.of(context).primaryColor,), onTap: () { _mentionedUsers.add(m.user); @@ -894,10 +896,6 @@ class MessageInputState extends State { color: Colors.white, size: 16.0, ), - constraints: BoxConstraints( - maxWidth: 24.0, - maxHeight: 24.0, - ), ), ), ), From a1c7d82674162a717836cb31942c6f192d41af14 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Fri, 16 Oct 2020 16:39:06 +0530 Subject: [PATCH 0112/1140] feat: wip message input --- lib/src/message_input.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 130a9bf2..3fb4d592 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -449,7 +449,7 @@ class MessageInputState extends State { ), title: Text('${m.user.name}', style: TextStyle(fontWeight: FontWeight.bold),), subtitle: Text('${m.userId}'), - trailing: Icon(Icons.alternate_email, color: StreamChatTheme.of(context).primaryColor,), + trailing: Icon(Icons.alternate_email, color: StreamChatTheme.of(context).accentColor,), onTap: () { _mentionedUsers.add(m.user); From 35a4069d83ac896fa7ed2eedd6169cdd193a06bc Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Fri, 16 Oct 2020 17:31:10 +0530 Subject: [PATCH 0113/1140] feat: wip message input --- lib/src/message_input.dart | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 3fb4d592..b093de7f 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -447,9 +447,15 @@ class MessageInputState extends State { leading: UserAvatar( user: m.user, ), - title: Text('${m.user.name}', style: TextStyle(fontWeight: FontWeight.bold),), + title: Text( + '${m.user.name}', + style: TextStyle(fontWeight: FontWeight.bold), + ), subtitle: Text('${m.userId}'), - trailing: Icon(Icons.alternate_email, color: StreamChatTheme.of(context).accentColor,), + trailing: Icon( + Icons.alternate_email, + color: StreamChatTheme.of(context).accentColor, + ), onTap: () { _mentionedUsers.add(m.user); @@ -846,7 +852,7 @@ class MessageInputState extends State { Widget _buildIdleSendButton(BuildContext context) { return IconTheme( data: - StreamChatTheme.of(context).channelTheme.messageInputButtonIconTheme, + StreamChatTheme.of(context).channelTheme.messageInputButtonIconTheme, child: Padding( padding: const EdgeInsets.all(8.0), child: Center( From 29643131e2a50a6130a59279314b8a53b0f6663b Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Fri, 16 Oct 2020 15:20:35 +0530 Subject: [PATCH 0114/1140] feat: wip message input --- lib/src/message_input.dart | 210 ++++++++++++++----------------------- 1 file changed, 80 insertions(+), 130 deletions(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index b093de7f..c2d7506e 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -202,7 +202,7 @@ class MessageInputState extends State { Flex _buildTextField(BuildContext context) { return Flex( direction: Axis.horizontal, - crossAxisAlignment: CrossAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.end, children: [ if (!widget.disableAttachments) _buildAttachmentButton(), if (widget.actionsLocation == ActionsLocation.left) @@ -222,7 +222,7 @@ class MessageInputState extends State { ? CrossFadeState.showFirst : CrossFadeState.showSecond, firstChild: _buildSendButton(context), - secondChild: _buildIdleSendButton(context), + secondChild: SizedBox(), duration: Duration(milliseconds: 300), alignment: Alignment.center, ); @@ -230,64 +230,60 @@ class MessageInputState extends State { Expanded _buildTextInput(BuildContext context) { return Expanded( - child: Center( - child: LimitedBox( - maxHeight: widget.maxHeight, - child: TextField( - key: Key('messageInputText'), - enabled: _inputEnabled, - minLines: null, - maxLines: null, - onSubmitted: (_) { - sendMessage(); - }, - keyboardType: widget.keyboardType, - controller: textEditingController, - focusNode: _focusNode, - onChanged: (s) { - StreamChannel.of(context).channel.keyStroke(); + child: LimitedBox( + maxHeight: widget.maxHeight, + child: TextField( + key: Key('messageInputText'), + enabled: _inputEnabled, + minLines: null, + maxLines: null, + onSubmitted: (_) { + sendMessage(); + }, + keyboardType: widget.keyboardType, + controller: textEditingController, + focusNode: _focusNode, + onChanged: (s) { + StreamChannel.of(context).channel.keyStroke(); - setState(() { - _messageIsPresent = s.trim().isNotEmpty; - }); + setState(() { + _messageIsPresent = s.trim().isNotEmpty; + }); - _commandsOverlay?.remove(); - _commandsOverlay = null; - _mentionsOverlay?.remove(); - _mentionsOverlay = null; + _commandsOverlay?.remove(); + _commandsOverlay = null; + _mentionsOverlay?.remove(); + _mentionsOverlay = null; - if (s.startsWith('/')) { - _commandsOverlay = _buildCommandsOverlayEntry(); - Overlay.of(context).insert(_commandsOverlay); - } + if (s.startsWith('/')) { + _commandsOverlay = _buildCommandsOverlayEntry(); + Overlay.of(context).insert(_commandsOverlay); + } - if (textEditingController.selection.isCollapsed && - (s[textEditingController.selection.start - 1] == '@' || - textEditingController.text - .substring(0, textEditingController.selection.start) - .split(' ') - .last - .contains('@'))) { - _mentionsOverlay = _buildMentionsOverlayEntry(); - Overlay.of(context).insert(_mentionsOverlay); - } - }, - onTap: () { - setState(() { - _typingStarted = true; - }); - }, - style: Theme.of(context).textTheme.bodyText2, - autofocus: false, - decoration: InputDecoration( - hintText: 'Write a message', - prefixText: ' ', - border: OutlineInputBorder( - borderRadius: BorderRadius.circular(32), - ), - ), - textCapitalization: TextCapitalization.sentences, + if (textEditingController.selection.isCollapsed && + (s[textEditingController.selection.start - 1] == '@' || + textEditingController.text + .substring(0, textEditingController.selection.start) + .split(' ') + .last + .contains('@'))) { + _mentionsOverlay = _buildMentionsOverlayEntry(); + Overlay.of(context).insert(_mentionsOverlay); + } + }, + onTap: () { + setState(() { + _typingStarted = true; + }); + }, + style: Theme.of(context).textTheme.bodyText2, + autofocus: false, + decoration: InputDecoration( + hintText: 'Write a message', + prefixText: ' ', + border: OutlineInputBorder(), ), + textCapitalization: TextCapitalization.sentences, ), ), ); @@ -447,15 +443,7 @@ class MessageInputState extends State { leading: UserAvatar( user: m.user, ), - title: Text( - '${m.user.name}', - style: TextStyle(fontWeight: FontWeight.bold), - ), - subtitle: Text('${m.userId}'), - trailing: Icon( - Icons.alternate_email, - color: StreamChatTheme.of(context).accentColor, - ), + title: Text('${m.user.name}'), onTap: () { _mentionedUsers.add(m.user); @@ -614,24 +602,22 @@ class MessageInputState extends State { } } - Widget _buildAttachmentButton() { - return Center( - child: Material( - clipBehavior: Clip.hardEdge, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(32), - ), - color: Colors.transparent, - child: IconButton( - onPressed: () { - showAttachmentModal(); - }, - icon: Transform.rotate( - child: Icon( - Icons.attach_file_sharp, - ), - angle: 0.4, + Material _buildAttachmentButton() { + return Material( + clipBehavior: Clip.hardEdge, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(32), + ), + color: Colors.transparent, + child: IconButton( + onPressed: () { + showAttachmentModal(); + }, + icon: Transform.rotate( + child: Icon( + Icons.attach_file_sharp, ), + angle: - 0.3, ), ), ); @@ -849,60 +835,24 @@ class MessageInputState extends State { return res.file; } - Widget _buildIdleSendButton(BuildContext context) { - return IconTheme( - data: - StreamChatTheme.of(context).channelTheme.messageInputButtonIconTheme, - child: Padding( - padding: const EdgeInsets.all(8.0), - child: Center( - child: Material( - clipBehavior: Clip.hardEdge, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(32), - ), - color: Colors.grey, - child: IconButton( - key: Key('sendButton'), - onPressed: () { - sendMessage(); - }, - icon: Icon( - Icons.arrow_forward, - color: Colors.white, - size: 16.0, - ), - ), - ), - ), - ), - ); - } - Widget _buildSendButton(BuildContext context) { return IconTheme( data: StreamChatTheme.of(context).channelTheme.messageInputButtonIconTheme, - child: Center( - child: Padding( - padding: const EdgeInsets.all(8.0), - child: Material( - clipBehavior: Clip.hardEdge, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(32), - ), + child: Material( + clipBehavior: Clip.hardEdge, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(32), + ), + color: Colors.transparent, + child: IconButton( + key: Key('sendButton'), + onPressed: () { + sendMessage(); + }, + icon: Icon( + Icons.send, color: StreamChatTheme.of(context).accentColor, - child: IconButton( - key: Key('sendButton'), - onPressed: () { - sendMessage(); - }, - icon: Icon( - Icons.arrow_upward, - color: Colors.white, - size: 16.0, - ), - ), ), ), ), From ede6af99476a045d1e5cd14ebda925635aded5c6 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Fri, 16 Oct 2020 15:45:00 +0530 Subject: [PATCH 0115/1140] feat: wip message input --- lib/src/message_input.dart | 34 +++++++++++++++++++++++++++++----- 1 file changed, 29 insertions(+), 5 deletions(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index c2d7506e..8ad19388 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -222,7 +222,7 @@ class MessageInputState extends State { ? CrossFadeState.showFirst : CrossFadeState.showSecond, firstChild: _buildSendButton(context), - secondChild: SizedBox(), + secondChild: _buildIdleSendButton(context), duration: Duration(milliseconds: 300), alignment: Alignment.center, ); @@ -617,7 +617,7 @@ class MessageInputState extends State { child: Icon( Icons.attach_file_sharp, ), - angle: - 0.3, + angle: 0.4, ), ), ); @@ -835,6 +835,30 @@ class MessageInputState extends State { return res.file; } + Widget _buildIdleSendButton(BuildContext context) { + return IconTheme( + data: + StreamChatTheme.of(context).channelTheme.messageInputButtonIconTheme, + child: Material( + clipBehavior: Clip.hardEdge, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(32), + ), + color: Colors.grey, + child: IconButton( + key: Key('sendButton'), + onPressed: () { + sendMessage(); + }, + icon: Icon( + Icons.arrow_forward, + color: Colors.white, + ), + ), + ), + ); + } + Widget _buildSendButton(BuildContext context) { return IconTheme( data: @@ -844,15 +868,15 @@ class MessageInputState extends State { shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(32), ), - color: Colors.transparent, + color: StreamChatTheme.of(context).accentColor, child: IconButton( key: Key('sendButton'), onPressed: () { sendMessage(); }, icon: Icon( - Icons.send, - color: StreamChatTheme.of(context).accentColor, + Icons.arrow_upward, + color: Colors.white, ), ), ), From 6df66bc5adde30d9d57c6011d06dd91c17c8d9f6 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Fri, 16 Oct 2020 15:56:09 +0530 Subject: [PATCH 0116/1140] feat: wip message input --- lib/src/message_input.dart | 66 ++++++++++++++++++++++---------------- 1 file changed, 38 insertions(+), 28 deletions(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 8ad19388..6e0b8b90 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -839,20 +839,25 @@ class MessageInputState extends State { return IconTheme( data: StreamChatTheme.of(context).channelTheme.messageInputButtonIconTheme, - child: Material( - clipBehavior: Clip.hardEdge, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(32), - ), - color: Colors.grey, - child: IconButton( - key: Key('sendButton'), - onPressed: () { - sendMessage(); - }, - icon: Icon( - Icons.arrow_forward, - color: Colors.white, + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Center( + child: Material( + clipBehavior: Clip.hardEdge, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(24), + ), + color: Colors.grey, + child: IconButton( + key: Key('sendButton'), + onPressed: () { + sendMessage(); + }, + icon: Icon( + Icons.arrow_forward, + color: Colors.white, + ), + ), ), ), ), @@ -863,20 +868,25 @@ class MessageInputState extends State { return IconTheme( data: StreamChatTheme.of(context).channelTheme.messageInputButtonIconTheme, - child: Material( - clipBehavior: Clip.hardEdge, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(32), - ), - color: StreamChatTheme.of(context).accentColor, - child: IconButton( - key: Key('sendButton'), - onPressed: () { - sendMessage(); - }, - icon: Icon( - Icons.arrow_upward, - color: Colors.white, + child: Center( + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Material( + clipBehavior: Clip.hardEdge, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(24), + ), + color: StreamChatTheme.of(context).accentColor, + child: IconButton( + key: Key('sendButton'), + onPressed: () { + sendMessage(); + }, + icon: Icon( + Icons.arrow_upward, + color: Colors.white, + ), + ), ), ), ), From 1c6a0210e84206d4222aca74009715d40f51ebb7 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Fri, 16 Oct 2020 16:01:40 +0530 Subject: [PATCH 0117/1140] feat: wip message input --- lib/src/message_input.dart | 138 +++++++++++++++++++------------------ 1 file changed, 72 insertions(+), 66 deletions(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 6e0b8b90..217ef438 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -230,60 +230,62 @@ class MessageInputState extends State { Expanded _buildTextInput(BuildContext context) { return Expanded( - child: LimitedBox( - maxHeight: widget.maxHeight, - child: TextField( - key: Key('messageInputText'), - enabled: _inputEnabled, - minLines: null, - maxLines: null, - onSubmitted: (_) { - sendMessage(); - }, - keyboardType: widget.keyboardType, - controller: textEditingController, - focusNode: _focusNode, - onChanged: (s) { - StreamChannel.of(context).channel.keyStroke(); + child: Center( + child: LimitedBox( + maxHeight: widget.maxHeight, + child: TextField( + key: Key('messageInputText'), + enabled: _inputEnabled, + minLines: null, + maxLines: null, + onSubmitted: (_) { + sendMessage(); + }, + keyboardType: widget.keyboardType, + controller: textEditingController, + focusNode: _focusNode, + onChanged: (s) { + StreamChannel.of(context).channel.keyStroke(); - setState(() { - _messageIsPresent = s.trim().isNotEmpty; - }); + setState(() { + _messageIsPresent = s.trim().isNotEmpty; + }); - _commandsOverlay?.remove(); - _commandsOverlay = null; - _mentionsOverlay?.remove(); - _mentionsOverlay = null; + _commandsOverlay?.remove(); + _commandsOverlay = null; + _mentionsOverlay?.remove(); + _mentionsOverlay = null; - if (s.startsWith('/')) { - _commandsOverlay = _buildCommandsOverlayEntry(); - Overlay.of(context).insert(_commandsOverlay); - } + if (s.startsWith('/')) { + _commandsOverlay = _buildCommandsOverlayEntry(); + Overlay.of(context).insert(_commandsOverlay); + } - if (textEditingController.selection.isCollapsed && - (s[textEditingController.selection.start - 1] == '@' || - textEditingController.text - .substring(0, textEditingController.selection.start) - .split(' ') - .last - .contains('@'))) { - _mentionsOverlay = _buildMentionsOverlayEntry(); - Overlay.of(context).insert(_mentionsOverlay); - } - }, - onTap: () { - setState(() { - _typingStarted = true; - }); - }, - style: Theme.of(context).textTheme.bodyText2, - autofocus: false, - decoration: InputDecoration( - hintText: 'Write a message', - prefixText: ' ', - border: OutlineInputBorder(), + if (textEditingController.selection.isCollapsed && + (s[textEditingController.selection.start - 1] == '@' || + textEditingController.text + .substring(0, textEditingController.selection.start) + .split(' ') + .last + .contains('@'))) { + _mentionsOverlay = _buildMentionsOverlayEntry(); + Overlay.of(context).insert(_mentionsOverlay); + } + }, + onTap: () { + setState(() { + _typingStarted = true; + }); + }, + style: Theme.of(context).textTheme.bodyText2, + autofocus: false, + decoration: InputDecoration( + hintText: 'Write a message', + prefixText: ' ', + border: OutlineInputBorder(), + ), + textCapitalization: TextCapitalization.sentences, ), - textCapitalization: TextCapitalization.sentences, ), ), ); @@ -602,22 +604,24 @@ class MessageInputState extends State { } } - Material _buildAttachmentButton() { - return Material( - clipBehavior: Clip.hardEdge, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(32), - ), - color: Colors.transparent, - child: IconButton( - onPressed: () { - showAttachmentModal(); - }, - icon: Transform.rotate( - child: Icon( - Icons.attach_file_sharp, + Widget _buildAttachmentButton() { + return Center( + child: Material( + clipBehavior: Clip.hardEdge, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(32), + ), + color: Colors.transparent, + child: IconButton( + onPressed: () { + showAttachmentModal(); + }, + icon: Transform.rotate( + child: Icon( + Icons.attach_file_sharp, + ), + angle: 0.4, ), - angle: 0.4, ), ), ); @@ -845,7 +849,7 @@ class MessageInputState extends State { child: Material( clipBehavior: Clip.hardEdge, shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(24), + borderRadius: BorderRadius.circular(32), ), color: Colors.grey, child: IconButton( @@ -856,6 +860,7 @@ class MessageInputState extends State { icon: Icon( Icons.arrow_forward, color: Colors.white, + size: 18.0, ), ), ), @@ -874,7 +879,7 @@ class MessageInputState extends State { child: Material( clipBehavior: Clip.hardEdge, shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(24), + borderRadius: BorderRadius.circular(32), ), color: StreamChatTheme.of(context).accentColor, child: IconButton( @@ -885,6 +890,7 @@ class MessageInputState extends State { icon: Icon( Icons.arrow_upward, color: Colors.white, + size: 18.0, ), ), ), From 2bbf33da789b97a6e5cd9d58e4ae8ca3a08b3b7b Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Fri, 16 Oct 2020 16:09:25 +0530 Subject: [PATCH 0118/1140] feat: wip message input --- lib/src/message_input.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 217ef438..af0413f8 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -202,7 +202,7 @@ class MessageInputState extends State { Flex _buildTextField(BuildContext context) { return Flex( direction: Axis.horizontal, - crossAxisAlignment: CrossAxisAlignment.end, + crossAxisAlignment: CrossAxisAlignment.center, children: [ if (!widget.disableAttachments) _buildAttachmentButton(), if (widget.actionsLocation == ActionsLocation.left) From 3c0de91d16843c3677a9c5aa463060a35648d554 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Fri, 16 Oct 2020 16:20:18 +0530 Subject: [PATCH 0119/1140] feat: wip message input --- lib/src/message_input.dart | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index af0413f8..10225e6b 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -282,7 +282,9 @@ class MessageInputState extends State { decoration: InputDecoration( hintText: 'Write a message', prefixText: ' ', - border: OutlineInputBorder(), + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(32), + ), ), textCapitalization: TextCapitalization.sentences, ), @@ -860,7 +862,7 @@ class MessageInputState extends State { icon: Icon( Icons.arrow_forward, color: Colors.white, - size: 18.0, + size: 16.0, ), ), ), @@ -890,7 +892,11 @@ class MessageInputState extends State { icon: Icon( Icons.arrow_upward, color: Colors.white, - size: 18.0, + size: 16.0, + ), + constraints: BoxConstraints( + maxWidth: 24.0, + maxHeight: 24.0, ), ), ), From d35a3f208c24de9bf1120e4dc8bf331d3401df9f Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Fri, 16 Oct 2020 16:33:53 +0530 Subject: [PATCH 0120/1140] feat: wip message input --- lib/src/message_input.dart | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 10225e6b..130a9bf2 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -447,7 +447,9 @@ class MessageInputState extends State { leading: UserAvatar( user: m.user, ), - title: Text('${m.user.name}'), + title: Text('${m.user.name}', style: TextStyle(fontWeight: FontWeight.bold),), + subtitle: Text('${m.userId}'), + trailing: Icon(Icons.alternate_email, color: StreamChatTheme.of(context).primaryColor,), onTap: () { _mentionedUsers.add(m.user); @@ -894,10 +896,6 @@ class MessageInputState extends State { color: Colors.white, size: 16.0, ), - constraints: BoxConstraints( - maxWidth: 24.0, - maxHeight: 24.0, - ), ), ), ), From ef7e224c9e189dbb1b90e6ca08966cbe45b132a8 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Fri, 16 Oct 2020 16:39:06 +0530 Subject: [PATCH 0121/1140] feat: wip message input --- lib/src/message_input.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 130a9bf2..3fb4d592 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -449,7 +449,7 @@ class MessageInputState extends State { ), title: Text('${m.user.name}', style: TextStyle(fontWeight: FontWeight.bold),), subtitle: Text('${m.userId}'), - trailing: Icon(Icons.alternate_email, color: StreamChatTheme.of(context).primaryColor,), + trailing: Icon(Icons.alternate_email, color: StreamChatTheme.of(context).accentColor,), onTap: () { _mentionedUsers.add(m.user); From 21f22f65d666de0b982dfb57c439644d2ae48e11 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Fri, 16 Oct 2020 15:20:35 +0530 Subject: [PATCH 0122/1140] feat: wip message input --- lib/src/message_input.dart | 204 +++++++++++++++---------------------- 1 file changed, 80 insertions(+), 124 deletions(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 3fb4d592..c2d7506e 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -202,7 +202,7 @@ class MessageInputState extends State { Flex _buildTextField(BuildContext context) { return Flex( direction: Axis.horizontal, - crossAxisAlignment: CrossAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.end, children: [ if (!widget.disableAttachments) _buildAttachmentButton(), if (widget.actionsLocation == ActionsLocation.left) @@ -222,7 +222,7 @@ class MessageInputState extends State { ? CrossFadeState.showFirst : CrossFadeState.showSecond, firstChild: _buildSendButton(context), - secondChild: _buildIdleSendButton(context), + secondChild: SizedBox(), duration: Duration(milliseconds: 300), alignment: Alignment.center, ); @@ -230,64 +230,60 @@ class MessageInputState extends State { Expanded _buildTextInput(BuildContext context) { return Expanded( - child: Center( - child: LimitedBox( - maxHeight: widget.maxHeight, - child: TextField( - key: Key('messageInputText'), - enabled: _inputEnabled, - minLines: null, - maxLines: null, - onSubmitted: (_) { - sendMessage(); - }, - keyboardType: widget.keyboardType, - controller: textEditingController, - focusNode: _focusNode, - onChanged: (s) { - StreamChannel.of(context).channel.keyStroke(); + child: LimitedBox( + maxHeight: widget.maxHeight, + child: TextField( + key: Key('messageInputText'), + enabled: _inputEnabled, + minLines: null, + maxLines: null, + onSubmitted: (_) { + sendMessage(); + }, + keyboardType: widget.keyboardType, + controller: textEditingController, + focusNode: _focusNode, + onChanged: (s) { + StreamChannel.of(context).channel.keyStroke(); - setState(() { - _messageIsPresent = s.trim().isNotEmpty; - }); + setState(() { + _messageIsPresent = s.trim().isNotEmpty; + }); - _commandsOverlay?.remove(); - _commandsOverlay = null; - _mentionsOverlay?.remove(); - _mentionsOverlay = null; + _commandsOverlay?.remove(); + _commandsOverlay = null; + _mentionsOverlay?.remove(); + _mentionsOverlay = null; - if (s.startsWith('/')) { - _commandsOverlay = _buildCommandsOverlayEntry(); - Overlay.of(context).insert(_commandsOverlay); - } + if (s.startsWith('/')) { + _commandsOverlay = _buildCommandsOverlayEntry(); + Overlay.of(context).insert(_commandsOverlay); + } - if (textEditingController.selection.isCollapsed && - (s[textEditingController.selection.start - 1] == '@' || - textEditingController.text - .substring(0, textEditingController.selection.start) - .split(' ') - .last - .contains('@'))) { - _mentionsOverlay = _buildMentionsOverlayEntry(); - Overlay.of(context).insert(_mentionsOverlay); - } - }, - onTap: () { - setState(() { - _typingStarted = true; - }); - }, - style: Theme.of(context).textTheme.bodyText2, - autofocus: false, - decoration: InputDecoration( - hintText: 'Write a message', - prefixText: ' ', - border: OutlineInputBorder( - borderRadius: BorderRadius.circular(32), - ), - ), - textCapitalization: TextCapitalization.sentences, + if (textEditingController.selection.isCollapsed && + (s[textEditingController.selection.start - 1] == '@' || + textEditingController.text + .substring(0, textEditingController.selection.start) + .split(' ') + .last + .contains('@'))) { + _mentionsOverlay = _buildMentionsOverlayEntry(); + Overlay.of(context).insert(_mentionsOverlay); + } + }, + onTap: () { + setState(() { + _typingStarted = true; + }); + }, + style: Theme.of(context).textTheme.bodyText2, + autofocus: false, + decoration: InputDecoration( + hintText: 'Write a message', + prefixText: ' ', + border: OutlineInputBorder(), ), + textCapitalization: TextCapitalization.sentences, ), ), ); @@ -447,9 +443,7 @@ class MessageInputState extends State { leading: UserAvatar( user: m.user, ), - title: Text('${m.user.name}', style: TextStyle(fontWeight: FontWeight.bold),), - subtitle: Text('${m.userId}'), - trailing: Icon(Icons.alternate_email, color: StreamChatTheme.of(context).accentColor,), + title: Text('${m.user.name}'), onTap: () { _mentionedUsers.add(m.user); @@ -608,24 +602,22 @@ class MessageInputState extends State { } } - Widget _buildAttachmentButton() { - return Center( - child: Material( - clipBehavior: Clip.hardEdge, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(32), - ), - color: Colors.transparent, - child: IconButton( - onPressed: () { - showAttachmentModal(); - }, - icon: Transform.rotate( - child: Icon( - Icons.attach_file_sharp, - ), - angle: 0.4, + Material _buildAttachmentButton() { + return Material( + clipBehavior: Clip.hardEdge, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(32), + ), + color: Colors.transparent, + child: IconButton( + onPressed: () { + showAttachmentModal(); + }, + icon: Transform.rotate( + child: Icon( + Icons.attach_file_sharp, ), + angle: - 0.3, ), ), ); @@ -843,60 +835,24 @@ class MessageInputState extends State { return res.file; } - Widget _buildIdleSendButton(BuildContext context) { - return IconTheme( - data: - StreamChatTheme.of(context).channelTheme.messageInputButtonIconTheme, - child: Padding( - padding: const EdgeInsets.all(8.0), - child: Center( - child: Material( - clipBehavior: Clip.hardEdge, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(32), - ), - color: Colors.grey, - child: IconButton( - key: Key('sendButton'), - onPressed: () { - sendMessage(); - }, - icon: Icon( - Icons.arrow_forward, - color: Colors.white, - size: 16.0, - ), - ), - ), - ), - ), - ); - } - Widget _buildSendButton(BuildContext context) { return IconTheme( data: StreamChatTheme.of(context).channelTheme.messageInputButtonIconTheme, - child: Center( - child: Padding( - padding: const EdgeInsets.all(8.0), - child: Material( - clipBehavior: Clip.hardEdge, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(32), - ), + child: Material( + clipBehavior: Clip.hardEdge, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(32), + ), + color: Colors.transparent, + child: IconButton( + key: Key('sendButton'), + onPressed: () { + sendMessage(); + }, + icon: Icon( + Icons.send, color: StreamChatTheme.of(context).accentColor, - child: IconButton( - key: Key('sendButton'), - onPressed: () { - sendMessage(); - }, - icon: Icon( - Icons.arrow_upward, - color: Colors.white, - size: 16.0, - ), - ), ), ), ), From 52b70002eb4e2903fde587dfb904b17fc052051a Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Fri, 16 Oct 2020 15:45:00 +0530 Subject: [PATCH 0123/1140] feat: wip message input --- lib/src/message_input.dart | 34 +++++++++++++++++++++++++++++----- 1 file changed, 29 insertions(+), 5 deletions(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index c2d7506e..8ad19388 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -222,7 +222,7 @@ class MessageInputState extends State { ? CrossFadeState.showFirst : CrossFadeState.showSecond, firstChild: _buildSendButton(context), - secondChild: SizedBox(), + secondChild: _buildIdleSendButton(context), duration: Duration(milliseconds: 300), alignment: Alignment.center, ); @@ -617,7 +617,7 @@ class MessageInputState extends State { child: Icon( Icons.attach_file_sharp, ), - angle: - 0.3, + angle: 0.4, ), ), ); @@ -835,6 +835,30 @@ class MessageInputState extends State { return res.file; } + Widget _buildIdleSendButton(BuildContext context) { + return IconTheme( + data: + StreamChatTheme.of(context).channelTheme.messageInputButtonIconTheme, + child: Material( + clipBehavior: Clip.hardEdge, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(32), + ), + color: Colors.grey, + child: IconButton( + key: Key('sendButton'), + onPressed: () { + sendMessage(); + }, + icon: Icon( + Icons.arrow_forward, + color: Colors.white, + ), + ), + ), + ); + } + Widget _buildSendButton(BuildContext context) { return IconTheme( data: @@ -844,15 +868,15 @@ class MessageInputState extends State { shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(32), ), - color: Colors.transparent, + color: StreamChatTheme.of(context).accentColor, child: IconButton( key: Key('sendButton'), onPressed: () { sendMessage(); }, icon: Icon( - Icons.send, - color: StreamChatTheme.of(context).accentColor, + Icons.arrow_upward, + color: Colors.white, ), ), ), From dc7c00399bb5b15b37683670d04e5215d2b8a1c2 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Fri, 16 Oct 2020 15:56:09 +0530 Subject: [PATCH 0124/1140] feat: wip message input --- lib/src/message_input.dart | 66 ++++++++++++++++++++++---------------- 1 file changed, 38 insertions(+), 28 deletions(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 8ad19388..6e0b8b90 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -839,20 +839,25 @@ class MessageInputState extends State { return IconTheme( data: StreamChatTheme.of(context).channelTheme.messageInputButtonIconTheme, - child: Material( - clipBehavior: Clip.hardEdge, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(32), - ), - color: Colors.grey, - child: IconButton( - key: Key('sendButton'), - onPressed: () { - sendMessage(); - }, - icon: Icon( - Icons.arrow_forward, - color: Colors.white, + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Center( + child: Material( + clipBehavior: Clip.hardEdge, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(24), + ), + color: Colors.grey, + child: IconButton( + key: Key('sendButton'), + onPressed: () { + sendMessage(); + }, + icon: Icon( + Icons.arrow_forward, + color: Colors.white, + ), + ), ), ), ), @@ -863,20 +868,25 @@ class MessageInputState extends State { return IconTheme( data: StreamChatTheme.of(context).channelTheme.messageInputButtonIconTheme, - child: Material( - clipBehavior: Clip.hardEdge, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(32), - ), - color: StreamChatTheme.of(context).accentColor, - child: IconButton( - key: Key('sendButton'), - onPressed: () { - sendMessage(); - }, - icon: Icon( - Icons.arrow_upward, - color: Colors.white, + child: Center( + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Material( + clipBehavior: Clip.hardEdge, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(24), + ), + color: StreamChatTheme.of(context).accentColor, + child: IconButton( + key: Key('sendButton'), + onPressed: () { + sendMessage(); + }, + icon: Icon( + Icons.arrow_upward, + color: Colors.white, + ), + ), ), ), ), From 96bb9efbbaa0dcc9d2be62e504e7737c8bfeba5a Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Fri, 16 Oct 2020 16:01:40 +0530 Subject: [PATCH 0125/1140] feat: wip message input --- lib/src/message_input.dart | 138 +++++++++++++++++++------------------ 1 file changed, 72 insertions(+), 66 deletions(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 6e0b8b90..217ef438 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -230,60 +230,62 @@ class MessageInputState extends State { Expanded _buildTextInput(BuildContext context) { return Expanded( - child: LimitedBox( - maxHeight: widget.maxHeight, - child: TextField( - key: Key('messageInputText'), - enabled: _inputEnabled, - minLines: null, - maxLines: null, - onSubmitted: (_) { - sendMessage(); - }, - keyboardType: widget.keyboardType, - controller: textEditingController, - focusNode: _focusNode, - onChanged: (s) { - StreamChannel.of(context).channel.keyStroke(); + child: Center( + child: LimitedBox( + maxHeight: widget.maxHeight, + child: TextField( + key: Key('messageInputText'), + enabled: _inputEnabled, + minLines: null, + maxLines: null, + onSubmitted: (_) { + sendMessage(); + }, + keyboardType: widget.keyboardType, + controller: textEditingController, + focusNode: _focusNode, + onChanged: (s) { + StreamChannel.of(context).channel.keyStroke(); - setState(() { - _messageIsPresent = s.trim().isNotEmpty; - }); + setState(() { + _messageIsPresent = s.trim().isNotEmpty; + }); - _commandsOverlay?.remove(); - _commandsOverlay = null; - _mentionsOverlay?.remove(); - _mentionsOverlay = null; + _commandsOverlay?.remove(); + _commandsOverlay = null; + _mentionsOverlay?.remove(); + _mentionsOverlay = null; - if (s.startsWith('/')) { - _commandsOverlay = _buildCommandsOverlayEntry(); - Overlay.of(context).insert(_commandsOverlay); - } + if (s.startsWith('/')) { + _commandsOverlay = _buildCommandsOverlayEntry(); + Overlay.of(context).insert(_commandsOverlay); + } - if (textEditingController.selection.isCollapsed && - (s[textEditingController.selection.start - 1] == '@' || - textEditingController.text - .substring(0, textEditingController.selection.start) - .split(' ') - .last - .contains('@'))) { - _mentionsOverlay = _buildMentionsOverlayEntry(); - Overlay.of(context).insert(_mentionsOverlay); - } - }, - onTap: () { - setState(() { - _typingStarted = true; - }); - }, - style: Theme.of(context).textTheme.bodyText2, - autofocus: false, - decoration: InputDecoration( - hintText: 'Write a message', - prefixText: ' ', - border: OutlineInputBorder(), + if (textEditingController.selection.isCollapsed && + (s[textEditingController.selection.start - 1] == '@' || + textEditingController.text + .substring(0, textEditingController.selection.start) + .split(' ') + .last + .contains('@'))) { + _mentionsOverlay = _buildMentionsOverlayEntry(); + Overlay.of(context).insert(_mentionsOverlay); + } + }, + onTap: () { + setState(() { + _typingStarted = true; + }); + }, + style: Theme.of(context).textTheme.bodyText2, + autofocus: false, + decoration: InputDecoration( + hintText: 'Write a message', + prefixText: ' ', + border: OutlineInputBorder(), + ), + textCapitalization: TextCapitalization.sentences, ), - textCapitalization: TextCapitalization.sentences, ), ), ); @@ -602,22 +604,24 @@ class MessageInputState extends State { } } - Material _buildAttachmentButton() { - return Material( - clipBehavior: Clip.hardEdge, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(32), - ), - color: Colors.transparent, - child: IconButton( - onPressed: () { - showAttachmentModal(); - }, - icon: Transform.rotate( - child: Icon( - Icons.attach_file_sharp, + Widget _buildAttachmentButton() { + return Center( + child: Material( + clipBehavior: Clip.hardEdge, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(32), + ), + color: Colors.transparent, + child: IconButton( + onPressed: () { + showAttachmentModal(); + }, + icon: Transform.rotate( + child: Icon( + Icons.attach_file_sharp, + ), + angle: 0.4, ), - angle: 0.4, ), ), ); @@ -845,7 +849,7 @@ class MessageInputState extends State { child: Material( clipBehavior: Clip.hardEdge, shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(24), + borderRadius: BorderRadius.circular(32), ), color: Colors.grey, child: IconButton( @@ -856,6 +860,7 @@ class MessageInputState extends State { icon: Icon( Icons.arrow_forward, color: Colors.white, + size: 18.0, ), ), ), @@ -874,7 +879,7 @@ class MessageInputState extends State { child: Material( clipBehavior: Clip.hardEdge, shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(24), + borderRadius: BorderRadius.circular(32), ), color: StreamChatTheme.of(context).accentColor, child: IconButton( @@ -885,6 +890,7 @@ class MessageInputState extends State { icon: Icon( Icons.arrow_upward, color: Colors.white, + size: 18.0, ), ), ), From 8f47d0ff370ab8e17a6bb67c94fec84a783ec660 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Fri, 16 Oct 2020 16:09:25 +0530 Subject: [PATCH 0126/1140] feat: wip message input --- lib/src/message_input.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 217ef438..af0413f8 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -202,7 +202,7 @@ class MessageInputState extends State { Flex _buildTextField(BuildContext context) { return Flex( direction: Axis.horizontal, - crossAxisAlignment: CrossAxisAlignment.end, + crossAxisAlignment: CrossAxisAlignment.center, children: [ if (!widget.disableAttachments) _buildAttachmentButton(), if (widget.actionsLocation == ActionsLocation.left) From d010fb27c85318c95cf8639cc6c20bc025196c59 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Fri, 16 Oct 2020 16:20:18 +0530 Subject: [PATCH 0127/1140] feat: wip message input --- lib/src/message_input.dart | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index af0413f8..10225e6b 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -282,7 +282,9 @@ class MessageInputState extends State { decoration: InputDecoration( hintText: 'Write a message', prefixText: ' ', - border: OutlineInputBorder(), + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(32), + ), ), textCapitalization: TextCapitalization.sentences, ), @@ -860,7 +862,7 @@ class MessageInputState extends State { icon: Icon( Icons.arrow_forward, color: Colors.white, - size: 18.0, + size: 16.0, ), ), ), @@ -890,7 +892,11 @@ class MessageInputState extends State { icon: Icon( Icons.arrow_upward, color: Colors.white, - size: 18.0, + size: 16.0, + ), + constraints: BoxConstraints( + maxWidth: 24.0, + maxHeight: 24.0, ), ), ), From 820cbf976edbd3f770a7b6d373bfb2c74ca19e66 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Fri, 16 Oct 2020 16:33:53 +0530 Subject: [PATCH 0128/1140] feat: wip message input --- lib/src/message_input.dart | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 10225e6b..130a9bf2 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -447,7 +447,9 @@ class MessageInputState extends State { leading: UserAvatar( user: m.user, ), - title: Text('${m.user.name}'), + title: Text('${m.user.name}', style: TextStyle(fontWeight: FontWeight.bold),), + subtitle: Text('${m.userId}'), + trailing: Icon(Icons.alternate_email, color: StreamChatTheme.of(context).primaryColor,), onTap: () { _mentionedUsers.add(m.user); @@ -894,10 +896,6 @@ class MessageInputState extends State { color: Colors.white, size: 16.0, ), - constraints: BoxConstraints( - maxWidth: 24.0, - maxHeight: 24.0, - ), ), ), ), From 1454cfd73a227285aa9ba01e0075ecefec72d78a Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Fri, 16 Oct 2020 16:39:06 +0530 Subject: [PATCH 0129/1140] feat: wip message input --- lib/src/message_input.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 130a9bf2..3fb4d592 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -449,7 +449,7 @@ class MessageInputState extends State { ), title: Text('${m.user.name}', style: TextStyle(fontWeight: FontWeight.bold),), subtitle: Text('${m.userId}'), - trailing: Icon(Icons.alternate_email, color: StreamChatTheme.of(context).primaryColor,), + trailing: Icon(Icons.alternate_email, color: StreamChatTheme.of(context).accentColor,), onTap: () { _mentionedUsers.add(m.user); From 4b62874dacbde2ab26cbbdab78f99fd55a091270 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Fri, 16 Oct 2020 16:20:18 +0530 Subject: [PATCH 0130/1140] feat: wip message input --- lib/src/message_input.dart | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 3fb4d592..10225e6b 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -447,9 +447,7 @@ class MessageInputState extends State { leading: UserAvatar( user: m.user, ), - title: Text('${m.user.name}', style: TextStyle(fontWeight: FontWeight.bold),), - subtitle: Text('${m.userId}'), - trailing: Icon(Icons.alternate_email, color: StreamChatTheme.of(context).accentColor,), + title: Text('${m.user.name}'), onTap: () { _mentionedUsers.add(m.user); @@ -896,6 +894,10 @@ class MessageInputState extends State { color: Colors.white, size: 16.0, ), + constraints: BoxConstraints( + maxWidth: 24.0, + maxHeight: 24.0, + ), ), ), ), From 6a5f2b4db3f08aa1cbe7deab47bdbee2e4abf107 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Fri, 16 Oct 2020 16:33:53 +0530 Subject: [PATCH 0131/1140] feat: wip message input --- lib/src/message_input.dart | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 10225e6b..130a9bf2 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -447,7 +447,9 @@ class MessageInputState extends State { leading: UserAvatar( user: m.user, ), - title: Text('${m.user.name}'), + title: Text('${m.user.name}', style: TextStyle(fontWeight: FontWeight.bold),), + subtitle: Text('${m.userId}'), + trailing: Icon(Icons.alternate_email, color: StreamChatTheme.of(context).primaryColor,), onTap: () { _mentionedUsers.add(m.user); @@ -894,10 +896,6 @@ class MessageInputState extends State { color: Colors.white, size: 16.0, ), - constraints: BoxConstraints( - maxWidth: 24.0, - maxHeight: 24.0, - ), ), ), ), From 545f7bd90f3721711b975aed5b1d7fc85e3ffbfb Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Fri, 16 Oct 2020 16:39:06 +0530 Subject: [PATCH 0132/1140] feat: wip message input --- lib/src/message_input.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 130a9bf2..3fb4d592 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -449,7 +449,7 @@ class MessageInputState extends State { ), title: Text('${m.user.name}', style: TextStyle(fontWeight: FontWeight.bold),), subtitle: Text('${m.userId}'), - trailing: Icon(Icons.alternate_email, color: StreamChatTheme.of(context).primaryColor,), + trailing: Icon(Icons.alternate_email, color: StreamChatTheme.of(context).accentColor,), onTap: () { _mentionedUsers.add(m.user); From 21e769ca739990a7479f4839206478d44f7d015b Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Fri, 16 Oct 2020 17:31:10 +0530 Subject: [PATCH 0133/1140] feat: wip message input --- lib/src/message_input.dart | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 3fb4d592..b093de7f 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -447,9 +447,15 @@ class MessageInputState extends State { leading: UserAvatar( user: m.user, ), - title: Text('${m.user.name}', style: TextStyle(fontWeight: FontWeight.bold),), + title: Text( + '${m.user.name}', + style: TextStyle(fontWeight: FontWeight.bold), + ), subtitle: Text('${m.userId}'), - trailing: Icon(Icons.alternate_email, color: StreamChatTheme.of(context).accentColor,), + trailing: Icon( + Icons.alternate_email, + color: StreamChatTheme.of(context).accentColor, + ), onTap: () { _mentionedUsers.add(m.user); @@ -846,7 +852,7 @@ class MessageInputState extends State { Widget _buildIdleSendButton(BuildContext context) { return IconTheme( data: - StreamChatTheme.of(context).channelTheme.messageInputButtonIconTheme, + StreamChatTheme.of(context).channelTheme.messageInputButtonIconTheme, child: Padding( padding: const EdgeInsets.all(8.0), child: Center( From 084e5eedbb6f456e3184a5516e4a111834b02bc8 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Fri, 16 Oct 2020 14:12:57 +0200 Subject: [PATCH 0134/1140] add reaction_bubble_test --- lib/src/reaction_bubble.dart | 10 ++-- lib/src/reaction_picker.dart | 6 +-- lib/src/stream_chat_theme.dart | 4 +- test/src/reaction_bubble_test.dart | 87 ++++++++++++++++++++++++++++++ 4 files changed, 96 insertions(+), 11 deletions(-) create mode 100644 test/src/reaction_bubble_test.dart diff --git a/lib/src/reaction_bubble.dart b/lib/src/reaction_bubble.dart index 7c36cdf3..0d37d87f 100644 --- a/lib/src/reaction_bubble.dart +++ b/lib/src/reaction_bubble.dart @@ -21,7 +21,7 @@ class ReactionBubble extends StatelessWidget { @override Widget build(BuildContext context) { - final reactionAssets = StreamChatTheme.of(context).reactionIcons; + final reactionIcons = StreamChatTheme.of(context).reactionIcons; return Transform( transform: Matrix4.rotationY(reverse ? pi : 0), alignment: Alignment.center, @@ -42,11 +42,11 @@ class ReactionBubble extends StatelessWidget { child: Wrap( children: [ ...reactions.map((reaction) { - final reactionAsset = reactionAssets.firstWhere( - (reactionAsset) => reactionAsset.type == reaction.type, + final reactionIcon = reactionIcons.firstWhere( + (r) => r.type == reaction.type, orElse: () => null, ); - if (reactionAsset == null) { + if (reactionIcon == null) { return Text( '?', style: TextStyle( @@ -56,7 +56,7 @@ class ReactionBubble extends StatelessWidget { } return Icon( - reactionAsset.iconData, + reactionIcon.iconData, size: 16, color: StreamChatTheme.of(context).accentColor, ); diff --git a/lib/src/reaction_picker.dart b/lib/src/reaction_picker.dart index ddeb6ad5..4f6cdf91 100644 --- a/lib/src/reaction_picker.dart +++ b/lib/src/reaction_picker.dart @@ -1,5 +1,3 @@ -import 'dart:math'; - import 'package:flutter/material.dart'; import 'package:stream_chat_flutter/src/reaction_bubble.dart'; @@ -25,7 +23,7 @@ class ReactionPicker extends StatelessWidget { @override Widget build(BuildContext context) { - final reactionAssets = StreamChatTheme.of(context).reactionIcons; + final reactionIcons = StreamChatTheme.of(context).reactionIcons; return Stack( fit: StackFit.passthrough, children: [ @@ -39,7 +37,7 @@ class ReactionPicker extends StatelessWidget { crossAxisAlignment: CrossAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.center, mainAxisSize: MainAxisSize.min, - children: reactionAssets.map((reactionIcon) { + children: reactionIcons.map((reactionIcon) { final ownReactionIndex = message.ownReactions?.indexWhere( (reaction) => reaction.type == reactionIcon.type) ?? -1; diff --git a/lib/src/stream_chat_theme.dart b/lib/src/stream_chat_theme.dart index 56f71a93..84271ec0 100644 --- a/lib/src/stream_chat_theme.dart +++ b/lib/src/stream_chat_theme.dart @@ -142,7 +142,7 @@ class StreamChatThemeData { Widget Function(BuildContext, Channel) defaultChannelImage, Widget Function(BuildContext, User) defaultUserImage, IconThemeData primaryIconTheme, - List reactionAssets, + List reactionIcons, }) => StreamChatThemeData( primaryColor: primaryColor ?? this.primaryColor, @@ -211,7 +211,7 @@ class StreamChatThemeData { this.otherMessageTheme.avatarTheme, ) ?? this.otherMessageTheme, - reactionIcons: reactionAssets ?? this.reactionIcons, + reactionIcons: reactionIcons ?? this.reactionIcons, ); /// Get the default Stream Chat theme diff --git a/test/src/reaction_bubble_test.dart b/test/src/reaction_bubble_test.dart new file mode 100644 index 00000000..dc0381de --- /dev/null +++ b/test/src/reaction_bubble_test.dart @@ -0,0 +1,87 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:stream_chat_flutter/src/reaction_bubble.dart'; +import 'package:stream_chat_flutter/stream_chat_flutter.dart'; + +void main() { + testWidgets( + 'it should show no reactions', + (WidgetTester tester) async { + await tester.pumpWidget( + MaterialApp( + home: StreamChatTheme( + data: StreamChatThemeData(), + child: Container( + child: ReactionBubble( + reactions: [], + borderColor: Colors.black, + backgroundColor: Colors.white, + ), + ), + ), + ), + ); + + expect(find.byIcon(StreamIcons.thumbs_up_reaction), findsNothing); + }, + ); + + testWidgets( + 'it should show a thumb up', + (WidgetTester tester) async { + final themeData = ThemeData(); + await tester.pumpWidget( + MaterialApp( + theme: themeData, + home: StreamChatTheme( + data: StreamChatThemeData.getDefaultTheme(themeData), + child: Container( + child: ReactionBubble( + reactions: [ + Reaction( + type: 'thumbs_up', + ), + ], + borderColor: Colors.black, + backgroundColor: Colors.white, + ), + ), + ), + ), + ); + + expect(find.byIcon(StreamIcons.thumbs_up_reaction), findsOneWidget); + }, + ); + testWidgets( + 'it should show two reactions', + (WidgetTester tester) async { + final themeData = ThemeData(); + await tester.pumpWidget( + MaterialApp( + theme: themeData, + home: StreamChatTheme( + data: StreamChatThemeData.getDefaultTheme(themeData), + child: Container( + child: ReactionBubble( + reactions: [ + Reaction( + type: 'thumbs_up', + ), + Reaction( + type: 'love', + ), + ], + borderColor: Colors.black, + backgroundColor: Colors.white, + ), + ), + ), + ), + ); + + expect(find.byIcon(StreamIcons.thumbs_up_reaction), findsOneWidget); + expect(find.byIcon(StreamIcons.love_reaction), findsOneWidget); + }, + ); +} From ad44e44911a0d7441616051f9eda8f8a17a99cba Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Fri, 16 Oct 2020 17:47:05 +0530 Subject: [PATCH 0135/1140] feat: wip message input --- lib/src/message_input.dart | 77 ++++++++++++++++++++++---------------- 1 file changed, 45 insertions(+), 32 deletions(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index b093de7f..5ba50a55 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -165,6 +165,7 @@ class MessageInputState extends State { bool _inputEnabled = true; bool _messageIsPresent = false; bool _typingStarted = false; + bool _giphyEnabled = false; OverlayEntry _commandsOverlay, _mentionsOverlay; /// The editing controller passed to the input TextField @@ -205,6 +206,7 @@ class MessageInputState extends State { crossAxisAlignment: CrossAxisAlignment.center, children: [ if (!widget.disableAttachments) _buildAttachmentButton(), + _buildGiphyButton(), if (widget.actionsLocation == ActionsLocation.left) ...widget.actions ?? [], _buildTextInput(context), @@ -614,6 +616,31 @@ class MessageInputState extends State { } } + Widget _buildGiphyButton() { + return Center( + child: Material( + clipBehavior: Clip.hardEdge, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(32), + ), + color: Colors.transparent, + child: IconButton( + onPressed: () { + setState(() { + _giphyEnabled = true; + }); + }, + icon: Transform.rotate( + child: Icon( + StreamIcons.lightning, + ), + angle: 0.4, + ), + ), + ), + ); + } + Widget _buildAttachmentButton() { return Center( child: Material( @@ -856,22 +883,15 @@ class MessageInputState extends State { child: Padding( padding: const EdgeInsets.all(8.0), child: Center( - child: Material( - clipBehavior: Clip.hardEdge, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(32), - ), - color: Colors.grey, - child: IconButton( - key: Key('sendButton'), - onPressed: () { - sendMessage(); - }, - icon: Icon( - Icons.arrow_forward, - color: Colors.white, - size: 16.0, - ), + child: IconButton( + key: Key('sendButtonIdle'), + onPressed: () { + sendMessage(); + }, + icon: Icon( + StreamIcons.send_message, + color: Colors.grey, + size: 16.0, ), ), ), @@ -886,22 +906,15 @@ class MessageInputState extends State { child: Center( child: Padding( padding: const EdgeInsets.all(8.0), - child: Material( - clipBehavior: Clip.hardEdge, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(32), - ), - color: StreamChatTheme.of(context).accentColor, - child: IconButton( - key: Key('sendButton'), - onPressed: () { - sendMessage(); - }, - icon: Icon( - Icons.arrow_upward, - color: Colors.white, - size: 16.0, - ), + child: IconButton( + key: Key('sendButton'), + onPressed: () { + sendMessage(); + }, + icon: Icon( + StreamIcons.send_message, + color: StreamChatTheme.of(context).accentColor, + size: 16.0, ), ), ), From aa867b34b5d2ee9e92fb6aae04979dc6806dfcfa Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Fri, 16 Oct 2020 17:52:56 +0530 Subject: [PATCH 0136/1140] feat: wip message input --- lib/src/message_input.dart | 50 ++++++++++---------------------------- 1 file changed, 13 insertions(+), 37 deletions(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 5ba50a55..38c4a449 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -618,24 +618,14 @@ class MessageInputState extends State { Widget _buildGiphyButton() { return Center( - child: Material( - clipBehavior: Clip.hardEdge, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(32), - ), - color: Colors.transparent, - child: IconButton( - onPressed: () { - setState(() { - _giphyEnabled = true; - }); - }, - icon: Transform.rotate( - child: Icon( - StreamIcons.lightning, - ), - angle: 0.4, - ), + child: IconButton( + onPressed: () { + setState(() { + _giphyEnabled = true; + }); + }, + icon: Icon( + StreamIcons.lightning, ), ), ); @@ -643,23 +633,11 @@ class MessageInputState extends State { Widget _buildAttachmentButton() { return Center( - child: Material( - clipBehavior: Clip.hardEdge, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(32), - ), - color: Colors.transparent, - child: IconButton( - onPressed: () { - showAttachmentModal(); - }, - icon: Transform.rotate( - child: Icon( - Icons.attach_file_sharp, - ), - angle: 0.4, - ), - ), + child: IconButton( + onPressed: () { + showAttachmentModal(); + }, + icon: Icon(StreamIcons.attach), ), ); } @@ -891,7 +869,6 @@ class MessageInputState extends State { icon: Icon( StreamIcons.send_message, color: Colors.grey, - size: 16.0, ), ), ), @@ -914,7 +891,6 @@ class MessageInputState extends State { icon: Icon( StreamIcons.send_message, color: StreamChatTheme.of(context).accentColor, - size: 16.0, ), ), ), From 9315cc4a3f92c1515776a6d74ba43655369d93b2 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Fri, 16 Oct 2020 17:59:03 +0530 Subject: [PATCH 0137/1140] feat: wip message input --- lib/src/message_input.dart | 64 +++++++++++++++++++++----------------- 1 file changed, 36 insertions(+), 28 deletions(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 38c4a449..32c81d03 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -855,20 +855,24 @@ class MessageInputState extends State { } Widget _buildIdleSendButton(BuildContext context) { - return IconTheme( - data: - StreamChatTheme.of(context).channelTheme.messageInputButtonIconTheme, - child: Padding( - padding: const EdgeInsets.all(8.0), - child: Center( - child: IconButton( - key: Key('sendButtonIdle'), - onPressed: () { - sendMessage(); - }, - icon: Icon( - StreamIcons.send_message, - color: Colors.grey, + return SizedBox( + height: 24.0, + width: 24.0, + child: IconTheme( + data: + StreamChatTheme.of(context).channelTheme.messageInputButtonIconTheme, + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Center( + child: IconButton( + key: Key('sendButtonIdle'), + onPressed: () { + sendMessage(); + }, + icon: Icon( + StreamIcons.send_message, + color: Colors.grey, + ), ), ), ), @@ -877,20 +881,24 @@ class MessageInputState extends State { } Widget _buildSendButton(BuildContext context) { - return IconTheme( - data: - StreamChatTheme.of(context).channelTheme.messageInputButtonIconTheme, - child: Center( - child: Padding( - padding: const EdgeInsets.all(8.0), - child: IconButton( - key: Key('sendButton'), - onPressed: () { - sendMessage(); - }, - icon: Icon( - StreamIcons.send_message, - color: StreamChatTheme.of(context).accentColor, + return SizedBox( + height: 24.0, + width: 24.0, + child: IconTheme( + data: + StreamChatTheme.of(context).channelTheme.messageInputButtonIconTheme, + child: Center( + child: Padding( + padding: const EdgeInsets.all(8.0), + child: IconButton( + key: Key('sendButton'), + onPressed: () { + sendMessage(); + }, + icon: Icon( + StreamIcons.send_message, + color: StreamChatTheme.of(context).accentColor, + ), ), ), ), From c9f5afcf39b3e33a845a54e1b48d6633685b62aa Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Fri, 16 Oct 2020 18:01:41 +0530 Subject: [PATCH 0138/1140] feat: wip message input --- lib/src/message_input.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 32c81d03..3c9e9123 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -857,7 +857,7 @@ class MessageInputState extends State { Widget _buildIdleSendButton(BuildContext context) { return SizedBox( height: 24.0, - width: 24.0, + width: 16.0, child: IconTheme( data: StreamChatTheme.of(context).channelTheme.messageInputButtonIconTheme, @@ -883,7 +883,7 @@ class MessageInputState extends State { Widget _buildSendButton(BuildContext context) { return SizedBox( height: 24.0, - width: 24.0, + width: 16.0, child: IconTheme( data: StreamChatTheme.of(context).channelTheme.messageInputButtonIconTheme, From 3ddc521f2bae08a369070147fa3a225aec3c66d6 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Fri, 16 Oct 2020 18:05:11 +0530 Subject: [PATCH 0139/1140] feat: wip message input --- lib/src/message_input.dart | 68 ++++++++++++++++++-------------------- 1 file changed, 32 insertions(+), 36 deletions(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 3c9e9123..9372767e 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -627,6 +627,7 @@ class MessageInputState extends State { icon: Icon( StreamIcons.lightning, ), + iconSize: 14.0, ), ); } @@ -638,6 +639,7 @@ class MessageInputState extends State { showAttachmentModal(); }, icon: Icon(StreamIcons.attach), + iconSize: 14.0, ), ); } @@ -855,24 +857,21 @@ class MessageInputState extends State { } Widget _buildIdleSendButton(BuildContext context) { - return SizedBox( - height: 24.0, - width: 16.0, - child: IconTheme( - data: - StreamChatTheme.of(context).channelTheme.messageInputButtonIconTheme, - child: Padding( - padding: const EdgeInsets.all(8.0), - child: Center( - child: IconButton( - key: Key('sendButtonIdle'), - onPressed: () { - sendMessage(); - }, - icon: Icon( - StreamIcons.send_message, - color: Colors.grey, - ), + return IconTheme( + data: + StreamChatTheme.of(context).channelTheme.messageInputButtonIconTheme, + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Center( + child: IconButton( + iconSize: 14.0, + key: Key('sendButtonIdle'), + onPressed: () { + sendMessage(); + }, + icon: Icon( + StreamIcons.send_message, + color: Colors.grey, ), ), ), @@ -881,24 +880,21 @@ class MessageInputState extends State { } Widget _buildSendButton(BuildContext context) { - return SizedBox( - height: 24.0, - width: 16.0, - child: IconTheme( - data: - StreamChatTheme.of(context).channelTheme.messageInputButtonIconTheme, - child: Center( - child: Padding( - padding: const EdgeInsets.all(8.0), - child: IconButton( - key: Key('sendButton'), - onPressed: () { - sendMessage(); - }, - icon: Icon( - StreamIcons.send_message, - color: StreamChatTheme.of(context).accentColor, - ), + return IconTheme( + data: + StreamChatTheme.of(context).channelTheme.messageInputButtonIconTheme, + child: Center( + child: Padding( + padding: const EdgeInsets.all(8.0), + child: IconButton( + iconSize: 14.0, + key: Key('sendButton'), + onPressed: () { + sendMessage(); + }, + icon: Icon( + StreamIcons.send_message, + color: StreamChatTheme.of(context).accentColor, ), ), ), From bd8a6f9ecca6c6eff0b940fe65f37dd6e2cc5301 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Fri, 16 Oct 2020 18:09:42 +0530 Subject: [PATCH 0140/1140] feat: wip message input --- lib/src/message_input.dart | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 9372767e..f61ef3be 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -618,28 +618,24 @@ class MessageInputState extends State { Widget _buildGiphyButton() { return Center( - child: IconButton( - onPressed: () { + child: InkWell( + child: Icon(StreamIcons.lightning), + onTap: () { setState(() { _giphyEnabled = true; }); }, - icon: Icon( - StreamIcons.lightning, - ), - iconSize: 14.0, ), ); } Widget _buildAttachmentButton() { return Center( - child: IconButton( - onPressed: () { + child: InkWell( + child: Icon(StreamIcons.attach), + onTap: () { showAttachmentModal(); }, - icon: Icon(StreamIcons.attach), - iconSize: 14.0, ), ); } From 28bb2d2b7fbf85e581f331024ed0aeca7879a036 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Fri, 16 Oct 2020 18:15:04 +0530 Subject: [PATCH 0141/1140] feat: wip message input --- lib/src/message_input.dart | 36 +++++++++++++++++++++--------------- 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index f61ef3be..fe2b8c7e 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -1,5 +1,6 @@ import 'dart:async'; import 'dart:io'; +import 'dart:math'; import 'package:file_picker/file_picker.dart'; import 'package:flutter/cupertino.dart'; @@ -619,7 +620,10 @@ class MessageInputState extends State { Widget _buildGiphyButton() { return Center( child: InkWell( - child: Icon(StreamIcons.lightning), + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Icon(StreamIcons.lightning), + ), onTap: () { setState(() { _giphyEnabled = true; @@ -632,7 +636,10 @@ class MessageInputState extends State { Widget _buildAttachmentButton() { return Center( child: InkWell( - child: Icon(StreamIcons.attach), + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Icon(StreamIcons.attach), + ), onTap: () { showAttachmentModal(); }, @@ -859,17 +866,15 @@ class MessageInputState extends State { child: Padding( padding: const EdgeInsets.all(8.0), child: Center( - child: IconButton( - iconSize: 14.0, - key: Key('sendButtonIdle'), - onPressed: () { + child: InkWell( + onTap: () { sendMessage(); }, - icon: Icon( + child: Icon( StreamIcons.send_message, color: Colors.grey, ), - ), + ) ), ), ); @@ -882,15 +887,16 @@ class MessageInputState extends State { child: Center( child: Padding( padding: const EdgeInsets.all(8.0), - child: IconButton( - iconSize: 14.0, - key: Key('sendButton'), - onPressed: () { + child: InkWell( + onTap: () { sendMessage(); }, - icon: Icon( - StreamIcons.send_message, - color: StreamChatTheme.of(context).accentColor, + child: Transform.rotate( + angle: - pi / 2, + child: Icon( + StreamIcons.send_message, + color: StreamChatTheme.of(context).accentColor, + ), ), ), ), From 4b2f0f13c70379dd6fc72a525c8e021201785e50 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Fri, 16 Oct 2020 18:23:20 +0530 Subject: [PATCH 0142/1140] feat: wip message input --- lib/src/message_input.dart | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index fe2b8c7e..ec099258 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -288,6 +288,7 @@ class MessageInputState extends State { border: OutlineInputBorder( borderRadius: BorderRadius.circular(32), ), + contentPadding: EdgeInsets.all(4) ), textCapitalization: TextCapitalization.sentences, ), From 747ae96168dda950a2a799f5fcbb155b34e47fc9 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Fri, 16 Oct 2020 14:56:52 +0200 Subject: [PATCH 0143/1140] add message_reaction_modal_test --- lib/src/message_actions_modal.dart | 1 - lib/src/message_reactions_modal.dart | 9 +-- lib/src/message_widget.dart | 5 +- lib/src/reaction_picker.dart | 6 +- lib/src/user_avatar.dart | 2 +- test/src/channel_preview_test.dart | 8 +-- test/src/message_reaction_modal_test.dart | 87 +++++++++++++++++++++++ test/src/mocks.dart | 10 +++ 8 files changed, 107 insertions(+), 21 deletions(-) create mode 100644 test/src/message_reaction_modal_test.dart create mode 100644 test/src/mocks.dart diff --git a/lib/src/message_actions_modal.dart b/lib/src/message_actions_modal.dart index 012a2c9f..e02386d9 100644 --- a/lib/src/message_actions_modal.dart +++ b/lib/src/message_actions_modal.dart @@ -69,7 +69,6 @@ class MessageActionsModal extends StatelessWidget { message.status == null)) Center( child: ReactionPicker( - channel: channel, message: message, messageTheme: messageTheme, ), diff --git a/lib/src/message_reactions_modal.dart b/lib/src/message_reactions_modal.dart index 90e1fb97..6a7f398d 100644 --- a/lib/src/message_reactions_modal.dart +++ b/lib/src/message_reactions_modal.dart @@ -4,7 +4,6 @@ import 'package:flutter/material.dart'; import 'package:stream_chat/stream_chat.dart'; import 'package:stream_chat_flutter/src/reaction_bubble.dart'; import 'package:stream_chat_flutter/src/reaction_picker.dart'; -import 'package:stream_chat_flutter/src/stream_channel.dart'; import 'package:stream_chat_flutter/src/stream_chat.dart'; import 'package:stream_chat_flutter/src/user_avatar.dart'; @@ -28,20 +27,19 @@ class MessageReactionsModal extends StatelessWidget { Key key, @required this.message, @required this.messageTheme, - this.showReactions, + this.showReactions = true, this.showDeleteMessage, this.showEditMessage, this.onThreadTap, this.showReply, this.editMessageInputBuilder, this.messageShape, - this.reverse, + this.reverse = false, this.onUserAvatarTap, }) : super(key: key); @override Widget build(BuildContext context) { - final channel = StreamChannel.of(context).channel; return Stack( children: [ Positioned.fill( @@ -70,7 +68,6 @@ class MessageReactionsModal extends StatelessWidget { message.status == null)) Center( child: ReactionPicker( - channel: channel, message: message, messageTheme: messageTheme, ), @@ -91,7 +88,7 @@ class MessageReactionsModal extends StatelessWidget { SizedBox( height: 16, ), - if (message.latestReactions.isNotEmpty) + if (message.latestReactions?.isNotEmpty == true) 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 ef4eba2d..8135bea7 100644 --- a/lib/src/message_widget.dart +++ b/lib/src/message_widget.dart @@ -519,8 +519,9 @@ class _MessageWidgetState extends State { List _parseAttachments(BuildContext context) { final images = widget.message.attachments - .where((element) => element.type == 'image') - .toList(); + ?.where((element) => element.type == 'image') + ?.toList() ?? + []; if (images.length > 1) { return [ diff --git a/lib/src/reaction_picker.dart b/lib/src/reaction_picker.dart index 4f6cdf91..5855b59f 100644 --- a/lib/src/reaction_picker.dart +++ b/lib/src/reaction_picker.dart @@ -13,13 +13,11 @@ class ReactionPicker extends StatelessWidget { const ReactionPicker({ Key key, @required this.message, - @required this.channel, @required this.messageTheme, }) : super(key: key); final Message message; final MessageTheme messageTheme; - final Channel channel; @override Widget build(BuildContext context) { @@ -83,13 +81,13 @@ class ReactionPicker extends StatelessWidget { /// Add a reaction to the message void sendReaction(BuildContext context, String reactionType) { - channel.sendReaction(message, reactionType); + StreamChannel.of(context).channel.sendReaction(message, reactionType); Navigator.of(context).pop(); } /// Remove a reaction from the message void removeReaction(BuildContext context, Reaction reaction) { - channel.deleteReaction(message, reaction); + StreamChannel.of(context).channel.deleteReaction(message, reaction); Navigator.of(context).pop(); } } diff --git a/lib/src/user_avatar.dart b/lib/src/user_avatar.dart index a3d5b6f5..a86206eb 100644 --- a/lib/src/user_avatar.dart +++ b/lib/src/user_avatar.dart @@ -70,7 +70,7 @@ class UserAvatar extends StatelessWidget { : StreamChatTheme.of(context).defaultUserImage(context, user), ), ), - if (showOnlineStatus && user.online) + if (showOnlineStatus && user.online == true) Positioned( top: 0, right: 0, diff --git a/test/src/channel_preview_test.dart b/test/src/channel_preview_test.dart index 122e2283..94c45ac2 100644 --- a/test/src/channel_preview_test.dart +++ b/test/src/channel_preview_test.dart @@ -3,13 +3,7 @@ import 'package:flutter_test/flutter_test.dart'; import 'package:mockito/mockito.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; -class MockClient extends Mock implements Client {} - -class MockClientState extends Mock implements ClientState {} - -class MockChannel extends Mock implements Channel {} - -class MockChannelState extends Mock implements ChannelClientState {} +import 'mocks.dart'; void main() { testWidgets( diff --git a/test/src/message_reaction_modal_test.dart b/test/src/message_reaction_modal_test.dart new file mode 100644 index 00000000..566d02a0 --- /dev/null +++ b/test/src/message_reaction_modal_test.dart @@ -0,0 +1,87 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mockito/mockito.dart'; +import 'package:stream_chat_flutter/src/message_reactions_modal.dart'; +import 'package:stream_chat_flutter/stream_chat_flutter.dart'; + +import 'mocks.dart'; + +void main() { + testWidgets( + 'it should show one thumbs from the picker', + (WidgetTester tester) async { + final themeData = ThemeData(); + final streamTheme = StreamChatThemeData.getDefaultTheme(themeData); + await tester.pumpWidget( + MaterialApp( + theme: themeData, + home: StreamChatTheme( + data: streamTheme, + child: Container( + child: MessageReactionsModal( + message: Message( + text: 'test', + user: User( + id: 'test-user', + ), + ), + messageTheme: streamTheme.ownMessageTheme, + ), + ), + ), + ), + ); + + expect(find.byIcon(StreamIcons.thumbs_up_reaction), findsOneWidget); + }, + ); + + testWidgets( + 'it should show two reactions', + (WidgetTester tester) async { + final client = MockClient(); + final clientState = MockClientState(); + + when(client.state).thenReturn(clientState); + when(clientState.user).thenReturn(OwnUser(id: 'user-id')); + + final themeData = ThemeData(); + final streamTheme = StreamChatThemeData.getDefaultTheme(themeData); + await tester.pumpWidget( + MaterialApp( + theme: themeData, + home: StreamChat( + streamChatThemeData: streamTheme, + client: client, + child: Container( + child: MessageReactionsModal( + message: Message( + text: 'test', + user: User( + id: 'test-user', + ), + latestReactions: [ + Reaction( + type: 'thumbs_up', + user: User(id: 'test'), + ), + Reaction( + type: 'love', + user: User(id: 'test'), + ), + ], + ), + messageTheme: streamTheme.ownMessageTheme, + ), + ), + ), + ), + ); + await tester.pump(); + + expect(find.byIcon(StreamIcons.thumbs_up_reaction), findsNWidgets(2)); + expect(find.byIcon(StreamIcons.love_reaction), findsNWidgets(2)); + expect(find.text('test'), findsNWidgets(2)); + }, + ); +} diff --git a/test/src/mocks.dart b/test/src/mocks.dart new file mode 100644 index 00000000..37fa5530 --- /dev/null +++ b/test/src/mocks.dart @@ -0,0 +1,10 @@ +import 'package:mockito/mockito.dart'; +import 'package:stream_chat/stream_chat.dart'; + +class MockClient extends Mock implements Client {} + +class MockClientState extends Mock implements ClientState {} + +class MockChannel extends Mock implements Channel {} + +class MockChannelState extends Mock implements ChannelClientState {} From 49f054ef0d19e92ba660541049d6d823e097eec9 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Fri, 16 Oct 2020 18:30:40 +0530 Subject: [PATCH 0144/1140] feat: wip message input --- lib/src/message_input.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index ec099258..882d9cdd 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -622,7 +622,7 @@ class MessageInputState extends State { return Center( child: InkWell( child: Padding( - padding: const EdgeInsets.all(8.0), + padding: const EdgeInsets.only(top: 8.0, bottom: 8.0, left: 5.0, right: 10.0), child: Icon(StreamIcons.lightning), ), onTap: () { @@ -638,7 +638,7 @@ class MessageInputState extends State { return Center( child: InkWell( child: Padding( - padding: const EdgeInsets.all(8.0), + padding: const EdgeInsets.only(top: 8.0, bottom: 8.0, left: 10.0, right: 5.0), child: Icon(StreamIcons.attach), ), onTap: () { From ef449a98e65eb05cfa9a001e6c0979c61e740feb Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Fri, 16 Oct 2020 18:36:36 +0530 Subject: [PATCH 0145/1140] feat: wip message input --- lib/src/message_input.dart | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 882d9cdd..8fd077e1 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -206,8 +206,13 @@ class MessageInputState extends State { direction: Axis.horizontal, crossAxisAlignment: CrossAxisAlignment.center, children: [ - if (!widget.disableAttachments) _buildAttachmentButton(), - _buildGiphyButton(), + Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + if (!widget.disableAttachments) _buildAttachmentButton(), + _buildGiphyButton(), + ], + ), if (widget.actionsLocation == ActionsLocation.left) ...widget.actions ?? [], _buildTextInput(context), @@ -622,7 +627,7 @@ class MessageInputState extends State { return Center( child: InkWell( child: Padding( - padding: const EdgeInsets.only(top: 8.0, bottom: 8.0, left: 5.0, right: 10.0), + padding: const EdgeInsets.all(8.0), child: Icon(StreamIcons.lightning), ), onTap: () { @@ -638,7 +643,7 @@ class MessageInputState extends State { return Center( child: InkWell( child: Padding( - padding: const EdgeInsets.only(top: 8.0, bottom: 8.0, left: 10.0, right: 5.0), + padding: const EdgeInsets.all(8.0), child: Icon(StreamIcons.attach), ), onTap: () { From b05d57267b96781847035f4adec5dd26e2928085 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Fri, 16 Oct 2020 15:09:11 +0200 Subject: [PATCH 0146/1140] add copy button --- fonts/stream-icons.ttf | Bin 52056 -> 52024 bytes lib/src/message_actions_modal.dart | 23 +++++++++- pubspec.yaml | 1 + test/src/message_action_modal_test.dart | 58 ++++++++++++++++++++++++ 4 files changed, 81 insertions(+), 1 deletion(-) create mode 100644 test/src/message_action_modal_test.dart diff --git a/fonts/stream-icons.ttf b/fonts/stream-icons.ttf index 2e4d854086f4e1e0258f7e509df0df139b8dc9da..80660da49b37da1994c6044eb58c4b76501db4ee 100644 GIT binary patch delta 1225 zcmZ`(ZA@EL7(VCTt{qZXdq=-05TxxbP(E+lTj=Vge65LMCsEf(WqKhVzcn+P>n0S&W@B2LG zJ?8Mg1k0C#sLHXq=GR(g0kkeQf3z=p^%b5=-VHQ468!7Uj_hXAs#psIWml* z3~?NH9vV1yFy);uen)&1fa^E<4@9Dw$L~1+SV917KN2L1qItwe5ZCv|Mn)IF$;XIK z0zf7PhW1xRj@Qke0pMl;nXJbmqr>1&a1Vf67IYwYFcLd()O7j=;&}g);h`fVXi&61 zQ=h%&h7ZSK6MQIm;U8Y%OWzobOMnSD$!|#~x{?}{gM%OrCc$NN)wXkMJso0SWSW0dy70K=078?g`s793oRalgyLt_ajmDxPqtPyxL4s7ssce!Uq@r}a ziGYa8F?BHMx>RB@>8Ujsv`NoMswmBX%QC2BnHiUz$FsPiQ5POX&oFug7uLurjX|q5 zXehZR%xx*+oQ?IXRVuX~-9xI8QW+$XP3@#oifJ?mT6QB{oPvaG63vjNkwR^nPMRHJ zoS*?&VR|EN@m$!t5`64L1vhaf}%lFfu zX74V?Zy;5KpBs2E=XvmVHOUMlli|CgbJ<{Y!-S8XA7U2YE0`z z9~3thPZqD0I7|9V^`#Z1SIXWk`@DR%e1mCaR?K2EXTE9?Sv;16wb0sa{gkz{huKT) z&$dq6bcM3w&58?^&dN=Dw|#n#XU|0k?KtK5@r6rVKG({vR25a7uG(@|IHS(^YIRHX z8`X&#u4b%etv082uy(5U*E+6VSs$vOcFA0?yEffE_p9#5o)*u9XQLsb;l0M3#)-x! zO-$1hZ?E^O7xR3;H|6`LIj6a?`NQU?EuofqzukYam1_OC%@W88v&-rlKYb?a7EIaf>es-yxiKh#Y4Xm% z6Pq7~WUw$7Fw{@>i7cA@CQpFz#$^5|F(f>nTZoxKNK#S=gg2W63Hydx%Vq9#vfpK%}rso1O>Z%+&HbH)#wXB@6)6uk{f>r{#sWpx99x{&oIIRnIX!bWb53*K Date: Fri, 16 Oct 2020 18:44:54 +0530 Subject: [PATCH 0147/1140] feat: wip message input --- lib/src/message_input.dart | 56 +++++++++++++++++++++++++------------- 1 file changed, 37 insertions(+), 19 deletions(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 8fd077e1..9cae092c 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -206,13 +206,14 @@ class MessageInputState extends State { direction: Axis.horizontal, crossAxisAlignment: CrossAxisAlignment.center, children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - if (!widget.disableAttachments) _buildAttachmentButton(), - _buildGiphyButton(), - ], - ), + if (_giphyEnabled) + Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + if (!widget.disableAttachments) _buildAttachmentButton(), + _buildGiphyButton(), + ], + ), if (widget.actionsLocation == ActionsLocation.left) ...widget.actions ?? [], _buildTextInput(context), @@ -293,7 +294,25 @@ class MessageInputState extends State { border: OutlineInputBorder( borderRadius: BorderRadius.circular(32), ), - contentPadding: EdgeInsets.all(4) + contentPadding: EdgeInsets.all(4), + prefix: Chip( + backgroundColor: StreamChatTheme.of(context).accentColor, + label: Row( + children: [ + Icon(StreamIcons.lightning, color: Colors.white,), + SizedBox(width: 2,), + Text('GIPHY', style: TextStyle(color: Colors.white),), + ], + ) + ), + suffixIcon: IconButton( + icon: Icon(Icons.cancel_outlined), + onPressed: () { + setState(() { + _giphyEnabled = false; + }); + }, + ) ), textCapitalization: TextCapitalization.sentences, ), @@ -872,16 +891,15 @@ class MessageInputState extends State { child: Padding( padding: const EdgeInsets.all(8.0), child: Center( - child: InkWell( - onTap: () { - sendMessage(); - }, - child: Icon( - StreamIcons.send_message, - color: Colors.grey, - ), - ) - ), + child: InkWell( + onTap: () { + sendMessage(); + }, + child: Icon( + StreamIcons.send_message, + color: Colors.grey, + ), + )), ), ); } @@ -898,7 +916,7 @@ class MessageInputState extends State { sendMessage(); }, child: Transform.rotate( - angle: - pi / 2, + angle: -pi / 2, child: Icon( StreamIcons.send_message, color: StreamChatTheme.of(context).accentColor, From 1465cc0ba738225a75f37514b2259ed1a9953487 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Fri, 16 Oct 2020 18:49:03 +0530 Subject: [PATCH 0148/1140] feat: wip message input --- lib/src/message_input.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 9cae092c..38312620 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -290,7 +290,7 @@ class MessageInputState extends State { autofocus: false, decoration: InputDecoration( hintText: 'Write a message', - prefixText: ' ', + prefixText: _giphyEnabled ? null : ' ', border: OutlineInputBorder( borderRadius: BorderRadius.circular(32), ), From b64a651d2d5a28b5f154b8d11e341bc14779fd75 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Fri, 16 Oct 2020 18:53:21 +0530 Subject: [PATCH 0149/1140] feat: wip message input --- lib/src/message_input.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 38312620..5925f317 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -295,7 +295,7 @@ class MessageInputState extends State { borderRadius: BorderRadius.circular(32), ), contentPadding: EdgeInsets.all(4), - prefix: Chip( + prefix: _giphyEnabled ? Chip( backgroundColor: StreamChatTheme.of(context).accentColor, label: Row( children: [ @@ -304,7 +304,7 @@ class MessageInputState extends State { Text('GIPHY', style: TextStyle(color: Colors.white),), ], ) - ), + ) : null, suffixIcon: IconButton( icon: Icon(Icons.cancel_outlined), onPressed: () { From 11eb295c895248545ae45ae0f567e68a7ac2bf0f Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Fri, 16 Oct 2020 18:58:21 +0530 Subject: [PATCH 0150/1140] feat: wip message input --- lib/src/message_input.dart | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 5925f317..f8cf4255 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -206,7 +206,7 @@ class MessageInputState extends State { direction: Axis.horizontal, crossAxisAlignment: CrossAxisAlignment.center, children: [ - if (_giphyEnabled) + if (!_giphyEnabled) Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ @@ -305,14 +305,14 @@ class MessageInputState extends State { ], ) ) : null, - suffixIcon: IconButton( + suffixIcon: _giphyEnabled ? IconButton( icon: Icon(Icons.cancel_outlined), onPressed: () { setState(() { _giphyEnabled = false; }); }, - ) + ) : null, ), textCapitalization: TextCapitalization.sentences, ), From b48b59bda112041acd51cc88dbf7ef257676c902 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Fri, 16 Oct 2020 15:37:15 +0200 Subject: [PATCH 0151/1140] add message_action_modal_test --- lib/src/message_actions_modal.dart | 14 +-- lib/src/message_reactions_modal.dart | 9 +- lib/src/message_widget.dart | 4 - lib/src/stream_chat_theme.dart | 2 +- lib/src/stream_icons.dart | 125 +++++++++++----------- test/src/message_action_modal_test.dart | 68 +++++++++--- test/src/message_reaction_modal_test.dart | 55 +++++----- 7 files changed, 150 insertions(+), 127 deletions(-) diff --git a/lib/src/message_actions_modal.dart b/lib/src/message_actions_modal.dart index ec8d38be..75df5737 100644 --- a/lib/src/message_actions_modal.dart +++ b/lib/src/message_actions_modal.dart @@ -30,20 +30,19 @@ class MessageActionsModal extends StatelessWidget { Key key, @required this.message, @required this.messageTheme, - this.showReactions, - this.showDeleteMessage, - this.showEditMessage, + this.showReactions = true, + this.showDeleteMessage = true, + this.showEditMessage = true, this.onThreadTap, this.showCopyMessage = true, - this.showReply, + this.showReply = true, this.editMessageInputBuilder, this.messageShape, - this.reverse, + this.reverse = false, }) : super(key: key); @override Widget build(BuildContext context) { - final channel = StreamChannel.of(context).channel; return Stack( children: [ Positioned.fill( @@ -78,6 +77,7 @@ class MessageActionsModal extends StatelessWidget { ), AbsorbPointer( child: MessageWidget( + key: Key('MessageWidget'), reverse: reverse, message: message, messageTheme: messageTheme, @@ -277,7 +277,7 @@ class MessageActionsModal extends StatelessWidget { style: Theme.of(context).textTheme.headline6, ), leading: Icon( - StreamIcons.Thread_Reply, + StreamIcons.sorting_up, color: StreamChatTheme.of(context).primaryIconTheme.color, ), onTap: () { diff --git a/lib/src/message_reactions_modal.dart b/lib/src/message_reactions_modal.dart index 6a7f398d..d3486f1b 100644 --- a/lib/src/message_reactions_modal.dart +++ b/lib/src/message_reactions_modal.dart @@ -15,11 +15,8 @@ class MessageReactionsModal extends StatelessWidget { final void Function(Message) onThreadTap; final Message message; final MessageTheme messageTheme; - final bool showReactions; - final bool showDeleteMessage; - final bool showEditMessage; - final bool showReply; final bool reverse; + final bool showReactions; final ShapeBorder messageShape; final void Function(User) onUserAvatarTap; @@ -28,10 +25,7 @@ class MessageReactionsModal extends StatelessWidget { @required this.message, @required this.messageTheme, this.showReactions = true, - this.showDeleteMessage, - this.showEditMessage, this.onThreadTap, - this.showReply, this.editMessageInputBuilder, this.messageShape, this.reverse = false, @@ -74,6 +68,7 @@ class MessageReactionsModal extends StatelessWidget { ), AbsorbPointer( child: MessageWidget( + key: Key('MessageWidget'), reverse: reverse, message: message, messageTheme: messageTheme, diff --git a/lib/src/message_widget.dart b/lib/src/message_widget.dart index 8135bea7..967fb72b 100644 --- a/lib/src/message_widget.dart +++ b/lib/src/message_widget.dart @@ -489,14 +489,10 @@ class _MessageWidgetState extends State { messageTheme: widget.messageTheme, messageShape: widget.shape ?? _getDefaultShape(context), reverse: widget.reverse, - showDeleteMessage: widget.showDeleteMessage, message: widget.message, editMessageInputBuilder: widget.editMessageInputBuilder, onThreadTap: widget.onThreadTap, - showEditMessage: widget.showEditMessage, showReactions: widget.showReactions, - showReply: - widget.showReplyIndicator && widget.onThreadTap != null, ), ); }); diff --git a/lib/src/stream_chat_theme.dart b/lib/src/stream_chat_theme.dart index 84271ec0..540cd7e1 100644 --- a/lib/src/stream_chat_theme.dart +++ b/lib/src/stream_chat_theme.dart @@ -365,7 +365,7 @@ class StreamChatThemeData { ), ReactionIcon( type: 'thumbs_down', - iconData: StreamIcons.thumbs_up_reaction_1, + iconData: StreamIcons.thumbs_down_reaction, ), ReactionIcon( type: 'lol', diff --git a/lib/src/stream_icons.dart b/lib/src/stream_icons.dart index 73d1e5c0..c8fc6493 100644 --- a/lib/src/stream_icons.dart +++ b/lib/src/stream_icons.dart @@ -461,32 +461,32 @@ class StreamIcons { fontFamily: _fontFamily, fontPackage: _fontPackage, ); - static const IconData grey600 = IconData( + static const IconData grid = IconData( 0xe95b, fontFamily: _fontFamily, fontPackage: _fontPackage, ); - static const IconData grid = IconData( + static const IconData group = IconData( 0xe95c, fontFamily: _fontFamily, fontPackage: _fontPackage, ); - static const IconData heart_outline_add = IconData( + static const IconData heart_1 = IconData( 0xe95d, fontFamily: _fontFamily, fontPackage: _fontPackage, ); - static const IconData heart_outline_delete = IconData( + static const IconData heart_outline_add = IconData( 0xe95e, fontFamily: _fontFamily, fontPackage: _fontPackage, ); - static const IconData heart_pill = IconData( + static const IconData heart_outline_delete = IconData( 0xe95f, fontFamily: _fontFamily, fontPackage: _fontPackage, ); - static const IconData heart_1 = IconData( + static const IconData heart_pill = IconData( 0xe960, fontFamily: _fontFamily, fontPackage: _fontPackage, @@ -521,127 +521,127 @@ class StreamIcons { fontFamily: _fontFamily, fontPackage: _fontPackage, ); - static const IconData hourglass_full_1 = IconData( + static const IconData hourglass_full = IconData( 0xe967, fontFamily: _fontFamily, fontPackage: _fontPackage, ); - static const IconData hourglass_full = IconData( + static const IconData hourglass = IconData( 0xe968, fontFamily: _fontFamily, fontPackage: _fontPackage, ); - static const IconData hourglass = IconData( + static const IconData insurance_outline = IconData( 0xe969, fontFamily: _fontFamily, fontPackage: _fontPackage, ); - static const IconData insurance_outline = IconData( + static const IconData insurance = IconData( 0xe96a, fontFamily: _fontFamily, fontPackage: _fontPackage, ); - static const IconData insurance = IconData( + static const IconData left_right = IconData( 0xe96b, fontFamily: _fontFamily, fontPackage: _fontPackage, ); - static const IconData left_right = IconData( + static const IconData left = IconData( 0xe96c, fontFamily: _fontFamily, fontPackage: _fontPackage, ); - static const IconData left = IconData( + static const IconData light = IconData( 0xe96d, fontFamily: _fontFamily, fontPackage: _fontPackage, ); - static const IconData light = IconData( + static const IconData lightning = IconData( 0xe96e, fontFamily: _fontFamily, fontPackage: _fontPackage, ); - static const IconData lightning = IconData( + static const IconData link = IconData( 0xe96f, fontFamily: _fontFamily, fontPackage: _fontPackage, ); - static const IconData link = IconData( + static const IconData location_map = IconData( 0xe970, fontFamily: _fontFamily, fontPackage: _fontPackage, ); - static const IconData location_map = IconData( + static const IconData location = IconData( 0xe971, fontFamily: _fontFamily, fontPackage: _fontPackage, ); - static const IconData location = IconData( + static const IconData LOL_reaction = IconData( 0xe972, fontFamily: _fontFamily, fontPackage: _fontPackage, ); - static const IconData LOL_reaction = IconData( + static const IconData love_reaction = IconData( 0xe973, fontFamily: _fontFamily, fontPackage: _fontPackage, ); - static const IconData love_reaction = IconData( + static const IconData love = IconData( 0xe974, fontFamily: _fontFamily, fontPackage: _fontPackage, ); - static const IconData love = IconData( + static const IconData lungs = IconData( 0xe975, fontFamily: _fontFamily, fontPackage: _fontPackage, ); - static const IconData lungs = IconData( + static const IconData mail_open = IconData( 0xe976, fontFamily: _fontFamily, fontPackage: _fontPackage, ); - static const IconData mail_open = IconData( + static const IconData mail = IconData( 0xe977, fontFamily: _fontFamily, fontPackage: _fontPackage, ); - static const IconData mail = IconData( + static const IconData male = IconData( 0xe978, fontFamily: _fontFamily, fontPackage: _fontPackage, ); - static const IconData male = IconData( + static const IconData medical_bed = IconData( 0xe979, fontFamily: _fontFamily, fontPackage: _fontPackage, ); - static const IconData medical_bed = IconData( + static const IconData medical_blank = IconData( 0xe97a, fontFamily: _fontFamily, fontPackage: _fontPackage, ); - static const IconData medical_blank = IconData( + static const IconData medical_card_add = IconData( 0xe97b, fontFamily: _fontFamily, fontPackage: _fontPackage, ); - static const IconData medical_card_add = IconData( + static const IconData medical_card = IconData( 0xe97c, fontFamily: _fontFamily, fontPackage: _fontPackage, ); - static const IconData medical_card = IconData( + static const IconData medical_cross = IconData( 0xe97d, fontFamily: _fontFamily, fontPackage: _fontPackage, ); - static const IconData medical_cross = IconData( + static const IconData medical_load = IconData( 0xe97e, fontFamily: _fontFamily, fontPackage: _fontPackage, ); - static const IconData medical_load = IconData( + static const IconData menu_point_1 = IconData( 0xe97f, fontFamily: _fontFamily, fontPackage: _fontPackage, @@ -651,22 +651,22 @@ class StreamIcons { fontFamily: _fontFamily, fontPackage: _fontPackage, ); - static const IconData menu_point_1 = IconData( + static const IconData menu_point = IconData( 0xe981, fontFamily: _fontFamily, fontPackage: _fontPackage, ); - static const IconData menu_point = IconData( + static const IconData menu = IconData( 0xe982, fontFamily: _fontFamily, fontPackage: _fontPackage, ); - static const IconData menu = IconData( + static const IconData message = IconData( 0xe983, fontFamily: _fontFamily, fontPackage: _fontPackage, ); - static const IconData message = IconData( + static const IconData mic_1 = IconData( 0xe984, fontFamily: _fontFamily, fontPackage: _fontPackage, @@ -886,12 +886,12 @@ class StreamIcons { fontFamily: _fontFamily, fontPackage: _fontPackage, ); - static const IconData save_check = IconData( + static const IconData save_1 = IconData( 0xe9b0, fontFamily: _fontFamily, fontPackage: _fontPackage, ); - static const IconData save_1 = IconData( + static const IconData save_check = IconData( 0xe9b1, fontFamily: _fontFamily, fontPackage: _fontPackage, @@ -1061,17 +1061,17 @@ class StreamIcons { fontFamily: _fontFamily, fontPackage: _fontPackage, ); - static const IconData Thread_Reply = IconData( + static const IconData thumbs_down_reaction = IconData( 0xe9d3, fontFamily: _fontFamily, fontPackage: _fontPackage, ); - static const IconData thumbs_up_reaction_1 = IconData( + static const IconData thumbs_up_reaction = IconData( 0xe9d4, fontFamily: _fontFamily, fontPackage: _fontPackage, ); - static const IconData thumbs_up_reaction = IconData( + static const IconData time_1 = IconData( 0xe9d5, fontFamily: _fontFamily, fontPackage: _fontPackage, @@ -1081,109 +1081,104 @@ class StreamIcons { fontFamily: _fontFamily, fontPackage: _fontPackage, ); - static const IconData time_1 = IconData( + static const IconData time = IconData( 0xe9d7, fontFamily: _fontFamily, fontPackage: _fontPackage, ); - static const IconData time = IconData( + static const IconData tooth = IconData( 0xe9d8, fontFamily: _fontFamily, fontPackage: _fontPackage, ); - static const IconData tooth = IconData( + static const IconData tube_full = IconData( 0xe9d9, fontFamily: _fontFamily, fontPackage: _fontPackage, ); - static const IconData tube_full = IconData( + static const IconData tv_check = IconData( 0xe9da, fontFamily: _fontFamily, fontPackage: _fontPackage, ); - static const IconData tv_check = IconData( + static const IconData tv_rating = IconData( 0xe9db, fontFamily: _fontFamily, fontPackage: _fontPackage, ); - static const IconData tv_rating = IconData( + static const IconData unfold_less_h = IconData( 0xe9dc, fontFamily: _fontFamily, fontPackage: _fontPackage, ); - static const IconData unfold_less_h = IconData( + static const IconData unfold_less = IconData( 0xe9dd, fontFamily: _fontFamily, fontPackage: _fontPackage, ); - static const IconData unfold_less = IconData( + static const IconData unfold_more_h = IconData( 0xe9de, fontFamily: _fontFamily, fontPackage: _fontPackage, ); - static const IconData unfold_more_h = IconData( + static const IconData unfold_more = IconData( 0xe9df, fontFamily: _fontFamily, fontPackage: _fontPackage, ); - static const IconData unfold_more = IconData( + static const IconData unread = IconData( 0xe9e0, fontFamily: _fontFamily, fontPackage: _fontPackage, ); - static const IconData unread = IconData( + static const IconData up_down = IconData( 0xe9e1, fontFamily: _fontFamily, fontPackage: _fontPackage, ); - static const IconData up_down = IconData( + static const IconData up = IconData( 0xe9e2, fontFamily: _fontFamily, fontPackage: _fontPackage, ); - static const IconData up = IconData( + static const IconData upload = IconData( 0xe9e3, fontFamily: _fontFamily, fontPackage: _fontPackage, ); - static const IconData upload = IconData( + static const IconData user_add = IconData( 0xe9e4, fontFamily: _fontFamily, fontPackage: _fontPackage, ); - static const IconData user_add = IconData( + static const IconData user_delete = IconData( 0xe9e5, fontFamily: _fontFamily, fontPackage: _fontPackage, ); - static const IconData user_delete = IconData( + static const IconData user_minus = IconData( 0xe9e6, fontFamily: _fontFamily, fontPackage: _fontPackage, ); - static const IconData user_minus = IconData( + static const IconData user = IconData( 0xe9e7, fontFamily: _fontFamily, fontPackage: _fontPackage, ); - static const IconData user = IconData( + static const IconData voice = IconData( 0xe9e8, fontFamily: _fontFamily, fontPackage: _fontPackage, ); - static const IconData voice = IconData( + static const IconData world = IconData( 0xe9e9, fontFamily: _fontFamily, fontPackage: _fontPackage, ); - static const IconData world = IconData( + static const IconData wut_reaction = IconData( 0xe9ea, fontFamily: _fontFamily, fontPackage: _fontPackage, ); - static const IconData wut_reaction = IconData( - 0xe9eb, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); } diff --git a/test/src/message_action_modal_test.dart b/test/src/message_action_modal_test.dart index e491e81e..1427edd6 100644 --- a/test/src/message_action_modal_test.dart +++ b/test/src/message_action_modal_test.dart @@ -1,14 +1,14 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:mockito/mockito.dart'; -import 'package:stream_chat_flutter/src/message_reactions_modal.dart'; +import 'package:stream_chat_flutter/src/message_actions_modal.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; import 'mocks.dart'; void main() { testWidgets( - 'it should show two reactions', + 'it should show the all actions', (WidgetTester tester) async { final client = MockClient(); final clientState = MockClientState(); @@ -25,22 +25,12 @@ void main() { streamChatThemeData: streamTheme, client: client, child: Container( - child: MessageReactionsModal( + child: MessageActionsModal( message: Message( text: 'test', user: User( id: 'user-id', ), - latestReactions: [ - Reaction( - type: 'thumbs_up', - user: User(id: 'test'), - ), - Reaction( - type: 'love', - user: User(id: 'test'), - ), - ], ), messageTheme: streamTheme.ownMessageTheme, ), @@ -50,9 +40,55 @@ void main() { ); await tester.pump(); - expect(find.byIcon(StreamIcons.thumbs_up_reaction), findsNWidgets(2)); - expect(find.byIcon(StreamIcons.love_reaction), findsNWidgets(2)); - expect(find.text('test'), findsNWidgets(2)); + expect(find.byKey(Key('MessageWidget')), findsOneWidget); + expect(find.byIcon(StreamIcons.sorting_up), findsOneWidget); + expect(find.byIcon(StreamIcons.edit), findsOneWidget); + expect(find.byIcon(StreamIcons.delete), findsOneWidget); + expect(find.byIcon(StreamIcons.copy), findsOneWidget); + }, + ); + testWidgets( + 'it should show some actions', + (WidgetTester tester) async { + final client = MockClient(); + final clientState = MockClientState(); + + when(client.state).thenReturn(clientState); + when(clientState.user).thenReturn(OwnUser(id: 'user-id')); + + final themeData = ThemeData(); + final streamTheme = StreamChatThemeData.getDefaultTheme(themeData); + await tester.pumpWidget( + MaterialApp( + theme: themeData, + home: StreamChat( + streamChatThemeData: streamTheme, + client: client, + child: Container( + child: MessageActionsModal( + showEditMessage: false, + showCopyMessage: false, + showDeleteMessage: false, + showReply: false, + message: Message( + text: 'test', + user: User( + id: 'user-id', + ), + ), + messageTheme: streamTheme.ownMessageTheme, + ), + ), + ), + ), + ); + await tester.pump(); + + expect(find.byKey(Key('MessageWidget')), findsOneWidget); + expect(find.byIcon(StreamIcons.sorting_up), findsNothing); + expect(find.byIcon(StreamIcons.edit), findsNothing); + expect(find.byIcon(StreamIcons.delete), findsNothing); + expect(find.byIcon(StreamIcons.copy), findsNothing); }, ); } diff --git a/test/src/message_reaction_modal_test.dart b/test/src/message_reaction_modal_test.dart index 566d02a0..e3972780 100644 --- a/test/src/message_reaction_modal_test.dart +++ b/test/src/message_reaction_modal_test.dart @@ -17,21 +17,21 @@ void main() { theme: themeData, home: StreamChatTheme( data: streamTheme, - child: Container( - child: MessageReactionsModal( - message: Message( - text: 'test', - user: User( - id: 'test-user', - ), + child: MessageReactionsModal( + message: Message( + id: 'test', + text: 'test message', + user: User( + id: 'test-user', ), - messageTheme: streamTheme.ownMessageTheme, ), + messageTheme: streamTheme.ownMessageTheme, ), ), ), ); + expect(find.byKey(Key('MessageWidget')), findsOneWidget); expect(find.byIcon(StreamIcons.thumbs_up_reaction), findsOneWidget); }, ); @@ -47,41 +47,42 @@ void main() { final themeData = ThemeData(); final streamTheme = StreamChatThemeData.getDefaultTheme(themeData); + final testUserId = 'test user'; + await tester.pumpWidget( MaterialApp( theme: themeData, home: StreamChat( streamChatThemeData: streamTheme, client: client, - child: Container( - child: MessageReactionsModal( - message: Message( - text: 'test', - user: User( - id: 'test-user', - ), - latestReactions: [ - Reaction( - type: 'thumbs_up', - user: User(id: 'test'), - ), - Reaction( - type: 'love', - user: User(id: 'test'), - ), - ], + child: MessageReactionsModal( + message: Message( + text: 'test message', + user: User( + id: 'test-user', ), - messageTheme: streamTheme.ownMessageTheme, + latestReactions: [ + Reaction( + type: 'thumbs_up', + user: User(id: testUserId), + ), + Reaction( + type: 'love', + user: User(id: testUserId), + ), + ], ), + messageTheme: streamTheme.ownMessageTheme, ), ), ), ); await tester.pump(); + expect(find.byKey(Key('MessageWidget')), findsOneWidget); expect(find.byIcon(StreamIcons.thumbs_up_reaction), findsNWidgets(2)); expect(find.byIcon(StreamIcons.love_reaction), findsNWidgets(2)); - expect(find.text('test'), findsNWidgets(2)); + expect(find.text(testUserId), findsNWidgets(2)); }, ); } From 8f73d3e40ba75a752e36cf7af22f07c6e657ec9b Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Fri, 16 Oct 2020 17:25:40 +0200 Subject: [PATCH 0152/1140] updatep podfile.lock --- example/ios/Podfile.lock | 26 +++++++++++++------------- example/pubspec.yaml | 2 +- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock index f289e1b7..d22f1e0d 100644 --- a/example/ios/Podfile.lock +++ b/example/ios/Podfile.lock @@ -38,10 +38,10 @@ PODS: - Firebase/Messaging (6.26.0): - Firebase/CoreOnly - FirebaseMessaging (~> 4.4.1) - - firebase_core (0.5.0): + - firebase_core (0.5.0-1): - Firebase/CoreOnly (~> 6.26.0) - Flutter - - firebase_messaging (7.0.2): + - firebase_messaging (7.0.3): - Firebase/CoreOnly (~> 6.26.0) - Firebase/Messaging (~> 6.26.0) - firebase_core @@ -87,7 +87,7 @@ PODS: - FMDB (2.7.5): - FMDB/standard (= 2.7.5) - FMDB/standard (2.7.5) - - GoogleDataTransport (7.4.0): + - GoogleDataTransport (7.5.1): - nanopb (~> 1.30906.0) - GoogleUtilities/AppDelegateSwizzler (6.7.2): - GoogleUtilities/Environment @@ -115,11 +115,11 @@ PODS: - nanopb/encode (1.30906.0) - path_provider (0.0.1): - Flutter - - PromisesObjC (1.2.10) + - PromisesObjC (1.2.11) - Protobuf (3.13.0) - - SDWebImage (5.9.2): - - SDWebImage/Core (= 5.9.2) - - SDWebImage/Core (5.9.2) + - SDWebImage (5.9.3): + - SDWebImage/Core (= 5.9.3) + - SDWebImage/Core (5.9.3) - shared_preferences (0.0.1): - Flutter - sqflite (0.0.1): @@ -233,8 +233,8 @@ SPEC CHECKSUMS: DKPhotoGallery: fdfad5125a9fdda9cc57df834d49df790dbb4179 file_picker: 3e6c3790de664ccf9b882732d9db5eaf6b8d4eb1 Firebase: 7cf5f9c67f03cb3b606d1d6535286e1080e57eb6 - firebase_core: 3134fe79d257d430f163b558caf52a10a87efe8a - firebase_messaging: 2844c37f9ce87c0904b38fe435223161b1a71528 + firebase_core: 00e54a4744164a6b5a250b96dd1ad5afaba7a342 + firebase_messaging: 666d9994651b1ecf8c582b52dd913f3fa58c17ef FirebaseAnalyticsInterop: 3f86269c38ae41f47afeb43ebf32a001f58fcdae FirebaseCore: f42e5e5f382cdcf6b617ed737bf6c871a6947b17 FirebaseCoreDiagnostics: 770ac5958e1372ce67959ae4b4f31d8e127c3ac1 @@ -247,14 +247,14 @@ SPEC CHECKSUMS: flutter_keyboard_visibility: 0339d06371254c3eb25eeb90ba8d17dca8f9c069 flutter_local_notifications: 0c0b1ae97e741e1521e4c1629a459d04b9aec743 FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a - GoogleDataTransport: b7f406340a291370045a270c599e53c6fa6ec20f + GoogleDataTransport: f56af7caa4ed338dc8e138a5d7c5973e66440833 GoogleUtilities: 7f2f5a07f888cdb145101d6042bc4422f57e70b3 image_picker: 9c3312491f862b28d21ecd8fdf0ee14e601b3f09 nanopb: 59317e09cf1f1a0af72f12af412d54edf52603fc path_provider: abfe2b5c733d04e238b0d8691db0cfd63a27a93c - PromisesObjC: b14b1c6b68e306650688599de8a45e49fae81151 + PromisesObjC: 8c196f5a328c2cba3e74624585467a557dcb482f Protobuf: 3dac39b34a08151c6d949560efe3f86134a3f748 - SDWebImage: 0b42b8719ab0c5257177d5894306e8a336b21cbb + SDWebImage: a31ee8e90a97303529e03fb0c333eae0eacb88e9 shared_preferences: af6bfa751691cdc24be3045c43ec037377ada40d sqflite: 4001a31ff81d210346b500c55b17f4d6c7589dd0 sqlite3: 8f7d2078ae27778699a622a94b853285793422a2 @@ -268,4 +268,4 @@ SPEC CHECKSUMS: PODFILE CHECKSUM: eb001256612a59f8f9e4d083ad8b9671e69dd184 -COCOAPODS: 1.8.4 +COCOAPODS: 1.10.0.rc.1 diff --git a/example/pubspec.yaml b/example/pubspec.yaml index c3ab3b46..a5a2f73f 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -1,7 +1,7 @@ name: example description: A new Flutter project. -version: 1.0.28+30 +version: 1.0.30+32 environment: sdk: ">=2.2.2 <3.0.0" From 95e7fd22bbc140729bcb2fa26c7c4973300dd04e Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Mon, 19 Oct 2020 12:02:01 +0530 Subject: [PATCH 0153/1140] fix: Corrected padding and giphy chip --- lib/src/message_input.dart | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index f8cf4255..c7548b37 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -298,6 +298,7 @@ class MessageInputState extends State { prefix: _giphyEnabled ? Chip( backgroundColor: StreamChatTheme.of(context).accentColor, label: Row( + mainAxisSize: MainAxisSize.min, children: [ Icon(StreamIcons.lightning, color: Colors.white,), SizedBox(width: 2,), @@ -646,7 +647,7 @@ class MessageInputState extends State { return Center( child: InkWell( child: Padding( - padding: const EdgeInsets.all(8.0), + padding: const EdgeInsets.only(left: 8.0, right: 4.0, top: 8.0, bottom: 8.0), child: Icon(StreamIcons.lightning), ), onTap: () { @@ -662,7 +663,7 @@ class MessageInputState extends State { return Center( child: InkWell( child: Padding( - padding: const EdgeInsets.all(8.0), + padding: const EdgeInsets.only(left: 4.0, right: 8.0, top: 8.0, bottom: 8.0), child: Icon(StreamIcons.attach), ), onTap: () { From 77978eee1249dbddd53762944fc39d5feb3a0eec Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Mon, 19 Oct 2020 12:07:07 +0530 Subject: [PATCH 0154/1140] fix: Corrected padding and giphy chip --- lib/src/message_input.dart | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index c7548b37..a2fda653 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -288,6 +288,7 @@ class MessageInputState extends State { }, style: Theme.of(context).textTheme.bodyText2, autofocus: false, + textAlignVertical: TextAlignVertical.center, decoration: InputDecoration( hintText: 'Write a message', prefixText: _giphyEnabled ? null : ' ', @@ -295,16 +296,18 @@ class MessageInputState extends State { borderRadius: BorderRadius.circular(32), ), contentPadding: EdgeInsets.all(4), - prefix: _giphyEnabled ? Chip( - backgroundColor: StreamChatTheme.of(context).accentColor, - label: Row( - mainAxisSize: MainAxisSize.min, - children: [ - Icon(StreamIcons.lightning, color: Colors.white,), - SizedBox(width: 2,), - Text('GIPHY', style: TextStyle(color: Colors.white),), - ], - ) + prefix: _giphyEnabled ? Center( + child: Chip( + backgroundColor: StreamChatTheme.of(context).accentColor, + label: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Icon(StreamIcons.lightning, color: Colors.white,), + SizedBox(width: 2,), + Text('GIPHY', style: TextStyle(color: Colors.white),), + ], + ) + ), ) : null, suffixIcon: _giphyEnabled ? IconButton( icon: Icon(Icons.cancel_outlined), @@ -647,7 +650,7 @@ class MessageInputState extends State { return Center( child: InkWell( child: Padding( - padding: const EdgeInsets.only(left: 8.0, right: 4.0, top: 8.0, bottom: 8.0), + padding: const EdgeInsets.only(left: 4.0, right: 8.0, top: 8.0, bottom: 8.0), child: Icon(StreamIcons.lightning), ), onTap: () { @@ -663,7 +666,7 @@ class MessageInputState extends State { return Center( child: InkWell( child: Padding( - padding: const EdgeInsets.only(left: 4.0, right: 8.0, top: 8.0, bottom: 8.0), + padding: const EdgeInsets.only(left: 8.0, right: 4.0, top: 8.0, bottom: 8.0), child: Icon(StreamIcons.attach), ), onTap: () { From bb346ea55e1cf82cec9c4d8a89696e073b3a353d Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Mon, 19 Oct 2020 12:15:47 +0530 Subject: [PATCH 0155/1140] fix: Corrected giphy chip --- lib/src/message_input.dart | 50 ++++++++++++++++++++------------------ 1 file changed, 27 insertions(+), 23 deletions(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index a2fda653..1dc21fc8 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -296,27 +296,29 @@ class MessageInputState extends State { borderRadius: BorderRadius.circular(32), ), contentPadding: EdgeInsets.all(4), - prefix: _giphyEnabled ? Center( - child: Chip( - backgroundColor: StreamChatTheme.of(context).accentColor, - label: Row( - mainAxisSize: MainAxisSize.min, - children: [ - Icon(StreamIcons.lightning, color: Colors.white,), - SizedBox(width: 2,), - Text('GIPHY', style: TextStyle(color: Colors.white),), - ], - ) - ), - ) : null, - suffixIcon: _giphyEnabled ? IconButton( - icon: Icon(Icons.cancel_outlined), - onPressed: () { - setState(() { - _giphyEnabled = false; - }); - }, - ) : null, + prefix: _giphyEnabled + ? Chip( + backgroundColor: StreamChatTheme.of(context).accentColor, + label: Text( + 'GIPHY', + style: TextStyle(color: Colors.white), + ), + avatar: Icon( + StreamIcons.lightning, + color: Colors.white, + ), + ) + : null, + suffixIcon: _giphyEnabled + ? IconButton( + icon: Icon(Icons.cancel_outlined), + onPressed: () { + setState(() { + _giphyEnabled = false; + }); + }, + ) + : null, ), textCapitalization: TextCapitalization.sentences, ), @@ -650,7 +652,8 @@ class MessageInputState extends State { return Center( child: InkWell( child: Padding( - padding: const EdgeInsets.only(left: 4.0, right: 8.0, top: 8.0, bottom: 8.0), + padding: const EdgeInsets.only( + left: 4.0, right: 8.0, top: 8.0, bottom: 8.0), child: Icon(StreamIcons.lightning), ), onTap: () { @@ -666,7 +669,8 @@ class MessageInputState extends State { return Center( child: InkWell( child: Padding( - padding: const EdgeInsets.only(left: 8.0, right: 4.0, top: 8.0, bottom: 8.0), + padding: const EdgeInsets.only( + left: 8.0, right: 4.0, top: 8.0, bottom: 8.0), child: Icon(StreamIcons.attach), ), onTap: () { From def852891530cccbb00997e615eff5743ddd247d Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Mon, 19 Oct 2020 12:40:20 +0530 Subject: [PATCH 0156/1140] fix: Corrected giphy chip --- lib/src/message_input.dart | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 1dc21fc8..95f03672 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -183,17 +183,11 @@ class MessageInputState extends State { }, child: Padding( padding: const EdgeInsets.all(8.0), - child: Stack( - clipBehavior: Clip.none, - children: [ - //_buildBorder(context), - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - _buildAttachments(), - _buildTextField(context), - ], - ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + _buildAttachments(), + _buildTextField(context), ], ), ), From 7e55c98cb21344bc0f9de8904965152077a61782 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Mon, 19 Oct 2020 12:47:16 +0530 Subject: [PATCH 0157/1140] fix: Corrected giphy chip --- lib/src/message_input.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 95f03672..5a35acc4 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -290,7 +290,7 @@ class MessageInputState extends State { borderRadius: BorderRadius.circular(32), ), contentPadding: EdgeInsets.all(4), - prefix: _giphyEnabled + prefixIcon: _giphyEnabled ? Chip( backgroundColor: StreamChatTheme.of(context).accentColor, label: Text( From 830076e2bd94cb636fe8add790967aada2c6eb40 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Mon, 19 Oct 2020 13:16:04 +0530 Subject: [PATCH 0158/1140] feat: Added giphy for giphyEnabled mode --- lib/src/message_input.dart | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 5a35acc4..bdaf02ba 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -291,17 +291,20 @@ class MessageInputState extends State { ), contentPadding: EdgeInsets.all(4), prefixIcon: _giphyEnabled - ? Chip( - backgroundColor: StreamChatTheme.of(context).accentColor, - label: Text( - 'GIPHY', - style: TextStyle(color: Colors.white), + ? Padding( + padding: const EdgeInsets.symmetric(horizontal: 2.0), + child: Chip( + backgroundColor: StreamChatTheme.of(context).accentColor, + label: Text( + 'GIPHY', + style: TextStyle(color: Colors.white), + ), + avatar: Icon( + StreamIcons.lightning, + color: Colors.white, + ), ), - avatar: Icon( - StreamIcons.lightning, - color: Colors.white, - ), - ) + ) : null, suffixIcon: _giphyEnabled ? IconButton( @@ -932,11 +935,15 @@ class MessageInputState extends State { /// Sends the current message void sendMessage() async { - final text = textEditingController.text.trim(); + var text = textEditingController.text.trim(); if (text.isEmpty && _attachments.isEmpty) { return; } + if(_giphyEnabled) { + text = '/giphy' + text; + } + final attachments = List<_SendingAttachment>.from(_attachments); textEditingController.clear(); From de03dfd21da35a0baa9872156768051f571ca9b5 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Mon, 19 Oct 2020 13:18:34 +0530 Subject: [PATCH 0159/1140] fix: Giphy corrections --- lib/src/message_input.dart | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index bdaf02ba..71879fa6 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -941,7 +941,7 @@ class MessageInputState extends State { } if(_giphyEnabled) { - text = '/giphy' + text; + text = '/giphy ' + text; } final attachments = List<_SendingAttachment>.from(_attachments); @@ -952,6 +952,7 @@ class MessageInputState extends State { setState(() { _messageIsPresent = false; _typingStarted = false; + _giphyEnabled = false; }); _commandsOverlay?.remove(); From 90c70fb23b33f39fa2585185049510883633fc33 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Mon, 19 Oct 2020 13:18:56 +0530 Subject: [PATCH 0160/1140] fix: Giphy corrections --- lib/src/message_input.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 71879fa6..d296b924 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -292,7 +292,7 @@ class MessageInputState extends State { contentPadding: EdgeInsets.all(4), prefixIcon: _giphyEnabled ? Padding( - padding: const EdgeInsets.symmetric(horizontal: 2.0), + padding: const EdgeInsets.symmetric(horizontal: 4.0), child: Chip( backgroundColor: StreamChatTheme.of(context).accentColor, label: Text( From b656c0b3a290c03e3fea5cfe2bbca02886e25457 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Mon, 19 Oct 2020 09:50:52 +0200 Subject: [PATCH 0161/1140] fix copy message logic --- lib/src/message_actions_modal.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/message_actions_modal.dart b/lib/src/message_actions_modal.dart index 75df5737..890761d7 100644 --- a/lib/src/message_actions_modal.dart +++ b/lib/src/message_actions_modal.dart @@ -113,7 +113,7 @@ class MessageActionsModal extends StatelessWidget { _buildReplyButton(context), if (showEditMessage) _buildEditMessage(context), if (showDeleteMessage) _buildDeleteButton(context), - if (showDeleteMessage) _buildCopyButton(context), + if (showCopyMessage) _buildCopyButton(context), ], ).toList(), ), From f209797a6a06af9612ad85323b179942000d1a43 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Mon, 19 Oct 2020 09:53:45 +0200 Subject: [PATCH 0162/1140] center member list in channel sheet --- lib/src/channel_bottom_sheet.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/channel_bottom_sheet.dart b/lib/src/channel_bottom_sheet.dart index 0de24270..187fc6a9 100644 --- a/lib/src/channel_bottom_sheet.dart +++ b/lib/src/channel_bottom_sheet.dart @@ -154,7 +154,7 @@ class ChannelBottomSheet extends StatelessWidget { height: 83, child: ListView( padding: EdgeInsets.only( - left: (MediaQuery.of(context).size.width / 2) - 80, + left: (MediaQuery.of(context).size.width / 2) - 48, ), scrollDirection: Axis.horizontal, children: snapshot.data.map((m) { From 3d68da4e78d4ff2182656f93b9a28578805ff965 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Mon, 19 Oct 2020 13:24:57 +0530 Subject: [PATCH 0163/1140] fix: Giphy corrections --- lib/src/message_input.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index d296b924..3ad57dfe 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -292,7 +292,7 @@ class MessageInputState extends State { contentPadding: EdgeInsets.all(4), prefixIcon: _giphyEnabled ? Padding( - padding: const EdgeInsets.symmetric(horizontal: 4.0), + padding: const EdgeInsets.symmetric(horizontal: 8.0), child: Chip( backgroundColor: StreamChatTheme.of(context).accentColor, label: Text( From 6998d4e9ccfe7f2bfdcc987a37e3c80810491c49 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Mon, 19 Oct 2020 13:45:43 +0530 Subject: [PATCH 0164/1140] fix: Disable giphy button when editing, change close icon --- lib/src/message_actions_modal.dart | 39 +++++++----------------------- lib/src/message_input.dart | 2 +- 2 files changed, 10 insertions(+), 31 deletions(-) diff --git a/lib/src/message_actions_modal.dart b/lib/src/message_actions_modal.dart index 31086885..569ae22e 100644 --- a/lib/src/message_actions_modal.dart +++ b/lib/src/message_actions_modal.dart @@ -193,37 +193,16 @@ class MessageActionsModal extends StatelessWidget { 'Edit message', style: Theme.of(context).textTheme.headline6, ), - Container( - height: 30, - padding: const EdgeInsets.all(2.0), - child: AspectRatio( - aspectRatio: 1, - child: RawMaterialButton( - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(4), - ), - elevation: 0, - highlightElevation: 0, - focusElevation: 0, - disabledElevation: 0, - hoverElevation: 0, - onPressed: () { - Navigator.of(context).pop(); - }, - fillColor: - Theme.of(context).brightness == Brightness.dark - ? Colors.white.withOpacity(.1) - : Colors.black.withOpacity(.1), - padding: EdgeInsets.all(4), - child: Icon( - Icons.close, - size: 15, - color: StreamChatTheme.of(context) - .primaryIconTheme - .color, - ), - ), + IconButton( + icon: Icon( + Icons.cancel_outlined, + size: 15, + color: + StreamChatTheme.of(context).primaryIconTheme.color, ), + onPressed: () { + Navigator.of(context).pop(); + }, ), ], ), diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 3ad57dfe..a17874ff 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -205,7 +205,7 @@ class MessageInputState extends State { mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ if (!widget.disableAttachments) _buildAttachmentButton(), - _buildGiphyButton(), + if (widget.editMessage != null) _buildGiphyButton(), ], ), if (widget.actionsLocation == ActionsLocation.left) From f33a4ba1f4ca175289ef6ea70169166febb29a9c Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Mon, 19 Oct 2020 13:48:05 +0530 Subject: [PATCH 0165/1140] fix: Disable giphy button when editing, change close icon --- lib/src/message_input.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index a17874ff..0bd22b9e 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -205,7 +205,7 @@ class MessageInputState extends State { mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ if (!widget.disableAttachments) _buildAttachmentButton(), - if (widget.editMessage != null) _buildGiphyButton(), + if (widget.editMessage == null) _buildGiphyButton(), ], ), if (widget.actionsLocation == ActionsLocation.left) From e3992358b113de2727f6aa4dc883c2775238e22b Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Mon, 19 Oct 2020 17:54:22 +0530 Subject: [PATCH 0166/1140] feat: Fixed commands (removed giphy hardcode) --- lib/src/message_input.dart | 35 +++++++++++++++++------------------ 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 0bd22b9e..b614fbb9 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -166,9 +166,11 @@ class MessageInputState extends State { bool _inputEnabled = true; bool _messageIsPresent = false; bool _typingStarted = false; - bool _giphyEnabled = false; + bool _commandEnabled = false; OverlayEntry _commandsOverlay, _mentionsOverlay; + Command chosenCommand; + /// The editing controller passed to the input TextField TextEditingController textEditingController; @@ -200,7 +202,7 @@ class MessageInputState extends State { direction: Axis.horizontal, crossAxisAlignment: CrossAxisAlignment.center, children: [ - if (!_giphyEnabled) + if (!_commandEnabled) Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ @@ -285,18 +287,18 @@ class MessageInputState extends State { textAlignVertical: TextAlignVertical.center, decoration: InputDecoration( hintText: 'Write a message', - prefixText: _giphyEnabled ? null : ' ', + prefixText: _commandEnabled ? null : ' ', border: OutlineInputBorder( borderRadius: BorderRadius.circular(32), ), - contentPadding: EdgeInsets.all(4), - prefixIcon: _giphyEnabled + contentPadding: EdgeInsets.all(8), + prefixIcon: _commandEnabled ? Padding( padding: const EdgeInsets.symmetric(horizontal: 8.0), child: Chip( backgroundColor: StreamChatTheme.of(context).accentColor, label: Text( - 'GIPHY', + chosenCommand?.name ?? "", style: TextStyle(color: Colors.white), ), avatar: Icon( @@ -306,12 +308,12 @@ class MessageInputState extends State { ), ) : null, - suffixIcon: _giphyEnabled + suffixIcon: _commandEnabled ? IconButton( icon: Icon(Icons.cancel_outlined), onPressed: () { setState(() { - _giphyEnabled = false; + _commandEnabled = false; }); }, ) @@ -517,12 +519,9 @@ class MessageInputState extends State { } void _setCommand(Command c) { - textEditingController.value = TextEditingValue( - text: '/${c.name} ', - selection: TextSelection.collapsed( - offset: c.name.length + 2, - ), - ); + setState(() { + chosenCommand = c; + }); _commandsOverlay?.remove(); _commandsOverlay = null; } @@ -655,7 +654,7 @@ class MessageInputState extends State { ), onTap: () { setState(() { - _giphyEnabled = true; + _commandEnabled = true; }); }, ), @@ -940,8 +939,8 @@ class MessageInputState extends State { return; } - if(_giphyEnabled) { - text = '/giphy ' + text; + if(_commandEnabled) { + text = '/${chosenCommand.args} ' + text; } final attachments = List<_SendingAttachment>.from(_attachments); @@ -952,7 +951,7 @@ class MessageInputState extends State { setState(() { _messageIsPresent = false; _typingStarted = false; - _giphyEnabled = false; + _commandEnabled = false; }); _commandsOverlay?.remove(); From 806f176ee37e347f36b1e985e7973872af3067a7 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Mon, 19 Oct 2020 18:00:00 +0530 Subject: [PATCH 0167/1140] feat: Fixed commands (removed giphy hardcode) --- lib/src/message_input.dart | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index b614fbb9..191da65f 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -521,6 +521,7 @@ class MessageInputState extends State { void _setCommand(Command c) { setState(() { chosenCommand = c; + _commandEnabled = true; }); _commandsOverlay?.remove(); _commandsOverlay = null; @@ -940,7 +941,7 @@ class MessageInputState extends State { } if(_commandEnabled) { - text = '/${chosenCommand.args} ' + text; + text = '/${chosenCommand.name} ' + text; } final attachments = List<_SendingAttachment>.from(_attachments); From 8a51fdf531b74d88a0c5f6e837d4bc2c266d2e0b Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Mon, 19 Oct 2020 18:06:45 +0530 Subject: [PATCH 0168/1140] feat: Fixed lightning button --- lib/src/message_input.dart | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 191da65f..2bb38217 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -207,7 +207,7 @@ class MessageInputState extends State { mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ if (!widget.disableAttachments) _buildAttachmentButton(), - if (widget.editMessage == null) _buildGiphyButton(), + if (widget.editMessage == null) _buildCommandButton(), ], ), if (widget.actionsLocation == ActionsLocation.left) @@ -519,6 +519,7 @@ class MessageInputState extends State { } void _setCommand(Command c) { + textEditingController.clear(); setState(() { chosenCommand = c; _commandEnabled = true; @@ -645,7 +646,7 @@ class MessageInputState extends State { } } - Widget _buildGiphyButton() { + Widget _buildCommandButton() { return Center( child: InkWell( child: Padding( @@ -654,9 +655,10 @@ class MessageInputState extends State { child: Icon(StreamIcons.lightning), ), onTap: () { - setState(() { - _commandEnabled = true; - }); + if(_commandsOverlay == null) { + _commandsOverlay = _buildCommandsOverlayEntry(); + Overlay.of(context).insert(_commandsOverlay); + } }, ), ); From 4dd6cc7f17e46637547a1c1294e2bb1c5494cafb Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Mon, 19 Oct 2020 18:20:27 +0530 Subject: [PATCH 0169/1140] feat: Fixed lightning button --- lib/src/message_input.dart | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 2bb38217..f2fdda3f 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -658,6 +658,9 @@ class MessageInputState extends State { if(_commandsOverlay == null) { _commandsOverlay = _buildCommandsOverlayEntry(); Overlay.of(context).insert(_commandsOverlay); + } else { + _commandsOverlay?.remove(); + _commandsOverlay = null; } }, ), From 9be191b856e9681bc657d61b74f4c851764ce943 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Tue, 20 Oct 2020 10:11:43 +0200 Subject: [PATCH 0170/1140] add scroll to bottom fab --- lib/src/message_list_view.dart | 282 +++++++++++------- ...reaction_asset.dart => reaction_icon.dart} | 0 lib/src/stream_chat_theme.dart | 3 +- 3 files changed, 176 insertions(+), 109 deletions(-) rename lib/src/{reaction_asset.dart => reaction_icon.dart} (100%) diff --git a/lib/src/message_list_view.dart b/lib/src/message_list_view.dart index 85fba5a8..7c529f95 100644 --- a/lib/src/message_list_view.dart +++ b/lib/src/message_list_view.dart @@ -97,6 +97,7 @@ class MessageListView extends StatefulWidget { /// Instantiate a new MessageListView MessageListView({ Key key, + this.showScrollToBottom = true, this.messageBuilder, this.parentMessageBuilder, this.parentMessage, @@ -120,6 +121,9 @@ class MessageListView extends StatefulWidget { /// By default it calls [Navigator.push] using the widget built using [threadBuilder] final ThreadTapCallback onThreadTap; + /// If true will show a scroll to bottom message when there are new messages and the scroll offset is not zero + final bool showScrollToBottom; + /// Parent message in case of a thread final Message parentMessage; @@ -144,132 +148,193 @@ class _MessageListViewState extends State { List _messages = []; List _newMessageList = []; Function _onThreadTap; + bool _showScrollToBottom = false; @override Widget build(BuildContext context) { final streamChannel = StreamChannel.of(context); /// TODO: find a better solution when (https://github.com/flutter/flutter/issues/21023) is fixed - return NotificationListener( - onNotification: (_) { - if (_scrollController.offset < 150 && _newMessageList.isNotEmpty) { - setState(() { - _messages.insertAll(0, _newMessageList); - _newMessageList.clear(); - }); - } - return true; - }, - child: ListView.custom( - key: Key('messageListView'), - physics: widget.scrollPhysics, - keyboardDismissBehavior: widget.keyboardDismissBehavior, - controller: _scrollController, - reverse: true, - childrenDelegate: SliverChildBuilderDelegate( - (context, i) { - if (i == _messages.length + 1) { - if (widget.parentMessage != null) { - if (widget.parentMessageBuilder != null) { - return widget.parentMessageBuilder( + return Stack( + children: [ + NotificationListener( + onNotification: (_) { + if (_scrollController.offset < 150 && _newMessageList.isNotEmpty) { + setState(() { + _messages.insertAll(0, _newMessageList); + _newMessageList.clear(); + }); + } + return true; + }, + child: ListView.custom( + key: Key('messageListView'), + physics: widget.scrollPhysics, + keyboardDismissBehavior: widget.keyboardDismissBehavior, + controller: _scrollController, + reverse: true, + childrenDelegate: SliverChildBuilderDelegate( + (context, i) { + if (i == _messages.length + 1) { + if (widget.parentMessage != null) { + if (widget.parentMessageBuilder != null) { + return widget.parentMessageBuilder( + context, + widget.parentMessage, + ); + } else { + return Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + buildParentMessage(widget.parentMessage), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 32), + child: Container( + padding: const EdgeInsets.all(8), + child: Text( + 'Start of thread', + textAlign: TextAlign.center, + ), + color: + Theme.of(context).accentColor.withAlpha(50), + ), + ), + ], + ); + } + } else { + return SizedBox(); + } + } + + if (i == _messages.length) { + return _buildLoadingIndicator(streamChannel); + } + final message = _messages[i]; + final nextMessage = i > 0 ? _messages[i - 1] : null; + + Widget messageWidget; + + if (i == 0) { + messageWidget = _buildBottomMessage( context, - widget.parentMessage, + message, + _messages, + streamChannel, + ); + } else if (i == _messages.length - 1) { + messageWidget = _buildTopMessage( + context, + message, + _messages, + streamChannel, ); } else { + if (widget.messageBuilder != null) { + messageWidget = Builder( + key: ValueKey('MESSAGE-${message.id}'), + builder: (_) => widget.messageBuilder( + context, + MessageDetails( + context, + message, + _messages, + i, + ), + _messages), + ); + } else { + messageWidget = buildMessage(message, _messages, i); + } + } + + if (nextMessage != null && + !Jiffy(message.createdAt.toLocal()) + .isSame(nextMessage.createdAt.toLocal(), Units.DAY)) { return Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ - buildParentMessage(widget.parentMessage), + messageWidget, Padding( - padding: const EdgeInsets.symmetric(horizontal: 32), - child: Container( - padding: const EdgeInsets.all(8), - child: Text( - 'Start of thread', - textAlign: TextAlign.center, - ), - color: Theme.of(context).accentColor.withAlpha(50), - ), + padding: const EdgeInsets.symmetric(vertical: 12.0), + child: widget.dateDividerBuilder != null + ? widget.dateDividerBuilder( + nextMessage.createdAt.toLocal()) + : DateDivider( + dateTime: nextMessage.createdAt.toLocal(), + ), ), ], ); } - } else { - return SizedBox(); - } - } - if (i == _messages.length) { - return _buildLoadingIndicator(streamChannel); - } - final message = _messages[i]; - final nextMessage = i > 0 ? _messages[i - 1] : null; - - Widget messageWidget; - - if (i == 0) { - messageWidget = _buildBottomMessage( - context, - message, - _messages, - streamChannel, - ); - } else if (i == _messages.length - 1) { - messageWidget = _buildTopMessage( - context, - message, - _messages, - streamChannel, - ); - } else { - if (widget.messageBuilder != null) { - messageWidget = Builder( - key: ValueKey('MESSAGE-${message.id}'), - builder: (_) => widget.messageBuilder( - context, - MessageDetails( - context, - message, - _messages, - i, - ), - _messages), - ); - } else { - 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; - }, - childCount: _messages.length + 2, - findChildIndexCallback: (key) { - final ValueKey valueKey = key; - final index = _messages - .indexWhere((m) => 'MESSAGE-${m.id}' == valueKey.value); - return index != -1 ? index : null; - }, + return messageWidget; + }, + childCount: _messages.length + 2, + findChildIndexCallback: (key) { + final ValueKey valueKey = key; + final index = _messages + .indexWhere((m) => 'MESSAGE-${m.id}' == valueKey.value); + return index != -1 ? index : null; + }, + ), + ), ), + if (widget.showScrollToBottom) + StreamBuilder( + stream: streamChannel.channel.on( + EventType.messageNew, + ), + builder: (context, _) { + if (!_showScrollToBottom || + streamChannel.channel.state.unreadCount == 0) { + return SizedBox(); + } + return _buildScrollToBottom(streamChannel); + }), + ], + ); + } + + Widget _buildScrollToBottom(StreamChannelState streamChannel) { + return Positioned( + bottom: 8, + right: 8, + width: 40, + height: 40, + child: Stack( + clipBehavior: Clip.none, + children: [ + FloatingActionButton( + backgroundColor: Colors.white, + child: Icon( + StreamIcons.down, + color: Colors.black, + ), + onPressed: () { + Future.delayed(Duration(milliseconds: 500), () { + setState(() { + _showScrollToBottom = false; + }); + }); + _scrollController.animateTo( + 0, + duration: Duration(seconds: 1), + curve: Curves.easeInOut, + ); + }, + ), + Positioned( + width: 20, + height: 20, + left: 10, + top: -10, + child: CircleAvatar( + radius: 20, + child: Text(streamChannel.channel.state.unreadCount.toString()), + ), + ), + ], ), ); } @@ -381,6 +446,9 @@ class _MessageListViewState extends State { } } _bottomWasVisible = isVisible; + setState(() { + _showScrollToBottom = !isVisible; + }); }, child: messageWidget, ); diff --git a/lib/src/reaction_asset.dart b/lib/src/reaction_icon.dart similarity index 100% rename from lib/src/reaction_asset.dart rename to lib/src/reaction_icon.dart diff --git a/lib/src/stream_chat_theme.dart b/lib/src/stream_chat_theme.dart index 540cd7e1..359ab102 100644 --- a/lib/src/stream_chat_theme.dart +++ b/lib/src/stream_chat_theme.dart @@ -3,10 +3,9 @@ import 'package:stream_chat/stream_chat.dart'; import 'package:stream_chat_flutter/src/channel_header.dart'; import 'package:stream_chat_flutter/src/channel_preview.dart'; import 'package:stream_chat_flutter/src/message_input.dart'; +import 'package:stream_chat_flutter/src/reaction_icon.dart'; import 'package:stream_chat_flutter/src/stream_icons.dart'; -import 'reaction_asset.dart'; - /// Inherited widget providing the [StreamChatThemeData] to the widget tree class StreamChatTheme extends InheritedWidget { final StreamChatThemeData data; From 71a80286f7d422f62a2d54a8bbc3fbafaff19520 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Tue, 20 Oct 2020 12:21:35 +0200 Subject: [PATCH 0171/1140] clip message in actions if too long --- lib/src/message_actions_modal.dart | 5 ++++- lib/src/message_reactions_modal.dart | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/lib/src/message_actions_modal.dart b/lib/src/message_actions_modal.dart index 890761d7..714966ce 100644 --- a/lib/src/message_actions_modal.dart +++ b/lib/src/message_actions_modal.dart @@ -79,7 +79,10 @@ class MessageActionsModal extends StatelessWidget { child: MessageWidget( key: Key('MessageWidget'), reverse: reverse, - message: message, + message: message.text.length > 200 + ? message.copyWith( + text: '${message.text.substring(0, 200)}...') + : message, messageTheme: messageTheme, showReactions: false, showUsername: false, diff --git a/lib/src/message_reactions_modal.dart b/lib/src/message_reactions_modal.dart index d3486f1b..b30f92b3 100644 --- a/lib/src/message_reactions_modal.dart +++ b/lib/src/message_reactions_modal.dart @@ -70,7 +70,10 @@ class MessageReactionsModal extends StatelessWidget { child: MessageWidget( key: Key('MessageWidget'), reverse: reverse, - message: message, + message: message.text.length > 200 + ? message.copyWith( + text: '${message.text.substring(0, 200)}...') + : message, messageTheme: messageTheme, showReactions: false, showUsername: false, From b35babd79d75385f836ac74da15713e7573f1d20 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Tue, 20 Oct 2020 17:01:33 +0530 Subject: [PATCH 0172/1140] feat: Shrink actions on type --- lib/src/message_input.dart | 45 ++++++++++++++++++++++++++++---------- 1 file changed, 33 insertions(+), 12 deletions(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index f2fdda3f..2c27665a 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -169,7 +169,8 @@ class MessageInputState extends State { bool _commandEnabled = false; OverlayEntry _commandsOverlay, _mentionsOverlay; - Command chosenCommand; + Command _chosenCommand; + bool _actionsShrunk = false; /// The editing controller passed to the input TextField TextEditingController textEditingController; @@ -202,14 +203,8 @@ class MessageInputState extends State { direction: Axis.horizontal, crossAxisAlignment: CrossAxisAlignment.center, children: [ - if (!_commandEnabled) - Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - if (!widget.disableAttachments) _buildAttachmentButton(), - if (widget.editMessage == null) _buildCommandButton(), - ], - ), + if(!_commandEnabled) + _buildExpandActionsButton(), if (widget.actionsLocation == ActionsLocation.left) ...widget.actions ?? [], _buildTextInput(context), @@ -233,6 +228,31 @@ class MessageInputState extends State { ); } + Widget _buildExpandActionsButton() { + return AnimatedCrossFade( + crossFadeState: _actionsShrunk + ? CrossFadeState.showFirst + : CrossFadeState.showSecond, + firstChild: IconButton( + onPressed: () { + setState(() { + _actionsShrunk = false; + }); + }, + icon: Icon(StreamIcons.arrow_right, color: StreamChatTheme.of(context).accentColor,), + ), + secondChild: Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + if (!widget.disableAttachments) _buildAttachmentButton(), + if (widget.editMessage == null) _buildCommandButton(), + ], + ), + duration: Duration(milliseconds: 300), + alignment: Alignment.center, + ); + } + Expanded _buildTextInput(BuildContext context) { return Expanded( child: Center( @@ -254,6 +274,7 @@ class MessageInputState extends State { setState(() { _messageIsPresent = s.trim().isNotEmpty; + _actionsShrunk = true; }); _commandsOverlay?.remove(); @@ -298,7 +319,7 @@ class MessageInputState extends State { child: Chip( backgroundColor: StreamChatTheme.of(context).accentColor, label: Text( - chosenCommand?.name ?? "", + _chosenCommand?.name ?? "", style: TextStyle(color: Colors.white), ), avatar: Icon( @@ -521,7 +542,7 @@ class MessageInputState extends State { void _setCommand(Command c) { textEditingController.clear(); setState(() { - chosenCommand = c; + _chosenCommand = c; _commandEnabled = true; }); _commandsOverlay?.remove(); @@ -946,7 +967,7 @@ class MessageInputState extends State { } if(_commandEnabled) { - text = '/${chosenCommand.name} ' + text; + text = '/${_chosenCommand.name} ' + text; } final attachments = List<_SendingAttachment>.from(_attachments); From c7fb3a229ffd54e1b3aa13eeaa6c53b630bbdced Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Tue, 20 Oct 2020 17:13:14 +0530 Subject: [PATCH 0173/1140] feat: Shrink actions on type --- lib/src/message_input.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 2c27665a..b9af8102 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -239,7 +239,7 @@ class MessageInputState extends State { _actionsShrunk = false; }); }, - icon: Icon(StreamIcons.arrow_right, color: StreamChatTheme.of(context).accentColor,), + icon: Icon(StreamIcons.circle_left, color: StreamChatTheme.of(context).accentColor,), ), secondChild: Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, @@ -274,7 +274,7 @@ class MessageInputState extends State { setState(() { _messageIsPresent = s.trim().isNotEmpty; - _actionsShrunk = true; + _actionsShrunk = s.trim().isNotEmpty; }); _commandsOverlay?.remove(); From 4fb41bf601763de9d7c98009a044d48bf956147d Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Wed, 21 Oct 2020 10:02:46 +0200 Subject: [PATCH 0174/1140] 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 0175/1140] 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 0176/1140] 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 0177/1140] 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 00e9e796e4dcf17c5a9689ca4de1610e489c6ad1 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Wed, 21 Oct 2020 10:39:50 +0200 Subject: [PATCH 0178/1140] fix unread indicator --- lib/src/unread_indicator.dart | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/lib/src/unread_indicator.dart b/lib/src/unread_indicator.dart index 96bf0a00..debe1d1b 100644 --- a/lib/src/unread_indicator.dart +++ b/lib/src/unread_indicator.dart @@ -12,17 +12,23 @@ class UnreadIndicator extends StatelessWidget { @override Widget build(BuildContext context) { - return Padding( - padding: const EdgeInsets.only(left: 8.0), - child: CircleAvatar( - backgroundColor: - StreamChatTheme.of(context).channelPreviewTheme.unreadCounterColor, - radius: 8, - child: Text( - '${channel.state.unreadCount}', - style: TextStyle( - fontSize: 11, - color: Colors.white, + return Material( + borderRadius: BorderRadius.circular(8), + color: StreamChatTheme.of(context).channelPreviewTheme.unreadCounterColor, + child: Padding( + padding: const EdgeInsets.only( + left: 5.0, + right: 5.0, + top: 2, + bottom: 1, + ), + child: Center( + child: Text( + '${channel.state.unreadCount}', + style: TextStyle( + fontSize: 11, + color: Colors.white, + ), ), ), ), From 00828eb0e28ec713c43efffe03dbf7e3c1b27f2d Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Fri, 23 Oct 2020 13:58:21 +0530 Subject: [PATCH 0179/1140] feat: commands ui --- lib/src/message_input.dart | 57 ++++++++++++++++++++++++-------------- 1 file changed, 36 insertions(+), 21 deletions(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index b9af8102..2143433c 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -415,30 +415,44 @@ class MessageInputState extends State { child: ListView( padding: const EdgeInsets.all(0), shrinkWrap: true, - children: commands - .map( - (c) => ListTile( - title: Text.rich( - TextSpan( - text: '${c.name}', - style: TextStyle(fontWeight: FontWeight.bold), - children: [ - TextSpan( - text: ' ${c.args}', - style: TextStyle( - fontWeight: FontWeight.w300, - ), + children: [ + Padding( + padding: const EdgeInsets.all(4.0), + child: Row( + children: [ + Padding( + padding: const EdgeInsets.symmetric(horizontal: 8.0), + child: Icon(StreamIcons.lightning, color: StreamChatTheme.of(context).accentColor), + ), + Text('Instant Commands') + ], + ), + ), + ...commands + .map( + (c) => ListTile( + title: Text.rich( + TextSpan( + text: '${c.name}', + style: TextStyle(fontWeight: FontWeight.bold), + children: [ + TextSpan( + text: ' ${c.args}', + style: TextStyle( + fontWeight: FontWeight.w300, ), - ], - ), + ), + ], ), - subtitle: Text(c.description), - onTap: () { - _setCommand(c); - }, ), - ) - .toList(), + subtitle: Text(c.description), + onTap: () { + _setCommand(c); + }, + ), + ) + .toList(), + ], ), ), ), @@ -544,6 +558,7 @@ class MessageInputState extends State { setState(() { _chosenCommand = c; _commandEnabled = true; + _messageIsPresent = false; }); _commandsOverlay?.remove(); _commandsOverlay = null; From e58b051bfac341e219f463fe31da61b023899e1e Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Fri, 23 Oct 2020 16:58:28 +0530 Subject: [PATCH 0180/1140] feat: commands ui --- analysis_options.yaml | 2 ++ lib/src/message_input.dart | 18 ++++++++++++++---- pubspec.yaml | 2 +- 3 files changed, 17 insertions(+), 5 deletions(-) diff --git a/analysis_options.yaml b/analysis_options.yaml index 3723c0af..8d6f9064 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -1,6 +1,8 @@ include: package:pedantic/analysis_options.yaml analyzer: + enable-experiment: + - extension-methods exclude: - lib/**/*.g.dart - example/** diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 2143433c..549acb5f 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -417,7 +417,7 @@ class MessageInputState extends State { shrinkWrap: true, children: [ Padding( - padding: const EdgeInsets.all(4.0), + padding: const EdgeInsets.only(left: 8.0, top: 8.0), child: Row( children: [ Padding( @@ -433,11 +433,11 @@ class MessageInputState extends State { (c) => ListTile( title: Text.rich( TextSpan( - text: '${c.name}', + text: '${c.name.capitalize()}', style: TextStyle(fontWeight: FontWeight.bold), children: [ TextSpan( - text: ' ${c.args}', + text: ' /${c.name} ${c.args}', style: TextStyle( fontWeight: FontWeight.w300, ), @@ -445,7 +445,11 @@ class MessageInputState extends State { ], ), ), - subtitle: Text(c.description), + trailing: CircleAvatar( + backgroundColor: StreamChatTheme.of(context).accentColor, + child: Icon(StreamIcons.lightning, color: Colors.white,), + ), + //subtitle: Text(c.description), onTap: () { _setCommand(c); }, @@ -1139,3 +1143,9 @@ class _SendingAttachment { this.uploaded = false, }); } + +extension StringExtension on String { + String capitalize() { + return "${this[0].toUpperCase()}${this.substring(1)}"; + } +} \ No newline at end of file diff --git a/pubspec.yaml b/pubspec.yaml index 3fb1b5ff..a39ac7ff 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -6,7 +6,7 @@ repository: https://github.com/GetStream/stream-chat-flutter issue_tracker: https://github.com/GetStream/stream-chat-flutter/issues environment: - sdk: ">=2.3.0 <3.0.0" + sdk: ">=2.6.0 <3.0.0" dependencies: flutter: From 05e980dbaca635bf87c893ecbf31d0ae01567ecd Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Fri, 23 Oct 2020 17:16:39 +0530 Subject: [PATCH 0181/1140] feat: commands ui --- lib/src/message_input.dart | 114 +++++++++++++++++++------------------ 1 file changed, 59 insertions(+), 55 deletions(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 549acb5f..ab5c55bb 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -398,65 +398,69 @@ class MessageInputState extends State { bottom: size.height + MediaQuery.of(context).viewInsets.bottom, left: 0, right: 0, - child: Material( - color: StreamChatTheme.of(context).primaryColor, - child: Container( - constraints: BoxConstraints.loose(Size.fromHeight(400)), - decoration: BoxDecoration( - boxShadow: [ - BoxShadow( - spreadRadius: -8, - blurRadius: 5.0, - offset: Offset(0, -4), - ), - ], - color: StreamChatTheme.of(context).primaryColor, - ), - child: ListView( - padding: const EdgeInsets.all(0), - shrinkWrap: true, - children: [ - Padding( - padding: const EdgeInsets.only(left: 8.0, top: 8.0), - child: Row( - children: [ - Padding( - padding: const EdgeInsets.symmetric(horizontal: 8.0), - child: Icon(StreamIcons.lightning, color: StreamChatTheme.of(context).accentColor), - ), - Text('Instant Commands') - ], + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Material( + color: StreamChatTheme.of(context).primaryColor, + child: Container( + constraints: BoxConstraints.loose(Size.fromHeight(400)), + decoration: BoxDecoration( + boxShadow: [ + BoxShadow( + spreadRadius: -8, + blurRadius: 5.0, + offset: Offset(0, -4), ), - ), - ...commands - .map( - (c) => ListTile( - title: Text.rich( - TextSpan( - text: '${c.name.capitalize()}', - style: TextStyle(fontWeight: FontWeight.bold), - children: [ - TextSpan( - text: ' /${c.name} ${c.args}', - style: TextStyle( - fontWeight: FontWeight.w300, + ], + color: StreamChatTheme.of(context).primaryColor, + ), + child: ListView( + padding: const EdgeInsets.all(0), + shrinkWrap: true, + children: [ + Padding( + padding: const EdgeInsets.only(left: 8.0, top: 8.0), + child: Row( + children: [ + Padding( + padding: const EdgeInsets.symmetric(horizontal: 8.0), + child: Icon(StreamIcons.lightning, color: StreamChatTheme.of(context).accentColor), + ), + Text('Instant Commands') + ], + ), + ), + ...commands + .map( + (c) => ListTile( + title: Text.rich( + TextSpan( + text: '${c.name.capitalize()}', + style: TextStyle(fontWeight: FontWeight.bold), + children: [ + TextSpan( + text: ' /${c.name} ${c.args}', + style: TextStyle( + fontWeight: FontWeight.w300, + ), ), - ), - ], + ], + ), ), + trailing: CircleAvatar( + backgroundColor: StreamChatTheme.of(context).accentColor, + child: Icon(StreamIcons.lightning, color: Colors.white,), + maxRadius: 40.0, + ), + //subtitle: Text(c.description), + onTap: () { + _setCommand(c); + }, ), - trailing: CircleAvatar( - backgroundColor: StreamChatTheme.of(context).accentColor, - child: Icon(StreamIcons.lightning, color: Colors.white,), - ), - //subtitle: Text(c.description), - onTap: () { - _setCommand(c); - }, - ), - ) - .toList(), - ], + ) + .toList(), + ], + ), ), ), ), From 64cf493629b83e32a71e5aa515587117f9e063ac Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Fri, 23 Oct 2020 17:19:15 +0530 Subject: [PATCH 0182/1140] feat: commands ui --- lib/src/message_input.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index ab5c55bb..d89441cc 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -400,7 +400,7 @@ class MessageInputState extends State { right: 0, child: Padding( padding: const EdgeInsets.all(8.0), - child: Material( + child: Card( color: StreamChatTheme.of(context).primaryColor, child: Container( constraints: BoxConstraints.loose(Size.fromHeight(400)), @@ -450,7 +450,7 @@ class MessageInputState extends State { trailing: CircleAvatar( backgroundColor: StreamChatTheme.of(context).accentColor, child: Icon(StreamIcons.lightning, color: Colors.white,), - maxRadius: 40.0, + maxRadius: 25.0, ), //subtitle: Text(c.description), onTap: () { From 9ed54d5328cd6ab7f314451df4fe243c89ce963f Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Fri, 23 Oct 2020 17:24:02 +0530 Subject: [PATCH 0183/1140] feat: commands ui --- lib/src/message_input.dart | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index d89441cc..602217e8 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -402,17 +402,19 @@ class MessageInputState extends State { padding: const EdgeInsets.all(8.0), child: Card( color: StreamChatTheme.of(context).primaryColor, + clipBehavior: Clip.antiAlias, child: Container( constraints: BoxConstraints.loose(Size.fromHeight(400)), decoration: BoxDecoration( - boxShadow: [ - BoxShadow( - spreadRadius: -8, - blurRadius: 5.0, - offset: Offset(0, -4), - ), - ], + // boxShadow: [ + // BoxShadow( + // spreadRadius: -8, + // blurRadius: 5.0, + // offset: Offset(0, -4), + // ), + // ], color: StreamChatTheme.of(context).primaryColor, + borderRadius: BorderRadius.circular(8.0) ), child: ListView( padding: const EdgeInsets.all(0), @@ -450,7 +452,7 @@ class MessageInputState extends State { trailing: CircleAvatar( backgroundColor: StreamChatTheme.of(context).accentColor, child: Icon(StreamIcons.lightning, color: Colors.white,), - maxRadius: 25.0, + maxRadius: 15.0, ), //subtitle: Text(c.description), onTap: () { From b1ac512ab433d92d65dfadaded1b3a81ac99ec0d Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Fri, 23 Oct 2020 17:27:58 +0530 Subject: [PATCH 0184/1140] feat: commands ui --- lib/src/message_input.dart | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 602217e8..303badd7 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -406,13 +406,13 @@ class MessageInputState extends State { child: Container( constraints: BoxConstraints.loose(Size.fromHeight(400)), decoration: BoxDecoration( - // boxShadow: [ - // BoxShadow( - // spreadRadius: -8, - // blurRadius: 5.0, - // offset: Offset(0, -4), - // ), - // ], + boxShadow: [ + BoxShadow( + spreadRadius: -8, + blurRadius: 5.0, + offset: Offset(0, -4), + ), + ], color: StreamChatTheme.of(context).primaryColor, borderRadius: BorderRadius.circular(8.0) ), @@ -451,8 +451,8 @@ class MessageInputState extends State { ), trailing: CircleAvatar( backgroundColor: StreamChatTheme.of(context).accentColor, - child: Icon(StreamIcons.lightning, color: Colors.white,), - maxRadius: 15.0, + child: Icon(StreamIcons.lightning, color: Colors.white, size: 10.0,), + maxRadius: 12.5, ), //subtitle: Text(c.description), onTap: () { From 03713684a54431c950eb960f0c025f9efda40047 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Fri, 23 Oct 2020 17:33:10 +0530 Subject: [PATCH 0185/1140] feat: commands ui --- lib/src/message_input.dart | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 303badd7..8f91277b 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -401,18 +401,19 @@ class MessageInputState extends State { child: Padding( padding: const EdgeInsets.all(8.0), child: Card( + elevation: 4.0, color: StreamChatTheme.of(context).primaryColor, clipBehavior: Clip.antiAlias, child: Container( constraints: BoxConstraints.loose(Size.fromHeight(400)), decoration: BoxDecoration( - boxShadow: [ - BoxShadow( - spreadRadius: -8, - blurRadius: 5.0, - offset: Offset(0, -4), - ), - ], + // boxShadow: [ + // BoxShadow( + // spreadRadius: -8, + // blurRadius: 5.0, + // offset: Offset(0, -4), + // ), + // ], color: StreamChatTheme.of(context).primaryColor, borderRadius: BorderRadius.circular(8.0) ), @@ -451,7 +452,7 @@ class MessageInputState extends State { ), trailing: CircleAvatar( backgroundColor: StreamChatTheme.of(context).accentColor, - child: Icon(StreamIcons.lightning, color: Colors.white, size: 10.0,), + child: Icon(StreamIcons.lightning, color: Colors.white, size: 12.5,), maxRadius: 12.5, ), //subtitle: Text(c.description), From 4eb06896ee23628dcf2b81120335b2975f5430b5 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Fri, 23 Oct 2020 17:35:06 +0530 Subject: [PATCH 0186/1140] feat: commands ui --- lib/src/message_input.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 8f91277b..a494b65a 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -401,7 +401,7 @@ class MessageInputState extends State { child: Padding( padding: const EdgeInsets.all(8.0), child: Card( - elevation: 4.0, + elevation: 2.0, color: StreamChatTheme.of(context).primaryColor, clipBehavior: Clip.antiAlias, child: Container( From 494a1e60b9c453ecb7b0e479f2ba8c6f1c3016a0 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Fri, 23 Oct 2020 17:38:42 +0530 Subject: [PATCH 0187/1140] feat: commands ui --- lib/src/message_input.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index a494b65a..f6080178 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -453,7 +453,7 @@ class MessageInputState extends State { trailing: CircleAvatar( backgroundColor: StreamChatTheme.of(context).accentColor, child: Icon(StreamIcons.lightning, color: Colors.white, size: 12.5,), - maxRadius: 12.5, + maxRadius: 15, ), //subtitle: Text(c.description), onTap: () { From 2eee935f9c6365be86f8c29531f8fb64d7f4a447 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Mon, 26 Oct 2020 14:36:46 +0530 Subject: [PATCH 0188/1140] fix: overlay ui --- lib/src/message_input.dart | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index f6080178..d20abc0e 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -500,8 +500,10 @@ class MessageInputState extends State { bottom: size.height + MediaQuery.of(context).viewInsets.bottom, left: 0, right: 0, - child: Material( + child: Card( + margin: EdgeInsets.all(8.0), color: StreamChatTheme.of(context).primaryColor, + clipBehavior: Clip.antiAlias, child: Container( constraints: BoxConstraints.loose(Size.fromHeight(400)), decoration: BoxDecoration( From 92ef94f05236fd588e2fa2e497c0116e5c03205b Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Mon, 26 Oct 2020 14:41:53 +0530 Subject: [PATCH 0189/1140] fix: overlay ui --- lib/src/message_input.dart | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index d20abc0e..dd0b3133 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -502,6 +502,7 @@ class MessageInputState extends State { right: 0, child: Card( margin: EdgeInsets.all(8.0), + elevation: 2.0, color: StreamChatTheme.of(context).primaryColor, clipBehavior: Clip.antiAlias, child: Container( From 027ff3cff78054ab16df52cf6df67ac24ebf647b Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Mon, 26 Oct 2020 15:02:30 +0530 Subject: [PATCH 0190/1140] fix: edit ui --- lib/src/message_actions_modal.dart | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/lib/src/message_actions_modal.dart b/lib/src/message_actions_modal.dart index 569ae22e..e39e7eed 100644 --- a/lib/src/message_actions_modal.dart +++ b/lib/src/message_actions_modal.dart @@ -189,6 +189,15 @@ class MessageActionsModal extends StatelessWidget { child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ + IconButton( + icon: Icon( + StreamIcons.form_edit, + size: 18, + color: + StreamChatTheme.of(context).primaryIconTheme.color, + ), + onPressed: () {}, + ), Text( 'Edit message', style: Theme.of(context).textTheme.headline6, @@ -196,7 +205,7 @@ class MessageActionsModal extends StatelessWidget { IconButton( icon: Icon( Icons.cancel_outlined, - size: 15, + size: 18, color: StreamChatTheme.of(context).primaryIconTheme.color, ), From b487e205cb4243d2382aa1d79d288a483d2b9eed Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Mon, 26 Oct 2020 15:09:38 +0530 Subject: [PATCH 0191/1140] fix: edit ui --- lib/src/message_actions_modal.dart | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/src/message_actions_modal.dart b/lib/src/message_actions_modal.dart index e39e7eed..653f98cb 100644 --- a/lib/src/message_actions_modal.dart +++ b/lib/src/message_actions_modal.dart @@ -192,7 +192,7 @@ class MessageActionsModal extends StatelessWidget { IconButton( icon: Icon( StreamIcons.form_edit, - size: 18, + size: 22, color: StreamChatTheme.of(context).primaryIconTheme.color, ), @@ -200,12 +200,12 @@ class MessageActionsModal extends StatelessWidget { ), Text( 'Edit message', - style: Theme.of(context).textTheme.headline6, + style: Theme.of(context).textTheme.headline6.copyWith(fontWeight: FontWeight.bold), ), IconButton( icon: Icon( Icons.cancel_outlined, - size: 18, + size: 2, color: StreamChatTheme.of(context).primaryIconTheme.color, ), From 35b6788ddc448e73eb92a25e924e493c4d680f83 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Mon, 26 Oct 2020 15:12:08 +0530 Subject: [PATCH 0192/1140] fix: edit ui --- lib/src/message_actions_modal.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/message_actions_modal.dart b/lib/src/message_actions_modal.dart index 653f98cb..e8e0d6e1 100644 --- a/lib/src/message_actions_modal.dart +++ b/lib/src/message_actions_modal.dart @@ -205,7 +205,7 @@ class MessageActionsModal extends StatelessWidget { IconButton( icon: Icon( Icons.cancel_outlined, - size: 2, + size: 22, color: StreamChatTheme.of(context).primaryIconTheme.color, ), From 657e2c2d0f4e11dd5048b7b88dd0c86b61207350 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Mon, 26 Oct 2020 15:20:00 +0530 Subject: [PATCH 0193/1140] fix: edit ui --- lib/src/message_actions_modal.dart | 2 +- lib/src/message_input.dart | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/src/message_actions_modal.dart b/lib/src/message_actions_modal.dart index e8e0d6e1..0f5e6c0d 100644 --- a/lib/src/message_actions_modal.dart +++ b/lib/src/message_actions_modal.dart @@ -191,7 +191,7 @@ class MessageActionsModal extends StatelessWidget { children: [ IconButton( icon: Icon( - StreamIcons.form_edit, + StreamIcons.edit, size: 22, color: StreamChatTheme.of(context).primaryIconTheme.color, diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index dd0b3133..c5650c66 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -309,7 +309,7 @@ class MessageInputState extends State { decoration: InputDecoration( hintText: 'Write a message', prefixText: _commandEnabled ? null : ' ', - border: OutlineInputBorder( + border: widget.editMessage == null ? null : OutlineInputBorder( borderRadius: BorderRadius.circular(32), ), contentPadding: EdgeInsets.all(8), From 33f46ee48d837f3096ff505cb83db1e14d16f70a Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Mon, 26 Oct 2020 15:23:42 +0530 Subject: [PATCH 0194/1140] fix: edit ui --- lib/src/message_input.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index c5650c66..dd0b3133 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -309,7 +309,7 @@ class MessageInputState extends State { decoration: InputDecoration( hintText: 'Write a message', prefixText: _commandEnabled ? null : ' ', - border: widget.editMessage == null ? null : OutlineInputBorder( + border: OutlineInputBorder( borderRadius: BorderRadius.circular(32), ), contentPadding: EdgeInsets.all(8), From 0340e4271f2dc32418e25ffe035ecd91fb4b8cb8 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Mon, 26 Oct 2020 15:29:59 +0530 Subject: [PATCH 0195/1140] fix: attachments ui --- lib/src/message_input.dart | 162 +++++++++++++++++++------------------ 1 file changed, 83 insertions(+), 79 deletions(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index dd0b3133..fdadb91a 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -189,7 +189,6 @@ class MessageInputState extends State { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - _buildAttachments(), _buildTextField(context), ], ), @@ -258,89 +257,94 @@ class MessageInputState extends State { child: Center( child: LimitedBox( maxHeight: widget.maxHeight, - child: TextField( - key: Key('messageInputText'), - enabled: _inputEnabled, - minLines: null, - maxLines: null, - onSubmitted: (_) { - sendMessage(); - }, - keyboardType: widget.keyboardType, - controller: textEditingController, - focusNode: _focusNode, - onChanged: (s) { - StreamChannel.of(context).channel.keyStroke(); + child: Column( + children: [ + _buildAttachments(), + TextField( + key: Key('messageInputText'), + enabled: _inputEnabled, + minLines: null, + maxLines: null, + onSubmitted: (_) { + sendMessage(); + }, + keyboardType: widget.keyboardType, + controller: textEditingController, + focusNode: _focusNode, + onChanged: (s) { + StreamChannel.of(context).channel.keyStroke(); - setState(() { - _messageIsPresent = s.trim().isNotEmpty; - _actionsShrunk = s.trim().isNotEmpty; - }); + setState(() { + _messageIsPresent = s.trim().isNotEmpty; + _actionsShrunk = s.trim().isNotEmpty; + }); - _commandsOverlay?.remove(); - _commandsOverlay = null; - _mentionsOverlay?.remove(); - _mentionsOverlay = null; + _commandsOverlay?.remove(); + _commandsOverlay = null; + _mentionsOverlay?.remove(); + _mentionsOverlay = null; - if (s.startsWith('/')) { - _commandsOverlay = _buildCommandsOverlayEntry(); - Overlay.of(context).insert(_commandsOverlay); - } + if (s.startsWith('/')) { + _commandsOverlay = _buildCommandsOverlayEntry(); + Overlay.of(context).insert(_commandsOverlay); + } - if (textEditingController.selection.isCollapsed && - (s[textEditingController.selection.start - 1] == '@' || - textEditingController.text - .substring(0, textEditingController.selection.start) - .split(' ') - .last - .contains('@'))) { - _mentionsOverlay = _buildMentionsOverlayEntry(); - Overlay.of(context).insert(_mentionsOverlay); - } - }, - onTap: () { - setState(() { - _typingStarted = true; - }); - }, - style: Theme.of(context).textTheme.bodyText2, - autofocus: false, - textAlignVertical: TextAlignVertical.center, - decoration: InputDecoration( - hintText: 'Write a message', - prefixText: _commandEnabled ? null : ' ', - border: OutlineInputBorder( - borderRadius: BorderRadius.circular(32), + if (textEditingController.selection.isCollapsed && + (s[textEditingController.selection.start - 1] == '@' || + textEditingController.text + .substring(0, textEditingController.selection.start) + .split(' ') + .last + .contains('@'))) { + _mentionsOverlay = _buildMentionsOverlayEntry(); + Overlay.of(context).insert(_mentionsOverlay); + } + }, + onTap: () { + setState(() { + _typingStarted = true; + }); + }, + style: Theme.of(context).textTheme.bodyText2, + autofocus: false, + textAlignVertical: TextAlignVertical.center, + decoration: InputDecoration( + hintText: 'Write a message', + prefixText: _commandEnabled ? null : ' ', + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(32), + ), + contentPadding: EdgeInsets.all(8), + prefixIcon: _commandEnabled + ? Padding( + padding: const EdgeInsets.symmetric(horizontal: 8.0), + child: Chip( + backgroundColor: StreamChatTheme.of(context).accentColor, + label: Text( + _chosenCommand?.name ?? "", + style: TextStyle(color: Colors.white), + ), + avatar: Icon( + StreamIcons.lightning, + color: Colors.white, + ), + ), + ) + : null, + suffixIcon: _commandEnabled + ? IconButton( + icon: Icon(Icons.cancel_outlined), + onPressed: () { + setState(() { + _commandEnabled = false; + }); + }, + ) + : null, + ), + textCapitalization: TextCapitalization.sentences, ), - contentPadding: EdgeInsets.all(8), - prefixIcon: _commandEnabled - ? Padding( - padding: const EdgeInsets.symmetric(horizontal: 8.0), - child: Chip( - backgroundColor: StreamChatTheme.of(context).accentColor, - label: Text( - _chosenCommand?.name ?? "", - style: TextStyle(color: Colors.white), - ), - avatar: Icon( - StreamIcons.lightning, - color: Colors.white, - ), - ), - ) - : null, - suffixIcon: _commandEnabled - ? IconButton( - icon: Icon(Icons.cancel_outlined), - onPressed: () { - setState(() { - _commandEnabled = false; - }); - }, - ) - : null, - ), - textCapitalization: TextCapitalization.sentences, + ], ), ), ), From b9ad19b4d66a43bd17d15023c15ef94dd0a52d9e Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Mon, 26 Oct 2020 15:33:00 +0530 Subject: [PATCH 0196/1140] fix: attachments ui --- lib/src/message_input.dart | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index fdadb91a..95de7dad 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -258,6 +258,7 @@ class MessageInputState extends State { child: LimitedBox( maxHeight: widget.maxHeight, child: Column( + mainAxisSize: MainAxisSize.min, children: [ _buildAttachments(), TextField( From e79c3654aeec910e8b16edda1349136275d609ed Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Mon, 26 Oct 2020 15:36:08 +0530 Subject: [PATCH 0197/1140] fix: attachments ui --- lib/src/message_input.dart | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 95de7dad..96fd6022 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -186,12 +186,7 @@ class MessageInputState extends State { }, child: Padding( padding: const EdgeInsets.all(8.0), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - _buildTextField(context), - ], - ), + child: _buildTextField(context), ), ), ); @@ -200,7 +195,7 @@ class MessageInputState extends State { Flex _buildTextField(BuildContext context) { return Flex( direction: Axis.horizontal, - crossAxisAlignment: CrossAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.end, children: [ if(!_commandEnabled) _buildExpandActionsButton(), From b93b7fd85339a5c1638c769d2666618e4217ffae Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Mon, 26 Oct 2020 15:42:03 +0530 Subject: [PATCH 0198/1140] fix: attachments ui --- lib/src/message_input.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 96fd6022..ad32e1ab 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -592,8 +592,8 @@ class MessageInputState extends State { } Widget _buildAttachments() { - return Wrap( - direction: Axis.horizontal, + return ListView( + scrollDirection: Axis.horizontal, children: _attachments .map( (attachment) => Padding( From 5095b8e3c3ec8dff6c7faa0e3e3c7e38ea8e0a66 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Mon, 26 Oct 2020 15:46:47 +0530 Subject: [PATCH 0199/1140] fix: attachments ui --- lib/src/message_input.dart | 173 +++++++++++++++++++------------------ 1 file changed, 89 insertions(+), 84 deletions(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index ad32e1ab..5d135ded 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -252,95 +252,100 @@ class MessageInputState extends State { child: Center( child: LimitedBox( maxHeight: widget.maxHeight, - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - _buildAttachments(), - TextField( - key: Key('messageInputText'), - enabled: _inputEnabled, - minLines: null, - maxLines: null, - onSubmitted: (_) { - sendMessage(); - }, - keyboardType: widget.keyboardType, - controller: textEditingController, - focusNode: _focusNode, - onChanged: (s) { - StreamChannel.of(context).channel.keyStroke(); + child: Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(8.0), + ), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + _buildAttachments(), + TextField( + key: Key('messageInputText'), + enabled: _inputEnabled, + minLines: null, + maxLines: null, + onSubmitted: (_) { + sendMessage(); + }, + keyboardType: widget.keyboardType, + controller: textEditingController, + focusNode: _focusNode, + onChanged: (s) { + StreamChannel.of(context).channel.keyStroke(); - setState(() { - _messageIsPresent = s.trim().isNotEmpty; - _actionsShrunk = s.trim().isNotEmpty; - }); + setState(() { + _messageIsPresent = s.trim().isNotEmpty; + _actionsShrunk = s.trim().isNotEmpty; + }); - _commandsOverlay?.remove(); - _commandsOverlay = null; - _mentionsOverlay?.remove(); - _mentionsOverlay = null; + _commandsOverlay?.remove(); + _commandsOverlay = null; + _mentionsOverlay?.remove(); + _mentionsOverlay = null; - if (s.startsWith('/')) { - _commandsOverlay = _buildCommandsOverlayEntry(); - Overlay.of(context).insert(_commandsOverlay); - } + if (s.startsWith('/')) { + _commandsOverlay = _buildCommandsOverlayEntry(); + Overlay.of(context).insert(_commandsOverlay); + } - if (textEditingController.selection.isCollapsed && - (s[textEditingController.selection.start - 1] == '@' || - textEditingController.text - .substring(0, textEditingController.selection.start) - .split(' ') - .last - .contains('@'))) { - _mentionsOverlay = _buildMentionsOverlayEntry(); - Overlay.of(context).insert(_mentionsOverlay); - } - }, - onTap: () { - setState(() { - _typingStarted = true; - }); - }, - style: Theme.of(context).textTheme.bodyText2, - autofocus: false, - textAlignVertical: TextAlignVertical.center, - decoration: InputDecoration( - hintText: 'Write a message', - prefixText: _commandEnabled ? null : ' ', - border: OutlineInputBorder( - borderRadius: BorderRadius.circular(32), - ), - contentPadding: EdgeInsets.all(8), - prefixIcon: _commandEnabled - ? Padding( - padding: const EdgeInsets.symmetric(horizontal: 8.0), - child: Chip( - backgroundColor: StreamChatTheme.of(context).accentColor, - label: Text( - _chosenCommand?.name ?? "", - style: TextStyle(color: Colors.white), + if (textEditingController.selection.isCollapsed && + (s[textEditingController.selection.start - 1] == '@' || + textEditingController.text + .substring(0, textEditingController.selection.start) + .split(' ') + .last + .contains('@'))) { + _mentionsOverlay = _buildMentionsOverlayEntry(); + Overlay.of(context).insert(_mentionsOverlay); + } + }, + onTap: () { + setState(() { + _typingStarted = true; + }); + }, + style: Theme.of(context).textTheme.bodyText2, + autofocus: false, + textAlignVertical: TextAlignVertical.center, + decoration: InputDecoration( + hintText: 'Write a message', + prefixText: _commandEnabled ? null : ' ', + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(32), + ), + contentPadding: EdgeInsets.all(8), + prefixIcon: _commandEnabled + ? Padding( + padding: const EdgeInsets.symmetric(horizontal: 8.0), + child: Chip( + backgroundColor: StreamChatTheme.of(context).accentColor, + label: Text( + _chosenCommand?.name ?? "", + style: TextStyle(color: Colors.white), + ), + avatar: Icon( + StreamIcons.lightning, + color: Colors.white, + ), ), - avatar: Icon( - StreamIcons.lightning, - color: Colors.white, - ), - ), - ) - : null, - suffixIcon: _commandEnabled - ? IconButton( - icon: Icon(Icons.cancel_outlined), - onPressed: () { - setState(() { - _commandEnabled = false; - }); - }, ) - : null, + : null, + suffixIcon: _commandEnabled + ? IconButton( + icon: Icon(Icons.cancel_outlined), + onPressed: () { + setState(() { + _commandEnabled = false; + }); + }, + ) + : null, + ), + textCapitalization: TextCapitalization.sentences, ), - textCapitalization: TextCapitalization.sentences, - ), - ], + ], + ), ), ), ), @@ -592,8 +597,8 @@ class MessageInputState extends State { } Widget _buildAttachments() { - return ListView( - scrollDirection: Axis.horizontal, + return Wrap( + direction: Axis.horizontal, children: _attachments .map( (attachment) => Padding( From 4833b47798591aee527dfe7b80537f39eea83c83 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Mon, 26 Oct 2020 15:49:56 +0530 Subject: [PATCH 0200/1140] fix: attachments ui --- lib/src/message_input.dart | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 5d135ded..1e0a7787 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -255,6 +255,7 @@ class MessageInputState extends State { child: Container( decoration: BoxDecoration( borderRadius: BorderRadius.circular(8.0), + border: Border.all() ), child: Column( mainAxisSize: MainAxisSize.min, From c20ee15f60adbb380b9a37cbf70330639ffc34cb Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Mon, 26 Oct 2020 16:07:16 +0530 Subject: [PATCH 0201/1140] fix: attachments ui --- lib/src/message_input.dart | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 1e0a7787..700a726f 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -254,8 +254,14 @@ class MessageInputState extends State { maxHeight: widget.maxHeight, child: Container( decoration: BoxDecoration( - borderRadius: BorderRadius.circular(8.0), - border: Border.all() + borderRadius: BorderRadius.circular(16.0), + border: Border.all( + color: _typingStarted + ? Colors.transparent + : Theme.of(context).brightness == Brightness.dark + ? Colors.white.withOpacity(.2) + : Colors.black.withOpacity(.2)), + ) ), child: Column( mainAxisSize: MainAxisSize.min, @@ -312,9 +318,11 @@ class MessageInputState extends State { decoration: InputDecoration( hintText: 'Write a message', prefixText: _commandEnabled ? null : ' ', - border: OutlineInputBorder( - borderRadius: BorderRadius.circular(32), - ), + border: InputBorder.none, + focusedBorder: InputBorder.none, + enabledBorder: InputBorder.none, + errorBorder: InputBorder.none, + disabledBorder: InputBorder.none, contentPadding: EdgeInsets.all(8), prefixIcon: _commandEnabled ? Padding( From 70caff0277d69abb13ef2ca1ef3f2083366b92f5 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Mon, 26 Oct 2020 16:08:10 +0530 Subject: [PATCH 0202/1140] fix: attachments ui --- lib/src/message_input.dart | 116 ++++++++++++++++++++----------------- 1 file changed, 62 insertions(+), 54 deletions(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 700a726f..5d9a8cc2 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -197,8 +197,7 @@ class MessageInputState extends State { direction: Axis.horizontal, crossAxisAlignment: CrossAxisAlignment.end, children: [ - if(!_commandEnabled) - _buildExpandActionsButton(), + if (!_commandEnabled) _buildExpandActionsButton(), if (widget.actionsLocation == ActionsLocation.left) ...widget.actions ?? [], _buildTextInput(context), @@ -224,16 +223,18 @@ class MessageInputState extends State { Widget _buildExpandActionsButton() { return AnimatedCrossFade( - crossFadeState: _actionsShrunk - ? CrossFadeState.showFirst - : CrossFadeState.showSecond, + crossFadeState: + _actionsShrunk ? CrossFadeState.showFirst : CrossFadeState.showSecond, firstChild: IconButton( onPressed: () { setState(() { _actionsShrunk = false; }); }, - icon: Icon(StreamIcons.circle_left, color: StreamChatTheme.of(context).accentColor,), + icon: Icon( + StreamIcons.circle_left, + color: StreamChatTheme.of(context).accentColor, + ), ), secondChild: Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, @@ -254,14 +255,13 @@ class MessageInputState extends State { maxHeight: widget.maxHeight, child: Container( decoration: BoxDecoration( - borderRadius: BorderRadius.circular(16.0), + borderRadius: BorderRadius.circular(8.0), border: Border.all( - color: _typingStarted - ? Colors.transparent - : Theme.of(context).brightness == Brightness.dark - ? Colors.white.withOpacity(.2) - : Colors.black.withOpacity(.2)), - ) + color: _typingStarted + ? Colors.transparent + : Theme.of(context).brightness == Brightness.dark + ? Colors.white.withOpacity(.2) + : Colors.black.withOpacity(.2)), ), child: Column( mainAxisSize: MainAxisSize.min, @@ -299,7 +299,8 @@ class MessageInputState extends State { if (textEditingController.selection.isCollapsed && (s[textEditingController.selection.start - 1] == '@' || textEditingController.text - .substring(0, textEditingController.selection.start) + .substring( + 0, textEditingController.selection.start) .split(' ') .last .contains('@'))) { @@ -326,9 +327,11 @@ class MessageInputState extends State { contentPadding: EdgeInsets.all(8), prefixIcon: _commandEnabled ? Padding( - padding: const EdgeInsets.symmetric(horizontal: 8.0), - child: Chip( - backgroundColor: StreamChatTheme.of(context).accentColor, + padding: + const EdgeInsets.symmetric(horizontal: 8.0), + child: Chip( + backgroundColor: + StreamChatTheme.of(context).accentColor, label: Text( _chosenCommand?.name ?? "", style: TextStyle(color: Colors.white), @@ -338,7 +341,7 @@ class MessageInputState extends State { color: Colors.white, ), ), - ) + ) : null, suffixIcon: _commandEnabled ? IconButton( @@ -421,16 +424,15 @@ class MessageInputState extends State { child: Container( constraints: BoxConstraints.loose(Size.fromHeight(400)), decoration: BoxDecoration( - // boxShadow: [ - // BoxShadow( - // spreadRadius: -8, - // blurRadius: 5.0, - // offset: Offset(0, -4), - // ), - // ], - color: StreamChatTheme.of(context).primaryColor, - borderRadius: BorderRadius.circular(8.0) - ), + // boxShadow: [ + // BoxShadow( + // spreadRadius: -8, + // blurRadius: 5.0, + // offset: Offset(0, -4), + // ), + // ], + color: StreamChatTheme.of(context).primaryColor, + borderRadius: BorderRadius.circular(8.0)), child: ListView( padding: const EdgeInsets.all(0), shrinkWrap: true, @@ -441,7 +443,8 @@ class MessageInputState extends State { children: [ Padding( padding: const EdgeInsets.symmetric(horizontal: 8.0), - child: Icon(StreamIcons.lightning, color: StreamChatTheme.of(context).accentColor), + child: Icon(StreamIcons.lightning, + color: StreamChatTheme.of(context).accentColor), ), Text('Instant Commands') ], @@ -450,31 +453,36 @@ class MessageInputState extends State { ...commands .map( (c) => ListTile( - title: Text.rich( - TextSpan( - text: '${c.name.capitalize()}', - style: TextStyle(fontWeight: FontWeight.bold), - children: [ + title: Text.rich( TextSpan( - text: ' /${c.name} ${c.args}', - style: TextStyle( - fontWeight: FontWeight.w300, - ), + text: '${c.name.capitalize()}', + style: TextStyle(fontWeight: FontWeight.bold), + children: [ + TextSpan( + text: ' /${c.name} ${c.args}', + style: TextStyle( + fontWeight: FontWeight.w300, + ), + ), + ], ), - ], + ), + trailing: CircleAvatar( + backgroundColor: + StreamChatTheme.of(context).accentColor, + child: Icon( + StreamIcons.lightning, + color: Colors.white, + size: 12.5, + ), + maxRadius: 15, + ), + //subtitle: Text(c.description), + onTap: () { + _setCommand(c); + }, ), - ), - trailing: CircleAvatar( - backgroundColor: StreamChatTheme.of(context).accentColor, - child: Icon(StreamIcons.lightning, color: Colors.white, size: 12.5,), - maxRadius: 15, - ), - //subtitle: Text(c.description), - onTap: () { - _setCommand(c); - }, - ), - ) + ) .toList(), ], ), @@ -719,7 +727,7 @@ class MessageInputState extends State { child: Icon(StreamIcons.lightning), ), onTap: () { - if(_commandsOverlay == null) { + if (_commandsOverlay == null) { _commandsOverlay = _buildCommandsOverlayEntry(); Overlay.of(context).insert(_commandsOverlay); } else { @@ -1009,7 +1017,7 @@ class MessageInputState extends State { return; } - if(_commandEnabled) { + if (_commandEnabled) { text = '/${_chosenCommand.name} ' + text; } @@ -1172,4 +1180,4 @@ extension StringExtension on String { String capitalize() { return "${this[0].toUpperCase()}${this.substring(1)}"; } -} \ No newline at end of file +} From adbc0a8ed98a2496775487504e0d1fb9abfaf7b8 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Mon, 26 Oct 2020 16:12:56 +0530 Subject: [PATCH 0203/1140] fix: attachments ui --- lib/src/message_input.dart | 120 ++++++++++++++++--------------------- 1 file changed, 53 insertions(+), 67 deletions(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 5d9a8cc2..81635796 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -197,7 +197,8 @@ class MessageInputState extends State { direction: Axis.horizontal, crossAxisAlignment: CrossAxisAlignment.end, children: [ - if (!_commandEnabled) _buildExpandActionsButton(), + if(!_commandEnabled) + _buildExpandActionsButton(), if (widget.actionsLocation == ActionsLocation.left) ...widget.actions ?? [], _buildTextInput(context), @@ -223,18 +224,16 @@ class MessageInputState extends State { Widget _buildExpandActionsButton() { return AnimatedCrossFade( - crossFadeState: - _actionsShrunk ? CrossFadeState.showFirst : CrossFadeState.showSecond, + crossFadeState: _actionsShrunk + ? CrossFadeState.showFirst + : CrossFadeState.showSecond, firstChild: IconButton( onPressed: () { setState(() { _actionsShrunk = false; }); }, - icon: Icon( - StreamIcons.circle_left, - color: StreamChatTheme.of(context).accentColor, - ), + icon: Icon(StreamIcons.circle_left, color: StreamChatTheme.of(context).accentColor,), ), secondChild: Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, @@ -255,13 +254,10 @@ class MessageInputState extends State { maxHeight: widget.maxHeight, child: Container( decoration: BoxDecoration( - borderRadius: BorderRadius.circular(8.0), + borderRadius: BorderRadius.circular(16.0), border: Border.all( - color: _typingStarted - ? Colors.transparent - : Theme.of(context).brightness == Brightness.dark - ? Colors.white.withOpacity(.2) - : Colors.black.withOpacity(.2)), + color: Colors.grey, + ) ), child: Column( mainAxisSize: MainAxisSize.min, @@ -299,8 +295,7 @@ class MessageInputState extends State { if (textEditingController.selection.isCollapsed && (s[textEditingController.selection.start - 1] == '@' || textEditingController.text - .substring( - 0, textEditingController.selection.start) + .substring(0, textEditingController.selection.start) .split(' ') .last .contains('@'))) { @@ -319,19 +314,15 @@ class MessageInputState extends State { decoration: InputDecoration( hintText: 'Write a message', prefixText: _commandEnabled ? null : ' ', - border: InputBorder.none, - focusedBorder: InputBorder.none, - enabledBorder: InputBorder.none, - errorBorder: InputBorder.none, - disabledBorder: InputBorder.none, + border: OutlineInputBorder( + borderSide: BorderSide(color: Colors.transparent) + ), contentPadding: EdgeInsets.all(8), prefixIcon: _commandEnabled ? Padding( - padding: - const EdgeInsets.symmetric(horizontal: 8.0), - child: Chip( - backgroundColor: - StreamChatTheme.of(context).accentColor, + padding: const EdgeInsets.symmetric(horizontal: 8.0), + child: Chip( + backgroundColor: StreamChatTheme.of(context).accentColor, label: Text( _chosenCommand?.name ?? "", style: TextStyle(color: Colors.white), @@ -341,7 +332,7 @@ class MessageInputState extends State { color: Colors.white, ), ), - ) + ) : null, suffixIcon: _commandEnabled ? IconButton( @@ -424,15 +415,16 @@ class MessageInputState extends State { child: Container( constraints: BoxConstraints.loose(Size.fromHeight(400)), decoration: BoxDecoration( - // boxShadow: [ - // BoxShadow( - // spreadRadius: -8, - // blurRadius: 5.0, - // offset: Offset(0, -4), - // ), - // ], - color: StreamChatTheme.of(context).primaryColor, - borderRadius: BorderRadius.circular(8.0)), + // boxShadow: [ + // BoxShadow( + // spreadRadius: -8, + // blurRadius: 5.0, + // offset: Offset(0, -4), + // ), + // ], + color: StreamChatTheme.of(context).primaryColor, + borderRadius: BorderRadius.circular(8.0) + ), child: ListView( padding: const EdgeInsets.all(0), shrinkWrap: true, @@ -443,8 +435,7 @@ class MessageInputState extends State { children: [ Padding( padding: const EdgeInsets.symmetric(horizontal: 8.0), - child: Icon(StreamIcons.lightning, - color: StreamChatTheme.of(context).accentColor), + child: Icon(StreamIcons.lightning, color: StreamChatTheme.of(context).accentColor), ), Text('Instant Commands') ], @@ -453,36 +444,31 @@ class MessageInputState extends State { ...commands .map( (c) => ListTile( - title: Text.rich( + title: Text.rich( + TextSpan( + text: '${c.name.capitalize()}', + style: TextStyle(fontWeight: FontWeight.bold), + children: [ TextSpan( - text: '${c.name.capitalize()}', - style: TextStyle(fontWeight: FontWeight.bold), - children: [ - TextSpan( - text: ' /${c.name} ${c.args}', - style: TextStyle( - fontWeight: FontWeight.w300, - ), - ), - ], + text: ' /${c.name} ${c.args}', + style: TextStyle( + fontWeight: FontWeight.w300, + ), ), - ), - trailing: CircleAvatar( - backgroundColor: - StreamChatTheme.of(context).accentColor, - child: Icon( - StreamIcons.lightning, - color: Colors.white, - size: 12.5, - ), - maxRadius: 15, - ), - //subtitle: Text(c.description), - onTap: () { - _setCommand(c); - }, + ], ), - ) + ), + trailing: CircleAvatar( + backgroundColor: StreamChatTheme.of(context).accentColor, + child: Icon(StreamIcons.lightning, color: Colors.white, size: 12.5,), + maxRadius: 15, + ), + //subtitle: Text(c.description), + onTap: () { + _setCommand(c); + }, + ), + ) .toList(), ], ), @@ -727,7 +713,7 @@ class MessageInputState extends State { child: Icon(StreamIcons.lightning), ), onTap: () { - if (_commandsOverlay == null) { + if(_commandsOverlay == null) { _commandsOverlay = _buildCommandsOverlayEntry(); Overlay.of(context).insert(_commandsOverlay); } else { @@ -1017,7 +1003,7 @@ class MessageInputState extends State { return; } - if (_commandEnabled) { + if(_commandEnabled) { text = '/${_chosenCommand.name} ' + text; } @@ -1180,4 +1166,4 @@ extension StringExtension on String { String capitalize() { return "${this[0].toUpperCase()}${this.substring(1)}"; } -} +} \ No newline at end of file From 0aba24d5a733b10f606cc24ca445fff791792b3d Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Mon, 26 Oct 2020 16:17:10 +0530 Subject: [PATCH 0204/1140] fix: attachments ui --- lib/src/message_input.dart | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 81635796..57ecc22a 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -317,6 +317,18 @@ class MessageInputState extends State { border: OutlineInputBorder( borderSide: BorderSide(color: Colors.transparent) ), + focusedBorder: OutlineInputBorder( + borderSide: BorderSide(color: Colors.transparent) + ), + enabledBorder: OutlineInputBorder( + borderSide: BorderSide(color: Colors.transparent) + ), + errorBorder: OutlineInputBorder( + borderSide: BorderSide(color: Colors.transparent) + ), + disabledBorder: OutlineInputBorder( + borderSide: BorderSide(color: Colors.transparent) + ), contentPadding: EdgeInsets.all(8), prefixIcon: _commandEnabled ? Padding( From 41450706dc971ee5be1e5a87bfedf8ccbd3b44a6 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Mon, 26 Oct 2020 16:21:35 +0530 Subject: [PATCH 0205/1140] fix: attachments ui --- lib/src/message_input.dart | 59 ++++++++++++++++++++------------------ 1 file changed, 31 insertions(+), 28 deletions(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 57ecc22a..c8457fdb 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -612,38 +612,41 @@ class MessageInputState extends State { } Widget _buildAttachments() { - return Wrap( - direction: Axis.horizontal, - children: _attachments - .map( - (attachment) => Padding( - padding: const EdgeInsets.all(8.0), - child: ClipRRect( - borderRadius: BorderRadius.circular(10), - child: Stack( - children: [ - Container( - height: 50, - width: 50, - child: _buildAttachment(attachment), - ), - _buildRemoveButton(attachment), - attachment.uploaded - ? SizedBox() - : Positioned.fill( - child: Center( - child: Padding( - padding: const EdgeInsets.all(16.0), - child: CircularProgressIndicator(), + return Container( + height: 76.0, + child: ListView( + scrollDirection: Axis.horizontal, + children: _attachments + .map( + (attachment) => Padding( + padding: const EdgeInsets.all(8.0), + child: ClipRRect( + borderRadius: BorderRadius.circular(10), + child: Stack( + children: [ + Container( + height: 50, + width: 50, + child: _buildAttachment(attachment), + ), + _buildRemoveButton(attachment), + attachment.uploaded + ? SizedBox() + : Positioned.fill( + child: Center( + child: Padding( + padding: const EdgeInsets.all(16.0), + child: CircularProgressIndicator(), + ), ), ), - ), - ], + ], + ), ), ), - ), - ) - .toList(), + ) + .toList(), + ), ); } From 1eb3de9f236cea2254579e4ba1858cec019ef60e Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Mon, 26 Oct 2020 16:25:34 +0530 Subject: [PATCH 0206/1140] fix: attachments ui --- lib/src/message_input.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index c8457fdb..c8950cf1 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -612,8 +612,8 @@ class MessageInputState extends State { } Widget _buildAttachments() { - return Container( - height: 76.0, + return LimitedBox( + maxHeight: 76.0, child: ListView( scrollDirection: Axis.horizontal, children: _attachments From 1f3328a5f88ef3741fead386470844964aede8ce Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Mon, 26 Oct 2020 16:26:39 +0530 Subject: [PATCH 0207/1140] fix: attachments ui --- lib/src/message_input.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index c8950cf1..94c83013 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -613,7 +613,7 @@ class MessageInputState extends State { Widget _buildAttachments() { return LimitedBox( - maxHeight: 76.0, + maxHeight: 80.0, child: ListView( scrollDirection: Axis.horizontal, children: _attachments From f3a9b0939f76c6c9f3023eab3d53d63b0d4c0b1c Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Mon, 26 Oct 2020 16:31:30 +0530 Subject: [PATCH 0208/1140] fix: attachments ui --- lib/src/message_input.dart | 199 +++++++++++++++++++------------------ 1 file changed, 102 insertions(+), 97 deletions(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 94c83013..9cd4617b 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -197,8 +197,7 @@ class MessageInputState extends State { direction: Axis.horizontal, crossAxisAlignment: CrossAxisAlignment.end, children: [ - if(!_commandEnabled) - _buildExpandActionsButton(), + if (!_commandEnabled) _buildExpandActionsButton(), if (widget.actionsLocation == ActionsLocation.left) ...widget.actions ?? [], _buildTextInput(context), @@ -224,16 +223,18 @@ class MessageInputState extends State { Widget _buildExpandActionsButton() { return AnimatedCrossFade( - crossFadeState: _actionsShrunk - ? CrossFadeState.showFirst - : CrossFadeState.showSecond, + crossFadeState: + _actionsShrunk ? CrossFadeState.showFirst : CrossFadeState.showSecond, firstChild: IconButton( onPressed: () { setState(() { _actionsShrunk = false; }); }, - icon: Icon(StreamIcons.circle_left, color: StreamChatTheme.of(context).accentColor,), + icon: Icon( + StreamIcons.circle_left, + color: StreamChatTheme.of(context).accentColor, + ), ), secondChild: Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, @@ -254,11 +255,10 @@ class MessageInputState extends State { maxHeight: widget.maxHeight, child: Container( decoration: BoxDecoration( - borderRadius: BorderRadius.circular(16.0), - border: Border.all( - color: Colors.grey, - ) - ), + borderRadius: BorderRadius.circular(16.0), + border: Border.all( + color: Colors.grey, + )), child: Column( mainAxisSize: MainAxisSize.min, children: [ @@ -295,7 +295,8 @@ class MessageInputState extends State { if (textEditingController.selection.isCollapsed && (s[textEditingController.selection.start - 1] == '@' || textEditingController.text - .substring(0, textEditingController.selection.start) + .substring( + 0, textEditingController.selection.start) .split(' ') .last .contains('@'))) { @@ -315,26 +316,23 @@ class MessageInputState extends State { hintText: 'Write a message', prefixText: _commandEnabled ? null : ' ', border: OutlineInputBorder( - borderSide: BorderSide(color: Colors.transparent) - ), + borderSide: BorderSide(color: Colors.transparent)), focusedBorder: OutlineInputBorder( - borderSide: BorderSide(color: Colors.transparent) - ), + borderSide: BorderSide(color: Colors.transparent)), enabledBorder: OutlineInputBorder( - borderSide: BorderSide(color: Colors.transparent) - ), + borderSide: BorderSide(color: Colors.transparent)), errorBorder: OutlineInputBorder( - borderSide: BorderSide(color: Colors.transparent) - ), + borderSide: BorderSide(color: Colors.transparent)), disabledBorder: OutlineInputBorder( - borderSide: BorderSide(color: Colors.transparent) - ), + borderSide: BorderSide(color: Colors.transparent)), contentPadding: EdgeInsets.all(8), prefixIcon: _commandEnabled ? Padding( - padding: const EdgeInsets.symmetric(horizontal: 8.0), - child: Chip( - backgroundColor: StreamChatTheme.of(context).accentColor, + padding: + const EdgeInsets.symmetric(horizontal: 8.0), + child: Chip( + backgroundColor: + StreamChatTheme.of(context).accentColor, label: Text( _chosenCommand?.name ?? "", style: TextStyle(color: Colors.white), @@ -344,7 +342,7 @@ class MessageInputState extends State { color: Colors.white, ), ), - ) + ) : null, suffixIcon: _commandEnabled ? IconButton( @@ -427,16 +425,15 @@ class MessageInputState extends State { child: Container( constraints: BoxConstraints.loose(Size.fromHeight(400)), decoration: BoxDecoration( - // boxShadow: [ - // BoxShadow( - // spreadRadius: -8, - // blurRadius: 5.0, - // offset: Offset(0, -4), - // ), - // ], - color: StreamChatTheme.of(context).primaryColor, - borderRadius: BorderRadius.circular(8.0) - ), + // boxShadow: [ + // BoxShadow( + // spreadRadius: -8, + // blurRadius: 5.0, + // offset: Offset(0, -4), + // ), + // ], + color: StreamChatTheme.of(context).primaryColor, + borderRadius: BorderRadius.circular(8.0)), child: ListView( padding: const EdgeInsets.all(0), shrinkWrap: true, @@ -447,7 +444,8 @@ class MessageInputState extends State { children: [ Padding( padding: const EdgeInsets.symmetric(horizontal: 8.0), - child: Icon(StreamIcons.lightning, color: StreamChatTheme.of(context).accentColor), + child: Icon(StreamIcons.lightning, + color: StreamChatTheme.of(context).accentColor), ), Text('Instant Commands') ], @@ -456,31 +454,36 @@ class MessageInputState extends State { ...commands .map( (c) => ListTile( - title: Text.rich( - TextSpan( - text: '${c.name.capitalize()}', - style: TextStyle(fontWeight: FontWeight.bold), - children: [ + title: Text.rich( TextSpan( - text: ' /${c.name} ${c.args}', - style: TextStyle( - fontWeight: FontWeight.w300, - ), + text: '${c.name.capitalize()}', + style: TextStyle(fontWeight: FontWeight.bold), + children: [ + TextSpan( + text: ' /${c.name} ${c.args}', + style: TextStyle( + fontWeight: FontWeight.w300, + ), + ), + ], ), - ], + ), + trailing: CircleAvatar( + backgroundColor: + StreamChatTheme.of(context).accentColor, + child: Icon( + StreamIcons.lightning, + color: Colors.white, + size: 12.5, + ), + maxRadius: 15, + ), + //subtitle: Text(c.description), + onTap: () { + _setCommand(c); + }, ), - ), - trailing: CircleAvatar( - backgroundColor: StreamChatTheme.of(context).accentColor, - child: Icon(StreamIcons.lightning, color: Colors.white, size: 12.5,), - maxRadius: 15, - ), - //subtitle: Text(c.description), - onTap: () { - _setCommand(c); - }, - ), - ) + ) .toList(), ], ), @@ -612,42 +615,44 @@ class MessageInputState extends State { } Widget _buildAttachments() { - return LimitedBox( - maxHeight: 80.0, - child: ListView( - scrollDirection: Axis.horizontal, - children: _attachments - .map( - (attachment) => Padding( - padding: const EdgeInsets.all(8.0), - child: ClipRRect( - borderRadius: BorderRadius.circular(10), - child: Stack( - children: [ - Container( - height: 50, - width: 50, - child: _buildAttachment(attachment), - ), - _buildRemoveButton(attachment), - attachment.uploaded - ? SizedBox() - : Positioned.fill( - child: Center( - child: Padding( - padding: const EdgeInsets.all(16.0), - child: CircularProgressIndicator(), - ), - ), + return _attachments.isEmpty + ? Container() + : LimitedBox( + maxHeight: 80.0, + child: ListView( + scrollDirection: Axis.horizontal, + children: _attachments + .map( + (attachment) => Padding( + padding: const EdgeInsets.all(8.0), + child: ClipRRect( + borderRadius: BorderRadius.circular(10), + child: Stack( + children: [ + Container( + height: 50, + width: 50, + child: _buildAttachment(attachment), ), - ], - ), - ), - ), - ) - .toList(), - ), - ); + _buildRemoveButton(attachment), + attachment.uploaded + ? SizedBox() + : Positioned.fill( + child: Center( + child: Padding( + padding: const EdgeInsets.all(16.0), + child: CircularProgressIndicator(), + ), + ), + ), + ], + ), + ), + ), + ) + .toList(), + ), + ); } Positioned _buildRemoveButton(_SendingAttachment attachment) { @@ -728,7 +733,7 @@ class MessageInputState extends State { child: Icon(StreamIcons.lightning), ), onTap: () { - if(_commandsOverlay == null) { + if (_commandsOverlay == null) { _commandsOverlay = _buildCommandsOverlayEntry(); Overlay.of(context).insert(_commandsOverlay); } else { @@ -1018,7 +1023,7 @@ class MessageInputState extends State { return; } - if(_commandEnabled) { + if (_commandEnabled) { text = '/${_chosenCommand.name} ' + text; } @@ -1181,4 +1186,4 @@ extension StringExtension on String { String capitalize() { return "${this[0].toUpperCase()}${this.substring(1)}"; } -} \ No newline at end of file +} From 8dff93c641a3b690f4d2dcc32edcbabbef53b78f Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Mon, 26 Oct 2020 16:37:43 +0530 Subject: [PATCH 0209/1140] fix: attachments ui --- lib/src/message_input.dart | 47 ++++++++++++++++++++------------------ 1 file changed, 25 insertions(+), 22 deletions(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 9cd4617b..65d55d6f 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -618,34 +618,37 @@ class MessageInputState extends State { return _attachments.isEmpty ? Container() : LimitedBox( - maxHeight: 80.0, + maxHeight: 76.0, child: ListView( scrollDirection: Axis.horizontal, children: _attachments .map( - (attachment) => Padding( - padding: const EdgeInsets.all(8.0), - child: ClipRRect( - borderRadius: BorderRadius.circular(10), - child: Stack( - children: [ - Container( - height: 50, - width: 50, - child: _buildAttachment(attachment), - ), - _buildRemoveButton(attachment), - attachment.uploaded - ? SizedBox() - : Positioned.fill( - child: Center( - child: Padding( - padding: const EdgeInsets.all(16.0), - child: CircularProgressIndicator(), + (attachment) => AspectRatio( + aspectRatio: 1.0, + child: Padding( + padding: const EdgeInsets.all(8.0), + child: ClipRRect( + borderRadius: BorderRadius.circular(10), + child: Stack( + children: [ + Container( + height: 50, + width: 50, + child: _buildAttachment(attachment), + ), + _buildRemoveButton(attachment), + attachment.uploaded + ? SizedBox() + : Positioned.fill( + child: Center( + child: Padding( + padding: const EdgeInsets.all(16.0), + child: CircularProgressIndicator(), + ), ), ), - ), - ], + ], + ), ), ), ), From b93a450c76e5b2e5800652df27cdf81f0d851649 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Mon, 26 Oct 2020 16:43:38 +0530 Subject: [PATCH 0210/1140] fix: attachments ui --- lib/src/message_input.dart | 42 +++++++++++++++++++------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 65d55d6f..705bc8d6 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -255,7 +255,7 @@ class MessageInputState extends State { maxHeight: widget.maxHeight, child: Container( decoration: BoxDecoration( - borderRadius: BorderRadius.circular(16.0), + borderRadius: BorderRadius.circular(32.0), border: Border.all( color: Colors.grey, )), @@ -623,32 +623,32 @@ class MessageInputState extends State { scrollDirection: Axis.horizontal, children: _attachments .map( - (attachment) => AspectRatio( - aspectRatio: 1.0, - child: Padding( - padding: const EdgeInsets.all(8.0), - child: ClipRRect( - borderRadius: BorderRadius.circular(10), - child: Stack( - children: [ - Container( + (attachment) => Padding( + padding: const EdgeInsets.all(8.0), + child: ClipRRect( + borderRadius: BorderRadius.circular(10), + child: Stack( + children: [ + AspectRatio( + aspectRatio: 1.0, + child: Container( height: 50, width: 50, child: _buildAttachment(attachment), ), - _buildRemoveButton(attachment), - attachment.uploaded - ? SizedBox() - : Positioned.fill( - child: Center( - child: Padding( - padding: const EdgeInsets.all(16.0), - child: CircularProgressIndicator(), - ), + ), + _buildRemoveButton(attachment), + attachment.uploaded + ? SizedBox() + : Positioned.fill( + child: Center( + child: Padding( + padding: const EdgeInsets.all(16.0), + child: CircularProgressIndicator(), ), ), - ], - ), + ), + ], ), ), ), From 64937ffb3768a8833f078333e22bd48388007708 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Mon, 26 Oct 2020 16:47:02 +0530 Subject: [PATCH 0211/1140] fix: attachments border ui --- lib/src/message_input.dart | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 705bc8d6..f1f8bba9 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -254,11 +254,13 @@ class MessageInputState extends State { child: LimitedBox( maxHeight: widget.maxHeight, child: Container( + clipBehavior: Clip.antiAlias, decoration: BoxDecoration( - borderRadius: BorderRadius.circular(32.0), - border: Border.all( - color: Colors.grey, - )), + borderRadius: BorderRadius.circular(32.0), + border: Border.all( + color: Colors.grey, + ), + ), child: Column( mainAxisSize: MainAxisSize.min, children: [ From 41e75ca9cd0ddfdc2a071f376c94e8ef61408d2b Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Tue, 27 Oct 2020 11:52:11 +0530 Subject: [PATCH 0212/1140] feat: Auto chip when command entered --- lib/src/message_input.dart | 46 ++++++++++++++++++++++++++------------ 1 file changed, 32 insertions(+), 14 deletions(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index f1f8bba9..e2a8f754 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -290,8 +290,24 @@ class MessageInputState extends State { _mentionsOverlay = null; if (s.startsWith('/')) { - _commandsOverlay = _buildCommandsOverlayEntry(); - Overlay.of(context).insert(_commandsOverlay); + var matchedCommandsList = StreamChannel.of(context) + .channel + .config + .commands.where((element) => element.name == s.substring(1)).toList(); + + if(matchedCommandsList.length == 1) { + _chosenCommand = matchedCommandsList[0]; + textEditingController.clear(); + _typingStarted = false; + setState(() { + _commandEnabled = true; + }); + _commandsOverlay.remove(); + _commandsOverlay = null; + } else { + _commandsOverlay = _buildCommandsOverlayEntry(); + Overlay.of(context).insert(_commandsOverlay); + } } if (textEditingController.selection.isCollapsed && @@ -440,19 +456,21 @@ class MessageInputState extends State { padding: const EdgeInsets.all(0), shrinkWrap: true, children: [ - Padding( - padding: const EdgeInsets.only(left: 8.0, top: 8.0), - child: Row( - children: [ - Padding( - padding: const EdgeInsets.symmetric(horizontal: 8.0), - child: Icon(StreamIcons.lightning, - color: StreamChatTheme.of(context).accentColor), - ), - Text('Instant Commands') - ], + if (commands.isNotEmpty) + Padding( + padding: const EdgeInsets.only(left: 8.0, top: 8.0), + child: Row( + children: [ + Padding( + padding: + const EdgeInsets.symmetric(horizontal: 8.0), + child: Icon(StreamIcons.lightning, + color: StreamChatTheme.of(context).accentColor), + ), + Text('Instant Commands') + ], + ), ), - ), ...commands .map( (c) => ListTile( From e48fdef1b07b80cb68db7d818b6c2dc2d52a2ca1 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Tue, 27 Oct 2020 12:00:13 +0530 Subject: [PATCH 0213/1140] fix: Button is no longer blue when chip is auto added --- lib/src/message_input.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index e2a8f754..2547c9cd 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -298,7 +298,7 @@ class MessageInputState extends State { if(matchedCommandsList.length == 1) { _chosenCommand = matchedCommandsList[0]; textEditingController.clear(); - _typingStarted = false; + _messageIsPresent = false; setState(() { _commandEnabled = true; }); From bbb71ec47fb6d1ba349654e87c04a9bc4ee7ba78 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Tue, 27 Oct 2020 13:28:17 +0530 Subject: [PATCH 0214/1140] feat: Added sticky header to display position data --- lib/src/message_list_view.dart | 278 ++++++++++++++++++--------------- pubspec.yaml | 1 + 2 files changed, 149 insertions(+), 130 deletions(-) diff --git a/lib/src/message_list_view.dart b/lib/src/message_list_view.dart index 7c529f95..42b434fd 100644 --- a/lib/src/message_list_view.dart +++ b/lib/src/message_list_view.dart @@ -6,6 +6,7 @@ import 'package:stream_chat/stream_chat.dart'; import 'package:stream_chat_flutter/src/message_widget.dart'; import 'package:stream_chat_flutter/src/system_message.dart'; import 'package:visibility_detector/visibility_detector.dart'; +import 'package:widgets_visibility_provider/widgets_visibility_provider.dart'; import '../stream_chat_flutter.dart'; import 'date_divider.dart'; @@ -149,150 +150,167 @@ class _MessageListViewState extends State { List _newMessageList = []; Function _onThreadTap; bool _showScrollToBottom = false; + var positionData; @override Widget build(BuildContext context) { final streamChannel = StreamChannel.of(context); /// TODO: find a better solution when (https://github.com/flutter/flutter/issues/21023) is fixed - return Stack( - children: [ - NotificationListener( - onNotification: (_) { - if (_scrollController.offset < 150 && _newMessageList.isNotEmpty) { - setState(() { - _messages.insertAll(0, _newMessageList); - _newMessageList.clear(); - }); - } - return true; - }, - child: ListView.custom( - key: Key('messageListView'), - physics: widget.scrollPhysics, - keyboardDismissBehavior: widget.keyboardDismissBehavior, - controller: _scrollController, - reverse: true, - childrenDelegate: SliverChildBuilderDelegate( - (context, i) { - if (i == _messages.length + 1) { - if (widget.parentMessage != null) { - if (widget.parentMessageBuilder != null) { - return widget.parentMessageBuilder( - context, - widget.parentMessage, - ); - } else { - return Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - buildParentMessage(widget.parentMessage), - Padding( - padding: const EdgeInsets.symmetric(horizontal: 32), - child: Container( - padding: const EdgeInsets.all(8), - child: Text( - 'Start of thread', - textAlign: TextAlign.center, - ), - color: - Theme.of(context).accentColor.withAlpha(50), - ), - ), - ], - ); - } - } else { - return SizedBox(); - } - } - - if (i == _messages.length) { - return _buildLoadingIndicator(streamChannel); - } - final message = _messages[i]; - final nextMessage = i > 0 ? _messages[i - 1] : null; - - Widget messageWidget; - - if (i == 0) { - messageWidget = _buildBottomMessage( - context, - message, - _messages, - streamChannel, - ); - } else if (i == _messages.length - 1) { - messageWidget = _buildTopMessage( - context, - message, - _messages, - streamChannel, - ); - } else { - if (widget.messageBuilder != null) { - messageWidget = Builder( - key: ValueKey('MESSAGE-${message.id}'), - builder: (_) => widget.messageBuilder( + return WidgetsVisibilityProvider( + condition: (c) => null, + child: Stack( + children: [ + NotificationListener( + onNotification: (_) { + if (_scrollController.offset < 150 && _newMessageList.isNotEmpty) { + setState(() { + _messages.insertAll(0, _newMessageList); + _newMessageList.clear(); + }); + } + return true; + }, + child: ListView.custom( + key: Key('messageListView'), + physics: widget.scrollPhysics, + keyboardDismissBehavior: widget.keyboardDismissBehavior, + controller: _scrollController, + reverse: true, + childrenDelegate: SliverChildBuilderDelegate( + (context, i) { + if (i == _messages.length + 1) { + if (widget.parentMessage != null) { + if (widget.parentMessageBuilder != null) { + return widget.parentMessageBuilder( context, - MessageDetails( - context, - message, - _messages, - i, - ), - _messages), + widget.parentMessage, + ); + } else { + return Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + buildParentMessage(widget.parentMessage), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 32), + child: Container( + padding: const EdgeInsets.all(8), + child: Text( + 'Start of thread', + textAlign: TextAlign.center, + ), + color: + Theme.of(context).accentColor.withAlpha(50), + ), + ), + ], + ); + } + } else { + return SizedBox(); + } + } + + if (i == _messages.length) { + return _buildLoadingIndicator(streamChannel); + } + final message = _messages[i]; + final nextMessage = i > 0 ? _messages[i - 1] : null; + + Widget messageWidget; + + if (i == 0) { + messageWidget = _buildBottomMessage( + context, + message, + _messages, + streamChannel, + ); + } else if (i == _messages.length - 1) { + messageWidget = _buildTopMessage( + context, + message, + _messages, + streamChannel, ); } else { - messageWidget = buildMessage(message, _messages, i); + if (widget.messageBuilder != null) { + messageWidget = Builder( + key: ValueKey('MESSAGE-${message.id}'), + builder: (_) => widget.messageBuilder( + context, + MessageDetails( + context, + message, + _messages, + i, + ), + _messages), + ); + } else { + 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(), - ), - ), - ], - ); - } + 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; - }, - childCount: _messages.length + 2, - findChildIndexCallback: (key) { - final ValueKey valueKey = key; - final index = _messages - .indexWhere((m) => 'MESSAGE-${m.id}' == valueKey.value); - return index != -1 ? index : null; - }, + return VisibleNotifierWidget(child: messageWidget); + }, + childCount: _messages.length + 2, + findChildIndexCallback: (key) { + final ValueKey valueKey = key; + final index = _messages + .indexWhere((m) => 'MESSAGE-${m.id}' == valueKey.value); + return index != -1 ? index : null; + }, + ), ), ), - ), - if (widget.showScrollToBottom) - StreamBuilder( - stream: streamChannel.channel.on( - EventType.messageNew, - ), - builder: (context, _) { - if (!_showScrollToBottom || - streamChannel.channel.state.unreadCount == 0) { - return SizedBox(); - } - return _buildScrollToBottom(streamChannel); - }), - ], + if (widget.showScrollToBottom) + StreamBuilder( + stream: streamChannel.channel.on( + EventType.messageNew, + ), + builder: (context, _) { + if (!_showScrollToBottom || + streamChannel.channel.state.unreadCount == 0) { + return SizedBox(); + } + return _buildScrollToBottom(streamChannel); + }), + Positioned( + top: 20.0, + child: WidgetsVisibilityListener( + listener: (context, event) { + setState(() { + positionData = event.positionDataList.first.startPosition; + }); + }, + child: Chip( + label: Text(positionData.toString()), + ), + ), + ), + ], + ), ); } diff --git a/pubspec.yaml b/pubspec.yaml index 4ae31b50..26144e64 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -30,6 +30,7 @@ dependencies: flutter_slidable: ^0.5.4 carousel_slider: ^2.2.1 clipboard: ^0.1.2+8 + widgets_visibility_provider: ^2.0.2 flutter: fonts: From d93dfb5af4014cac52f6433bf5edd2b36bfdbba9 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Tue, 27 Oct 2020 13:37:00 +0530 Subject: [PATCH 0215/1140] feat: Added sticky header to display position data --- lib/src/message_list_view.dart | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/lib/src/message_list_view.dart b/lib/src/message_list_view.dart index 42b434fd..0eaab75b 100644 --- a/lib/src/message_list_view.dart +++ b/lib/src/message_list_view.dart @@ -160,6 +160,7 @@ class _MessageListViewState extends State { return WidgetsVisibilityProvider( condition: (c) => null, child: Stack( + alignment: Alignment.center, children: [ NotificationListener( onNotification: (_) { @@ -301,13 +302,13 @@ class _MessageListViewState extends State { child: WidgetsVisibilityListener( listener: (context, event) { setState(() { - positionData = event.positionDataList.first.startPosition; + positionData = event.positionDataList.isNotEmpty ? event.positionDataList[0] : null; }); }, - child: Chip( - label: Text(positionData.toString()), + child: DateDivider( + dateTime: _messages[positionData].createdAt.toLocal(), + ), ), - ), ), ], ), From 6de4ee9963e2d447e7c8f9647271b60f6da5f642 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Tue, 27 Oct 2020 13:50:16 +0530 Subject: [PATCH 0216/1140] feat: Added sticky header to display position data --- lib/src/message_list_view.dart | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/src/message_list_view.dart b/lib/src/message_list_view.dart index 0eaab75b..83fbd75f 100644 --- a/lib/src/message_list_view.dart +++ b/lib/src/message_list_view.dart @@ -273,7 +273,7 @@ class _MessageListViewState extends State { ); } - return VisibleNotifierWidget(child: messageWidget); + return VisibleNotifierWidget(child: messageWidget, data: i,); }, childCount: _messages.length + 2, findChildIndexCallback: (key) { @@ -297,12 +297,13 @@ class _MessageListViewState extends State { } return _buildScrollToBottom(streamChannel); }), + if(positionData != null) Positioned( top: 20.0, child: WidgetsVisibilityListener( listener: (context, event) { setState(() { - positionData = event.positionDataList.isNotEmpty ? event.positionDataList[0] : null; + positionData = event.positionDataList.isNotEmpty ? event.positionDataList[0].data : null; }); }, child: DateDivider( From 1cb007ec2da153eebbe15fe562696900c8c69665 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Tue, 27 Oct 2020 14:14:00 +0530 Subject: [PATCH 0217/1140] feat: Added sticky header to display position data --- lib/src/message_list_view.dart | 34 +++++++++++++++++++--------------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/lib/src/message_list_view.dart b/lib/src/message_list_view.dart index 83fbd75f..e3502539 100644 --- a/lib/src/message_list_view.dart +++ b/lib/src/message_list_view.dart @@ -150,7 +150,6 @@ class _MessageListViewState extends State { List _newMessageList = []; Function _onThreadTap; bool _showScrollToBottom = false; - var positionData; @override Widget build(BuildContext context) { @@ -164,7 +163,8 @@ class _MessageListViewState extends State { children: [ NotificationListener( onNotification: (_) { - if (_scrollController.offset < 150 && _newMessageList.isNotEmpty) { + if (_scrollController.offset < 150 && + _newMessageList.isNotEmpty) { setState(() { _messages.insertAll(0, _newMessageList); _newMessageList.clear(); @@ -193,7 +193,8 @@ class _MessageListViewState extends State { children: [ buildParentMessage(widget.parentMessage), Padding( - padding: const EdgeInsets.symmetric(horizontal: 32), + padding: + const EdgeInsets.symmetric(horizontal: 32), child: Container( padding: const EdgeInsets.all(8), child: Text( @@ -273,7 +274,10 @@ class _MessageListViewState extends State { ); } - return VisibleNotifierWidget(child: messageWidget, data: i,); + return VisibleNotifierWidget( + child: messageWidget, + data: i, + ); }, childCount: _messages.length + 2, findChildIndexCallback: (key) { @@ -297,19 +301,19 @@ class _MessageListViewState extends State { } return _buildScrollToBottom(streamChannel); }), - if(positionData != null) Positioned( top: 20.0, - child: WidgetsVisibilityListener( - listener: (context, event) { - setState(() { - positionData = event.positionDataList.isNotEmpty ? event.positionDataList[0].data : null; - }); - }, - child: DateDivider( - dateTime: _messages[positionData].createdAt.toLocal(), - ), - ), + child: WidgetsVisibilityConsumer( + builder: (context, event) { + if(event.positionDataList == null || event.positionDataList.isEmpty) { + return Container(); + } + + return DateDivider( + dateTime: _messages[event.positionDataList[0].data].createdAt.toLocal(), + ); + }, + ), ), ], ), From 42d758264af3a53ebf60b2b4b89b65e4c4836399 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Tue, 27 Oct 2020 14:27:56 +0530 Subject: [PATCH 0218/1140] fix: Corrected date header --- lib/src/message_list_view.dart | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/src/message_list_view.dart b/lib/src/message_list_view.dart index e3502539..e833f2e1 100644 --- a/lib/src/message_list_view.dart +++ b/lib/src/message_list_view.dart @@ -304,13 +304,14 @@ class _MessageListViewState extends State { Positioned( top: 20.0, child: WidgetsVisibilityConsumer( + listener: (context, event,) {}, builder: (context, event) { if(event.positionDataList == null || event.positionDataList.isEmpty) { return Container(); } return DateDivider( - dateTime: _messages[event.positionDataList[0].data].createdAt.toLocal(), + dateTime: _messages[event.positionDataList.last.data].createdAt.toLocal(), ); }, ), From ba37258427b48a7b8fa99b2821fcb77df5c756f9 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Tue, 27 Oct 2020 09:58:15 +0100 Subject: [PATCH 0219/1140] 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 0220/1140] 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 2d169418c4c8cb103d70e355d4ba8a572b38001e Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Tue, 27 Oct 2020 15:23:18 +0530 Subject: [PATCH 0221/1140] fix: Replace send with check for edit --- lib/src/message_input.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 2547c9cd..c2041c56 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -1029,7 +1029,7 @@ class MessageInputState extends State { child: Transform.rotate( angle: -pi / 2, child: Icon( - StreamIcons.send_message, + widget.editMessage == null ? StreamIcons.send_message : StreamIcons.check, color: StreamChatTheme.of(context).accentColor, ), ), From e181a7ba5825b0063a5b1883f3fab60c4eb1cb5b Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Tue, 27 Oct 2020 15:26:55 +0530 Subject: [PATCH 0222/1140] fix: Replace send with check for edit --- lib/src/message_input.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index c2041c56..9e8f68a2 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -1027,7 +1027,7 @@ class MessageInputState extends State { sendMessage(); }, child: Transform.rotate( - angle: -pi / 2, + angle: widget.editMessage == null ? -pi / 2 : 0, child: Icon( widget.editMessage == null ? StreamIcons.send_message : StreamIcons.check, color: StreamChatTheme.of(context).accentColor, From 5b9c3ca5b7673ba300c97b4e0afc8d96697208ec Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Tue, 27 Oct 2020 15:30:37 +0530 Subject: [PATCH 0223/1140] fix: Replace send with check for edit --- lib/src/message_input.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 9e8f68a2..6657d812 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -1029,7 +1029,7 @@ class MessageInputState extends State { child: Transform.rotate( angle: widget.editMessage == null ? -pi / 2 : 0, child: Icon( - widget.editMessage == null ? StreamIcons.send_message : StreamIcons.check, + widget.editMessage == null ? StreamIcons.send_message : StreamIcons.check_send, color: StreamChatTheme.of(context).accentColor, ), ), From f0ec3415dce6e90d8ca9d170effa2a52699be2cf Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Tue, 27 Oct 2020 16:03:34 +0530 Subject: [PATCH 0224/1140] feat: Add dm message for thread --- lib/src/message_input.dart | 29 ++++++++++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 6657d812..a3d93859 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -171,6 +171,7 @@ class MessageInputState extends State { Command _chosenCommand; bool _actionsShrunk = false; + bool _sendAsDm = false; /// The editing controller passed to the input TextField TextEditingController textEditingController; @@ -184,9 +185,19 @@ class MessageInputState extends State { _focusNode.unfocus(); } }, - child: Padding( - padding: const EdgeInsets.all(8.0), - child: _buildTextField(context), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Padding( + padding: const EdgeInsets.all(8.0), + child: _buildTextField(context), + ), + if(widget.parentMessage != null) + Padding( + padding: const EdgeInsets.all(8.0), + child: _buildDmCheckbox(), + ), + ], ), ), ); @@ -208,6 +219,18 @@ class MessageInputState extends State { ); } + Widget _buildDmCheckbox() { + return Row( + children: [ + Checkbox(value: _sendAsDm, onChanged: (val) => setState(() {_sendAsDm = val;})), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 8.0), + child: Text('Send also as direct message'), + ), + ], + ); + } + AnimatedCrossFade _animateSendButton(BuildContext context) { return AnimatedCrossFade( crossFadeState: ((_messageIsPresent || _attachments.isNotEmpty) && From cdc549f24eff7b489c57f9ce1a578edc29cb0329 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Tue, 27 Oct 2020 16:56:19 +0530 Subject: [PATCH 0225/1140] feat: Added sending thread messages and fixed padding issues --- lib/src/message_input.dart | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index a3d93859..34901c92 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -194,7 +194,7 @@ class MessageInputState extends State { ), if(widget.parentMessage != null) Padding( - padding: const EdgeInsets.all(8.0), + padding: const EdgeInsets.symmetric(horizontal: 8.0), child: _buildDmCheckbox(), ), ], @@ -206,7 +206,7 @@ class MessageInputState extends State { Flex _buildTextField(BuildContext context) { return Flex( direction: Axis.horizontal, - crossAxisAlignment: CrossAxisAlignment.end, + crossAxisAlignment: CrossAxisAlignment.center, children: [ if (!_commandEnabled) _buildExpandActionsButton(), if (widget.actionsLocation == ActionsLocation.left) @@ -792,11 +792,12 @@ class MessageInputState extends State { } Widget _buildAttachmentButton() { + var padding = widget.editMessage == null ? 4.0 : 8.0; return Center( child: InkWell( child: Padding( - padding: const EdgeInsets.only( - left: 8.0, right: 4.0, 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: () { @@ -1082,6 +1083,7 @@ class MessageInputState extends State { _messageIsPresent = false; _typingStarted = false; _commandEnabled = false; + _sendAsDm = false; }); _commandsOverlay?.remove(); @@ -1107,6 +1109,7 @@ class MessageInputState extends State { attachments: _getAttachments(attachments).toList(), mentionedUsers: _mentionedUsers.where((u) => text.contains('@${u.name}')).toList(), + showInChannel: widget.parentMessage != null ? _sendAsDm : null, ); } From eb27807aa5109d3b094d28cdc5049a721e34eab9 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Tue, 27 Oct 2020 18:15:46 +0530 Subject: [PATCH 0226/1140] fix: Fixed DM --- lib/src/message_input.dart | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 34901c92..30910924 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -1083,7 +1083,6 @@ class MessageInputState extends State { _messageIsPresent = false; _typingStarted = false; _commandEnabled = false; - _sendAsDm = false; }); _commandsOverlay?.remove(); From e8411d3aa4fe39cb7907da22f5ea6397d16cf5c8 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Tue, 27 Oct 2020 16:15:50 +0100 Subject: [PATCH 0227/1140] 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 0228/1140] 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 0229/1140] 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 b22cf7bdf36f88aeb2b07cf483c973cdc1f4f1a1 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Wed, 28 Oct 2020 13:24:41 +0530 Subject: [PATCH 0230/1140] fix: Fixed Visiblity --- lib/src/message_list_view.dart | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/lib/src/message_list_view.dart b/lib/src/message_list_view.dart index e833f2e1..da260b0e 100644 --- a/lib/src/message_list_view.dart +++ b/lib/src/message_list_view.dart @@ -257,20 +257,23 @@ class _MessageListViewState extends State { 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 VisibleNotifierWidget( + data: i, + child: 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(), + ), + ), + ], + ), ); } From 34375127729e5889c035e6a799ab64bf4aab4e68 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Wed, 28 Oct 2020 14:11:04 +0530 Subject: [PATCH 0231/1140] fix: qa fixes --- lib/src/message_input.dart | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 30910924..fffe90b5 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -354,7 +354,7 @@ class MessageInputState extends State { autofocus: false, textAlignVertical: TextAlignVertical.center, decoration: InputDecoration( - hintText: 'Write a message', + hintText: (_commandEnabled && _chosenCommand.name == 'giphy') ? 'Search GIFs' :'Write a message', prefixText: _commandEnabled ? null : ' ', border: OutlineInputBorder( borderSide: BorderSide(color: Colors.transparent)), @@ -461,6 +461,9 @@ class MessageInputState extends State { padding: const EdgeInsets.all(8.0), child: Card( elevation: 2.0, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8.0), + ), color: StreamChatTheme.of(context).primaryColor, clipBehavior: Clip.antiAlias, child: Container( @@ -519,7 +522,7 @@ class MessageInputState extends State { color: Colors.white, size: 12.5, ), - maxRadius: 15, + maxRadius: 12, ), //subtitle: Text(c.description), onTap: () { @@ -776,7 +779,7 @@ class MessageInputState extends State { child: Padding( padding: const EdgeInsets.only( left: 4.0, right: 8.0, top: 8.0, bottom: 8.0), - child: Icon(StreamIcons.lightning), + child: Icon(StreamIcons.lightning, color: Color(0xFF000000).withAlpha(128),), ), onTap: () { if (_commandsOverlay == null) { @@ -798,7 +801,7 @@ class MessageInputState extends State { child: Padding( padding: EdgeInsets.only( left: 8.0, right: padding, top: 8.0, bottom: 8.0), - child: Icon(StreamIcons.attach), + child: Icon(StreamIcons.attach, color: Color(0xFF000000).withAlpha(128),), ), onTap: () { showAttachmentModal(); From e16ad47e59e90fe3868d5a33a7d5a42e378569f9 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Wed, 28 Oct 2020 14:29:20 +0530 Subject: [PATCH 0232/1140] fix: qa fixes --- lib/src/message_input.dart | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index fffe90b5..81649764 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -573,6 +573,9 @@ class MessageInputState extends State { margin: EdgeInsets.all(8.0), elevation: 2.0, color: StreamChatTheme.of(context).primaryColor, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8.0), + ), clipBehavior: Clip.antiAlias, child: Container( constraints: BoxConstraints.loose(Size.fromHeight(400)), @@ -602,7 +605,7 @@ class MessageInputState extends State { '${m.user.name}', style: TextStyle(fontWeight: FontWeight.bold), ), - subtitle: Text('${m.userId}'), + subtitle: Text('@${m.userId}'), trailing: Icon( Icons.alternate_email, color: StreamChatTheme.of(context).accentColor, From 3f619fe79c4a8a95f52c70896781d13738c53cee Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Wed, 28 Oct 2020 10:39:55 +0100 Subject: [PATCH 0233/1140] 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 e2164c3cef380a210376cf2eee3b840709ca2e20 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Wed, 28 Oct 2020 15:33:23 +0530 Subject: [PATCH 0234/1140] fix: qa fixes --- lib/src/message_input.dart | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 81649764..e3ab5574 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -607,7 +607,7 @@ class MessageInputState extends State { ), subtitle: Text('@${m.userId}'), trailing: Icon( - Icons.alternate_email, + StreamIcons.at_mention, color: StreamChatTheme.of(context).accentColor, ), onTap: () { @@ -1037,7 +1037,7 @@ class MessageInputState extends State { sendMessage(); }, child: Icon( - StreamIcons.send_message, + _getIdleSendIcon(), color: Colors.grey, ), )), @@ -1059,7 +1059,7 @@ 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, + _getSendIcon(), color: StreamChatTheme.of(context).accentColor, ), ), @@ -1069,6 +1069,24 @@ class MessageInputState extends State { ); } + IconData _getIdleSendIcon() { + if (_commandEnabled) { + return StreamIcons.search; + } else { + return StreamIcons.send_message; + } + } + + IconData _getSendIcon() { + if(widget.editMessage != null) { + return StreamIcons.check_send; + } else if (_commandEnabled) { + return StreamIcons.search; + } else { + return StreamIcons.send_message; + } + } + /// Sends the current message void sendMessage() async { var text = textEditingController.text.trim(); From 5ec32086d3bb06840e9c4b0104aff6aff998f1b0 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Wed, 28 Oct 2020 11:05:58 +0100 Subject: [PATCH 0235/1140] 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 8b635b440e93e91b21528bb1eb56ab6c0b7b040d Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Wed, 28 Oct 2020 15:52:13 +0530 Subject: [PATCH 0236/1140] fix: qa fixes --- lib/src/message_input.dart | 62 +++++++++++++++++++++++++------------- 1 file changed, 41 insertions(+), 21 deletions(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index e3ab5574..b3744152 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; @@ -354,7 +360,10 @@ class MessageInputState extends State { autofocus: false, textAlignVertical: TextAlignVertical.center, decoration: InputDecoration( - hintText: (_commandEnabled && _chosenCommand.name == 'giphy') ? 'Search GIFs' :'Write a message', + hintText: + (_commandEnabled && _chosenCommand.name == 'giphy') + ? 'Search GIFs' + : 'Write a message', prefixText: _commandEnabled ? null : ' ', border: OutlineInputBorder( borderSide: BorderSide(color: Colors.transparent)), @@ -782,7 +791,10 @@ class MessageInputState extends State { child: Padding( padding: const EdgeInsets.only( left: 4.0, right: 8.0, top: 8.0, bottom: 8.0), - child: Icon(StreamIcons.lightning, color: Color(0xFF000000).withAlpha(128),), + child: Icon( + StreamIcons.lightning, + color: Color(0xFF000000).withAlpha(128), + ), ), onTap: () { if (_commandsOverlay == null) { @@ -802,9 +814,12 @@ class MessageInputState extends State { return Center( child: InkWell( child: Padding( - padding: EdgeInsets.only( - left: 8.0, right: padding, top: 8.0, bottom: 8.0), - child: Icon(StreamIcons.attach, color: Color(0xFF000000).withAlpha(128),), + padding: + EdgeInsets.only(left: 8.0, right: padding, top: 8.0, bottom: 8.0), + child: Icon( + StreamIcons.attach, + color: Color(0xFF000000).withAlpha(128), + ), ), onTap: () { showAttachmentModal(); @@ -1056,13 +1071,7 @@ class MessageInputState extends State { onTap: () { sendMessage(); }, - child: Transform.rotate( - angle: widget.editMessage == null ? -pi / 2 : 0, - child: Icon( - _getSendIcon(), - color: StreamChatTheme.of(context).accentColor, - ), - ), + child: _getSendIcon(), ), ), ), @@ -1077,13 +1086,24 @@ class MessageInputState extends State { } } - IconData _getSendIcon() { - if(widget.editMessage != null) { - return StreamIcons.check_send; + Widget _getSendIcon() { + if (widget.editMessage != null) { + return Icon( + StreamIcons.check_send, + color: StreamChatTheme.of(context).accentColor, + ); } else if (_commandEnabled) { - return StreamIcons.search; + return Icon( + StreamIcons.search, + color: StreamChatTheme.of(context).accentColor, + ); } else { - return StreamIcons.send_message; + return Transform.rotate( + angle: -pi / 2, + child: Icon( + StreamIcons.send_message, + color: StreamChatTheme.of(context).accentColor, + )); } } From 5087aecff450e949464126f7d45ec9b91449550c Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Wed, 28 Oct 2020 16:01:18 +0530 Subject: [PATCH 0237/1140] fix: qa fixes --- lib/src/message_input.dart | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index b3744152..9e4998d8 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -223,10 +223,14 @@ class MessageInputState extends State { return Row( children: [ Checkbox( - value: _sendAsDm, - onChanged: (val) => setState(() { - _sendAsDm = val; - })), + value: _sendAsDm, + onChanged: (val) => setState( + () { + _sendAsDm = val; + }, + ), + activeColor: Color(0xFF006CFF), + ), Padding( padding: const EdgeInsets.symmetric(horizontal: 8.0), child: Text('Send also as direct message'), From bb46710f2416b5409160ee56daf470b35b3140e6 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Wed, 28 Oct 2020 11:42:02 +0100 Subject: [PATCH 0238/1140] modify condition --- example/ios/Flutter/.last_build_id | 2 +- example/pubspec.yaml | 2 +- lib/src/message_list_view.dart | 46 +++++++++++++++++++++--------- 3 files changed, 34 insertions(+), 16 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/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 da260b0e..bb0f98c0 100644 --- a/lib/src/message_list_view.dart +++ b/lib/src/message_list_view.dart @@ -157,7 +157,9 @@ class _MessageListViewState extends State { /// TODO: find a better solution when (https://github.com/flutter/flutter/issues/21023) is fixed return WidgetsVisibilityProvider( - condition: (c) => null, + condition: (positionData) => + positionData.endPosition >= 20 && + positionData.startPosition <= positionData.viewportSize, child: Stack( alignment: Alignment.center, children: [ @@ -257,14 +259,24 @@ class _MessageListViewState extends State { if (nextMessage != null && !Jiffy(message.createdAt.toLocal()) .isSame(nextMessage.createdAt.toLocal(), Units.DAY)) { - return VisibleNotifierWidget( - data: i, - child: Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - messageWidget, - Padding( - padding: const EdgeInsets.symmetric(vertical: 12.0), + return Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + messageWidget, + Padding( + padding: const EdgeInsets.symmetric(vertical: 12.0), + child: VisibleNotifierWidget( + condition: ( + ScrollNotification previousNotification, + PositionData previousPositionData, + ScrollNotification currentNotification, + PositionData currentPositionData, + ) { + print( + 'currentPositionData.endPosition: ${currentPositionData.endPosition}'); + return true; + }, + data: i, child: widget.dateDividerBuilder != null ? widget.dateDividerBuilder( nextMessage.createdAt.toLocal()) @@ -272,8 +284,8 @@ class _MessageListViewState extends State { dateTime: nextMessage.createdAt.toLocal(), ), ), - ], - ), + ), + ], ); } @@ -307,14 +319,20 @@ class _MessageListViewState extends State { Positioned( top: 20.0, child: WidgetsVisibilityConsumer( - listener: (context, event,) {}, + listener: ( + context, + event, + ) {}, builder: (context, event) { - if(event.positionDataList == null || event.positionDataList.isEmpty) { + if (event.positionDataList == null || + event.positionDataList.isEmpty) { return Container(); } return DateDivider( - dateTime: _messages[event.positionDataList.last.data].createdAt.toLocal(), + dateTime: _messages[event.positionDataList.last.data] + .createdAt + .toLocal(), ); }, ), From d5f23549f456b426ad4fe7b5fe5f2f665b2997d8 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Wed, 28 Oct 2020 11:42:09 +0100 Subject: [PATCH 0239/1140] modify condition --- lib/src/message_actions_modal.dart | 7 +++++-- lib/src/message_input.dart | 22 +++++++++++++++------- 2 files changed, 20 insertions(+), 9 deletions(-) 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, ), ), From f361d7f7f5a80b4abf8167be7d9e6d0135f60578 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Wed, 28 Oct 2020 14:12:59 +0100 Subject: [PATCH 0240/1140] 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 0241/1140] 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 0242/1140] 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 0243/1140] 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" From f858cbf46044e2ec478485e7960fd0844d966abc Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Thu, 29 Oct 2020 15:12:46 +0530 Subject: [PATCH 0244/1140] fix: qa fixes --- images/giphy_icon.png | Bin 0 -> 400 bytes lib/src/message_input.dart | 6 ++++++ pubspec.yaml | 2 ++ 3 files changed, 8 insertions(+) create mode 100644 images/giphy_icon.png diff --git a/images/giphy_icon.png b/images/giphy_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..ea99e8341848dcbb49d654ff1847818bb301cf92 GIT binary patch literal 400 zcmV;B0dM|^P)xRK7oUqgCh17d;%Xq#3#_r!AWp;a1b4&P(?>Wp+hP3 z51~VHPf!1(ZFq-TZqD{20kU0~*(*mS~qP@%xE^K=!GnI-@@WFcR1u(CkFdy`sC*C;@Zdf(X!+WEF zj_*ekOxFp8L1^OW#Bm-=C7iLLk|2p^*Tq+}Ikeh0j`8DdLHP$s4B~#bTBx#Q;BeR7 z)eI)^TJqZkWYXC+4Pw{;gPCpQ13(%`=OGdcJ`W%@ioBj0baEi~67BmFByp=-NI!7# uGHx5*#vp6MKRCiN=+#dc|9??~b?E~xRAC+pj+ux60000 { enabled: _inputEnabled, minLines: null, maxLines: null, + expands: true, onSubmitted: (_) { sendMessage(); }, @@ -513,6 +514,11 @@ class MessageInputState extends State { ...commands .map( (c) => ListTile( + leading: c.name == 'giphy' ? CircleAvatar( + backgroundColor: Colors.black, + child: Image.asset('images/giphy_icon.png'), + maxRadius: 12.0, + ) : null, title: Text.rich( TextSpan( text: '${c.name.capitalize()}', diff --git a/pubspec.yaml b/pubspec.yaml index edd19589..a9285b4c 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -32,6 +32,8 @@ dependencies: clipboard: ^0.1.2+8 flutter: + assets: + - images/giphy_icon.png fonts: - family: stream-icons fonts: From 76f5b0a0607e60e20cf127479a9454460445666e Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Thu, 29 Oct 2020 15:18:45 +0530 Subject: [PATCH 0245/1140] fix: qa fixes --- lib/src/message_input.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 0b84e823..116b66d5 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -514,7 +514,7 @@ class MessageInputState extends State { ...commands .map( (c) => ListTile( - leading: c.name == 'giphy' ? CircleAvatar( + leading: c.name == '/giphy' ? CircleAvatar( backgroundColor: Colors.black, child: Image.asset('images/giphy_icon.png'), maxRadius: 12.0, From d9d0bba99946594ebc8a48142e74dd9bf822f2a0 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Thu, 29 Oct 2020 15:20:45 +0530 Subject: [PATCH 0246/1140] fix: qa fixes --- lib/src/message_input.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 116b66d5..0b84e823 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -514,7 +514,7 @@ class MessageInputState extends State { ...commands .map( (c) => ListTile( - leading: c.name == '/giphy' ? CircleAvatar( + leading: c.name == 'giphy' ? CircleAvatar( backgroundColor: Colors.black, child: Image.asset('images/giphy_icon.png'), maxRadius: 12.0, From dbb4b37161c96bf60a26ab39c17fe9f0ffedd242 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Thu, 29 Oct 2020 15:40:30 +0530 Subject: [PATCH 0247/1140] fix: textfield height issues solved --- lib/src/message_input.dart | 45 +++++++++++++++++++------------------- 1 file changed, 23 insertions(+), 22 deletions(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 0b84e823..56a3989a 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -282,26 +282,25 @@ class MessageInputState extends State { Expanded _buildTextInput(BuildContext context) { return Expanded( child: Center( - child: LimitedBox( - maxHeight: widget.maxHeight, - child: Container( - clipBehavior: Clip.antiAlias, - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(32.0), - border: Border.all( - color: Colors.grey, - ), + child: Container( + clipBehavior: Clip.antiAlias, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(32.0), + border: Border.all( + color: Colors.grey, ), - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - _buildAttachments(), - TextField( + ), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + _buildAttachments(), + LimitedBox( + maxHeight: widget.maxHeight, + child: TextField( key: Key('messageInputText'), enabled: _inputEnabled, minLines: null, maxLines: null, - expands: true, onSubmitted: (_) { sendMessage(); }, @@ -412,8 +411,8 @@ class MessageInputState extends State { ), textCapitalization: TextCapitalization.sentences, ), - ], - ), + ) + ], ), ), ), @@ -514,11 +513,13 @@ class MessageInputState extends State { ...commands .map( (c) => ListTile( - leading: c.name == 'giphy' ? CircleAvatar( - backgroundColor: Colors.black, - child: Image.asset('images/giphy_icon.png'), - maxRadius: 12.0, - ) : null, + leading: c.name == 'giphy' + ? CircleAvatar( + backgroundColor: Colors.black, + child: Image.asset('images/giphy_icon.png'), + maxRadius: 12.0, + ) + : null, title: Text.rich( TextSpan( text: '${c.name.capitalize()}', From ccd70a2a7aa40636004de5f1b1d8654f155e8160 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Thu, 29 Oct 2020 15:54:13 +0530 Subject: [PATCH 0248/1140] fix: giphy fixes --- lib/src/message_input.dart | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 56a3989a..631bf9ef 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -516,7 +516,12 @@ class MessageInputState extends State { leading: c.name == 'giphy' ? CircleAvatar( backgroundColor: Colors.black, - child: Image.asset('images/giphy_icon.png'), + child: Image.asset( + 'images/giphy_icon.png', + package: 'stream_chat_flutter', + width: 16.0, + height: 16.0, + ), maxRadius: 12.0, ) : null, From c9c790e120604cfa3ba65846e1aa016b24bee12d Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Thu, 29 Oct 2020 12:24:40 +0100 Subject: [PATCH 0249/1140] fix ios staus bar icon colors --- analysis_options.yaml | 126 +++++++++++++-------------- example/ios/Podfile.lock | 8 +- example/ios/Runner/AppDelegate.swift | 4 + example/ios/Runner/Info.plist | 4 + example/pubspec.yaml | 2 +- example/test/widget_test.dart | 30 ------- lib/src/channel_header.dart | 1 + lib/src/message_actions_modal.dart | 2 +- lib/src/message_reactions_modal.dart | 2 +- 9 files changed, 79 insertions(+), 100 deletions(-) delete mode 100644 example/test/widget_test.dart diff --git a/analysis_options.yaml b/analysis_options.yaml index 8d6f9064..ef7efa9f 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -1,63 +1,63 @@ -include: package:pedantic/analysis_options.yaml - -analyzer: - enable-experiment: - - extension-methods - exclude: - - lib/**/*.g.dart - - example/** - -linter: - rules: - # these rules are documented on and in the same order as - # the Dart Lint rules page to make maintenance easier - # https://github.com/dart-lang/linter/blob/master/example/all.yaml - # - always_declare_return_types - # - always_specify_types - # - annotate_overrides - # - avoid_as - - avoid_empty_else - - avoid_init_to_null - - avoid_return_types_on_setters - - avoid_web_libraries_in_flutter - - await_only_futures - - camel_case_types - - cancel_subscriptions - - close_sinks - # - comment_references # we do not presume as to what people want to reference in their dartdocs - # - constant_identifier_names # https://github.com/dart-lang/linter/issues/204 - - control_flow_in_finally - - empty_constructor_bodies - - empty_statements - - hash_and_equals - - implementation_imports - # - invariant_booleans - # - iterable_contains_unrelated_type - - library_names - # - library_prefixes - # - list_remove_unrelated_type - # - literal_only_boolean_expressions - - non_constant_identifier_names - # - one_member_abstracts - # - only_throw_errors - # - overridden_fields -# - package_api_docs - - package_names - - package_prefixed_library_names - - prefer_is_not_empty - # - prefer_mixin # https://github.com/dart-lang/language/issues/32 - - public_member_api_docs - - slash_for_doc_comments - # - sort_constructors_first - # - sort_unnamed_constructors_first - # - super_goes_last # no longer needed w/ Dart 2 - - test_types_in_equals - - throw_in_finally - # - type_annotate_public_apis # subset of always_specify_types - - type_init_formals - # - unawaited_futures - - unnecessary_brace_in_string_interps - - unnecessary_getters_setters - - unnecessary_statements - - unrelated_type_equality_checks - - valid_regexps +#include: package:pedantic/analysis_options.yaml +# +#analyzer: +# enable-experiment: +# - extension-methods +# exclude: +# - lib/**/*.g.dart +# - example/** +# +#linter: +# rules: +# # these rules are documented on and in the same order as +# # the Dart Lint rules page to make maintenance easier +# # https://github.com/dart-lang/linter/blob/master/example/all.yaml +# # - always_declare_return_types +# # - always_specify_types +# # - annotate_overrides +# # - avoid_as +# - avoid_empty_else +# - avoid_init_to_null +# - avoid_return_types_on_setters +# - avoid_web_libraries_in_flutter +# - await_only_futures +# - camel_case_types +# - cancel_subscriptions +# - close_sinks +# # - comment_references # we do not presume as to what people want to reference in their dartdocs +# # - constant_identifier_names # https://github.com/dart-lang/linter/issues/204 +# - control_flow_in_finally +# - empty_constructor_bodies +# - empty_statements +# - hash_and_equals +# - implementation_imports +# # - invariant_booleans +# # - iterable_contains_unrelated_type +# - library_names +# # - library_prefixes +# # - list_remove_unrelated_type +# # - literal_only_boolean_expressions +# - non_constant_identifier_names +# # - one_member_abstracts +# # - only_throw_errors +# # - overridden_fields +## - package_api_docs +# - package_names +# - package_prefixed_library_names +# - prefer_is_not_empty +# # - prefer_mixin # https://github.com/dart-lang/language/issues/32 +# - public_member_api_docs +# - slash_for_doc_comments +# # - sort_constructors_first +# # - sort_unnamed_constructors_first +# # - super_goes_last # no longer needed w/ Dart 2 +# - test_types_in_equals +# - throw_in_finally +# # - type_annotate_public_apis # subset of always_specify_types +# - type_init_formals +# # - unawaited_futures +# - unnecessary_brace_in_string_interps +# - unnecessary_getters_setters +# - unnecessary_statements +# - unrelated_type_equality_checks +# - valid_regexps diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock index 1e268608..0068f96c 100644 --- a/example/ios/Podfile.lock +++ b/example/ios/Podfile.lock @@ -124,9 +124,9 @@ PODS: - SDWebImage/Core (5.9.3) - shared_preferences (0.0.1): - Flutter - - sqflite (0.0.1): + - sqflite (0.0.2): - Flutter - - FMDB (~> 2.7.2) + - FMDB (>= 2.7.5) - sqlite3 (3.32.3): - sqlite3/common (= 3.32.3) - sqlite3/common (3.32.3) @@ -248,7 +248,7 @@ SPEC CHECKSUMS: FirebaseInstanceID: cef67c4967c7cecb56ea65d8acbb4834825c587b FirebaseMessaging: 29543feb343b09546ab3aa04d008ee8595b43c44 Flutter: 0e3d915762c693b495b44d77113d4970485de6ec - flutter_apns: f516b118e423fe7c0a38771180549c4d6cb67c2f + flutter_apns: ddc629f26016140bf52165040b0a8e8869f9ce32 flutter_app_badger: 65de4d6f0c34a891df49e6cfb8a1c0496426fa68 flutter_keyboard_visibility: 0339d06371254c3eb25eeb90ba8d17dca8f9c069 flutter_local_notifications: 0c0b1ae97e741e1521e4c1629a459d04b9aec743 @@ -262,7 +262,7 @@ SPEC CHECKSUMS: Protobuf: 3dac39b34a08151c6d949560efe3f86134a3f748 SDWebImage: a31ee8e90a97303529e03fb0c333eae0eacb88e9 shared_preferences: af6bfa751691cdc24be3045c43ec037377ada40d - sqflite: 4001a31ff81d210346b500c55b17f4d6c7589dd0 + sqflite: 6d358c025f5b867b29ed92fc697fd34924e11904 sqlite3: 8f7d2078ae27778699a622a94b853285793422a2 sqlite3_flutter_libs: 5651f8ff48e3b44d910863c4ea5916085b1b245f Starscream: 5178aed56b316f13fa3bc55694e583d35dd414d9 diff --git a/example/ios/Runner/AppDelegate.swift b/example/ios/Runner/AppDelegate.swift index 69a7daf4..e024c1ef 100644 --- a/example/ios/Runner/AppDelegate.swift +++ b/example/ios/Runner/AppDelegate.swift @@ -14,6 +14,10 @@ import Flutter sharedDefaults?.removeObject(forKey: "messageQueue") } + if #available(iOS 10.0, *) { + UNUserNotificationCenter.current().delegate = self + } + GeneratedPluginRegistrant.register(with: self) return super.application(application, didFinishLaunchingWithOptions: launchOptions) } diff --git a/example/ios/Runner/Info.plist b/example/ios/Runner/Info.plist index 6c2c8e27..b41f1c19 100644 --- a/example/ios/Runner/Info.plist +++ b/example/ios/Runner/Info.plist @@ -58,5 +58,9 @@ remote-notification + UIUserInterfaceStyle + Light + UIViewControllerBasedStatusBarAppearance + diff --git a/example/pubspec.yaml b/example/pubspec.yaml index c73804eb..dac40d3b 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -1,6 +1,6 @@ name: example description: A new Flutter project. -version: 1.0.36+38 +version: 1.0.37+39 environment: sdk: ">=2.2.2 <3.0.0" diff --git a/example/test/widget_test.dart b/example/test/widget_test.dart deleted file mode 100644 index 747db1da..00000000 --- a/example/test/widget_test.dart +++ /dev/null @@ -1,30 +0,0 @@ -// This is a basic Flutter widget test. -// -// To perform an interaction with a widget in your test, use the WidgetTester -// utility that Flutter provides. For example, you can send tap and scroll -// gestures. You can also use WidgetTester to find child widgets in the widget -// tree, read text, and verify that the values of widget properties are correct. - -import 'package:flutter/material.dart'; -import 'package:flutter_test/flutter_test.dart'; - -import 'package:example/main.dart'; - -void main() { - testWidgets('Counter increments smoke test', (WidgetTester tester) async { - // Build our app and trigger a frame. - await tester.pumpWidget(MyApp()); - - // Verify that our counter starts at 0. - expect(find.text('0'), findsOneWidget); - expect(find.text('1'), findsNothing); - - // Tap the '+' icon and trigger a frame. - await tester.tap(find.byIcon(Icons.add)); - await tester.pump(); - - // Verify that our counter has incremented. - expect(find.text('0'), findsNothing); - expect(find.text('1'), findsOneWidget); - }); -} diff --git a/lib/src/channel_header.dart b/lib/src/channel_header.dart index 16aa70fc..81f95a87 100644 --- a/lib/src/channel_header.dart +++ b/lib/src/channel_header.dart @@ -78,6 +78,7 @@ class ChannelHeader extends StatelessWidget implements PreferredSizeWidget { Widget build(BuildContext context) { final channel = StreamChannel.of(context).channel; return AppBar( + brightness: Theme.of(context).brightness, elevation: 1, leading: showBackButton ? StreamBackButton(onPressed: onBackPressed) diff --git a/lib/src/message_actions_modal.dart b/lib/src/message_actions_modal.dart index 93e1c0db..9144de1e 100644 --- a/lib/src/message_actions_modal.dart +++ b/lib/src/message_actions_modal.dart @@ -58,7 +58,7 @@ class MessageActionsModal extends StatelessWidget { sigmaY: 10.8731, ), child: Container( - color: Colors.black.withOpacity(0.2), + color: Colors.black.withOpacity(0.1), ), ), ), diff --git a/lib/src/message_reactions_modal.dart b/lib/src/message_reactions_modal.dart index 375da94e..88e2525d 100644 --- a/lib/src/message_reactions_modal.dart +++ b/lib/src/message_reactions_modal.dart @@ -49,7 +49,7 @@ class MessageReactionsModal extends StatelessWidget { sigmaY: 10.8731, ), child: Container( - color: Colors.black.withOpacity(0.2), + color: Colors.black.withOpacity(0.1), ), ), ), From 8424e3a9721caec56c448667e4f0f24f841e7d8e Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Thu, 29 Oct 2020 12:33:18 +0100 Subject: [PATCH 0250/1140] center user avatar in modal --- lib/src/message_actions_modal.dart | 8 ++++---- lib/src/message_reactions_modal.dart | 8 ++++---- lib/src/message_widget.dart | 18 +++++++++++++++++- 3 files changed, 25 insertions(+), 9 deletions(-) diff --git a/lib/src/message_actions_modal.dart b/lib/src/message_actions_modal.dart index 9144de1e..b675a688 100644 --- a/lib/src/message_actions_modal.dart +++ b/lib/src/message_actions_modal.dart @@ -25,6 +25,7 @@ class MessageActionsModal extends StatelessWidget { final bool showReply; final bool reverse; final ShapeBorder messageShape; + final DisplayWidget showUserAvatar; const MessageActionsModal({ Key key, @@ -36,6 +37,7 @@ class MessageActionsModal extends StatelessWidget { this.onThreadTap, this.showCopyMessage = true, this.showReply = true, + this.showUserAvatar = DisplayWidget.show, this.editMessageInputBuilder, this.messageShape, this.reverse = false, @@ -43,7 +45,6 @@ class MessageActionsModal extends StatelessWidget { @override Widget build(BuildContext context) { - final ownId = StreamChat.of(context).user.id; return GestureDetector( behavior: HitTestBehavior.translucent, onTap: () { @@ -92,10 +93,9 @@ class MessageActionsModal extends StatelessWidget { showReactions: false, showUsername: false, showReplyIndicator: false, - showUserAvatar: message.user.id == ownId - ? DisplayWidget.gone - : DisplayWidget.show, + showUserAvatar: showUserAvatar, showTimestamp: false, + translateUserAvatar: false, showSendingIndicator: DisplayWidget.gone, shape: messageShape, ), diff --git a/lib/src/message_reactions_modal.dart b/lib/src/message_reactions_modal.dart index 88e2525d..a8013fde 100644 --- a/lib/src/message_reactions_modal.dart +++ b/lib/src/message_reactions_modal.dart @@ -17,6 +17,7 @@ class MessageReactionsModal extends StatelessWidget { final MessageTheme messageTheme; final bool reverse; final bool showReactions; + final DisplayWidget showUserAvatar; final ShapeBorder messageShape; final void Function(User) onUserAvatarTap; @@ -29,12 +30,12 @@ class MessageReactionsModal extends StatelessWidget { this.editMessageInputBuilder, this.messageShape, this.reverse = false, + this.showUserAvatar = DisplayWidget.show, this.onUserAvatarTap, }) : super(key: key); @override Widget build(BuildContext context) { - final ownId = StreamChat.of(context).user.id; return GestureDetector( behavior: HitTestBehavior.translucent, onTap: () { @@ -82,11 +83,10 @@ class MessageReactionsModal extends StatelessWidget { messageTheme: messageTheme, showReactions: false, showUsername: false, - showUserAvatar: message.user.id == ownId - ? DisplayWidget.gone - : DisplayWidget.show, + showUserAvatar: showUserAvatar, showReplyIndicator: false, showTimestamp: false, + translateUserAvatar: false, showSendingIndicator: DisplayWidget.gone, shape: messageShape, ), diff --git a/lib/src/message_widget.dart b/lib/src/message_widget.dart index 0e703fa0..4378086f 100644 --- a/lib/src/message_widget.dart +++ b/lib/src/message_widget.dart @@ -115,11 +115,15 @@ class MessageWidget extends StatefulWidget { final bool showEditMessage; final Map attachmentBuilders; + /// Center user avatar with bottom of the message + final bool translateUserAvatar; + MessageWidget({ Key key, @required this.message, @required this.messageTheme, this.reverse = false, + this.translateUserAvatar = true, this.shape, this.attachmentShape, this.borderSide, @@ -423,6 +427,10 @@ class _MessageWidgetState extends State { return StreamChannel( channel: channel, child: MessageActionsModal( + showUserAvatar: + widget.message.user.id == channel.client.state.user.id + ? DisplayWidget.gone + : DisplayWidget.show, messageTheme: widget.messageTheme, messageShape: widget.shape ?? _getDefaultShape(context), reverse: widget.reverse, @@ -447,6 +455,10 @@ class _MessageWidgetState extends State { return StreamChannel( channel: channel, child: MessageReactionsModal( + showUserAvatar: + widget.message.user.id == channel.client.state.user.id + ? DisplayWidget.gone + : DisplayWidget.show, onUserAvatarTap: widget.onUserAvatarTap, messageTheme: widget.messageTheme, messageShape: widget.shape ?? _getDefaultShape(context), @@ -614,7 +626,11 @@ class _MessageWidgetState extends State { padding: const EdgeInsets.symmetric(horizontal: 4.0), child: Transform.translate( offset: Offset( - 0, widget.messageTheme.avatarTheme.constraints.maxHeight / 2), + 0, + widget.translateUserAvatar + ? widget.messageTheme.avatarTheme.constraints.maxHeight / 2 + : 0, + ), child: UserAvatar( user: widget.message.user, onTap: widget.onUserAvatarTap, From daf028d805acac440c24a7090eb6b4f2f6c46660 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Thu, 29 Oct 2020 12:49:25 +0100 Subject: [PATCH 0251/1140] align reaction picker bubbles --- lib/src/message_actions_modal.dart | 1 + lib/src/message_reactions_modal.dart | 1 + lib/src/message_widget.dart | 85 +++++++++++++++++--------- lib/src/reaction_picker.dart | 90 ++++++++++++---------------- 4 files changed, 95 insertions(+), 82 deletions(-) diff --git a/lib/src/message_actions_modal.dart b/lib/src/message_actions_modal.dart index b675a688..9562a797 100644 --- a/lib/src/message_actions_modal.dart +++ b/lib/src/message_actions_modal.dart @@ -96,6 +96,7 @@ class MessageActionsModal extends StatelessWidget { showUserAvatar: showUserAvatar, showTimestamp: false, translateUserAvatar: false, + showReactionPickerIndicator: true, showSendingIndicator: DisplayWidget.gone, shape: messageShape, ), diff --git a/lib/src/message_reactions_modal.dart b/lib/src/message_reactions_modal.dart index a8013fde..4ef35be2 100644 --- a/lib/src/message_reactions_modal.dart +++ b/lib/src/message_reactions_modal.dart @@ -89,6 +89,7 @@ class MessageReactionsModal extends StatelessWidget { translateUserAvatar: false, showSendingIndicator: DisplayWidget.gone, shape: messageShape, + showReactionPickerIndicator: true, ), ), SizedBox( diff --git a/lib/src/message_widget.dart b/lib/src/message_widget.dart index 4378086f..e65da576 100644 --- a/lib/src/message_widget.dart +++ b/lib/src/message_widget.dart @@ -106,6 +106,9 @@ class MessageWidget extends StatefulWidget { /// The function called when tapping on a link final void Function(String) onLinkTap; + /// Used in [MessageReactionsModal] and [MessageActionsModal] + final bool showReactionPickerIndicator; + final List readList; /// If true show the users username next to the timestamp of the message @@ -131,6 +134,7 @@ class MessageWidget extends StatefulWidget { this.borderRadiusGeometry, this.attachmentBorderRadiusGeometry, this.onMentionTap, + this.showReactionPickerIndicator = false, this.showUserAvatar = DisplayWidget.show, this.showSendingIndicator = DisplayWidget.show, this.showReplyIndicator = true, @@ -251,39 +255,62 @@ class _MessageWidgetState extends State { ), 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) - ? Transform( - alignment: Alignment.center, + child: Stack( + clipBehavior: Clip.none, + children: [ + 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) + ? Transform( + alignment: Alignment.center, + transform: Matrix4.rotationY( + widget.reverse ? pi : 0), + child: DeletedMessage( + messageTheme: widget.messageTheme, + ), + ) + : Column( + crossAxisAlignment: + CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + ..._parseAttachments(context), + if (widget.message.text + .trim() + .isNotEmpty) + _buildTextBubble(context), + ], + ), + ), + if (widget.showReactionPickerIndicator) + Positioned( + right: 0, + top: -6, + child: Transform( transform: Matrix4.rotationY( widget.reverse ? pi : 0), - child: DeletedMessage( - messageTheme: widget.messageTheme, + child: CustomPaint( + painter: ReactionBubblePainter( + widget.messageTheme + .reactionsBackgroundColor, + widget.messageTheme + .reactionsBorderColor, + ), ), - ) - : Column( - crossAxisAlignment: - CrossAxisAlignment.start, - mainAxisSize: MainAxisSize.min, - children: [ - ..._parseAttachments(context), - if (widget.message.text - .trim() - .isNotEmpty) - _buildTextBubble(context), - ], ), + ), + ], ), ), ), diff --git a/lib/src/reaction_picker.dart b/lib/src/reaction_picker.dart index 87487cde..bf4c4ed0 100644 --- a/lib/src/reaction_picker.dart +++ b/lib/src/reaction_picker.dart @@ -1,5 +1,4 @@ import 'package:flutter/material.dart'; -import 'package:stream_chat_flutter/src/reaction_bubble.dart'; import '../stream_chat_flutter.dart'; @@ -22,59 +21,44 @@ class ReactionPicker extends StatelessWidget { @override Widget build(BuildContext context) { final reactionIcons = StreamChatTheme.of(context).reactionIcons; - return Stack( - fit: StackFit.passthrough, - children: [ - Material( - color: messageTheme.reactionsBackgroundColor, - clipBehavior: Clip.hardEdge, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(24), - ), - child: Row( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: MainAxisAlignment.center, - mainAxisSize: MainAxisSize.min, - children: reactionIcons.map((reactionIcon) { - final ownReactionIndex = message.ownReactions?.indexWhere( - (reaction) => reaction.type == reactionIcon.type) ?? - -1; - return IconButton( - iconSize: 24, - icon: Icon( - reactionIcon.iconData, - color: ownReactionIndex != -1 - ? StreamChatTheme.of(context).accentColor - : Theme.of(context).iconTheme.color.withOpacity(.5), - ), - onPressed: () { - if (ownReactionIndex != -1) { - removeReaction( - context, - message.ownReactions[ownReactionIndex], - ); - } else { - sendReaction( - context, - reactionIcon.type, - ); - } - }, - ); - }).toList(), - ), - ), - Positioned( - right: 14, - bottom: 0, - child: CustomPaint( - painter: ReactionBubblePainter( - messageTheme.reactionsBackgroundColor, - messageTheme.reactionsBorderColor, + return Material( + color: messageTheme.reactionsBackgroundColor, + clipBehavior: Clip.hardEdge, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(24), + ), + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.center, + mainAxisSize: MainAxisSize.min, + children: reactionIcons.map((reactionIcon) { + final ownReactionIndex = message.ownReactions?.indexWhere( + (reaction) => reaction.type == reactionIcon.type) ?? + -1; + return IconButton( + iconSize: 24, + icon: Icon( + reactionIcon.iconData, + color: ownReactionIndex != -1 + ? StreamChatTheme.of(context).accentColor + : Theme.of(context).iconTheme.color.withOpacity(.5), ), - ), - ), - ], + onPressed: () { + if (ownReactionIndex != -1) { + removeReaction( + context, + message.ownReactions[ownReactionIndex], + ); + } else { + sendReaction( + context, + reactionIcon.type, + ); + } + }, + ); + }).toList(), + ), ); } From 6566a3fc8f2ccc4062d590f0c7c9e6776d850189 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Thu, 29 Oct 2020 12:50:27 +0100 Subject: [PATCH 0252/1140] revert analysis options --- analysis_options.yaml | 126 +++++++++++++++++++++--------------------- 1 file changed, 63 insertions(+), 63 deletions(-) diff --git a/analysis_options.yaml b/analysis_options.yaml index ef7efa9f..8d6f9064 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -1,63 +1,63 @@ -#include: package:pedantic/analysis_options.yaml -# -#analyzer: -# enable-experiment: -# - extension-methods -# exclude: -# - lib/**/*.g.dart -# - example/** -# -#linter: -# rules: -# # these rules are documented on and in the same order as -# # the Dart Lint rules page to make maintenance easier -# # https://github.com/dart-lang/linter/blob/master/example/all.yaml -# # - always_declare_return_types -# # - always_specify_types -# # - annotate_overrides -# # - avoid_as -# - avoid_empty_else -# - avoid_init_to_null -# - avoid_return_types_on_setters -# - avoid_web_libraries_in_flutter -# - await_only_futures -# - camel_case_types -# - cancel_subscriptions -# - close_sinks -# # - comment_references # we do not presume as to what people want to reference in their dartdocs -# # - constant_identifier_names # https://github.com/dart-lang/linter/issues/204 -# - control_flow_in_finally -# - empty_constructor_bodies -# - empty_statements -# - hash_and_equals -# - implementation_imports -# # - invariant_booleans -# # - iterable_contains_unrelated_type -# - library_names -# # - library_prefixes -# # - list_remove_unrelated_type -# # - literal_only_boolean_expressions -# - non_constant_identifier_names -# # - one_member_abstracts -# # - only_throw_errors -# # - overridden_fields -## - package_api_docs -# - package_names -# - package_prefixed_library_names -# - prefer_is_not_empty -# # - prefer_mixin # https://github.com/dart-lang/language/issues/32 -# - public_member_api_docs -# - slash_for_doc_comments -# # - sort_constructors_first -# # - sort_unnamed_constructors_first -# # - super_goes_last # no longer needed w/ Dart 2 -# - test_types_in_equals -# - throw_in_finally -# # - type_annotate_public_apis # subset of always_specify_types -# - type_init_formals -# # - unawaited_futures -# - unnecessary_brace_in_string_interps -# - unnecessary_getters_setters -# - unnecessary_statements -# - unrelated_type_equality_checks -# - valid_regexps +include: package:pedantic/analysis_options.yaml + +analyzer: + enable-experiment: + - extension-methods + exclude: + - lib/**/*.g.dart + - example/** + +linter: + rules: + # these rules are documented on and in the same order as + # the Dart Lint rules page to make maintenance easier + # https://github.com/dart-lang/linter/blob/master/example/all.yaml + # - always_declare_return_types + # - always_specify_types + # - annotate_overrides + # - avoid_as + - avoid_empty_else + - avoid_init_to_null + - avoid_return_types_on_setters + - avoid_web_libraries_in_flutter + - await_only_futures + - camel_case_types + - cancel_subscriptions + - close_sinks + # - comment_references # we do not presume as to what people want to reference in their dartdocs + # - constant_identifier_names # https://github.com/dart-lang/linter/issues/204 + - control_flow_in_finally + - empty_constructor_bodies + - empty_statements + - hash_and_equals + - implementation_imports + # - invariant_booleans + # - iterable_contains_unrelated_type + - library_names + # - library_prefixes + # - list_remove_unrelated_type + # - literal_only_boolean_expressions + - non_constant_identifier_names + # - one_member_abstracts + # - only_throw_errors + # - overridden_fields +# - package_api_docs + - package_names + - package_prefixed_library_names + - prefer_is_not_empty + # - prefer_mixin # https://github.com/dart-lang/language/issues/32 + - public_member_api_docs + - slash_for_doc_comments + # - sort_constructors_first + # - sort_unnamed_constructors_first + # - super_goes_last # no longer needed w/ Dart 2 + - test_types_in_equals + - throw_in_finally + # - type_annotate_public_apis # subset of always_specify_types + - type_init_formals + # - unawaited_futures + - unnecessary_brace_in_string_interps + - unnecessary_getters_setters + - unnecessary_statements + - unrelated_type_equality_checks + - valid_regexps From 8384b605323232616104d66ac28661a970acb6f6 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Thu, 29 Oct 2020 13:27:11 +0100 Subject: [PATCH 0253/1140] use stream chat theme --- lib/src/message_input.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 631bf9ef..5745f779 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -229,7 +229,7 @@ class MessageInputState extends State { _sendAsDm = val; }, ), - activeColor: Color(0xFF006CFF), + activeColor: StreamChatTheme.of(context).accentColor, ), Padding( padding: const EdgeInsets.symmetric(horizontal: 8.0), From 9f8248738d36fcd2bacac85ab1805eeed568b2ab Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Thu, 29 Oct 2020 19:31:48 +0530 Subject: [PATCH 0254/1140] feat: Converted png to svg --- images/giphy_icon.png | Bin 400 -> 0 bytes images/giphy_icon.svg | 9 +++++++++ lib/src/message_input.dart | 5 +++-- pubspec.yaml | 3 ++- 4 files changed, 14 insertions(+), 3 deletions(-) delete mode 100644 images/giphy_icon.png create mode 100644 images/giphy_icon.svg diff --git a/images/giphy_icon.png b/images/giphy_icon.png deleted file mode 100644 index ea99e8341848dcbb49d654ff1847818bb301cf92..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 400 zcmV;B0dM|^P)xRK7oUqgCh17d;%Xq#3#_r!AWp;a1b4&P(?>Wp+hP3 z51~VHPf!1(ZFq-TZqD{20kU0~*(*mS~qP@%xE^K=!GnI-@@WFcR1u(CkFdy`sC*C;@Zdf(X!+WEF zj_*ekOxFp8L1^OW#Bm-=C7iLLk|2p^*Tq+}Ikeh0j`8DdLHP$s4B~#bTBx#Q;BeR7 z)eI)^TJqZkWYXC+4Pw{;gPCpQ13(%`=OGdcJ`W%@ioBj0baEi~67BmFByp=-NI!7# uGHx5*#vp6MKRCiN=+#dc|9??~b?E~xRAC+pj+ux60000 + + + + + + + + diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 5745f779..9b0128e2 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -6,6 +6,7 @@ import 'package:file_picker/file_picker.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_keyboard_visibility/flutter_keyboard_visibility.dart'; +import 'package:flutter_svg/flutter_svg.dart'; import 'package:http_parser/http_parser.dart'; import 'package:image_picker/image_picker.dart'; import 'package:mime/mime.dart'; @@ -516,8 +517,8 @@ class MessageInputState extends State { leading: c.name == 'giphy' ? CircleAvatar( backgroundColor: Colors.black, - child: Image.asset( - 'images/giphy_icon.png', + child: SvgPicture.asset( + 'images/giphy_icon.svg', package: 'stream_chat_flutter', width: 16.0, height: 16.0, diff --git a/pubspec.yaml b/pubspec.yaml index d61e6874..bf894a2d 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -32,10 +32,11 @@ dependencies: carousel_slider: ^2.2.1 clipboard: ^0.1.2+8 widgets_visibility_provider: ^2.0.2 + flutter_svg: ^0.19.1 flutter: assets: - - images/giphy_icon.png + - images/giphy_icon.svg fonts: - family: stream-icons fonts: From 8c49ce2667575c9d6544945cf5ffca48f86d1be0 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Thu, 29 Oct 2020 19:48:05 +0530 Subject: [PATCH 0255/1140] Revert "feat: Converted png to svg" This reverts commit 9f824873 --- images/giphy_icon.png | Bin 0 -> 400 bytes images/giphy_icon.svg | 9 --------- lib/src/message_input.dart | 5 ++--- pubspec.yaml | 3 +-- 4 files changed, 3 insertions(+), 14 deletions(-) create mode 100644 images/giphy_icon.png delete mode 100644 images/giphy_icon.svg diff --git a/images/giphy_icon.png b/images/giphy_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..ea99e8341848dcbb49d654ff1847818bb301cf92 GIT binary patch literal 400 zcmV;B0dM|^P)xRK7oUqgCh17d;%Xq#3#_r!AWp;a1b4&P(?>Wp+hP3 z51~VHPf!1(ZFq-TZqD{20kU0~*(*mS~qP@%xE^K=!GnI-@@WFcR1u(CkFdy`sC*C;@Zdf(X!+WEF zj_*ekOxFp8L1^OW#Bm-=C7iLLk|2p^*Tq+}Ikeh0j`8DdLHP$s4B~#bTBx#Q;BeR7 z)eI)^TJqZkWYXC+4Pw{;gPCpQ13(%`=OGdcJ`W%@ioBj0baEi~67BmFByp=-NI!7# uGHx5*#vp6MKRCiN=+#dc|9??~b?E~xRAC+pj+ux60000 - - - - - - - - diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 9b0128e2..5745f779 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -6,7 +6,6 @@ import 'package:file_picker/file_picker.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_keyboard_visibility/flutter_keyboard_visibility.dart'; -import 'package:flutter_svg/flutter_svg.dart'; import 'package:http_parser/http_parser.dart'; import 'package:image_picker/image_picker.dart'; import 'package:mime/mime.dart'; @@ -517,8 +516,8 @@ class MessageInputState extends State { leading: c.name == 'giphy' ? CircleAvatar( backgroundColor: Colors.black, - child: SvgPicture.asset( - 'images/giphy_icon.svg', + child: Image.asset( + 'images/giphy_icon.png', package: 'stream_chat_flutter', width: 16.0, height: 16.0, diff --git a/pubspec.yaml b/pubspec.yaml index bf894a2d..d61e6874 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -32,11 +32,10 @@ dependencies: carousel_slider: ^2.2.1 clipboard: ^0.1.2+8 widgets_visibility_provider: ^2.0.2 - flutter_svg: ^0.19.1 flutter: assets: - - images/giphy_icon.svg + - images/giphy_icon.png fonts: - family: stream-icons fonts: From 4958f99151cfdda91f1e4ce8ee96e982ce84f0ce Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Thu, 29 Oct 2020 16:24:49 +0100 Subject: [PATCH 0256/1140] fix ci? --- example/ios/Flutter/.last_build_id | 2 +- example/ios/Podfile.lock | 8 ++++---- example/pubspec.yaml | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/example/ios/Flutter/.last_build_id b/example/ios/Flutter/.last_build_id index 661f8167..5d3809be 100644 --- a/example/ios/Flutter/.last_build_id +++ b/example/ios/Flutter/.last_build_id @@ -1 +1 @@ -89eb023669fee58472de747080d78b5a \ No newline at end of file +bdf1751976c4ee1e2ef7638eabcfd1ea \ No newline at end of file diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock index 1e268608..0068f96c 100644 --- a/example/ios/Podfile.lock +++ b/example/ios/Podfile.lock @@ -124,9 +124,9 @@ PODS: - SDWebImage/Core (5.9.3) - shared_preferences (0.0.1): - Flutter - - sqflite (0.0.1): + - sqflite (0.0.2): - Flutter - - FMDB (~> 2.7.2) + - FMDB (>= 2.7.5) - sqlite3 (3.32.3): - sqlite3/common (= 3.32.3) - sqlite3/common (3.32.3) @@ -248,7 +248,7 @@ SPEC CHECKSUMS: FirebaseInstanceID: cef67c4967c7cecb56ea65d8acbb4834825c587b FirebaseMessaging: 29543feb343b09546ab3aa04d008ee8595b43c44 Flutter: 0e3d915762c693b495b44d77113d4970485de6ec - flutter_apns: f516b118e423fe7c0a38771180549c4d6cb67c2f + flutter_apns: ddc629f26016140bf52165040b0a8e8869f9ce32 flutter_app_badger: 65de4d6f0c34a891df49e6cfb8a1c0496426fa68 flutter_keyboard_visibility: 0339d06371254c3eb25eeb90ba8d17dca8f9c069 flutter_local_notifications: 0c0b1ae97e741e1521e4c1629a459d04b9aec743 @@ -262,7 +262,7 @@ SPEC CHECKSUMS: Protobuf: 3dac39b34a08151c6d949560efe3f86134a3f748 SDWebImage: a31ee8e90a97303529e03fb0c333eae0eacb88e9 shared_preferences: af6bfa751691cdc24be3045c43ec037377ada40d - sqflite: 4001a31ff81d210346b500c55b17f4d6c7589dd0 + sqflite: 6d358c025f5b867b29ed92fc697fd34924e11904 sqlite3: 8f7d2078ae27778699a622a94b853285793422a2 sqlite3_flutter_libs: 5651f8ff48e3b44d910863c4ea5916085b1b245f Starscream: 5178aed56b316f13fa3bc55694e583d35dd414d9 diff --git a/example/pubspec.yaml b/example/pubspec.yaml index c73804eb..dac40d3b 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -1,6 +1,6 @@ name: example description: A new Flutter project. -version: 1.0.36+38 +version: 1.0.37+39 environment: sdk: ">=2.2.2 <3.0.0" From 8963697a89c14347aa7ab4d278b8c7d11b83f95b Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Thu, 29 Oct 2020 16:35:13 +0100 Subject: [PATCH 0257/1140] upagrad github action --- .github/workflows/build.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index e814cb60..e4c6f701 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,4 +1,4 @@ -name: CI +name: Build on: push: @@ -18,7 +18,7 @@ jobs: run: | cd example/ios bundle install - - uses: subosito/flutter-action@v1.3.2 + - uses: subosito/flutter-action@v1.4.0 with: channel: 'stable' - name: Install firebase-tools @@ -44,7 +44,7 @@ jobs: - uses: actions/setup-java@v1 with: java-version: '12.x' - - uses: subosito/flutter-action@v1.3.2 + - uses: subosito/flutter-action@v1.4.0 with: channel: 'stable' - run: | From 1f4caa1039428e003dcf900cc5a673c68c17ebcd Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Thu, 29 Oct 2020 16:53:05 +0100 Subject: [PATCH 0258/1140] fix android build --- example/android/app/build.gradle | 4 +- example/ios/Podfile.lock | 90 +++++++++++++++----------------- example/pubspec.yaml | 2 +- 3 files changed, 44 insertions(+), 52 deletions(-) diff --git a/example/android/app/build.gradle b/example/android/app/build.gradle index 474bfd75..33c33ff2 100644 --- a/example/android/app/build.gradle +++ b/example/android/app/build.gradle @@ -26,7 +26,7 @@ apply plugin: 'kotlin-android' apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" android { - compileSdkVersion 28 + compileSdkVersion 29 sourceSets { main.java.srcDirs += 'src/main/kotlin' @@ -40,7 +40,7 @@ android { // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). applicationId "com.example.example" minSdkVersion 21 - targetSdkVersion 28 + targetSdkVersion 29 versionCode flutterVersionCode.toInteger() versionName flutterVersionName testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock index 0068f96c..d20eaee6 100644 --- a/example/ios/Podfile.lock +++ b/example/ios/Podfile.lock @@ -33,49 +33,45 @@ PODS: - file_picker (0.0.1): - DKImagePickerController/PhotoGallery - Flutter - - Firebase/CoreOnly (6.26.0): - - FirebaseCore (= 6.7.2) - - Firebase/Messaging (6.26.0): + - Firebase/CoreOnly (6.33.0): + - FirebaseCore (= 6.10.3) + - Firebase/Messaging (6.33.0): - Firebase/CoreOnly - - FirebaseMessaging (~> 4.4.1) - - firebase_core (0.5.0-1): - - Firebase/CoreOnly (~> 6.26.0) + - FirebaseMessaging (~> 4.7.0) + - firebase_core (0.5.1): + - Firebase/CoreOnly (~> 6.33.0) - Flutter - firebase_messaging (7.0.3): - - Firebase/CoreOnly (~> 6.26.0) - - Firebase/Messaging (~> 6.26.0) + - Firebase/CoreOnly (~> 6.33.0) + - Firebase/Messaging (~> 6.33.0) - firebase_core - Flutter - - FirebaseAnalyticsInterop (1.5.0) - - FirebaseCore (6.7.2): - - FirebaseCoreDiagnostics (~> 1.3) - - FirebaseCoreDiagnosticsInterop (~> 1.2) - - GoogleUtilities/Environment (~> 6.5) - - GoogleUtilities/Logger (~> 6.5) + - FirebaseCore (6.10.3): + - FirebaseCoreDiagnostics (~> 1.6) + - GoogleUtilities/Environment (~> 6.7) + - GoogleUtilities/Logger (~> 6.7) - FirebaseCoreDiagnostics (1.7.0): - GoogleDataTransport (~> 7.4) - GoogleUtilities/Environment (~> 6.7) - GoogleUtilities/Logger (~> 6.7) - nanopb (~> 1.30906.0) - - FirebaseCoreDiagnosticsInterop (1.2.0) - - FirebaseInstallations (1.3.0): - - FirebaseCore (~> 6.6) - - GoogleUtilities/Environment (~> 6.6) - - GoogleUtilities/UserDefaults (~> 6.6) + - FirebaseInstallations (1.7.0): + - FirebaseCore (~> 6.10) + - GoogleUtilities/Environment (~> 6.7) + - GoogleUtilities/UserDefaults (~> 6.7) - PromisesObjC (~> 1.2) - - FirebaseInstanceID (4.3.4): - - FirebaseCore (~> 6.6) - - FirebaseInstallations (~> 1.0) - - GoogleUtilities/Environment (~> 6.5) - - GoogleUtilities/UserDefaults (~> 6.5) - - FirebaseMessaging (4.4.1): - - FirebaseAnalyticsInterop (~> 1.5) - - FirebaseCore (~> 6.6) - - FirebaseInstanceID (~> 4.3) - - GoogleUtilities/AppDelegateSwizzler (~> 6.5) - - GoogleUtilities/Environment (~> 6.5) - - GoogleUtilities/Reachability (~> 6.5) - - GoogleUtilities/UserDefaults (~> 6.5) + - FirebaseInstanceID (4.8.0): + - FirebaseCore (~> 6.10) + - FirebaseInstallations (~> 1.6) + - GoogleUtilities/Environment (~> 6.7) + - GoogleUtilities/UserDefaults (~> 6.7) + - FirebaseMessaging (4.7.1): + - FirebaseCore (~> 6.10) + - FirebaseInstanceID (~> 4.7) + - GoogleUtilities/AppDelegateSwizzler (~> 6.7) + - GoogleUtilities/Environment (~> 6.7) + - GoogleUtilities/Reachability (~> 6.7) + - GoogleUtilities/UserDefaults (~> 6.7) - Protobuf (>= 3.9.2, ~> 3.9) - Flutter (1.0.0) - flutter_apns (0.0.1): @@ -119,9 +115,9 @@ PODS: - Flutter - PromisesObjC (1.2.11) - Protobuf (3.13.0) - - SDWebImage (5.9.3): - - SDWebImage/Core (= 5.9.3) - - SDWebImage/Core (5.9.3) + - SDWebImage (5.9.4): + - SDWebImage/Core (= 5.9.4) + - SDWebImage/Core (5.9.4) - shared_preferences (0.0.1): - Flutter - sqflite (0.0.2): @@ -146,7 +142,7 @@ PODS: - sqlite3/perf-threadsafe - sqlite3/rtree - Starscream (4.0.4) - - StreamChatClient (2.4.0): + - StreamChatClient (2.4.1): - Starscream (~> 4.0) - SwiftyGif (5.3.0) - url_launcher (0.0.1): @@ -180,10 +176,8 @@ SPEC REPOS: - DKImagePickerController - DKPhotoGallery - Firebase - - FirebaseAnalyticsInterop - FirebaseCore - FirebaseCoreDiagnostics - - FirebaseCoreDiagnosticsInterop - FirebaseInstallations - FirebaseInstanceID - FirebaseMessaging @@ -237,16 +231,14 @@ SPEC CHECKSUMS: DKImagePickerController: b5eb7f7a388e4643264105d648d01f727110fc3d DKPhotoGallery: fdfad5125a9fdda9cc57df834d49df790dbb4179 file_picker: 3e6c3790de664ccf9b882732d9db5eaf6b8d4eb1 - Firebase: 7cf5f9c67f03cb3b606d1d6535286e1080e57eb6 - firebase_core: 00e54a4744164a6b5a250b96dd1ad5afaba7a342 - firebase_messaging: 666d9994651b1ecf8c582b52dd913f3fa58c17ef - FirebaseAnalyticsInterop: 3f86269c38ae41f47afeb43ebf32a001f58fcdae - FirebaseCore: f42e5e5f382cdcf6b617ed737bf6c871a6947b17 + Firebase: 8db6f2d1b2c5e2984efba4949a145875a8f65fe5 + firebase_core: aa25a5dc6b492ecab37587c53d8420135f0cac90 + firebase_messaging: 0aea2cd5885b65e19ede58ee3507f485c992cc75 + FirebaseCore: d889d9e12535b7f36ac8bfbf1713a0836a3012cd FirebaseCoreDiagnostics: 770ac5958e1372ce67959ae4b4f31d8e127c3ac1 - FirebaseCoreDiagnosticsInterop: 296e2c5f5314500a850ad0b83e9e7c10b011a850 - FirebaseInstallations: 6f5f680e65dc374397a483c32d1799ba822a395b - FirebaseInstanceID: cef67c4967c7cecb56ea65d8acbb4834825c587b - FirebaseMessaging: 29543feb343b09546ab3aa04d008ee8595b43c44 + FirebaseInstallations: 466c7b4d1f58fe16707693091da253726a731ed2 + FirebaseInstanceID: bd3ffc24367f901a43c063b36c640b345a4a5dd1 + FirebaseMessaging: 5eca4ef173de76253352511aafef774caa1cba2a Flutter: 0e3d915762c693b495b44d77113d4970485de6ec flutter_apns: ddc629f26016140bf52165040b0a8e8869f9ce32 flutter_app_badger: 65de4d6f0c34a891df49e6cfb8a1c0496426fa68 @@ -260,13 +252,13 @@ SPEC CHECKSUMS: path_provider: abfe2b5c733d04e238b0d8691db0cfd63a27a93c PromisesObjC: 8c196f5a328c2cba3e74624585467a557dcb482f Protobuf: 3dac39b34a08151c6d949560efe3f86134a3f748 - SDWebImage: a31ee8e90a97303529e03fb0c333eae0eacb88e9 + SDWebImage: b69257f4ab14e9b6a2ef53e910fdf914d8f757c1 shared_preferences: af6bfa751691cdc24be3045c43ec037377ada40d sqflite: 6d358c025f5b867b29ed92fc697fd34924e11904 sqlite3: 8f7d2078ae27778699a622a94b853285793422a2 sqlite3_flutter_libs: 5651f8ff48e3b44d910863c4ea5916085b1b245f Starscream: 5178aed56b316f13fa3bc55694e583d35dd414d9 - StreamChatClient: 8c83a141e753e45fa096ff56d4b782d59e46f251 + StreamChatClient: d061cf52babcd9df930aee9cf864ab0379427eff SwiftyGif: e466e86c660d343357ab944a819a101c4127cb40 url_launcher: 6fef411d543ceb26efce54b05a0a40bfd74cbbef video_player: 9cc823b1d9da7e8427ee591e8438bfbcde500e6e diff --git a/example/pubspec.yaml b/example/pubspec.yaml index dac40d3b..69a45dc9 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -1,6 +1,6 @@ name: example description: A new Flutter project. -version: 1.0.37+39 +version: 1.0.38+40 environment: sdk: ">=2.2.2 <3.0.0" From 6138389a8183f145499840dd0ec380081b427f4c Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Thu, 29 Oct 2020 17:54:42 +0100 Subject: [PATCH 0259/1140] fix reaction picker alignment --- lib/src/message_actions_modal.dart | 3 ++- lib/src/message_reactions_modal.dart | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/src/message_actions_modal.dart b/lib/src/message_actions_modal.dart index 9562a797..15210f4b 100644 --- a/lib/src/message_actions_modal.dart +++ b/lib/src/message_actions_modal.dart @@ -74,7 +74,8 @@ class MessageActionsModal extends StatelessWidget { if (showReactions && (message.status == MessageSendingStatus.SENT || message.status == null)) - Center( + Align( + alignment: Alignment(-0.3, 0.0), child: ReactionPicker( message: message, messageTheme: messageTheme, diff --git a/lib/src/message_reactions_modal.dart b/lib/src/message_reactions_modal.dart index 4ef35be2..99a48730 100644 --- a/lib/src/message_reactions_modal.dart +++ b/lib/src/message_reactions_modal.dart @@ -65,7 +65,8 @@ class MessageReactionsModal extends StatelessWidget { if (showReactions && (message.status == MessageSendingStatus.SENT || message.status == null)) - Center( + Align( + alignment: Alignment(-0.3, 0.0), child: ReactionPicker( message: message, messageTheme: messageTheme, From a1f556ca2d8dc53dc49924470f72bf7f4c7c6acb Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Thu, 29 Oct 2020 17:58:53 +0100 Subject: [PATCH 0260/1140] fix android build --- example/android/app/build.gradle | 1 + example/pubspec.yaml | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/example/android/app/build.gradle b/example/android/app/build.gradle index 33c33ff2..c5ff1b9e 100644 --- a/example/android/app/build.gradle +++ b/example/android/app/build.gradle @@ -27,6 +27,7 @@ apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" android { compileSdkVersion 29 + ndkVersion '21.3.6528147' sourceSets { main.java.srcDirs += 'src/main/kotlin' diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 69a45dc9..842f471c 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -1,6 +1,6 @@ name: example description: A new Flutter project. -version: 1.0.38+40 +version: 1.0.39+41 environment: sdk: ">=2.2.2 <3.0.0" From 95d466bb9ba85d917a9e596ae7444d3be85eff41 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Fri, 30 Oct 2020 13:51:02 +0530 Subject: [PATCH 0261/1140] init: Start working on attachment --- lib/src/giphy_attachment.dart | 104 +++++++++++++++++----------------- 1 file changed, 53 insertions(+), 51 deletions(-) diff --git a/lib/src/giphy_attachment.dart b/lib/src/giphy_attachment.dart index 62de980b..28092b02 100644 --- a/lib/src/giphy_attachment.dart +++ b/lib/src/giphy_attachment.dart @@ -31,63 +31,65 @@ class GiphyAttachment extends StatelessWidget { ); } - return Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - Stack( - children: [ - GestureDetector( - onTap: () { - Navigator.push(context, MaterialPageRoute(builder: (_) { - return FullScreenImage( - url: attachment.imageUrl ?? - attachment.assetUrl ?? - attachment.thumbUrl, - ); - })); - }, - child: CachedNetworkImage( - height: size?.height, - width: size?.width, - placeholder: (_, __) { - return Container( - width: size?.width, - height: size?.height, - child: Center( - child: CircularProgressIndicator(), - ), - ); + return Card( + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Stack( + children: [ + GestureDetector( + onTap: () { + Navigator.push(context, MaterialPageRoute(builder: (_) { + return FullScreenImage( + url: attachment.imageUrl ?? + attachment.assetUrl ?? + attachment.thumbUrl, + ); + })); }, - imageUrl: attachment.thumbUrl ?? - attachment.imageUrl ?? - attachment.assetUrl, - errorWidget: (context, url, error) => AttachmentError( + child: CachedNetworkImage( + height: size?.height, + width: size?.width, + placeholder: (_, __) { + return Container( + width: size?.width, + height: size?.height, + child: Center( + child: CircularProgressIndicator(), + ), + ); + }, + imageUrl: attachment.thumbUrl ?? + attachment.imageUrl ?? + attachment.assetUrl, + errorWidget: (context, url, error) => AttachmentError( + attachment: attachment, + size: size, + ), + fit: BoxFit.cover, + ), + ), + ], + ), + if (attachment.title != null) + Container( + alignment: Alignment.bottomCenter, + child: Material( + color: messageTheme.messageBackgroundColor, + child: AttachmentTitle( + messageTheme: messageTheme, attachment: attachment, - size: size, ), - fit: BoxFit.cover, ), ), - ], - ), - if (attachment.title != null) - Container( - alignment: Alignment.bottomCenter, - child: Material( - color: messageTheme.messageBackgroundColor, - child: AttachmentTitle( - messageTheme: messageTheme, - attachment: attachment, - ), + if (attachment.actions != null) + AttachmentActions( + attachment: attachment, + message: message, ), - ), - if (attachment.actions != null) - AttachmentActions( - attachment: attachment, - message: message, - ), - ], + ], + ), ); } } From d94d0ba8af67ee0b2b91c56649f285bdabf4e334 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Fri, 30 Oct 2020 13:56:24 +0530 Subject: [PATCH 0262/1140] init: Start working on attachment --- lib/src/giphy_attachment.dart | 104 +++++++++++++++++----------------- lib/src/message_widget.dart | 2 +- 2 files changed, 52 insertions(+), 54 deletions(-) diff --git a/lib/src/giphy_attachment.dart b/lib/src/giphy_attachment.dart index 28092b02..62de980b 100644 --- a/lib/src/giphy_attachment.dart +++ b/lib/src/giphy_attachment.dart @@ -31,65 +31,63 @@ class GiphyAttachment extends StatelessWidget { ); } - return Card( - child: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - Stack( - children: [ - GestureDetector( - onTap: () { - Navigator.push(context, MaterialPageRoute(builder: (_) { - return FullScreenImage( - url: attachment.imageUrl ?? - attachment.assetUrl ?? - attachment.thumbUrl, - ); - })); + return Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Stack( + children: [ + GestureDetector( + onTap: () { + Navigator.push(context, MaterialPageRoute(builder: (_) { + return FullScreenImage( + url: attachment.imageUrl ?? + attachment.assetUrl ?? + attachment.thumbUrl, + ); + })); + }, + child: CachedNetworkImage( + height: size?.height, + width: size?.width, + placeholder: (_, __) { + return Container( + width: size?.width, + height: size?.height, + child: Center( + child: CircularProgressIndicator(), + ), + ); }, - child: CachedNetworkImage( - height: size?.height, - width: size?.width, - placeholder: (_, __) { - return Container( - width: size?.width, - height: size?.height, - child: Center( - child: CircularProgressIndicator(), - ), - ); - }, - imageUrl: attachment.thumbUrl ?? - attachment.imageUrl ?? - attachment.assetUrl, - errorWidget: (context, url, error) => AttachmentError( - attachment: attachment, - size: size, - ), - fit: BoxFit.cover, - ), - ), - ], - ), - if (attachment.title != null) - Container( - alignment: Alignment.bottomCenter, - child: Material( - color: messageTheme.messageBackgroundColor, - child: AttachmentTitle( - messageTheme: messageTheme, + imageUrl: attachment.thumbUrl ?? + attachment.imageUrl ?? + attachment.assetUrl, + errorWidget: (context, url, error) => AttachmentError( attachment: attachment, + size: size, ), + fit: BoxFit.cover, ), ), - if (attachment.actions != null) - AttachmentActions( - attachment: attachment, - message: message, + ], + ), + if (attachment.title != null) + Container( + alignment: Alignment.bottomCenter, + child: Material( + color: messageTheme.messageBackgroundColor, + child: AttachmentTitle( + messageTheme: messageTheme, + attachment: attachment, + ), ), - ], - ), + ), + if (attachment.actions != null) + AttachmentActions( + attachment: attachment, + message: message, + ), + ], ); } } diff --git a/lib/src/message_widget.dart b/lib/src/message_widget.dart index 0e703fa0..e155e509 100644 --- a/lib/src/message_widget.dart +++ b/lib/src/message_widget.dart @@ -175,7 +175,7 @@ class MessageWidget extends StatefulWidget { 'giphy': (context, message, attachment) { return GiphyAttachment( attachment: attachment, - messageTheme: messageTheme, + messageTheme: messageTheme.copyWith(messageBackgroundColor: Colors.white), message: message, size: Size( MediaQuery.of(context).size.width * 0.8, From dcc9edd97864670822c7f9ee803d76186790fd44 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Fri, 30 Oct 2020 14:02:38 +0530 Subject: [PATCH 0263/1140] feat: giphy color --- lib/src/giphy_attachment.dart | 104 +++++++++++++++++----------------- lib/src/message_widget.dart | 2 +- 2 files changed, 54 insertions(+), 52 deletions(-) diff --git a/lib/src/giphy_attachment.dart b/lib/src/giphy_attachment.dart index 62de980b..ed0bfcbf 100644 --- a/lib/src/giphy_attachment.dart +++ b/lib/src/giphy_attachment.dart @@ -31,63 +31,65 @@ class GiphyAttachment extends StatelessWidget { ); } - return Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - Stack( - children: [ - GestureDetector( - onTap: () { - Navigator.push(context, MaterialPageRoute(builder: (_) { - return FullScreenImage( - url: attachment.imageUrl ?? - attachment.assetUrl ?? - attachment.thumbUrl, - ); - })); - }, - child: CachedNetworkImage( - height: size?.height, - width: size?.width, - placeholder: (_, __) { - return Container( - width: size?.width, - height: size?.height, - child: Center( - child: CircularProgressIndicator(), - ), - ); + return Container( + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Stack( + children: [ + GestureDetector( + onTap: () { + Navigator.push(context, MaterialPageRoute(builder: (_) { + return FullScreenImage( + url: attachment.imageUrl ?? + attachment.assetUrl ?? + attachment.thumbUrl, + ); + })); }, - imageUrl: attachment.thumbUrl ?? - attachment.imageUrl ?? - attachment.assetUrl, - errorWidget: (context, url, error) => AttachmentError( + child: CachedNetworkImage( + height: size?.height, + width: size?.width, + placeholder: (_, __) { + return Container( + width: size?.width, + height: size?.height, + child: Center( + child: CircularProgressIndicator(), + ), + ); + }, + imageUrl: attachment.thumbUrl ?? + attachment.imageUrl ?? + attachment.assetUrl, + errorWidget: (context, url, error) => AttachmentError( + attachment: attachment, + size: size, + ), + fit: BoxFit.cover, + ), + ), + ], + ), + if (attachment.title != null) + Container( + alignment: Alignment.bottomCenter, + child: Material( + color: Colors.white, + child: AttachmentTitle( + messageTheme: messageTheme, attachment: attachment, - size: size, ), - fit: BoxFit.cover, ), ), - ], - ), - if (attachment.title != null) - Container( - alignment: Alignment.bottomCenter, - child: Material( - color: messageTheme.messageBackgroundColor, - child: AttachmentTitle( - messageTheme: messageTheme, - attachment: attachment, - ), + if (attachment.actions != null) + AttachmentActions( + attachment: attachment, + message: message, ), - ), - if (attachment.actions != null) - AttachmentActions( - attachment: attachment, - message: message, - ), - ], + ], + ), ); } } diff --git a/lib/src/message_widget.dart b/lib/src/message_widget.dart index e155e509..021fd588 100644 --- a/lib/src/message_widget.dart +++ b/lib/src/message_widget.dart @@ -175,7 +175,7 @@ class MessageWidget extends StatefulWidget { 'giphy': (context, message, attachment) { return GiphyAttachment( attachment: attachment, - messageTheme: messageTheme.copyWith(messageBackgroundColor: Colors.white), + messageTheme: messageTheme.copyWith(messageBackgroundColor: Colors.white,), message: message, size: Size( MediaQuery.of(context).size.width * 0.8, From 59748a88f751b1e32d498e13bb53a34c88c038bf Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Fri, 30 Oct 2020 09:07:51 +0100 Subject: [PATCH 0264/1140] update llc dependency --- pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pubspec.yaml b/pubspec.yaml index d61e6874..452eb69a 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -24,7 +24,7 @@ dependencies: file_picker: ^2.0.8+1 image_picker: ^0.6.7+2 flutter_keyboard_visibility: ^3.2.1 - stream_chat: ^0.2.10 + stream_chat: ^0.2.10+1 mime: ^0.9.6+3 visibility_detector: ^0.1.5 http_parser: ^3.1.4 From 950d852b0ce9688de2afd4197e7048d7a3f55bdf Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Fri, 30 Oct 2020 14:04:46 +0530 Subject: [PATCH 0265/1140] feat: giphy color --- lib/src/giphy_attachment.dart | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/src/giphy_attachment.dart b/lib/src/giphy_attachment.dart index ed0bfcbf..febc757e 100644 --- a/lib/src/giphy_attachment.dart +++ b/lib/src/giphy_attachment.dart @@ -32,6 +32,7 @@ class GiphyAttachment extends StatelessWidget { } return Container( + color: Colors.white, child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.stretch, From 67499020cb25eeaa51a38e82b740be291390cdb7 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Fri, 30 Oct 2020 17:04:12 +0530 Subject: [PATCH 0266/1140] feat: Tried fix --- lib/src/reaction_picker.dart | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/src/reaction_picker.dart b/lib/src/reaction_picker.dart index bf4c4ed0..87e413ed 100644 --- a/lib/src/reaction_picker.dart +++ b/lib/src/reaction_picker.dart @@ -20,6 +20,7 @@ class ReactionPicker extends StatelessWidget { @override Widget build(BuildContext context) { + var user = StreamChat.of(context).user; final reactionIcons = StreamChatTheme.of(context).reactionIcons; return Material( color: messageTheme.reactionsBackgroundColor, @@ -29,7 +30,7 @@ class ReactionPicker extends StatelessWidget { ), child: Row( crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: MainAxisAlignment.center, + mainAxisAlignment: user.id == message.user.id ? MainAxisAlignment.end : MainAxisAlignment.start, mainAxisSize: MainAxisSize.min, children: reactionIcons.map((reactionIcon) { final ownReactionIndex = message.ownReactions?.indexWhere( From f10d63f713ae0c76b5313f7dde5a322c272f3007 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Fri, 30 Oct 2020 17:10:06 +0530 Subject: [PATCH 0267/1140] feat: Tried fix --- lib/src/reaction_picker.dart | 67 +++++++++++++++++++----------------- 1 file changed, 36 insertions(+), 31 deletions(-) diff --git a/lib/src/reaction_picker.dart b/lib/src/reaction_picker.dart index 87e413ed..3a0600fe 100644 --- a/lib/src/reaction_picker.dart +++ b/lib/src/reaction_picker.dart @@ -29,37 +29,42 @@ class ReactionPicker extends StatelessWidget { borderRadius: BorderRadius.circular(24), ), child: Row( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: user.id == message.user.id ? MainAxisAlignment.end : MainAxisAlignment.start, - mainAxisSize: MainAxisSize.min, - children: reactionIcons.map((reactionIcon) { - final ownReactionIndex = message.ownReactions?.indexWhere( - (reaction) => reaction.type == reactionIcon.type) ?? - -1; - return IconButton( - iconSize: 24, - icon: Icon( - reactionIcon.iconData, - color: ownReactionIndex != -1 - ? StreamChatTheme.of(context).accentColor - : Theme.of(context).iconTheme.color.withOpacity(.5), - ), - onPressed: () { - if (ownReactionIndex != -1) { - removeReaction( - context, - message.ownReactions[ownReactionIndex], - ); - } else { - sendReaction( - context, - reactionIcon.type, - ); - } - }, - ); - }).toList(), - ), + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.end, + mainAxisSize: MainAxisSize.min, + children: [ + if(user.id == message.id) + SizedBox( + width: 50.0, + ), + ...reactionIcons.map((reactionIcon) { + final ownReactionIndex = message.ownReactions?.indexWhere( + (reaction) => reaction.type == reactionIcon.type) ?? + -1; + return IconButton( + iconSize: 24, + icon: Icon( + reactionIcon.iconData, + color: ownReactionIndex != -1 + ? StreamChatTheme.of(context).accentColor + : Theme.of(context).iconTheme.color.withOpacity(.5), + ), + onPressed: () { + if (ownReactionIndex != -1) { + removeReaction( + context, + message.ownReactions[ownReactionIndex], + ); + } else { + sendReaction( + context, + reactionIcon.type, + ); + } + }, + ); + }).toList(), + ]), ); } From d36b1c64ea4c408725f44ca72f1e680065ebc7f2 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Fri, 30 Oct 2020 17:17:55 +0530 Subject: [PATCH 0268/1140] feat: Tried fix --- lib/src/message_reactions_modal.dart | 16 ++++++++++------ lib/src/reaction_picker.dart | 10 ++-------- 2 files changed, 12 insertions(+), 14 deletions(-) diff --git a/lib/src/message_reactions_modal.dart b/lib/src/message_reactions_modal.dart index 99a48730..af1d81ee 100644 --- a/lib/src/message_reactions_modal.dart +++ b/lib/src/message_reactions_modal.dart @@ -66,12 +66,16 @@ class MessageReactionsModal extends StatelessWidget { (message.status == MessageSendingStatus.SENT || message.status == null)) Align( - alignment: Alignment(-0.3, 0.0), - child: ReactionPicker( - message: message, - messageTheme: messageTheme, - ), - ), + alignment: Alignment(-0.3, 0.0), + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + ReactionPicker( + message: message, + messageTheme: messageTheme, + ), + ], + )), IgnorePointer( child: MessageWidget( key: Key('MessageWidget'), diff --git a/lib/src/reaction_picker.dart b/lib/src/reaction_picker.dart index 3a0600fe..e4a8bdf8 100644 --- a/lib/src/reaction_picker.dart +++ b/lib/src/reaction_picker.dart @@ -20,7 +20,6 @@ class ReactionPicker extends StatelessWidget { @override Widget build(BuildContext context) { - var user = StreamChat.of(context).user; final reactionIcons = StreamChatTheme.of(context).reactionIcons; return Material( color: messageTheme.reactionsBackgroundColor, @@ -32,12 +31,7 @@ class ReactionPicker extends StatelessWidget { crossAxisAlignment: CrossAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.end, mainAxisSize: MainAxisSize.min, - children: [ - if(user.id == message.id) - SizedBox( - width: 50.0, - ), - ...reactionIcons.map((reactionIcon) { + children: reactionIcons.map((reactionIcon) { final ownReactionIndex = message.ownReactions?.indexWhere( (reaction) => reaction.type == reactionIcon.type) ?? -1; @@ -64,7 +58,7 @@ class ReactionPicker extends StatelessWidget { }, ); }).toList(), - ]), + ), ); } From 5ff432eb794e41389f385de1eb19fb971addab92 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Fri, 30 Oct 2020 17:21:45 +0530 Subject: [PATCH 0269/1140] feat: Tried fix --- lib/src/message_reactions_modal.dart | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/lib/src/message_reactions_modal.dart b/lib/src/message_reactions_modal.dart index af1d81ee..7e1e100a 100644 --- a/lib/src/message_reactions_modal.dart +++ b/lib/src/message_reactions_modal.dart @@ -36,6 +36,7 @@ class MessageReactionsModal extends StatelessWidget { @override Widget build(BuildContext context) { + var user = StreamChat.of(context).user; return GestureDetector( behavior: HitTestBehavior.translucent, onTap: () { @@ -66,16 +67,12 @@ class MessageReactionsModal extends StatelessWidget { (message.status == MessageSendingStatus.SENT || message.status == null)) Align( - alignment: Alignment(-0.3, 0.0), - child: Row( - mainAxisSize: MainAxisSize.min, - children: [ - ReactionPicker( - message: message, - messageTheme: messageTheme, - ), - ], - )), + alignment: Alignment(-0.3 + (user.id == message.id ? 0.2 : 0.0), 0.0), + child: ReactionPicker( + message: message, + messageTheme: messageTheme, + ), + ), IgnorePointer( child: MessageWidget( key: Key('MessageWidget'), From b39038d0ab1a8cfb66fe8423ca14f5b9538d7981 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Fri, 30 Oct 2020 17:56:31 +0530 Subject: [PATCH 0270/1140] feat: Alignment is now calculated --- lib/src/message_reactions_modal.dart | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/lib/src/message_reactions_modal.dart b/lib/src/message_reactions_modal.dart index 7e1e100a..559e475c 100644 --- a/lib/src/message_reactions_modal.dart +++ b/lib/src/message_reactions_modal.dart @@ -36,7 +36,17 @@ class MessageReactionsModal extends StatelessWidget { @override Widget build(BuildContext context) { + var size = MediaQuery.of(context).size; var user = StreamChat.of(context).user; + + var roughMaxSize = 2 * size.width / 3; + var roughSentenceSize = message.text.length * messageTheme.messageText.fontSize * 1.2; + var divFactor = roughSentenceSize / roughMaxSize; + + print(roughMaxSize); + print(roughSentenceSize); + print(divFactor); + return GestureDetector( behavior: HitTestBehavior.translucent, onTap: () { @@ -67,7 +77,7 @@ class MessageReactionsModal extends StatelessWidget { (message.status == MessageSendingStatus.SENT || message.status == null)) Align( - alignment: Alignment(-0.3 + (user.id == message.id ? 0.2 : 0.0), 0.0), + alignment: Alignment(user.id == message.user.id ? (divFactor > 1.0 ? 0.0 : (1.0 - divFactor)) : (divFactor > 1.0 ? 0.0 : -(1.0 - divFactor)), 0.0), child: ReactionPicker( message: message, messageTheme: messageTheme, @@ -144,10 +154,10 @@ class MessageReactionsModal extends StatelessWidget { alignment: WrapAlignment.start, children: message.latestReactions .map((e) => _buildReaction( - e, - currentUser, - context, - )) + e, + currentUser, + context, + )) .toList(), ), ), @@ -160,10 +170,10 @@ class MessageReactionsModal extends StatelessWidget { } Widget _buildReaction( - Reaction reaction, - User currentUser, - BuildContext context, - ) { + Reaction reaction, + User currentUser, + BuildContext context, + ) { final isCurrentUser = reaction.user.id == currentUser.id; return ConstrainedBox( constraints: BoxConstraints.loose(Size( From 2859c257e9e193f7f77c5e5e7318be9bccf17aea Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Fri, 30 Oct 2020 17:58:53 +0530 Subject: [PATCH 0271/1140] removed print and dartfmt --- lib/src/message_reactions_modal.dart | 29 ++++++------- lib/src/reaction_picker.dart | 62 ++++++++++++++-------------- 2 files changed, 46 insertions(+), 45 deletions(-) diff --git a/lib/src/message_reactions_modal.dart b/lib/src/message_reactions_modal.dart index 559e475c..1c3c3e0f 100644 --- a/lib/src/message_reactions_modal.dart +++ b/lib/src/message_reactions_modal.dart @@ -40,13 +40,10 @@ class MessageReactionsModal extends StatelessWidget { var user = StreamChat.of(context).user; var roughMaxSize = 2 * size.width / 3; - var roughSentenceSize = message.text.length * messageTheme.messageText.fontSize * 1.2; + var roughSentenceSize = + message.text.length * messageTheme.messageText.fontSize * 1.2; var divFactor = roughSentenceSize / roughMaxSize; - print(roughMaxSize); - print(roughSentenceSize); - print(divFactor); - return GestureDetector( behavior: HitTestBehavior.translucent, onTap: () { @@ -77,7 +74,11 @@ class MessageReactionsModal extends StatelessWidget { (message.status == MessageSendingStatus.SENT || message.status == null)) Align( - alignment: Alignment(user.id == message.user.id ? (divFactor > 1.0 ? 0.0 : (1.0 - divFactor)) : (divFactor > 1.0 ? 0.0 : -(1.0 - divFactor)), 0.0), + alignment: Alignment( + user.id == message.user.id + ? (divFactor > 1.0 ? 0.0 : (1.0 - divFactor)) + : (divFactor > 1.0 ? 0.0 : -(1.0 - divFactor)), + 0.0), child: ReactionPicker( message: message, messageTheme: messageTheme, @@ -154,10 +155,10 @@ class MessageReactionsModal extends StatelessWidget { alignment: WrapAlignment.start, children: message.latestReactions .map((e) => _buildReaction( - e, - currentUser, - context, - )) + e, + currentUser, + context, + )) .toList(), ), ), @@ -170,10 +171,10 @@ class MessageReactionsModal extends StatelessWidget { } Widget _buildReaction( - Reaction reaction, - User currentUser, - BuildContext context, - ) { + Reaction reaction, + User currentUser, + BuildContext context, + ) { final isCurrentUser = reaction.user.id == currentUser.id; return ConstrainedBox( constraints: BoxConstraints.loose(Size( diff --git a/lib/src/reaction_picker.dart b/lib/src/reaction_picker.dart index e4a8bdf8..e7d302e6 100644 --- a/lib/src/reaction_picker.dart +++ b/lib/src/reaction_picker.dart @@ -28,37 +28,37 @@ class ReactionPicker extends StatelessWidget { borderRadius: BorderRadius.circular(24), ), child: Row( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: MainAxisAlignment.end, - mainAxisSize: MainAxisSize.min, - children: reactionIcons.map((reactionIcon) { - final ownReactionIndex = message.ownReactions?.indexWhere( - (reaction) => reaction.type == reactionIcon.type) ?? - -1; - return IconButton( - iconSize: 24, - icon: Icon( - reactionIcon.iconData, - color: ownReactionIndex != -1 - ? StreamChatTheme.of(context).accentColor - : Theme.of(context).iconTheme.color.withOpacity(.5), - ), - onPressed: () { - if (ownReactionIndex != -1) { - removeReaction( - context, - message.ownReactions[ownReactionIndex], - ); - } else { - sendReaction( - context, - reactionIcon.type, - ); - } - }, - ); - }).toList(), - ), + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.end, + mainAxisSize: MainAxisSize.min, + children: reactionIcons.map((reactionIcon) { + final ownReactionIndex = message.ownReactions?.indexWhere( + (reaction) => reaction.type == reactionIcon.type) ?? + -1; + return IconButton( + iconSize: 24, + icon: Icon( + reactionIcon.iconData, + color: ownReactionIndex != -1 + ? StreamChatTheme.of(context).accentColor + : Theme.of(context).iconTheme.color.withOpacity(.5), + ), + onPressed: () { + if (ownReactionIndex != -1) { + removeReaction( + context, + message.ownReactions[ownReactionIndex], + ); + } else { + sendReaction( + context, + reactionIcon.type, + ); + } + }, + ); + }).toList(), + ), ); } From 93101f99c4dd665b768584f320c1d3139efb3d84 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Fri, 30 Oct 2020 14:45:47 +0100 Subject: [PATCH 0272/1140] fix reaction picker for messages without text --- lib/src/message_actions_modal.dart | 15 ++++++++++++++- lib/src/message_reactions_modal.dart | 3 ++- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/lib/src/message_actions_modal.dart b/lib/src/message_actions_modal.dart index 15210f4b..00354a49 100644 --- a/lib/src/message_actions_modal.dart +++ b/lib/src/message_actions_modal.dart @@ -45,6 +45,15 @@ class MessageActionsModal extends StatelessWidget { @override Widget build(BuildContext context) { + var size = MediaQuery.of(context).size; + var user = StreamChat.of(context).user; + + var roughMaxSize = 2 * size.width / 3; + var roughSentenceSize = + message.text.length * messageTheme.messageText.fontSize * 1.2; + var divFactor = + roughSentenceSize == 0 ? 1 : (roughSentenceSize / roughMaxSize); + return GestureDetector( behavior: HitTestBehavior.translucent, onTap: () { @@ -75,7 +84,11 @@ class MessageActionsModal extends StatelessWidget { (message.status == MessageSendingStatus.SENT || message.status == null)) Align( - alignment: Alignment(-0.3, 0.0), + alignment: Alignment( + user.id == message.user.id + ? (divFactor > 1.0 ? 0.0 : (1.0 - divFactor)) + : (divFactor > 1.0 ? 0.0 : -(1.0 - divFactor)), + 0.0), child: ReactionPicker( message: message, messageTheme: messageTheme, diff --git a/lib/src/message_reactions_modal.dart b/lib/src/message_reactions_modal.dart index 1c3c3e0f..fc3f68a4 100644 --- a/lib/src/message_reactions_modal.dart +++ b/lib/src/message_reactions_modal.dart @@ -42,7 +42,8 @@ class MessageReactionsModal extends StatelessWidget { var roughMaxSize = 2 * size.width / 3; var roughSentenceSize = message.text.length * messageTheme.messageText.fontSize * 1.2; - var divFactor = roughSentenceSize / roughMaxSize; + var divFactor = + roughSentenceSize == 0 ? 1 : (roughSentenceSize / roughMaxSize); return GestureDetector( behavior: HitTestBehavior.translucent, From 5488fde66e3f17b7c4fac8ecb840fc94a7756666 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Mon, 2 Nov 2020 15:50:19 +0530 Subject: [PATCH 0273/1140] change bg to white --- lib/src/giphy_attachment.dart | 105 +++++++++++++++++----------------- lib/src/message_widget.dart | 6 +- 2 files changed, 54 insertions(+), 57 deletions(-) diff --git a/lib/src/giphy_attachment.dart b/lib/src/giphy_attachment.dart index febc757e..6a5d44b8 100644 --- a/lib/src/giphy_attachment.dart +++ b/lib/src/giphy_attachment.dart @@ -31,66 +31,63 @@ class GiphyAttachment extends StatelessWidget { ); } - return Container( - color: Colors.white, - child: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - Stack( - children: [ - GestureDetector( - onTap: () { - Navigator.push(context, MaterialPageRoute(builder: (_) { - return FullScreenImage( - url: attachment.imageUrl ?? - attachment.assetUrl ?? - attachment.thumbUrl, - ); - })); + return Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Stack( + children: [ + GestureDetector( + onTap: () { + Navigator.push(context, MaterialPageRoute(builder: (_) { + return FullScreenImage( + url: attachment.imageUrl ?? + attachment.assetUrl ?? + attachment.thumbUrl, + ); + })); + }, + child: CachedNetworkImage( + height: size?.height, + width: size?.width, + placeholder: (_, __) { + return Container( + width: size?.width, + height: size?.height, + child: Center( + child: CircularProgressIndicator(), + ), + ); }, - child: CachedNetworkImage( - height: size?.height, - width: size?.width, - placeholder: (_, __) { - return Container( - width: size?.width, - height: size?.height, - child: Center( - child: CircularProgressIndicator(), - ), - ); - }, - imageUrl: attachment.thumbUrl ?? - attachment.imageUrl ?? - attachment.assetUrl, - errorWidget: (context, url, error) => AttachmentError( - attachment: attachment, - size: size, - ), - fit: BoxFit.cover, - ), - ), - ], - ), - if (attachment.title != null) - Container( - alignment: Alignment.bottomCenter, - child: Material( - color: Colors.white, - child: AttachmentTitle( - messageTheme: messageTheme, + imageUrl: attachment.thumbUrl ?? + attachment.imageUrl ?? + attachment.assetUrl, + errorWidget: (context, url, error) => AttachmentError( attachment: attachment, + size: size, ), + fit: BoxFit.cover, ), ), - if (attachment.actions != null) - AttachmentActions( - attachment: attachment, - message: message, + ], + ), + if (attachment.title != null) + Container( + alignment: Alignment.bottomCenter, + child: Material( + color: Colors.white, + child: AttachmentTitle( + messageTheme: messageTheme, + attachment: attachment, + ), ), - ], - ), + ), + if (attachment.actions != null) + AttachmentActions( + attachment: attachment, + message: message, + ), + ], ); } } diff --git a/lib/src/message_widget.dart b/lib/src/message_widget.dart index 021fd588..73ace68b 100644 --- a/lib/src/message_widget.dart +++ b/lib/src/message_widget.dart @@ -512,12 +512,12 @@ class _MessageWidgetState extends State { widget.message, attachment, ); - return wrapAttachmentWidget(context, attachmentWidget); + return wrapAttachmentWidget(context, attachmentWidget, attachment: attachment); })?.toList() ?? []; } - Padding wrapAttachmentWidget(BuildContext context, Widget attachmentWidget) { + Padding wrapAttachmentWidget(BuildContext context, Widget attachmentWidget, {Attachment attachment}) { return Padding( padding: EdgeInsets.only( bottom: 4, @@ -526,7 +526,7 @@ class _MessageWidgetState extends State { onTap: () => retryMessage(context), onLongPress: () => onLongPress(context), child: Material( - color: _getBackgroundColor(), + color: attachment?.type == 'giphy' ? Colors.white : _getBackgroundColor(), clipBehavior: Clip.hardEdge, shape: widget.attachmentShape ?? widget.shape ?? From 8949598e2f0d0af80ceaad42241fde2adb342214 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Mon, 2 Nov 2020 18:57:55 +0530 Subject: [PATCH 0274/1140] created giphy sending and sent attachments --- lib/src/giphy_attachment.dart | 294 ++++++++++++++++++++++++++++------ 1 file changed, 245 insertions(+), 49 deletions(-) diff --git a/lib/src/giphy_attachment.dart b/lib/src/giphy_attachment.dart index 6a5d44b8..73278fb7 100644 --- a/lib/src/giphy_attachment.dart +++ b/lib/src/giphy_attachment.dart @@ -1,5 +1,7 @@ import 'package:cached_network_image/cached_network_image.dart'; +import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; +import 'package:jiffy/jiffy.dart'; import 'package:stream_chat_flutter/src/attachment_actions.dart'; import '../stream_chat_flutter.dart'; @@ -31,63 +33,257 @@ class GiphyAttachment extends StatelessWidget { ); } - return Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - Stack( - children: [ - GestureDetector( - onTap: () { - Navigator.push(context, MaterialPageRoute(builder: (_) { - return FullScreenImage( - url: attachment.imageUrl ?? - attachment.assetUrl ?? - attachment.thumbUrl, - ); - })); - }, - child: CachedNetworkImage( - height: size?.height, - width: size?.width, - placeholder: (_, __) { - return Container( - width: size?.width, - height: size?.height, - child: Center( - child: CircularProgressIndicator(), - ), - ); + return attachment.actions != null + ? _buildSendingAttachment(context) + : _buildSentAttachment(context); + } + + Widget _buildSendingAttachment(context) { + final streamChannel = StreamChannel.of(context); + + return Card( + clipBehavior: Clip.antiAlias, + shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8.0)), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Stack( + children: [ + GestureDetector( + onTap: () { + Navigator.push(context, MaterialPageRoute(builder: (_) { + return FullScreenImage( + url: attachment.imageUrl ?? + attachment.assetUrl ?? + attachment.thumbUrl, + ); + })); }, - imageUrl: attachment.thumbUrl ?? - attachment.imageUrl ?? - attachment.assetUrl, - errorWidget: (context, url, error) => AttachmentError( - attachment: attachment, - size: size, + child: Padding( + padding: const EdgeInsets.all(8.0), + child: CachedNetworkImage( + height: size?.height, + width: size?.width, + placeholder: (_, __) { + return Container( + width: size?.width, + height: size?.height, + child: Center( + child: CircularProgressIndicator(), + ), + ); + }, + imageUrl: attachment.thumbUrl ?? + attachment.imageUrl ?? + attachment.assetUrl, + errorWidget: (context, url, error) => AttachmentError( + attachment: attachment, + size: size, + ), + fit: BoxFit.cover, + ), + ), + ), + Positioned( + left: 0, + top: 0, + child: Container( + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.only( + bottomRight: Radius.circular(16.0), + )), + child: Padding( + padding: const EdgeInsets.only( + left: 4.0, right: 4.0, top: 6.0, bottom: 2.0), + child: Row( + children: [ + Icon( + StreamIcons.lightning, + color: StreamChatTheme.of(context).accentColor, + size: 15.0, + ), + Text( + 'GIPHY', + style: TextStyle( + color: StreamChatTheme.of(context).accentColor, + fontWeight: FontWeight.bold, + fontSize: 11.0, + ), + ), + ], + ), + ), + ), + ), + ], + ), + if (attachment.title != null) + Container( + alignment: Alignment.bottomCenter, + child: Material( + color: Colors.white, + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Card( + child: IconButton( + icon: Icon( + StreamIcons.left, + size: 18.0, + ), + onPressed: () { + streamChannel.channel.sendAction(message, { + 'image_action': 'shuffle', + }); + }, + ), + shape: CircleBorder(), + ), + Expanded( + child: Text( + '"${attachment.title}"', + style: TextStyle( + fontStyle: FontStyle.italic, + ), + ), + ), + Card( + child: IconButton( + icon: Icon( + StreamIcons.right, + size: 18.0, + ), + onPressed: () { + streamChannel.channel.sendAction(message, { + 'image_action': 'shuffle', + }); + }, + ), + shape: CircleBorder(), + ), + ], ), - fit: BoxFit.cover, ), ), - ], - ), - if (attachment.title != null) + SizedBox( + height: 4.0, + ), Container( - alignment: Alignment.bottomCenter, - child: Material( - color: Colors.white, - child: AttachmentTitle( - messageTheme: messageTheme, - attachment: attachment, + color: Colors.black.withOpacity(0.2), + width: double.infinity, + height: 0.5, + ), + Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + FlatButton( + onPressed: () { + streamChannel.channel.sendAction(message, { + 'image_action': 'cancel', + }); + }, + child: Row( + children: [ + Text( + 'Cancel', + style: TextStyle( + fontWeight: FontWeight.bold, + ), + ), + ], + ), ), + Container( + width: 0.5, + color: Colors.black.withOpacity(0.2), + height: 50.0, + ), + FlatButton( + onPressed: () { + streamChannel.channel.sendAction(message, { + 'image_action': 'send', + }); + }, + child: Row( + children: [ + Text( + 'Send', + style: TextStyle( + color: StreamChatTheme.of(context).accentColor, + fontWeight: FontWeight.bold), + ), + ], + ), + ), + ], + ), + ], + ), + ); + } + + Widget _buildSentAttachment(context) { + return Container( + child: Column( + children: [ + CachedNetworkImage( + height: size?.height, + width: size?.width, + placeholder: (_, __) { + return Container( + width: size?.width, + height: size?.height, + child: Center( + child: CircularProgressIndicator(), + ), + ); + }, + imageUrl: attachment.thumbUrl ?? + attachment.imageUrl ?? + attachment.assetUrl, + errorWidget: (context, url, error) => AttachmentError( + attachment: attachment, + size: size, ), + fit: BoxFit.cover, ), - if (attachment.actions != null) - AttachmentActions( - attachment: attachment, - message: message, - ), - ], + Padding( + padding: const EdgeInsets.symmetric(vertical: 8.0), + child: Row( + children: [ + Row( + children: [ + Icon( + StreamIcons.lightning, + color: StreamChatTheme.of(context).accentColor, + size: 15.0, + ), + Text( + 'GIPHY', + style: TextStyle( + color: StreamChatTheme.of(context).accentColor, + fontWeight: FontWeight.bold, + fontSize: 11.0, + ), + ), + ], + ), + Text( + Jiffy(message.createdAt.toLocal()).format(' HH:mm'), + style: TextStyle( + fontSize: 12.0, + color: Colors.black.withOpacity(0.5), + ), + ) + ], + mainAxisAlignment: MainAxisAlignment.spaceBetween, + ), + ) + ], + ), ); } } From c62c65ade50305a03a9bd90e253baae57a414b67 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Mon, 2 Nov 2020 15:46:35 +0100 Subject: [PATCH 0275/1140] add emoji picker --- lib/src/message_input.dart | 185 ++++++++++++++++++++++++++++--------- pubspec.yaml | 2 + 2 files changed, 145 insertions(+), 42 deletions(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 7bdbfd5d..be987950 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -1,11 +1,14 @@ import 'dart:async'; +import 'dart:convert'; import 'dart:math'; import 'package:file_picker/file_picker.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_emoji/flutter_emoji.dart'; import 'package:flutter_keyboard_visibility/flutter_keyboard_visibility.dart'; +import 'package:fuzzy/fuzzy.dart'; import 'package:http_parser/http_parser.dart'; import 'package:image_picker/image_picker.dart'; import 'package:mime/mime.dart'; @@ -167,7 +170,8 @@ class MessageInputState extends State { bool _messageIsPresent = false; bool _typingStarted = false; bool _commandEnabled = false; - OverlayEntry _commandsOverlay, _mentionsOverlay; + OverlayEntry _commandsOverlay, _mentionsOverlay, _emojiOverlay; + Fuzzy _emojiFuse; Command _chosenCommand; bool _actionsShrunk = false; @@ -319,6 +323,8 @@ class MessageInputState extends State { _commandsOverlay = null; _mentionsOverlay?.remove(); _mentionsOverlay = null; + _emojiOverlay?.remove(); + _emojiOverlay = null; if (s.startsWith('/')) { var matchedCommandsList = StreamChannel.of(context) @@ -354,6 +360,23 @@ class MessageInputState extends State { _mentionsOverlay = _buildMentionsOverlayEntry(); Overlay.of(context).insert(_mentionsOverlay); } + + if (textEditingController.selection.isCollapsed && + (s[textEditingController.selection.start - 1] == ':' || + textEditingController.text + .substring( + 0, + textEditingController.selection.start, + ) + .split(' ') + .last + .contains(':'))) { + _emojiOverlay = _buildEmojiOverlay(); + + if (_emojiOverlay != null) { + Overlay.of(context).insert(_emojiOverlay); + } + } }, onTap: () { setState(() { @@ -419,40 +442,6 @@ class MessageInputState extends State { ); } - Positioned _buildBorder(BuildContext context) { - return Positioned.fill( - child: Container( - width: MediaQuery.of(context).size.width, - padding: EdgeInsets.all(2), - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(10.0), - gradient: _getGradient(context), - ), - child: Container( - decoration: BoxDecoration( - color: StreamChatTheme.of(context) - .channelTheme - .inputBackground - .withAlpha(255), - borderRadius: BorderRadius.circular(10.0), - ), - child: Container( - decoration: BoxDecoration( - color: StreamChatTheme.of(context).channelTheme.inputBackground, - borderRadius: BorderRadius.circular(10.0), - border: Border.all( - color: _typingStarted - ? Colors.transparent - : Theme.of(context).brightness == Brightness.dark - ? Colors.white.withOpacity(.2) - : Colors.black.withOpacity(.2)), - ), - ), - ), - ), - ); - } - OverlayEntry _buildCommandsOverlayEntry() { final text = textEditingController.text; final commands = StreamChannel.of(context) @@ -482,13 +471,6 @@ class MessageInputState extends State { child: Container( constraints: BoxConstraints.loose(Size.fromHeight(400)), decoration: BoxDecoration( - // boxShadow: [ - // BoxShadow( - // spreadRadius: -8, - // blurRadius: 5.0, - // offset: Offset(0, -4), - // ), - // ], color: StreamChatTheme.of(context).primaryColor, borderRadius: BorderRadius.circular(8.0)), child: ListView( @@ -664,6 +646,105 @@ class MessageInputState extends State { }); } + OverlayEntry _buildEmojiOverlay() { + final splits = textEditingController.text + .substring(0, textEditingController.value.selection.start) + .split(':'); + final query = splits.last.toLowerCase(); + + if (query.isEmpty) { + return null; + } + + final parser = EmojiParser(); + final emojis = + _emojiFuse.search(query).map((e) => parser.get(e.item)).toList(); + + RenderBox renderBox = context.findRenderObject(); + final size = renderBox.size; + + return OverlayEntry(builder: (context) { + return Positioned( + bottom: size.height + MediaQuery.of(context).viewInsets.bottom, + left: 0, + right: 0, + child: Card( + margin: EdgeInsets.all(8.0), + elevation: 2.0, + color: StreamChatTheme.of(context).primaryColor, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8.0), + ), + clipBehavior: Clip.antiAlias, + child: Container( + constraints: BoxConstraints.loose(Size.fromHeight(200)), + decoration: BoxDecoration( + boxShadow: [ + BoxShadow( + spreadRadius: -8, + blurRadius: 5.0, + offset: Offset(0, -4), + ), + ], + color: StreamChatTheme.of(context).primaryColor, + ), + child: ListView( + padding: const EdgeInsets.all(0), + shrinkWrap: true, + children: [ + Padding( + padding: const EdgeInsets.only(left: 8.0, top: 8.0), + child: Row( + children: [ + Padding( + padding: const EdgeInsets.symmetric(horizontal: 8.0), + child: Icon( + StreamIcons.smile, + color: StreamChatTheme.of(context).accentColor, + ), + ), + Text( + 'Emoji matching "$query"', + style: TextStyle( + color: Colors.black.withOpacity(.5), + ), + ) + ], + ), + ), + ...emojis.map((emoji) => ListTile( + title: Text( + "${emoji.code} ${emoji.name.replaceAll('_', ' ')}", + style: TextStyle( + fontWeight: FontWeight.bold, + fontSize: 14.5, + ), + ), + onTap: () { + splits[splits.length - 1] = emoji.code; + final rejoin = splits.join(''); + + textEditingController.value = TextEditingValue( + text: rejoin + + textEditingController.text.substring( + textEditingController.selection.start), + selection: TextSelection.collapsed( + offset: rejoin.length, + ), + ); + + _emojiOverlay?.remove(); + _emojiOverlay = null; + }, + )) + ], + ), + ), + ), + ); + }); + } + void _setCommand(Command c) { textEditingController.clear(); setState(() { @@ -1217,6 +1298,13 @@ class MessageInputState extends State { @override void initState() { super.initState(); + Map emojiMap = jsonDecode(EmojiParser.JSON_EMOJI); + + _emojiFuse = Fuzzy(emojiMap.keys.toList(), + options: FuzzyOptions( + matchAllTokens: true, + tokenize: true, + )); if (!kIsWeb) { _keyboardListener = KeyboardVisibility.onChange.listen((visible) { @@ -1238,6 +1326,15 @@ class MessageInputState extends State { }); } } + + if (_emojiOverlay != null) { + if (textEditingController.text.contains('@')) { + WidgetsBinding.instance.addPostFrameCallback((_) { + _emojiOverlay = _buildEmojiOverlay(); + Overlay.of(context).insert(_emojiOverlay); + }); + } + } } else { if (_commandsOverlay != null) { _commandsOverlay.remove(); @@ -1245,6 +1342,9 @@ class MessageInputState extends State { if (_mentionsOverlay != null) { _mentionsOverlay.remove(); } + if (_emojiOverlay != null) { + _emojiOverlay.remove(); + } } }); } @@ -1273,6 +1373,7 @@ class MessageInputState extends State { @override void dispose() { _commandsOverlay?.remove(); + _emojiOverlay?.remove(); _mentionsOverlay?.remove(); _keyboardListener?.cancel(); super.dispose(); diff --git a/pubspec.yaml b/pubspec.yaml index 452eb69a..1dfb195f 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -25,7 +25,9 @@ dependencies: image_picker: ^0.6.7+2 flutter_keyboard_visibility: ^3.2.1 stream_chat: ^0.2.10+1 + flutter_emoji: ^2.2.1+1 mime: ^0.9.6+3 + fuzzy: ^0.2.3 visibility_detector: ^0.1.5 http_parser: ^3.1.4 flutter_slidable: ^0.5.4 From b0897d9cf017fb18c019bd9a4d736117cf5e1497 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Tue, 3 Nov 2020 10:09:30 +0100 Subject: [PATCH 0276/1140] show big emoji --- lib/src/message_widget.dart | 98 +++++++++++++++++++++++-------------- 1 file changed, 60 insertions(+), 38 deletions(-) diff --git a/lib/src/message_widget.dart b/lib/src/message_widget.dart index e65da576..2790f3c6 100644 --- a/lib/src/message_widget.dart +++ b/lib/src/message_widget.dart @@ -5,6 +5,7 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; +import 'package:flutter_emoji/flutter_emoji.dart'; import 'package:flutter_portal/flutter_portal.dart'; import 'package:jiffy/jiffy.dart'; import 'package:stream_chat_flutter/src/message_actions_modal.dart'; @@ -717,37 +718,69 @@ class _MessageWidgetState extends State { return SizedBox(); } + Widget _wrapTextInBubble({ + BuildContext context, + Widget child, + }) { + return Material( + shape: widget.shape ?? + RoundedRectangleBorder( + side: widget.borderSide ?? + BorderSide( + color: Theme.of(context).brightness == Brightness.dark + ? Colors.white.withAlpha(24) + : Colors.black.withAlpha(24), + ), + borderRadius: widget.borderRadiusGeometry ?? BorderRadius.zero, + ), + color: _getBackgroundColor(), + child: child, + ); + } + Widget _buildTextBubble(BuildContext context) { + final emojiParser = EmojiParser(); + final isOnlyEmoji = + widget.message.text.characters.every((c) => emojiParser.hasEmoji(c)); + + Widget child = Transform( + transform: Matrix4.rotationY(widget.reverse ? pi : 0), + alignment: Alignment.center, + child: Padding( + padding: widget.textPadding, + child: Column( + crossAxisAlignment: CrossAxisAlignment.end, + children: [ + getFailedMessageWidget(context), + widget.textBuilder != null + ? widget.textBuilder(context, widget.message) + : MessageText( + onLinkTap: widget.onLinkTap, + message: widget.message, + onMentionTap: widget.onMentionTap, + messageTheme: isOnlyEmoji + ? widget.messageTheme.copyWith( + messageText: + widget.messageTheme.messageText.copyWith( + fontSize: 40, + )) + : widget.messageTheme, + ), + ], + ), + ), + ); + + if (!isOnlyEmoji) { + child = _wrapTextInBubble( + context: context, + child: child, + ); + } return GestureDetector( onTap: () => retryMessage(context), onLongPress: () => onLongPress(context), - child: Material( - shape: widget.shape ?? - RoundedRectangleBorder( - side: widget.borderSide ?? - BorderSide( - color: Theme.of(context).brightness == Brightness.dark - ? Colors.white.withAlpha(24) - : Colors.black.withAlpha(24), - ), - borderRadius: widget.borderRadiusGeometry ?? BorderRadius.zero, - ), - color: _getBackgroundColor(), - child: Transform( - transform: Matrix4.rotationY(widget.reverse ? pi : 0), - alignment: Alignment.center, - child: Padding( - padding: widget.textPadding, - child: Column( - crossAxisAlignment: CrossAxisAlignment.end, - children: [ - getFailedMessageWidget(context), - _buildText(context), - ], - ), - ), - ), - ), + child: child, ); } @@ -781,15 +814,4 @@ class _MessageWidgetState extends State { return; } } - - Widget _buildText(BuildContext context) { - return widget.textBuilder != null - ? widget.textBuilder(context, widget.message) - : MessageText( - onLinkTap: widget.onLinkTap, - message: widget.message, - onMentionTap: widget.onMentionTap, - messageTheme: widget.messageTheme, - ); - } } From 5e714c93d00f616ec2a51b0eff5d5def73bc6ccd Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Tue, 3 Nov 2020 10:25:25 +0100 Subject: [PATCH 0277/1140] replace emoji after typing: --- lib/src/message_input.dart | 152 ++++++++++++++++++++++--------------- 1 file changed, 89 insertions(+), 63 deletions(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index be987950..4f56827e 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -326,57 +326,11 @@ class MessageInputState extends State { _emojiOverlay?.remove(); _emojiOverlay = null; - if (s.startsWith('/')) { - var matchedCommandsList = StreamChannel.of(context) - .channel - .config - .commands - .where((element) => element.name == s.substring(1)) - .toList(); + _checkCommands(s, context); - if (matchedCommandsList.length == 1) { - _chosenCommand = matchedCommandsList[0]; - textEditingController.clear(); - _messageIsPresent = false; - setState(() { - _commandEnabled = true; - }); - _commandsOverlay.remove(); - _commandsOverlay = null; - } else { - _commandsOverlay = _buildCommandsOverlayEntry(); - Overlay.of(context).insert(_commandsOverlay); - } - } + _checkMentions(s, context); - if (textEditingController.selection.isCollapsed && - (s[textEditingController.selection.start - 1] == '@' || - textEditingController.text - .substring( - 0, textEditingController.selection.start) - .split(' ') - .last - .contains('@'))) { - _mentionsOverlay = _buildMentionsOverlayEntry(); - Overlay.of(context).insert(_mentionsOverlay); - } - - if (textEditingController.selection.isCollapsed && - (s[textEditingController.selection.start - 1] == ':' || - textEditingController.text - .substring( - 0, - textEditingController.selection.start, - ) - .split(' ') - .last - .contains(':'))) { - _emojiOverlay = _buildEmojiOverlay(); - - if (_emojiOverlay != null) { - Overlay.of(context).insert(_emojiOverlay); - } - } + _checkEmoji(s, context); }, onTap: () { setState(() { @@ -442,6 +396,74 @@ class MessageInputState extends State { ); } + void _checkEmoji(String s, BuildContext context) { + if (textEditingController.selection.isCollapsed && + (s[textEditingController.selection.start - 1] == ':' || + textEditingController.text + .substring( + 0, + textEditingController.selection.start, + ) + .split(' ') + .last + .contains(':'))) { + final emojiParser = EmojiParser(); + final textToSelection = textEditingController.text + .substring(0, textEditingController.value.selection.start); + final splits = textToSelection.split(':'); + final query = splits[1]?.toLowerCase(); + final emoji = emojiParser.get(query); + + if (textToSelection.endsWith(':') && emoji.name != '') { + _chooseEmoji(splits, emoji); + } else { + _emojiOverlay = _buildEmojiOverlay(); + + if (_emojiOverlay != null) { + Overlay.of(context).insert(_emojiOverlay); + } + } + } + } + + void _checkMentions(String s, BuildContext context) { + if (textEditingController.selection.isCollapsed && + (s[textEditingController.selection.start - 1] == '@' || + textEditingController.text + .substring(0, textEditingController.selection.start) + .split(' ') + .last + .contains('@'))) { + _mentionsOverlay = _buildMentionsOverlayEntry(); + Overlay.of(context).insert(_mentionsOverlay); + } + } + + void _checkCommands(String s, BuildContext context) { + if (s.startsWith('/')) { + var matchedCommandsList = StreamChannel.of(context) + .channel + .config + .commands + .where((element) => element.name == s.substring(1)) + .toList(); + + if (matchedCommandsList.length == 1) { + _chosenCommand = matchedCommandsList[0]; + textEditingController.clear(); + _messageIsPresent = false; + setState(() { + _commandEnabled = true; + }); + _commandsOverlay.remove(); + _commandsOverlay = null; + } else { + _commandsOverlay = _buildCommandsOverlayEntry(); + Overlay.of(context).insert(_commandsOverlay); + } + } + } + OverlayEntry _buildCommandsOverlayEntry() { final text = textEditingController.text; final commands = StreamChannel.of(context) @@ -721,20 +743,7 @@ class MessageInputState extends State { ), ), onTap: () { - splits[splits.length - 1] = emoji.code; - final rejoin = splits.join(''); - - textEditingController.value = TextEditingValue( - text: rejoin + - textEditingController.text.substring( - textEditingController.selection.start), - selection: TextSelection.collapsed( - offset: rejoin.length, - ), - ); - - _emojiOverlay?.remove(); - _emojiOverlay = null; + _chooseEmoji(splits, emoji); }, )) ], @@ -745,6 +754,23 @@ class MessageInputState extends State { }); } + void _chooseEmoji(List splits, Emoji emoji) { + splits[1] = emoji.code; + final rejoin = splits.join(''); + + textEditingController.value = TextEditingValue( + text: rejoin + + textEditingController.text + .substring(textEditingController.selection.start), + selection: TextSelection.collapsed( + offset: rejoin.length, + ), + ); + + _emojiOverlay?.remove(); + _emojiOverlay = null; + } + void _setCommand(Command c) { textEditingController.clear(); setState(() { From c605821940a8005af0b0ad6ba684c836d4795888 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Wed, 4 Nov 2020 15:28:42 +0530 Subject: [PATCH 0278/1140] fix: Fix sizes and colors --- lib/src/giphy_attachment.dart | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/lib/src/giphy_attachment.dart b/lib/src/giphy_attachment.dart index 73278fb7..fded52cc 100644 --- a/lib/src/giphy_attachment.dart +++ b/lib/src/giphy_attachment.dart @@ -102,7 +102,7 @@ class GiphyAttachment extends StatelessWidget { Icon( StreamIcons.lightning, color: StreamChatTheme.of(context).accentColor, - size: 15.0, + size: 16.0, ), Text( 'GIPHY', @@ -142,10 +142,12 @@ class GiphyAttachment extends StatelessWidget { shape: CircleBorder(), ), Expanded( - child: Text( - '"${attachment.title}"', - style: TextStyle( - fontStyle: FontStyle.italic, + child: Center( + child: Text( + '"${attachment.title}"', + style: TextStyle( + fontStyle: FontStyle.italic, + ), ), ), ), @@ -191,6 +193,7 @@ class GiphyAttachment extends StatelessWidget { 'Cancel', style: TextStyle( fontWeight: FontWeight.bold, + color: Colors.black.withOpacity(0.5) ), ), ], From 3575089bf3c0cd02e5cf15533b39e309538e30d7 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Wed, 4 Nov 2020 16:41:59 +0530 Subject: [PATCH 0279/1140] fix: Fix sizes and colors --- lib/src/giphy_attachment.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/src/giphy_attachment.dart b/lib/src/giphy_attachment.dart index fded52cc..357d5024 100644 --- a/lib/src/giphy_attachment.dart +++ b/lib/src/giphy_attachment.dart @@ -131,7 +131,7 @@ class GiphyAttachment extends StatelessWidget { child: IconButton( icon: Icon( StreamIcons.left, - size: 18.0, + size: 24.0, ), onPressed: () { streamChannel.channel.sendAction(message, { @@ -155,7 +155,7 @@ class GiphyAttachment extends StatelessWidget { child: IconButton( icon: Icon( StreamIcons.right, - size: 18.0, + size: 24.0, ), onPressed: () { streamChannel.channel.sendAction(message, { From 9c3fc656e2bfa3898ff96948ebb8a93cd18b1bfa Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Wed, 4 Nov 2020 16:54:58 +0530 Subject: [PATCH 0280/1140] fix: Added visibility message --- lib/src/giphy_attachment.dart | 365 ++++++++++++++++++---------------- 1 file changed, 198 insertions(+), 167 deletions(-) diff --git a/lib/src/giphy_attachment.dart b/lib/src/giphy_attachment.dart index 357d5024..c96f34fd 100644 --- a/lib/src/giphy_attachment.dart +++ b/lib/src/giphy_attachment.dart @@ -41,190 +41,221 @@ class GiphyAttachment extends StatelessWidget { Widget _buildSendingAttachment(context) { final streamChannel = StreamChannel.of(context); - return Card( - clipBehavior: Clip.antiAlias, - shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8.0)), - child: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - Stack( + return Column( + mainAxisSize: MainAxisSize.min, + children: [ + Card( + clipBehavior: Clip.antiAlias, + shape: + RoundedRectangleBorder(borderRadius: BorderRadius.circular(8.0)), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.stretch, children: [ - GestureDetector( - onTap: () { - Navigator.push(context, MaterialPageRoute(builder: (_) { - return FullScreenImage( - url: attachment.imageUrl ?? - attachment.assetUrl ?? - attachment.thumbUrl, - ); - })); - }, - child: Padding( - padding: const EdgeInsets.all(8.0), - child: CachedNetworkImage( - height: size?.height, - width: size?.width, - placeholder: (_, __) { - return Container( - width: size?.width, - height: size?.height, - child: Center( - child: CircularProgressIndicator(), - ), - ); + Stack( + children: [ + GestureDetector( + onTap: () { + Navigator.push(context, MaterialPageRoute(builder: (_) { + return FullScreenImage( + url: attachment.imageUrl ?? + attachment.assetUrl ?? + attachment.thumbUrl, + ); + })); }, - imageUrl: attachment.thumbUrl ?? - attachment.imageUrl ?? - attachment.assetUrl, - errorWidget: (context, url, error) => AttachmentError( - attachment: attachment, - size: size, - ), - fit: BoxFit.cover, - ), - ), - ), - Positioned( - left: 0, - top: 0, - child: Container( - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.only( - bottomRight: Radius.circular(16.0), - )), - child: Padding( - padding: const EdgeInsets.only( - left: 4.0, right: 4.0, top: 6.0, bottom: 2.0), - child: Row( - children: [ - Icon( - StreamIcons.lightning, - color: StreamChatTheme.of(context).accentColor, - size: 16.0, + child: Padding( + padding: const EdgeInsets.all(8.0), + child: CachedNetworkImage( + height: size?.height, + width: size?.width, + placeholder: (_, __) { + return Container( + width: size?.width, + height: size?.height, + child: Center( + child: CircularProgressIndicator(), + ), + ); + }, + imageUrl: attachment.thumbUrl ?? + attachment.imageUrl ?? + attachment.assetUrl, + errorWidget: (context, url, error) => AttachmentError( + attachment: attachment, + size: size, ), - Text( - 'GIPHY', - style: TextStyle( - color: StreamChatTheme.of(context).accentColor, - fontWeight: FontWeight.bold, - fontSize: 11.0, + fit: BoxFit.cover, + ), + ), + ), + Positioned( + left: 0, + top: 0, + child: Container( + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.only( + bottomRight: Radius.circular(16.0), + )), + child: Padding( + padding: const EdgeInsets.only( + left: 4.0, right: 4.0, top: 6.0, bottom: 2.0), + child: Row( + children: [ + Icon( + StreamIcons.lightning, + color: StreamChatTheme.of(context).accentColor, + size: 16.0, + ), + Text( + 'GIPHY', + style: TextStyle( + color: StreamChatTheme.of(context).accentColor, + fontWeight: FontWeight.bold, + fontSize: 11.0, + ), + ), + ], + ), + ), + ), + ), + ], + ), + if (attachment.title != null) + Container( + alignment: Alignment.bottomCenter, + child: Material( + color: Colors.white, + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Card( + child: IconButton( + icon: Icon( + StreamIcons.left, + size: 24.0, + ), + onPressed: () { + streamChannel.channel.sendAction(message, { + 'image_action': 'shuffle', + }); + }, ), + shape: CircleBorder(), + ), + Expanded( + child: Center( + child: Text( + '"${attachment.title}"', + style: TextStyle( + fontStyle: FontStyle.italic, + ), + ), + ), + ), + Card( + child: IconButton( + icon: Icon( + StreamIcons.right, + size: 24.0, + ), + onPressed: () { + streamChannel.channel.sendAction(message, { + 'image_action': 'shuffle', + }); + }, + ), + shape: CircleBorder(), ), ], ), ), ), - ), - ], - ), - if (attachment.title != null) - Container( - alignment: Alignment.bottomCenter, - child: Material( - color: Colors.white, - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Card( - child: IconButton( - icon: Icon( - StreamIcons.left, - size: 24.0, - ), - onPressed: () { - streamChannel.channel.sendAction(message, { - 'image_action': 'shuffle', - }); - }, - ), - shape: CircleBorder(), - ), - Expanded( - child: Center( - child: Text( - '"${attachment.title}"', - style: TextStyle( - fontStyle: FontStyle.italic, - ), - ), - ), - ), - Card( - child: IconButton( - icon: Icon( - StreamIcons.right, - size: 24.0, - ), - onPressed: () { - streamChannel.channel.sendAction(message, { - 'image_action': 'shuffle', - }); - }, - ), - shape: CircleBorder(), - ), - ], - ), - ), - ), - SizedBox( - height: 4.0, - ), - Container( - color: Colors.black.withOpacity(0.2), - width: double.infinity, - height: 0.5, - ), - Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - FlatButton( - onPressed: () { - streamChannel.channel.sendAction(message, { - 'image_action': 'cancel', - }); - }, - child: Row( - children: [ - Text( - 'Cancel', - style: TextStyle( - fontWeight: FontWeight.bold, - color: Colors.black.withOpacity(0.5) - ), - ), - ], - ), + SizedBox( + height: 4.0, ), Container( - width: 0.5, color: Colors.black.withOpacity(0.2), - height: 50.0, + width: double.infinity, + height: 0.5, ), - FlatButton( - onPressed: () { - streamChannel.channel.sendAction(message, { - 'image_action': 'send', - }); - }, - child: Row( - children: [ - Text( - 'Send', - style: TextStyle( - color: StreamChatTheme.of(context).accentColor, - fontWeight: FontWeight.bold), + Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + FlatButton( + onPressed: () { + streamChannel.channel.sendAction(message, { + 'image_action': 'cancel', + }); + }, + child: Row( + children: [ + Text( + 'Cancel', + style: TextStyle( + fontWeight: FontWeight.bold, + color: Colors.black.withOpacity(0.5)), + ), + ], ), - ], - ), + ), + Container( + width: 0.5, + color: Colors.black.withOpacity(0.2), + height: 50.0, + ), + FlatButton( + onPressed: () { + streamChannel.channel.sendAction(message, { + 'image_action': 'send', + }); + }, + child: Row( + children: [ + Text( + 'Send', + style: TextStyle( + color: StreamChatTheme.of(context).accentColor, + fontWeight: FontWeight.bold), + ), + ], + ), + ), + ], ), ], ), - ], - ), + ), + SizedBox( + height: 4.0, + ), + Align( + alignment: Alignment.centerRight, + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 8.0), + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Icon( + StreamIcons.eye, + color: Colors.black.withOpacity(0.5), + size: 16.0, + ), + SizedBox( + width: 4.0, + ), + Text( + 'Only visible to you', + style: TextStyle(color: Colors.black.withOpacity(0.5)), + ), + ], + ), + ), + ), + ], ); } From c8a8b81102853a8fd9681cbf8accfdd058204b1e Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Wed, 4 Nov 2020 17:02:31 +0530 Subject: [PATCH 0281/1140] fix: Added visibility message --- lib/src/giphy_attachment.dart | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/lib/src/giphy_attachment.dart b/lib/src/giphy_attachment.dart index c96f34fd..7bb76a84 100644 --- a/lib/src/giphy_attachment.dart +++ b/lib/src/giphy_attachment.dart @@ -235,7 +235,7 @@ class GiphyAttachment extends StatelessWidget { Align( alignment: Alignment.centerRight, child: Padding( - padding: const EdgeInsets.symmetric(horizontal: 8.0), + padding: const EdgeInsets.symmetric(horizontal: 8.0, vertical: 4.0), child: Row( mainAxisSize: MainAxisSize.min, children: [ @@ -245,11 +245,14 @@ class GiphyAttachment extends StatelessWidget { size: 16.0, ), SizedBox( - width: 4.0, + width: 8.0, ), Text( 'Only visible to you', - style: TextStyle(color: Colors.black.withOpacity(0.5)), + style: TextStyle( + color: Colors.black.withOpacity(0.5), + fontSize: 12.0, + ), ), ], ), From 756e8d6555966a7caa788ea3e63e6051ba6015d5 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Wed, 4 Nov 2020 17:26:21 +0530 Subject: [PATCH 0282/1140] fix: Removed bubble for giphy --- 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 73ace68b..84115d18 100644 --- a/lib/src/message_widget.dart +++ b/lib/src/message_widget.dart @@ -276,7 +276,7 @@ class _MessageWidgetState extends State { ..._parseAttachments(context), if (widget.message.text .trim() - .isNotEmpty) + .isNotEmpty && widget.message.type != 'giphy') _buildTextBubble(context), ], ), From 312e1722784a337539331ea42ad80f875082193f Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Wed, 4 Nov 2020 17:48:31 +0530 Subject: [PATCH 0283/1140] fix: Removed bubble for giphy --- lib/src/giphy_attachment.dart | 9 +-------- lib/src/message_widget.dart | 23 +++++++++++++++++------ 2 files changed, 18 insertions(+), 14 deletions(-) diff --git a/lib/src/giphy_attachment.dart b/lib/src/giphy_attachment.dart index 7bb76a84..1227572d 100644 --- a/lib/src/giphy_attachment.dart +++ b/lib/src/giphy_attachment.dart @@ -308,15 +308,8 @@ class GiphyAttachment extends StatelessWidget { ), ], ), - Text( - Jiffy(message.createdAt.toLocal()).format(' HH:mm'), - style: TextStyle( - fontSize: 12.0, - color: Colors.black.withOpacity(0.5), - ), - ) ], - mainAxisAlignment: MainAxisAlignment.spaceBetween, + mainAxisAlignment: MainAxisAlignment.start, ), ) ], diff --git a/lib/src/message_widget.dart b/lib/src/message_widget.dart index 84115d18..53be9ae6 100644 --- a/lib/src/message_widget.dart +++ b/lib/src/message_widget.dart @@ -175,7 +175,9 @@ class MessageWidget extends StatefulWidget { 'giphy': (context, message, attachment) { return GiphyAttachment( attachment: attachment, - messageTheme: messageTheme.copyWith(messageBackgroundColor: Colors.white,), + messageTheme: messageTheme.copyWith( + messageBackgroundColor: Colors.white, + ), message: message, size: Size( MediaQuery.of(context).size.width * 0.8, @@ -205,6 +207,10 @@ class _MessageWidgetState extends State { var leftPadding = widget.showUserAvatar != DisplayWidget.gone ? widget.messageTheme.avatarTheme.constraints.maxWidth + 16.0 : 6.0; + + bool isGiphy = + widget.message.attachments.any((element) => element.type == 'giphy'); + return Portal( child: Padding( padding: widget.padding ?? EdgeInsets.all(8), @@ -275,8 +281,9 @@ class _MessageWidgetState extends State { children: [ ..._parseAttachments(context), if (widget.message.text - .trim() - .isNotEmpty && widget.message.type != 'giphy') + .trim() + .isNotEmpty && + !isGiphy) _buildTextBubble(context), ], ), @@ -512,12 +519,14 @@ class _MessageWidgetState extends State { widget.message, attachment, ); - return wrapAttachmentWidget(context, attachmentWidget, attachment: attachment); + return wrapAttachmentWidget(context, attachmentWidget, + attachment: attachment); })?.toList() ?? []; } - Padding wrapAttachmentWidget(BuildContext context, Widget attachmentWidget, {Attachment attachment}) { + Padding wrapAttachmentWidget(BuildContext context, Widget attachmentWidget, + {Attachment attachment}) { return Padding( padding: EdgeInsets.only( bottom: 4, @@ -526,7 +535,9 @@ class _MessageWidgetState extends State { onTap: () => retryMessage(context), onLongPress: () => onLongPress(context), child: Material( - color: attachment?.type == 'giphy' ? Colors.white : _getBackgroundColor(), + color: attachment?.type == 'giphy' + ? Colors.white + : _getBackgroundColor(), clipBehavior: Clip.hardEdge, shape: widget.attachmentShape ?? widget.shape ?? From 1f8e49c45a40c885c93462176863a6bea6e71da1 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Wed, 4 Nov 2020 18:10:25 +0530 Subject: [PATCH 0284/1140] fix: Removed bubble for giphy, changed border radii --- lib/src/giphy_attachment.dart | 48 +++++++++++++++++++++-------------- 1 file changed, 29 insertions(+), 19 deletions(-) diff --git a/lib/src/giphy_attachment.dart b/lib/src/giphy_attachment.dart index 1227572d..c1549aa9 100644 --- a/lib/src/giphy_attachment.dart +++ b/lib/src/giphy_attachment.dart @@ -266,26 +266,36 @@ class GiphyAttachment extends StatelessWidget { return Container( child: Column( children: [ - CachedNetworkImage( - height: size?.height, - width: size?.width, - placeholder: (_, __) { - return Container( - width: size?.width, - height: size?.height, - child: Center( - child: CircularProgressIndicator(), - ), - ); - }, - imageUrl: attachment.thumbUrl ?? - attachment.imageUrl ?? - attachment.assetUrl, - errorWidget: (context, url, error) => AttachmentError( - attachment: attachment, - size: size, + Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.only( + topRight: Radius.circular(8.0), + bottomRight: Radius.circular(0.0), + topLeft: Radius.circular(8.0), + bottomLeft: Radius.circular(8.0), + ), + ), + child: CachedNetworkImage( + height: size?.height, + width: size?.width, + placeholder: (_, __) { + return Container( + width: size?.width, + height: size?.height, + child: Center( + child: CircularProgressIndicator(), + ), + ); + }, + imageUrl: attachment.thumbUrl ?? + attachment.imageUrl ?? + attachment.assetUrl, + errorWidget: (context, url, error) => AttachmentError( + attachment: attachment, + size: size, + ), + fit: BoxFit.cover, ), - fit: BoxFit.cover, ), Padding( padding: const EdgeInsets.symmetric(vertical: 8.0), From aa419da05424bbec56beb0468e432dba298b9bee Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Wed, 4 Nov 2020 18:13:40 +0530 Subject: [PATCH 0285/1140] fix: Removed bubble for giphy, changed border radii --- lib/src/giphy_attachment.dart | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/src/giphy_attachment.dart b/lib/src/giphy_attachment.dart index c1549aa9..66641f59 100644 --- a/lib/src/giphy_attachment.dart +++ b/lib/src/giphy_attachment.dart @@ -275,6 +275,7 @@ class GiphyAttachment extends StatelessWidget { bottomLeft: Radius.circular(8.0), ), ), + clipBehavior: Clip.antiAlias, child: CachedNetworkImage( height: size?.height, width: size?.width, From 88501ed4f81cdd11d1a98479dc2bf8f03e080397 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Wed, 4 Nov 2020 18:37:04 +0530 Subject: [PATCH 0286/1140] fix: Removed bubble for giphy, changed border radii --- lib/src/giphy_attachment.dart | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/src/giphy_attachment.dart b/lib/src/giphy_attachment.dart index 66641f59..fbb2e585 100644 --- a/lib/src/giphy_attachment.dart +++ b/lib/src/giphy_attachment.dart @@ -269,10 +269,10 @@ class GiphyAttachment extends StatelessWidget { Container( decoration: BoxDecoration( borderRadius: BorderRadius.only( - topRight: Radius.circular(8.0), + topRight: Radius.circular(16.0), bottomRight: Radius.circular(0.0), - topLeft: Radius.circular(8.0), - bottomLeft: Radius.circular(8.0), + topLeft: Radius.circular(16.0), + bottomLeft: Radius.circular(16.0), ), ), clipBehavior: Clip.antiAlias, From 70e7a8dc83d352889840070bb7da29a16fee8de4 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Wed, 4 Nov 2020 19:21:33 +0530 Subject: [PATCH 0287/1140] fix: Removed bubble for giphy, changed border radii --- lib/src/giphy_attachment.dart | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/lib/src/giphy_attachment.dart b/lib/src/giphy_attachment.dart index fbb2e585..d6d378d2 100644 --- a/lib/src/giphy_attachment.dart +++ b/lib/src/giphy_attachment.dart @@ -46,8 +46,14 @@ class GiphyAttachment extends StatelessWidget { children: [ Card( clipBehavior: Clip.antiAlias, - shape: - RoundedRectangleBorder(borderRadius: BorderRadius.circular(8.0)), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.only( + topRight: Radius.circular(16.0), + bottomRight: Radius.circular(0.0), + topLeft: Radius.circular(16.0), + bottomLeft: Radius.circular(16.0), + ), + ), child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.stretch, From e27b45e4f88eb6cfbc01f5ae609e71b2f6127c15 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Thu, 5 Nov 2020 09:50:08 +0100 Subject: [PATCH 0288/1140] use scrollable_positioned_list --- lib/src/message_list_view.dart | 400 ++++++++++++++++----------------- pubspec.yaml | 2 +- 2 files changed, 194 insertions(+), 208 deletions(-) diff --git a/lib/src/message_list_view.dart b/lib/src/message_list_view.dart index bb0f98c0..d2e1d972 100644 --- a/lib/src/message_list_view.dart +++ b/lib/src/message_list_view.dart @@ -1,12 +1,13 @@ import 'dart:async'; +import 'dart:math'; import 'package:flutter/material.dart'; import 'package:jiffy/jiffy.dart'; +import 'package:scrollable_positioned_list/scrollable_positioned_list.dart'; import 'package:stream_chat/stream_chat.dart'; import 'package:stream_chat_flutter/src/message_widget.dart'; import 'package:stream_chat_flutter/src/system_message.dart'; import 'package:visibility_detector/visibility_detector.dart'; -import 'package:widgets_visibility_provider/widgets_visibility_provider.dart'; import '../stream_chat_flutter.dart'; import 'date_divider.dart'; @@ -106,7 +107,10 @@ class MessageListView extends StatefulWidget { this.onThreadTap, this.dateDividerBuilder, this.scrollPhysics = const AlwaysScrollableScrollPhysics(), - this.keyboardDismissBehavior = ScrollViewKeyboardDismissBehavior.manual, + this.initialScrollIndex, + this.initialAlignment, + this.scrollController, + this.itemPositionListener, }) : super(key: key); /// Function used to build a custom message widget @@ -131,95 +135,101 @@ class MessageListView extends StatefulWidget { /// Builder used to render date dividers final Widget Function(DateTime) dateDividerBuilder; + /// Index of an item to initially align within the viewport. + final int initialScrollIndex; + + /// Determines where the leading edge of the item at [initialScrollIndex] + /// should be placed. + final double initialAlignment; + + /// Controller for jumping or scrolling to an item. + final ItemScrollController scrollController; + + /// Provides a listenable iterable of [itemPositions] of items that are on + /// screen and their locations. + final ItemPositionsListener itemPositionListener; + /// The ScrollPhysics used by the ListView final ScrollPhysics scrollPhysics; - /// The [ScrollViewKeyboardDismissBehavior] used by the ListView - final ScrollViewKeyboardDismissBehavior keyboardDismissBehavior; - @override _MessageListViewState createState() => _MessageListViewState(); } class _MessageListViewState extends State { - static const _newMessageLoadingOffset = 100; - final ScrollController _scrollController = ScrollController(); - bool _bottomWasVisible = true; + ItemScrollController _scrollController; + bool _bottomWasVisible = false; bool _topWasVisible = false; - List _messages = []; - List _newMessageList = []; Function _onThreadTap; bool _showScrollToBottom = false; + ItemPositionsListener _itemPositionListener; @override Widget build(BuildContext context) { final streamChannel = StreamChannel.of(context); - /// TODO: find a better solution when (https://github.com/flutter/flutter/issues/21023) is fixed - return WidgetsVisibilityProvider( - condition: (positionData) => - positionData.endPosition >= 20 && - positionData.startPosition <= positionData.viewportSize, - child: Stack( - alignment: Alignment.center, - children: [ - NotificationListener( - onNotification: (_) { - if (_scrollController.offset < 150 && - _newMessageList.isNotEmpty) { - setState(() { - _messages.insertAll(0, _newMessageList); - _newMessageList.clear(); - }); - } - return true; - }, - child: ListView.custom( - key: Key('messageListView'), - physics: widget.scrollPhysics, - keyboardDismissBehavior: widget.keyboardDismissBehavior, - controller: _scrollController, - reverse: true, - childrenDelegate: SliverChildBuilderDelegate( - (context, i) { - if (i == _messages.length + 1) { - if (widget.parentMessage != null) { - if (widget.parentMessageBuilder != null) { - return widget.parentMessageBuilder( - context, - widget.parentMessage, - ); - } else { - return Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - buildParentMessage(widget.parentMessage), - Padding( - padding: - const EdgeInsets.symmetric(horizontal: 32), - child: Container( - padding: const EdgeInsets.all(8), - child: Text( - 'Start of thread', - textAlign: TextAlign.center, - ), - color: - Theme.of(context).accentColor.withAlpha(50), - ), - ), - ], - ); - } + final messagesStream = widget.parentMessage != null + ? streamChannel.channel.state.threadsStream + .where((threads) => threads.containsKey(widget.parentMessage.id)) + .map((threads) => threads[widget.parentMessage.id]) + : streamChannel.channel.state.messagesStream; + + return StreamBuilder>( + stream: messagesStream, + initialData: widget.parentMessage != null + ? streamChannel.channel.state.threads[widget.parentMessage.id] + : streamChannel.channel.state.messages, + builder: (context, snapshot) { + final messages = snapshot.data?.reversed?.toList() ?? []; + return Stack( + alignment: Alignment.center, + children: [ + ScrollablePositionedList.builder( + itemPositionsListener: _itemPositionListener, + addAutomaticKeepAlives: true, + key: Key('messageListView'), + initialScrollIndex: widget.initialScrollIndex, + initialAlignment: widget.initialAlignment, + physics: widget.scrollPhysics, + itemScrollController: _scrollController, + reverse: true, + itemCount: messages.length + + 1 + + (widget.parentMessage != null ? 1 : 0), + itemBuilder: (context, i) { + if (i == messages.length + 1) { + if (widget.parentMessageBuilder != null) { + return widget.parentMessageBuilder( + context, + widget.parentMessage, + ); } else { - return SizedBox(); + return Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + buildParentMessage(widget.parentMessage), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 32), + child: Container( + padding: const EdgeInsets.all(8), + child: Text( + 'Start of thread', + textAlign: TextAlign.center, + ), + color: + Theme.of(context).accentColor.withAlpha(50), + ), + ), + ], + ); } } - if (i == _messages.length) { + if (i == messages.length) { return _buildLoadingIndicator(streamChannel); } - final message = _messages[i]; - final nextMessage = i > 0 ? _messages[i - 1] : null; + final message = messages[i]; + final nextMessage = i > 0 ? messages[i - 1] : null; Widget messageWidget; @@ -227,14 +237,14 @@ class _MessageListViewState extends State { messageWidget = _buildBottomMessage( context, message, - _messages, + messages, streamChannel, ); - } else if (i == _messages.length - 1) { + } else if (i == messages.length - 1) { messageWidget = _buildTopMessage( context, message, - _messages, + messages, streamChannel, ); } else { @@ -246,13 +256,13 @@ class _MessageListViewState extends State { MessageDetails( context, message, - _messages, + messages, i, ), - _messages), + messages), ); } else { - messageWidget = buildMessage(message, _messages, i); + messageWidget = buildMessage(message, messages, i); } } @@ -265,84 +275,74 @@ class _MessageListViewState extends State { messageWidget, Padding( padding: const EdgeInsets.symmetric(vertical: 12.0), - child: VisibleNotifierWidget( - condition: ( - ScrollNotification previousNotification, - PositionData previousPositionData, - ScrollNotification currentNotification, - PositionData currentPositionData, - ) { - print( - 'currentPositionData.endPosition: ${currentPositionData.endPosition}'); - return true; - }, - data: i, - child: widget.dateDividerBuilder != null - ? widget.dateDividerBuilder( - nextMessage.createdAt.toLocal()) - : DateDivider( - dateTime: nextMessage.createdAt.toLocal(), - ), - ), + child: widget.dateDividerBuilder != null + ? widget.dateDividerBuilder( + nextMessage.createdAt.toLocal()) + : DateDivider( + dateTime: nextMessage.createdAt.toLocal(), + ), ), ], ); } - return VisibleNotifierWidget( - child: messageWidget, - data: i, - ); - }, - childCount: _messages.length + 2, - findChildIndexCallback: (key) { - final ValueKey valueKey = key; - final index = _messages - .indexWhere((m) => 'MESSAGE-${m.id}' == valueKey.value); - return index != -1 ? index : null; + return messageWidget; }, ), - ), - ), - if (widget.showScrollToBottom) - StreamBuilder( - stream: streamChannel.channel.on( - EventType.messageNew, - ), - builder: (context, _) { - if (!_showScrollToBottom || - streamChannel.channel.state.unreadCount == 0) { - return SizedBox(); - } - return _buildScrollToBottom(streamChannel); - }), - Positioned( - top: 20.0, - child: WidgetsVisibilityConsumer( - listener: ( - context, - event, - ) {}, - builder: (context, event) { - if (event.positionDataList == null || - event.positionDataList.isEmpty) { - return Container(); - } + if (widget.showScrollToBottom) + StreamBuilder( + stream: streamChannel.channel.state.unreadCountStream, + builder: (context, snapshot) { + if (!_showScrollToBottom || + !snapshot.hasData || + snapshot.data == 0) { + return SizedBox(); + } + return _buildScrollToBottom(snapshot.data); + }), + Positioned( + top: 20.0, + child: ValueListenableBuilder>( + valueListenable: _itemPositionListener.itemPositions, + builder: (context, values, _) { + final items = _itemPositionListener.itemPositions?.value; + if (items.isEmpty) { + return SizedBox(); + } - return DateDivider( - dateTime: _messages[event.positionDataList.last.data] - .createdAt - .toLocal(), - ); - }, - ), - ), - ], - ), - ); + var index = _getTopElement(values).index; + + if (index > messages.length) { + return SizedBox(); + } + + if (index == messages.length) { + index = max(index - 1, 0); + } + + return widget.dateDividerBuilder != null + ? widget.dateDividerBuilder( + messages[index].createdAt.toLocal(), + ) + : DateDivider( + dateTime: messages[index].createdAt.toLocal(), + ); + }, + ), + ), + ], + ); + }); } - Widget _buildScrollToBottom(StreamChannelState streamChannel) { + ItemPosition _getTopElement(Iterable values) { + return values + .where((ItemPosition position) => position.itemLeadingEdge < 0.9) + .reduce((ItemPosition max, ItemPosition position) => + position.itemLeadingEdge > max.itemLeadingEdge ? position : max); + } + + Widget _buildScrollToBottom(int unreadCount) { return Positioned( bottom: 8, right: 8, @@ -358,13 +358,11 @@ class _MessageListViewState extends State { color: Colors.black, ), onPressed: () { - Future.delayed(Duration(milliseconds: 500), () { - setState(() { - _showScrollToBottom = false; - }); + setState(() { + _showScrollToBottom = false; }); - _scrollController.animateTo( - 0, + _scrollController.scrollTo( + index: 0, duration: Duration(seconds: 1), curve: Curves.easeInOut, ); @@ -377,7 +375,7 @@ class _MessageListViewState extends State { top: -10, child: CircleAvatar( radius: 20, - child: Text(streamChannel.channel.state.unreadCount.toString()), + child: Text(unreadCount.toString()), ), ), ], @@ -387,7 +385,9 @@ class _MessageListViewState extends State { Container _buildLoadingIndicator(StreamChannelState streamChannel) { return Container( + key: Key('LOADING-INDICATOR'), height: 50, + width: double.infinity, child: StreamBuilder( stream: streamChannel.queryMessage, initialData: false, @@ -401,7 +401,7 @@ class _MessageListViewState extends State { ); } if (!snapshot.data) { - return Container(); + return SizedBox(); } return Center( child: Padding( @@ -428,14 +428,14 @@ class _MessageListViewState extends State { MessageDetails( context, message, - _messages, - _messages.length - 1, + messages, + messages.length - 1, ), - _messages, + messages, ), ); } else { - messageWidget = buildMessage(message, messages, _messages.length - 1); + messageWidget = buildMessage(message, messages, messages.length - 1); } return VisibilityDetector( @@ -470,10 +470,10 @@ class _MessageListViewState extends State { MessageDetails( context, message, - _messages, + messages, 0, ), - _messages, + messages, ), ); } else { @@ -492,9 +492,11 @@ class _MessageListViewState extends State { } } _bottomWasVisible = isVisible; - setState(() { - _showScrollToBottom = !isVisible; - }); + if (mounted) { + setState(() { + _showScrollToBottom = !isVisible; + }); + } }, child: messageWidget, ); @@ -541,6 +543,7 @@ class _MessageListViewState extends State { ) { if (message.type == 'system' && message.text?.isNotEmpty == true) { return SystemMessage( + key: ValueKey('MESSAGE-${message.id}'), message: message, ); } @@ -563,6 +566,7 @@ class _MessageListViewState extends State { final allRead = readList.length >= (channel.memberCount ?? 0) - 1; return MessageWidget( + key: ValueKey('MESSAGE-${message.id}'), message: message, reverse: isMyMessage, showReactions: !message.isDeleted, @@ -600,63 +604,45 @@ class _MessageListViewState extends State { ); } - StreamSubscription _streamListener; + StreamSubscription _messageNewListener; @override void initState() { super.initState(); + _scrollController = widget.scrollController ?? ItemScrollController(); + _itemPositionListener = + widget.itemPositionListener ?? ItemPositionsListener.create(); + final streamChannel = StreamChannel.of(context); - Stream> stream; - - if (widget.parentMessage == null) { - stream = streamChannel.channel.state.messagesStream; - } else { - streamChannel.getReplies(widget.parentMessage.id); - stream = streamChannel.channel.state.threadsStream - .where((threads) => threads.containsKey(widget.parentMessage.id)) - .map((threads) => threads[widget.parentMessage.id]); - } - - _streamListener = stream - .map((messages) => - messages - ?.where((m) => - !(m.status == MessageSendingStatus.FAILED && m.isDeleted)) - ?.toList() ?? - []) - .listen((newMessages) { - newMessages = newMessages.reversed.toList(); - if (_messages.isEmpty || - newMessages.isEmpty || - newMessages.first.id != _messages.first.id) { - if (!_scrollController.hasClients || - _scrollController.offset < _newMessageLoadingOffset) { - if (streamChannel.channel.state.unreadCount > 0) { - streamChannel.channel.markRead(); - } - setState(() { - _messages = newMessages; - }); - } else if (newMessages.first.user.id == - streamChannel.channel.client.state.user.id) { - _scrollController.jumpTo(0); - WidgetsBinding.instance.addPostFrameCallback((_) { - setState(() { - _messages = newMessages; - }); - }); - } else { - _newMessageList = newMessages; - } - } else { - setState(() { - _messages = newMessages; + _messageNewListener = + streamChannel.channel.on(EventType.messageNew).listen((event) { + final firstElementInViewport = + _itemPositionListener.itemPositions.value.first; + if (event.message.user.id == streamChannel.channel.client.state.user.id) { + WidgetsBinding.instance.addPostFrameCallback((_) { + _scrollController.jumpTo( + index: 0, + ); }); + } else { + if (firstElementInViewport.index != 0) { + _scrollController.jumpTo( + index: firstElementInViewport.index + 1, + alignment: firstElementInViewport.itemLeadingEdge, + ); + } + } + if (firstElementInViewport.index == 0) { + streamChannel.channel.markRead(); } }); + if (widget.parentMessage != null) { + streamChannel.getReplies(widget.parentMessage.id); + } + _getOnThreadTap(); } @@ -696,7 +682,7 @@ class _MessageListViewState extends State { @override void dispose() { - _streamListener.cancel(); + _messageNewListener?.cancel(); super.dispose(); } } diff --git a/pubspec.yaml b/pubspec.yaml index 452eb69a..e6f6bf38 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -14,6 +14,7 @@ dependencies: flutter_app_badger: ^1.1.2 photo_view: ^0.10.1 rxdart: ^0.24.1 + scrollable_positioned_list: ^0.1.8 jiffy: ^3.0.1 flutter_portal: ^0.3.0 cached_network_image: ^2.2.0+1 @@ -31,7 +32,6 @@ dependencies: flutter_slidable: ^0.5.4 carousel_slider: ^2.2.1 clipboard: ^0.1.2+8 - widgets_visibility_provider: ^2.0.2 flutter: assets: From af836d97112cc6577ee9b1f020ff20537625b69c Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Thu, 5 Nov 2020 10:42:13 +0100 Subject: [PATCH 0289/1140] fix button inkwells --- lib/src/attachment_actions.dart | 53 ------- lib/src/giphy_attachment.dart | 246 +++++++++++++++++--------------- lib/src/message_input.dart | 3 +- 3 files changed, 129 insertions(+), 173 deletions(-) delete mode 100644 lib/src/attachment_actions.dart diff --git a/lib/src/attachment_actions.dart b/lib/src/attachment_actions.dart deleted file mode 100644 index f101ef53..00000000 --- a/lib/src/attachment_actions.dart +++ /dev/null @@ -1,53 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:stream_chat_flutter/stream_chat_flutter.dart'; - -class AttachmentActions extends StatelessWidget { - final Attachment attachment; - final Message message; - - const AttachmentActions({ - Key key, - this.attachment, - this.message, - }) : super(key: key); - - @override - Widget build(BuildContext context) { - final streamChannel = StreamChannel.of(context); - return Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - mainAxisSize: MainAxisSize.min, - children: attachment.actions?.map((action) { - if (action.style == 'primary') { - return FlatButton( - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(16), - ), - child: Text('${action.text}'), - color: action.style == 'primary' - ? StreamChatTheme.of(context).accentColor - : null, - textColor: Colors.white, - onPressed: () { - streamChannel.channel.sendAction(message, { - action.name: action.value, - }); - }, - ); - } - return OutlineButton( - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(16), - ), - child: Text('${action.text}'), - color: StreamChatTheme.of(context).accentColor, - onPressed: () { - streamChannel.channel.sendAction(message, { - action.name: action.value, - }); - }, - ); - })?.toList(), - ); - } -} diff --git a/lib/src/giphy_attachment.dart b/lib/src/giphy_attachment.dart index d6d378d2..02c1ca5e 100644 --- a/lib/src/giphy_attachment.dart +++ b/lib/src/giphy_attachment.dart @@ -1,12 +1,9 @@ import 'package:cached_network_image/cached_network_image.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; -import 'package:jiffy/jiffy.dart'; -import 'package:stream_chat_flutter/src/attachment_actions.dart'; import '../stream_chat_flutter.dart'; import 'attachment_error.dart'; -import 'attachment_title.dart'; import 'full_screen_image.dart'; class GiphyAttachment extends StatelessWidget { @@ -58,76 +55,76 @@ class GiphyAttachment extends StatelessWidget { mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.stretch, children: [ - Stack( - children: [ - GestureDetector( - onTap: () { - Navigator.push(context, MaterialPageRoute(builder: (_) { - return FullScreenImage( - url: attachment.imageUrl ?? - attachment.assetUrl ?? - attachment.thumbUrl, - ); - })); - }, - child: Padding( - padding: const EdgeInsets.all(8.0), - child: CachedNetworkImage( - height: size?.height, + Padding( + padding: const EdgeInsets.all(8.0), + child: GestureDetector( + onTap: () { + Navigator.push(context, MaterialPageRoute(builder: (_) { + return FullScreenImage( + url: attachment.imageUrl ?? + attachment.assetUrl ?? + attachment.thumbUrl, + ); + })); + }, + child: CachedNetworkImage( + height: size?.height, + width: size?.width, + placeholder: (_, __) { + return Container( width: size?.width, - placeholder: (_, __) { - return Container( - width: size?.width, - height: size?.height, - child: Center( - child: CircularProgressIndicator(), - ), - ); - }, - imageUrl: attachment.thumbUrl ?? - attachment.imageUrl ?? - attachment.assetUrl, - errorWidget: (context, url, error) => AttachmentError( - attachment: attachment, - size: size, + height: size?.height, + child: Center( + child: CircularProgressIndicator(), ), - fit: BoxFit.cover, - ), + ); + }, + imageUrl: attachment.thumbUrl ?? + attachment.imageUrl ?? + attachment.assetUrl, + errorWidget: (context, url, error) => AttachmentError( + attachment: attachment, + size: size, + ), + fit: BoxFit.cover, + ), + ), + ), + Positioned( + left: 0, + top: 0, + child: Container( + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.only( + bottomRight: Radius.circular(16.0), + )), + child: Padding( + padding: const EdgeInsets.only( + left: 8.0, + right: 8.0, + top: 8.0, + bottom: 4.0, + ), + child: Row( + children: [ + Icon( + StreamIcons.lightning, + color: StreamChatTheme.of(context).accentColor, + size: 16.0, + ), + Text( + 'GIPHY', + style: TextStyle( + color: StreamChatTheme.of(context).accentColor, + fontWeight: FontWeight.bold, + fontSize: 11.0, + ), + ), + ], ), ), - Positioned( - left: 0, - top: 0, - child: Container( - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.only( - bottomRight: Radius.circular(16.0), - )), - child: Padding( - padding: const EdgeInsets.only( - left: 4.0, right: 4.0, top: 6.0, bottom: 2.0), - child: Row( - children: [ - Icon( - StreamIcons.lightning, - color: StreamChatTheme.of(context).accentColor, - size: 16.0, - ), - Text( - 'GIPHY', - style: TextStyle( - color: StreamChatTheme.of(context).accentColor, - fontWeight: FontWeight.bold, - fontSize: 11.0, - ), - ), - ], - ), - ), - ), - ), - ], + ), ), if (attachment.title != null) Container( @@ -143,6 +140,7 @@ class GiphyAttachment extends StatelessWidget { StreamIcons.left, size: 24.0, ), + splashRadius: 24, onPressed: () { streamChannel.channel.sendAction(message, { 'image_action': 'shuffle', @@ -167,6 +165,7 @@ class GiphyAttachment extends StatelessWidget { StreamIcons.right, size: 24.0, ), + splashRadius: 24, onPressed: () { streamChannel.channel.sendAction(message, { 'image_action': 'shuffle', @@ -188,24 +187,23 @@ class GiphyAttachment extends StatelessWidget { height: 0.5, ), Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.center, children: [ - FlatButton( - onPressed: () { - streamChannel.channel.sendAction(message, { - 'image_action': 'cancel', - }); - }, - child: Row( - children: [ - Text( - 'Cancel', - style: TextStyle( - fontWeight: FontWeight.bold, - color: Colors.black.withOpacity(0.5)), - ), - ], + Expanded( + child: FlatButton( + height: 50, + onPressed: () { + streamChannel.channel.sendAction(message, { + 'image_action': 'cancel', + }); + }, + child: Text( + 'Cancel', + style: TextStyle( + fontWeight: FontWeight.bold, + color: Colors.black.withOpacity(0.5)), + ), ), ), Container( @@ -213,21 +211,20 @@ class GiphyAttachment extends StatelessWidget { color: Colors.black.withOpacity(0.2), height: 50.0, ), - FlatButton( - onPressed: () { - streamChannel.channel.sendAction(message, { - 'image_action': 'send', - }); - }, - child: Row( - children: [ - Text( - 'Send', - style: TextStyle( - color: StreamChatTheme.of(context).accentColor, - fontWeight: FontWeight.bold), - ), - ], + Expanded( + child: FlatButton( + height: 50, + onPressed: () { + streamChannel.channel.sendAction(message, { + 'image_action': 'send', + }); + }, + child: Text( + 'Send', + style: TextStyle( + color: StreamChatTheme.of(context).accentColor, + fontWeight: FontWeight.bold), + ), ), ), ], @@ -282,26 +279,37 @@ class GiphyAttachment extends StatelessWidget { ), ), clipBehavior: Clip.antiAlias, - child: CachedNetworkImage( - height: size?.height, - width: size?.width, - placeholder: (_, __) { - return Container( - width: size?.width, - height: size?.height, - child: Center( - child: CircularProgressIndicator(), - ), - ); + child: GestureDetector( + onTap: () { + Navigator.push(context, MaterialPageRoute(builder: (_) { + return FullScreenImage( + url: attachment.imageUrl ?? + attachment.assetUrl ?? + attachment.thumbUrl, + ); + })); }, - imageUrl: attachment.thumbUrl ?? - attachment.imageUrl ?? - attachment.assetUrl, - errorWidget: (context, url, error) => AttachmentError( - attachment: attachment, - size: size, + child: CachedNetworkImage( + height: size?.height, + width: size?.width, + placeholder: (_, __) { + return Container( + width: size?.width, + height: size?.height, + child: Center( + child: CircularProgressIndicator(), + ), + ); + }, + imageUrl: attachment.thumbUrl ?? + attachment.imageUrl ?? + attachment.assetUrl, + errorWidget: (context, url, error) => AttachmentError( + attachment: attachment, + size: size, + ), + fit: BoxFit.cover, ), - fit: BoxFit.cover, ), ), Padding( diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 7bdbfd5d..9c9cf67f 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -335,7 +335,7 @@ class MessageInputState extends State { setState(() { _commandEnabled = true; }); - _commandsOverlay.remove(); + _commandsOverlay?.remove(); _commandsOverlay = null; } else { _commandsOverlay = _buildCommandsOverlayEntry(); @@ -344,6 +344,7 @@ class MessageInputState extends State { } if (textEditingController.selection.isCollapsed && + s.isNotEmpty && (s[textEditingController.selection.start - 1] == '@' || textEditingController.text .substring( From 16b199c91c4caec4244e75106595ea857dba0827 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Thu, 5 Nov 2020 10:50:48 +0100 Subject: [PATCH 0290/1140] fix padding --- lib/src/giphy_attachment.dart | 2 +- lib/src/message_widget.dart | 18 +++--------------- 2 files changed, 4 insertions(+), 16 deletions(-) diff --git a/lib/src/giphy_attachment.dart b/lib/src/giphy_attachment.dart index 02c1ca5e..f913b557 100644 --- a/lib/src/giphy_attachment.dart +++ b/lib/src/giphy_attachment.dart @@ -313,7 +313,7 @@ class GiphyAttachment extends StatelessWidget { ), ), Padding( - padding: const EdgeInsets.symmetric(vertical: 8.0), + padding: const EdgeInsets.only(top: 8.0), child: Row( children: [ Row( diff --git a/lib/src/message_widget.dart b/lib/src/message_widget.dart index d57ef0f9..e768c39d 100644 --- a/lib/src/message_widget.dart +++ b/lib/src/message_widget.dart @@ -293,8 +293,9 @@ class _MessageWidgetState extends State { children: [ ..._parseAttachments(context), if (widget.message.text - .trim() - .isNotEmpty) + .trim() + .isNotEmpty && + !isGiphy) _buildTextBubble(context), ], ), @@ -314,19 +315,6 @@ class _MessageWidgetState extends State { .reactionsBorderColor, ), ), - ) - : Column( - crossAxisAlignment: - CrossAxisAlignment.start, - mainAxisSize: MainAxisSize.min, - children: [ - ..._parseAttachments(context), - if (widget.message.text - .trim() - .isNotEmpty && - !isGiphy) - _buildTextBubble(context), - ], ), ), ], From 5099b55fdeb649336b4a3dc0e692a1e70eddfb63 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Thu, 5 Nov 2020 10:53:25 +0100 Subject: [PATCH 0291/1140] fix tests --- lib/src/message_widget.dart | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/src/message_widget.dart b/lib/src/message_widget.dart index e768c39d..ad574fc8 100644 --- a/lib/src/message_widget.dart +++ b/lib/src/message_widget.dart @@ -216,8 +216,9 @@ class _MessageWidgetState extends State { ? widget.messageTheme.avatarTheme.constraints.maxWidth + 16.0 : 6.0; - bool isGiphy = - widget.message.attachments.any((element) => element.type == 'giphy'); + final isGiphy = + widget.message.attachments?.any((element) => element.type == 'giphy') == + true; return Portal( child: Padding( From f10faee751fb6a3e98631d6d6c6f17fa54512aa3 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Thu, 5 Nov 2020 16:02:04 +0530 Subject: [PATCH 0292/1140] feat: Added file picker section space --- lib/src/message_input.dart | 165 +++++++++++++++++-------------------- 1 file changed, 76 insertions(+), 89 deletions(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 9c9cf67f..813ca707 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -172,6 +172,7 @@ class MessageInputState extends State { Command _chosenCommand; bool _actionsShrunk = false; bool _sendAsDm = false; + bool _openFilePickerSection = false; /// The editing controller passed to the input TextField TextEditingController textEditingController; @@ -197,6 +198,8 @@ class MessageInputState extends State { padding: const EdgeInsets.symmetric(horizontal: 8.0), child: _buildDmCheckbox(), ), + if(_openFilePickerSection) + _buildFilePickerSection(), ], ), ), @@ -420,40 +423,6 @@ class MessageInputState extends State { ); } - Positioned _buildBorder(BuildContext context) { - return Positioned.fill( - child: Container( - width: MediaQuery.of(context).size.width, - padding: EdgeInsets.all(2), - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(10.0), - gradient: _getGradient(context), - ), - child: Container( - decoration: BoxDecoration( - color: StreamChatTheme.of(context) - .channelTheme - .inputBackground - .withAlpha(255), - borderRadius: BorderRadius.circular(10.0), - ), - child: Container( - decoration: BoxDecoration( - color: StreamChatTheme.of(context).channelTheme.inputBackground, - borderRadius: BorderRadius.circular(10.0), - border: Border.all( - color: _typingStarted - ? Colors.transparent - : Theme.of(context).brightness == Brightness.dark - ? Colors.white.withOpacity(.2) - : Colors.black.withOpacity(.2)), - ), - ), - ), - ), - ); - } - OverlayEntry _buildCommandsOverlayEntry() { final text = textEditingController.text; final commands = StreamChannel.of(context) @@ -566,6 +535,12 @@ class MessageInputState extends State { }); } + Widget _buildFilePickerSection() { + return Container( + height: 200.0, + ); + } + OverlayEntry _buildMentionsOverlayEntry() { final splits = textEditingController.text .substring(0, textEditingController.value.selection.start) @@ -839,7 +814,13 @@ class MessageInputState extends State { ), ), onTap: () { - showAttachmentModal(); + if(_openFilePickerSection) { + setState(() { + _openFilePickerSection = false; + }); + } else { + showAttachmentModal(); + } }, ), ); @@ -851,73 +832,79 @@ class MessageInputState extends State { _focusNode.unfocus(); } - showModalBottomSheet( - clipBehavior: Clip.hardEdge, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.only( - topLeft: Radius.circular(32), - topRight: Radius.circular(32), + if(!kIsWeb) { + setState(() { + _openFilePickerSection = true; + }); + } else { + showModalBottomSheet( + clipBehavior: Clip.hardEdge, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.only( + topLeft: Radius.circular(32), + topRight: Radius.circular(32), + ), ), - ), - context: context, - isScrollControlled: true, - builder: (_) { - return Column( - mainAxisSize: MainAxisSize.min, - children: [ - ListTile( - title: Text( - 'Add a file', - style: TextStyle( - fontWeight: FontWeight.bold, + context: context, + isScrollControlled: true, + builder: (_) { + return Column( + mainAxisSize: MainAxisSize.min, + children: [ + ListTile( + title: Text( + 'Add a file', + style: TextStyle( + fontWeight: FontWeight.bold, + ), ), ), - ), - ListTile( - leading: Icon(Icons.image), - title: Text('Upload a photo'), - onTap: () { - pickFile(DefaultAttachmentTypes.image, false); - Navigator.pop(context); - }, - ), - ListTile( - leading: Icon(Icons.video_library), - title: Text('Upload a video'), - onTap: () { - pickFile(DefaultAttachmentTypes.video, false); - Navigator.pop(context); - }, - ), - if (!kIsWeb) ListTile( - leading: Icon(Icons.camera_alt), - title: Text('Photo from camera'), + leading: Icon(Icons.image), + title: Text('Upload a photo'), onTap: () { - pickFile(DefaultAttachmentTypes.image, true); + pickFile(DefaultAttachmentTypes.image, false); Navigator.pop(context); }, ), - if (!kIsWeb) ListTile( - leading: Icon(Icons.videocam), - title: Text('Video from camera'), + leading: Icon(Icons.video_library), + title: Text('Upload a video'), onTap: () { - pickFile(DefaultAttachmentTypes.video, true); + pickFile(DefaultAttachmentTypes.video, false); Navigator.pop(context); }, ), - ListTile( - leading: Icon(Icons.insert_drive_file), - title: Text('Upload a file'), - onTap: () { - pickFile(DefaultAttachmentTypes.file, false); - Navigator.pop(context); - }, - ), - ], - ); - }); + if (!kIsWeb) + ListTile( + leading: Icon(Icons.camera_alt), + title: Text('Photo from camera'), + onTap: () { + pickFile(DefaultAttachmentTypes.image, true); + Navigator.pop(context); + }, + ), + if (!kIsWeb) + ListTile( + leading: Icon(Icons.videocam), + title: Text('Video from camera'), + onTap: () { + pickFile(DefaultAttachmentTypes.video, true); + Navigator.pop(context); + }, + ), + ListTile( + leading: Icon(Icons.insert_drive_file), + title: Text('Upload a file'), + onTap: () { + pickFile(DefaultAttachmentTypes.file, false); + Navigator.pop(context); + }, + ), + ], + ); + }); + } } /// Add an attachment to the sending message From 4bb5598c71f47316330bede3b8b70783fcbed4b1 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Thu, 5 Nov 2020 11:35:24 +0100 Subject: [PATCH 0293/1140] use another emoji package --- lib/src/message_input.dart | 37 ++++++++++++++++++------------------- lib/src/message_widget.dart | 5 ++--- pubspec.yaml | 2 +- 3 files changed, 21 insertions(+), 23 deletions(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 4f56827e..8da205b9 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -1,12 +1,11 @@ import 'dart:async'; -import 'dart:convert'; import 'dart:math'; +import 'package:emojis/emoji.dart'; import 'package:file_picker/file_picker.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; -import 'package:flutter_emoji/flutter_emoji.dart'; import 'package:flutter_keyboard_visibility/flutter_keyboard_visibility.dart'; import 'package:fuzzy/fuzzy.dart'; import 'package:http_parser/http_parser.dart'; @@ -171,7 +170,7 @@ class MessageInputState extends State { bool _typingStarted = false; bool _commandEnabled = false; OverlayEntry _commandsOverlay, _mentionsOverlay, _emojiOverlay; - Fuzzy _emojiFuse; + Fuzzy _emojiFuse; Command _chosenCommand; bool _actionsShrunk = false; @@ -326,7 +325,7 @@ class MessageInputState extends State { _emojiOverlay?.remove(); _emojiOverlay = null; - _checkCommands(s, context); + _checkCommands(s.trimLeft(), context); _checkMentions(s, context); @@ -398,7 +397,7 @@ class MessageInputState extends State { void _checkEmoji(String s, BuildContext context) { if (textEditingController.selection.isCollapsed && - (s[textEditingController.selection.start - 1] == ':' || + (s.isNotEmpty && s[textEditingController.selection.start - 1] == ':' || textEditingController.text .substring( 0, @@ -407,14 +406,13 @@ class MessageInputState extends State { .split(' ') .last .contains(':'))) { - final emojiParser = EmojiParser(); final textToSelection = textEditingController.text .substring(0, textEditingController.value.selection.start); final splits = textToSelection.split(':'); final query = splits[1]?.toLowerCase(); - final emoji = emojiParser.get(query); + final emoji = Emoji.byName(query); - if (textToSelection.endsWith(':') && emoji.name != '') { + if (textToSelection.endsWith(':') && emoji != null) { _chooseEmoji(splits, emoji); } else { _emojiOverlay = _buildEmojiOverlay(); @@ -428,7 +426,7 @@ class MessageInputState extends State { void _checkMentions(String s, BuildContext context) { if (textEditingController.selection.isCollapsed && - (s[textEditingController.selection.start - 1] == '@' || + (s.isNotEmpty && s[textEditingController.selection.start - 1] == '@' || textEditingController.text .substring(0, textEditingController.selection.start) .split(' ') @@ -465,7 +463,7 @@ class MessageInputState extends State { } OverlayEntry _buildCommandsOverlayEntry() { - final text = textEditingController.text; + final text = textEditingController.text.trimLeft(); final commands = StreamChannel.of(context) .channel .config @@ -678,9 +676,11 @@ class MessageInputState extends State { return null; } - final parser = EmojiParser(); - final emojis = - _emojiFuse.search(query).map((e) => parser.get(e.item)).toList(); + final emojis = _emojiFuse + .search(query) + .map((e) => Emoji.byName(e.item)) + .where((e) => e != null) + .toList(); RenderBox renderBox = context.findRenderObject(); final size = renderBox.size; @@ -736,7 +736,7 @@ class MessageInputState extends State { ), ...emojis.map((emoji) => ListTile( title: Text( - "${emoji.code} ${emoji.name.replaceAll('_', ' ')}", + "${emoji.char} ${emoji.name.replaceAll('_', ' ')}", style: TextStyle( fontWeight: FontWeight.bold, fontSize: 14.5, @@ -755,7 +755,7 @@ class MessageInputState extends State { } void _chooseEmoji(List splits, Emoji emoji) { - splits[1] = emoji.code; + splits[1] = emoji.char; final rejoin = splits.join(''); textEditingController.value = TextEditingValue( @@ -1324,9 +1324,8 @@ class MessageInputState extends State { @override void initState() { super.initState(); - Map emojiMap = jsonDecode(EmojiParser.JSON_EMOJI); - _emojiFuse = Fuzzy(emojiMap.keys.toList(), + _emojiFuse = Fuzzy(Emoji.all().map((e) => e.name).toList(), options: FuzzyOptions( matchAllTokens: true, tokenize: true, @@ -1336,7 +1335,7 @@ class MessageInputState extends State { _keyboardListener = KeyboardVisibility.onChange.listen((visible) { if (visible) { if (_commandsOverlay != null) { - if (textEditingController.text.startsWith('/')) { + if (textEditingController.text.trimLeft().startsWith('/')) { WidgetsBinding.instance.addPostFrameCallback((_) { _commandsOverlay = _buildCommandsOverlayEntry(); Overlay.of(context).insert(_commandsOverlay); @@ -1354,7 +1353,7 @@ class MessageInputState extends State { } if (_emojiOverlay != null) { - if (textEditingController.text.contains('@')) { + if (textEditingController.text.contains(':')) { WidgetsBinding.instance.addPostFrameCallback((_) { _emojiOverlay = _buildEmojiOverlay(); Overlay.of(context).insert(_emojiOverlay); diff --git a/lib/src/message_widget.dart b/lib/src/message_widget.dart index d516aa1e..476217f3 100644 --- a/lib/src/message_widget.dart +++ b/lib/src/message_widget.dart @@ -1,11 +1,11 @@ import 'dart:math'; import 'dart:ui'; +import 'package:emojis/emoji.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; -import 'package:flutter_emoji/flutter_emoji.dart'; import 'package:flutter_portal/flutter_portal.dart'; import 'package:jiffy/jiffy.dart'; import 'package:stream_chat_flutter/src/message_actions_modal.dart'; @@ -751,9 +751,8 @@ class _MessageWidgetState extends State { } Widget _buildTextBubble(BuildContext context) { - final emojiParser = EmojiParser(); final isOnlyEmoji = - widget.message.text.characters.every((c) => emojiParser.hasEmoji(c)); + widget.message.text.characters.every((c) => Emoji.byChar(c) != null); Widget child = Transform( transform: Matrix4.rotationY(widget.reverse ? pi : 0), diff --git a/pubspec.yaml b/pubspec.yaml index 1dfb195f..6aa8aff3 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -25,7 +25,7 @@ dependencies: image_picker: ^0.6.7+2 flutter_keyboard_visibility: ^3.2.1 stream_chat: ^0.2.10+1 - flutter_emoji: ^2.2.1+1 + emojis: ^0.9.3 mime: ^0.9.6+3 fuzzy: ^0.2.3 visibility_detector: ^0.1.5 From da2ca558743e5e9ce603ae317210503e19e72184 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Thu, 5 Nov 2020 11:37:12 +0100 Subject: [PATCH 0294/1140] fix giphy corner tag --- lib/src/giphy_attachment.dart | 136 +++++++++++++++++----------------- 1 file changed, 70 insertions(+), 66 deletions(-) diff --git a/lib/src/giphy_attachment.dart b/lib/src/giphy_attachment.dart index f913b557..89beb4b1 100644 --- a/lib/src/giphy_attachment.dart +++ b/lib/src/giphy_attachment.dart @@ -55,76 +55,80 @@ class GiphyAttachment extends StatelessWidget { mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.stretch, children: [ - Padding( - padding: const EdgeInsets.all(8.0), - child: GestureDetector( - onTap: () { - Navigator.push(context, MaterialPageRoute(builder: (_) { - return FullScreenImage( - url: attachment.imageUrl ?? - attachment.assetUrl ?? - attachment.thumbUrl, - ); - })); - }, - child: CachedNetworkImage( - height: size?.height, - width: size?.width, - placeholder: (_, __) { - return Container( - width: size?.width, + Stack( + children: [ + Padding( + padding: const EdgeInsets.all(8.0), + child: GestureDetector( + onTap: () { + Navigator.push(context, MaterialPageRoute(builder: (_) { + return FullScreenImage( + url: attachment.imageUrl ?? + attachment.assetUrl ?? + attachment.thumbUrl, + ); + })); + }, + child: CachedNetworkImage( height: size?.height, - child: Center( - child: CircularProgressIndicator(), + width: size?.width, + placeholder: (_, __) { + return Container( + width: size?.width, + height: size?.height, + child: Center( + child: CircularProgressIndicator(), + ), + ); + }, + imageUrl: attachment.thumbUrl ?? + attachment.imageUrl ?? + attachment.assetUrl, + errorWidget: (context, url, error) => AttachmentError( + attachment: attachment, + size: size, ), - ); - }, - imageUrl: attachment.thumbUrl ?? - attachment.imageUrl ?? - attachment.assetUrl, - errorWidget: (context, url, error) => AttachmentError( - attachment: attachment, - size: size, - ), - fit: BoxFit.cover, - ), - ), - ), - Positioned( - left: 0, - top: 0, - child: Container( - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.only( - bottomRight: Radius.circular(16.0), - )), - child: Padding( - padding: const EdgeInsets.only( - left: 8.0, - right: 8.0, - top: 8.0, - bottom: 4.0, - ), - child: Row( - children: [ - Icon( - StreamIcons.lightning, - color: StreamChatTheme.of(context).accentColor, - size: 16.0, - ), - Text( - 'GIPHY', - style: TextStyle( - color: StreamChatTheme.of(context).accentColor, - fontWeight: FontWeight.bold, - fontSize: 11.0, - ), - ), - ], + fit: BoxFit.cover, + ), ), ), - ), + Positioned( + left: 0, + top: 0, + child: Container( + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.only( + bottomRight: Radius.circular(16.0), + )), + child: Padding( + padding: const EdgeInsets.only( + left: 8.0, + right: 8.0, + top: 8.0, + bottom: 4.0, + ), + child: Row( + children: [ + Icon( + StreamIcons.lightning, + color: StreamChatTheme.of(context).accentColor, + size: 16.0, + ), + Text( + 'GIPHY', + style: TextStyle( + color: StreamChatTheme.of(context).accentColor, + fontWeight: FontWeight.bold, + fontSize: 11.0, + ), + ), + ], + ), + ), + ), + ), + ], ), if (attachment.title != null) Container( From 44ab00e1078b56b17abcbd2953738b375cdef000 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Thu, 5 Nov 2020 17:21:23 +0530 Subject: [PATCH 0295/1140] feat: Added file picker sections and image support --- lib/src/message_input.dart | 148 ++++++++++++++++++++++++++++++++++++- pubspec.yaml | 1 + 2 files changed, 145 insertions(+), 4 deletions(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 813ca707..85878a40 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -1,4 +1,5 @@ import 'dart:async'; +import 'dart:io'; import 'dart:math'; import 'package:file_picker/file_picker.dart'; @@ -9,6 +10,7 @@ import 'package:flutter_keyboard_visibility/flutter_keyboard_visibility.dart'; import 'package:http_parser/http_parser.dart'; import 'package:image_picker/image_picker.dart'; import 'package:mime/mime.dart'; +import 'package:photo_gallery/photo_gallery.dart'; import 'package:stream_chat/stream_chat.dart'; import 'package:stream_chat_flutter/src/message_list_view.dart'; import 'package:stream_chat_flutter/src/stream_chat_theme.dart'; @@ -173,6 +175,8 @@ class MessageInputState extends State { bool _actionsShrunk = false; bool _sendAsDm = false; bool _openFilePickerSection = false; + int _filePickerIndex = 0; + Album _selectedAlbum; /// The editing controller passed to the input TextField TextEditingController textEditingController; @@ -198,8 +202,7 @@ class MessageInputState extends State { padding: const EdgeInsets.symmetric(horizontal: 8.0), child: _buildDmCheckbox(), ), - if(_openFilePickerSection) - _buildFilePickerSection(), + if (_openFilePickerSection) _buildFilePickerSection(), ], ), ), @@ -538,9 +541,146 @@ class MessageInputState extends State { Widget _buildFilePickerSection() { return Container( height: 200.0, + child: Column( + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + IconButton( + icon: Icon( + StreamIcons.picture, + color: _filePickerIndex == 0 + ? StreamChatTheme.of(context).accentColor + : Colors.black.withOpacity(0.5), + ), + onPressed: () { + setState(() { + _filePickerIndex = 0; + }); + }, + ), + IconButton( + icon: Icon( + StreamIcons.folder, + color: _filePickerIndex == 1 + ? StreamChatTheme.of(context).accentColor + : Colors.black.withOpacity(0.5), + ), + onPressed: () { + setState(() { + _filePickerIndex = 1; + }); + }, + ), + IconButton( + icon: Icon( + StreamIcons.camera, + color: _filePickerIndex == 2 + ? StreamChatTheme.of(context).accentColor + : Colors.black.withOpacity(0.5), + ), + onPressed: () { + setState(() { + _filePickerIndex = 2; + }); + }, + ), + ], + ), + Expanded( + child: _buildPickerSection(), + ), + ], + ), ); } + Widget _buildPickerSection() { + switch (_filePickerIndex) { + case 0: + if (_selectedAlbum != null) { + return FutureBuilder( + future: _selectedAlbum.listMedia(), + builder: (context, snapshot) { + if (!snapshot.hasData) { + return Center( + child: CircularProgressIndicator(), + ); + } + return GridView.builder( + itemCount: snapshot.data.total, + gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: 3), + itemBuilder: (context, position) { + return FutureBuilder( + future: snapshot.data.items[position].getFile(), + builder: (context, snapshot) { + if (!snapshot.hasData) { + return Center( + child: CircularProgressIndicator(), + ); + } + + return InkWell( + onTap: () { + + }, + child: AspectRatio( + child: Image.file(snapshot.data), + aspectRatio: 1.0, + ), + ); + }); + }, + ); + }); + } + + return FutureBuilder>( + future: PhotoGallery.listAlbums(mediumType: MediumType.image), + builder: (context, albumData) { + if (!albumData.hasData) { + return Center( + child: CircularProgressIndicator(), + ); + } + return GridView.builder( + itemCount: albumData.data.length, + gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: 3), + itemBuilder: (context, position) { + return FutureBuilder>( + future: albumData.data[position].getThumbnail(), + builder: (context, snapshot) { + if (!snapshot.hasData) { + return Center( + child: CircularProgressIndicator(), + ); + } + + return InkWell( + child: AspectRatio( + child: Image.memory(snapshot.data), + aspectRatio: 1.0, + ), + onTap: () { + setState(() { + _selectedAlbum = albumData.data[position]; + }); + }, + ); + }); + }, + ); + }); + break; + case 1: + break; + case 2: + break; + } + } + OverlayEntry _buildMentionsOverlayEntry() { final splits = textEditingController.text .substring(0, textEditingController.value.selection.start) @@ -814,7 +954,7 @@ class MessageInputState extends State { ), ), onTap: () { - if(_openFilePickerSection) { + if (_openFilePickerSection) { setState(() { _openFilePickerSection = false; }); @@ -832,7 +972,7 @@ class MessageInputState extends State { _focusNode.unfocus(); } - if(!kIsWeb) { + if (!kIsWeb) { setState(() { _openFilePickerSection = true; }); diff --git a/pubspec.yaml b/pubspec.yaml index 452eb69a..70b8188a 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -32,6 +32,7 @@ dependencies: carousel_slider: ^2.2.1 clipboard: ^0.1.2+8 widgets_visibility_provider: ^2.0.2 + photo_gallery: ^0.3.0 flutter: assets: From 5b93afcb5a2e1989d48645f3395459ff2871310b Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Thu, 5 Nov 2020 13:47:53 +0100 Subject: [PATCH 0296/1140] fix listview default params --- example/ios/Flutter/.last_build_id | 2 +- example/pubspec.yaml | 2 +- lib/src/message_list_view.dart | 7 +++---- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/example/ios/Flutter/.last_build_id b/example/ios/Flutter/.last_build_id index 5d3809be..8aba7787 100644 --- a/example/ios/Flutter/.last_build_id +++ b/example/ios/Flutter/.last_build_id @@ -1 +1 @@ -bdf1751976c4ee1e2ef7638eabcfd1ea \ No newline at end of file +bb5f9103d9045cd6244bcae1f5f343e5 \ No newline at end of file diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 842f471c..97971445 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -1,6 +1,6 @@ name: example description: A new Flutter project. -version: 1.0.39+41 +version: 1.0.40+42 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 d2e1d972..6c23ea4b 100644 --- a/lib/src/message_list_view.dart +++ b/lib/src/message_list_view.dart @@ -107,8 +107,8 @@ class MessageListView extends StatefulWidget { this.onThreadTap, this.dateDividerBuilder, this.scrollPhysics = const AlwaysScrollableScrollPhysics(), - this.initialScrollIndex, - this.initialAlignment, + this.initialScrollIndex = 0, + this.initialAlignment = 0, this.scrollController, this.itemPositionListener, }) : super(key: key); @@ -608,8 +608,6 @@ class _MessageListViewState extends State { @override void initState() { - super.initState(); - _scrollController = widget.scrollController ?? ItemScrollController(); _itemPositionListener = widget.itemPositionListener ?? ItemPositionsListener.create(); @@ -644,6 +642,7 @@ class _MessageListViewState extends State { } _getOnThreadTap(); + super.initState(); } void _getOnThreadTap() { From 4dd68d3de903be1d5e46281921ca5f0433509df1 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Thu, 5 Nov 2020 13:57:09 +0100 Subject: [PATCH 0297/1140] fix giphy padding --- lib/src/giphy_attachment.dart | 84 +++++++++++++++++------------------ 1 file changed, 42 insertions(+), 42 deletions(-) diff --git a/lib/src/giphy_attachment.dart b/lib/src/giphy_attachment.dart index 89beb4b1..7a1d0ad1 100644 --- a/lib/src/giphy_attachment.dart +++ b/lib/src/giphy_attachment.dart @@ -97,7 +97,7 @@ class GiphyAttachment extends StatelessWidget { top: 0, child: Container( decoration: BoxDecoration( - color: Colors.white, + color: Colors.transparent, borderRadius: BorderRadius.only( bottomRight: Radius.circular(16.0), )), @@ -133,53 +133,50 @@ class GiphyAttachment extends StatelessWidget { if (attachment.title != null) Container( alignment: Alignment.bottomCenter, - child: Material( - color: Colors.white, - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Card( - child: IconButton( - icon: Icon( - StreamIcons.left, - size: 24.0, - ), - splashRadius: 24, - onPressed: () { - streamChannel.channel.sendAction(message, { - 'image_action': 'shuffle', - }); - }, + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Card( + child: IconButton( + icon: Icon( + StreamIcons.left, + size: 24.0, ), - shape: CircleBorder(), + splashRadius: 24, + onPressed: () { + streamChannel.channel.sendAction(message, { + 'image_action': 'shuffle', + }); + }, ), - Expanded( - child: Center( - child: Text( - '"${attachment.title}"', - style: TextStyle( - fontStyle: FontStyle.italic, - ), + shape: CircleBorder(), + ), + Expanded( + child: Center( + child: Text( + '"${attachment.title}"', + style: TextStyle( + fontStyle: FontStyle.italic, ), ), ), - Card( - child: IconButton( - icon: Icon( - StreamIcons.right, - size: 24.0, - ), - splashRadius: 24, - onPressed: () { - streamChannel.channel.sendAction(message, { - 'image_action': 'shuffle', - }); - }, + ), + Card( + child: IconButton( + icon: Icon( + StreamIcons.right, + size: 24.0, ), - shape: CircleBorder(), + splashRadius: 24, + onPressed: () { + streamChannel.channel.sendAction(message, { + 'image_action': 'shuffle', + }); + }, ), - ], - ), + shape: CircleBorder(), + ), + ], ), ), SizedBox( @@ -317,7 +314,10 @@ class GiphyAttachment extends StatelessWidget { ), ), Padding( - padding: const EdgeInsets.only(top: 8.0), + padding: const EdgeInsets.only( + top: 8.0, + bottom: 8, + ), child: Row( children: [ Row( From be4805116fb27ab715ce70d9210d797c8afdadec Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Thu, 5 Nov 2020 14:15:22 +0100 Subject: [PATCH 0298/1140] fix giphy color --- lib/src/giphy_attachment.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/giphy_attachment.dart b/lib/src/giphy_attachment.dart index 7a1d0ad1..766f7720 100644 --- a/lib/src/giphy_attachment.dart +++ b/lib/src/giphy_attachment.dart @@ -97,7 +97,7 @@ class GiphyAttachment extends StatelessWidget { top: 0, child: Container( decoration: BoxDecoration( - color: Colors.transparent, + color: Colors.white, borderRadius: BorderRadius.only( bottomRight: Radius.circular(16.0), )), From 119c6660e9ab736ad1500350256309b92271e830 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Thu, 5 Nov 2020 14:35:50 +0100 Subject: [PATCH 0299/1140] fix qa problems --- example/ios/Flutter/.last_build_id | 2 +- example/pubspec.yaml | 2 +- lib/src/giphy_attachment.dart | 359 +++++++++++++++-------------- lib/src/message_input.dart | 20 +- 4 files changed, 195 insertions(+), 188 deletions(-) diff --git a/example/ios/Flutter/.last_build_id b/example/ios/Flutter/.last_build_id index 5d3809be..8aba7787 100644 --- a/example/ios/Flutter/.last_build_id +++ b/example/ios/Flutter/.last_build_id @@ -1 +1 @@ -bdf1751976c4ee1e2ef7638eabcfd1ea \ No newline at end of file +bb5f9103d9045cd6244bcae1f5f343e5 \ No newline at end of file diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 842f471c..97971445 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -1,6 +1,6 @@ name: example description: A new Flutter project. -version: 1.0.39+41 +version: 1.0.40+42 environment: sdk: ">=2.2.2 <3.0.0" diff --git a/lib/src/giphy_attachment.dart b/lib/src/giphy_attachment.dart index 766f7720..bfa21239 100644 --- a/lib/src/giphy_attachment.dart +++ b/lib/src/giphy_attachment.dart @@ -41,196 +41,211 @@ class GiphyAttachment extends StatelessWidget { return Column( mainAxisSize: MainAxisSize.min, children: [ - Card( - clipBehavior: Clip.antiAlias, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.only( - topRight: Radius.circular(16.0), - bottomRight: Radius.circular(0.0), - topLeft: Radius.circular(16.0), - bottomLeft: Radius.circular(16.0), + DecoratedBox( + decoration: BoxDecoration(), + child: Card( + elevation: 2, + clipBehavior: Clip.antiAlias, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.only( + topRight: Radius.circular(16.0), + bottomRight: Radius.circular(0.0), + topLeft: Radius.circular(16.0), + bottomLeft: Radius.circular(16.0), + ), ), - ), - child: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - Stack( - children: [ - Padding( - padding: const EdgeInsets.all(8.0), - child: GestureDetector( - onTap: () { - Navigator.push(context, MaterialPageRoute(builder: (_) { - return FullScreenImage( - url: attachment.imageUrl ?? - attachment.assetUrl ?? - attachment.thumbUrl, - ); - })); - }, - child: CachedNetworkImage( - height: size?.height, - width: size?.width, - placeholder: (_, __) { - return Container( - width: size?.width, - height: size?.height, - child: Center( - child: CircularProgressIndicator(), - ), - ); + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Stack( + children: [ + Padding( + padding: const EdgeInsets.all(8.0), + child: GestureDetector( + onTap: () { + Navigator.push(context, + MaterialPageRoute(builder: (_) { + return FullScreenImage( + url: attachment.imageUrl ?? + attachment.assetUrl ?? + attachment.thumbUrl, + ); + })); }, - imageUrl: attachment.thumbUrl ?? - attachment.imageUrl ?? - attachment.assetUrl, - errorWidget: (context, url, error) => AttachmentError( - attachment: attachment, - size: size, + child: CachedNetworkImage( + height: size?.height, + width: size?.width, + placeholder: (_, __) { + return Container( + width: size?.width, + height: size?.height, + child: Center( + child: CircularProgressIndicator(), + ), + ); + }, + imageUrl: attachment.thumbUrl ?? + attachment.imageUrl ?? + attachment.assetUrl, + errorWidget: (context, url, error) => AttachmentError( + attachment: attachment, + size: size, + ), + fit: BoxFit.cover, ), - fit: BoxFit.cover, ), ), - ), - Positioned( - left: 0, - top: 0, - child: Container( - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.only( - bottomRight: Radius.circular(16.0), - )), - child: Padding( - padding: const EdgeInsets.only( - left: 8.0, - right: 8.0, - top: 8.0, - bottom: 4.0, - ), - child: Row( - children: [ - Icon( - StreamIcons.lightning, - color: StreamChatTheme.of(context).accentColor, - size: 16.0, - ), - Text( - 'GIPHY', - style: TextStyle( + Positioned( + left: 0, + top: 0, + child: Container( + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.only( + bottomRight: Radius.circular(16.0), + )), + child: Padding( + padding: const EdgeInsets.only( + left: 8.0, + right: 8.0, + top: 8.0, + bottom: 4.0, + ), + child: Row( + children: [ + Icon( + StreamIcons.lightning, color: StreamChatTheme.of(context).accentColor, - fontWeight: FontWeight.bold, - fontSize: 11.0, + size: 16.0, + ), + Text( + 'GIPHY', + style: TextStyle( + color: + StreamChatTheme.of(context).accentColor, + fontWeight: FontWeight.bold, + fontSize: 11.0, + ), + ), + ], + ), + ), + ), + ), + ], + ), + if (attachment.title != null) + Container( + alignment: Alignment.bottomCenter, + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 8.0), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Card( + elevation: 2, + child: IconButton( + padding: const EdgeInsets.all(0), + constraints: BoxConstraints.tight(Size(32, 32)), + icon: Icon( + StreamIcons.left, + size: 24.0, + ), + splashRadius: 16, + onPressed: () { + streamChannel.channel.sendAction(message, { + 'image_action': 'shuffle', + }); + }, + ), + shape: CircleBorder(), + ), + Expanded( + child: Center( + child: Text( + '"${attachment.title}"', + style: TextStyle( + fontStyle: FontStyle.italic, + ), ), ), - ], - ), - ), - ), - ), - ], - ), - if (attachment.title != null) - Container( - alignment: Alignment.bottomCenter, - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Card( - child: IconButton( - icon: Icon( - StreamIcons.left, - size: 24.0, ), - splashRadius: 24, - onPressed: () { - streamChannel.channel.sendAction(message, { - 'image_action': 'shuffle', - }); - }, - ), - shape: CircleBorder(), - ), - Expanded( - child: Center( - child: Text( - '"${attachment.title}"', - style: TextStyle( - fontStyle: FontStyle.italic, + Card( + elevation: 2, + child: IconButton( + padding: const EdgeInsets.all(0), + constraints: BoxConstraints.tight(Size(32, 32)), + icon: Icon( + StreamIcons.right, + size: 24.0, + ), + splashRadius: 16, + onPressed: () { + streamChannel.channel.sendAction(message, { + 'image_action': 'shuffle', + }); + }, ), + shape: CircleBorder(), ), - ), + ], ), - Card( - child: IconButton( - icon: Icon( - StreamIcons.right, - size: 24.0, - ), - splashRadius: 24, - onPressed: () { - streamChannel.channel.sendAction(message, { - 'image_action': 'shuffle', - }); - }, - ), - shape: CircleBorder(), - ), - ], + ), ), + SizedBox( + height: 4.0, ), - SizedBox( - height: 4.0, - ), - Container( - color: Colors.black.withOpacity(0.2), - width: double.infinity, - height: 0.5, - ), - Row( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Expanded( - child: FlatButton( - height: 50, - onPressed: () { - streamChannel.channel.sendAction(message, { - 'image_action': 'cancel', - }); - }, - child: Text( - 'Cancel', - style: TextStyle( - fontWeight: FontWeight.bold, - color: Colors.black.withOpacity(0.5)), + Container( + color: Colors.black.withOpacity(0.2), + width: double.infinity, + height: 0.5, + ), + Row( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Expanded( + child: FlatButton( + height: 50, + onPressed: () { + streamChannel.channel.sendAction(message, { + 'image_action': 'cancel', + }); + }, + child: Text( + 'Cancel', + style: TextStyle( + fontWeight: FontWeight.bold, + color: Colors.black.withOpacity(0.5)), + ), ), ), - ), - Container( - width: 0.5, - color: Colors.black.withOpacity(0.2), - height: 50.0, - ), - Expanded( - child: FlatButton( - height: 50, - onPressed: () { - streamChannel.channel.sendAction(message, { - 'image_action': 'send', - }); - }, - child: Text( - 'Send', - style: TextStyle( - color: StreamChatTheme.of(context).accentColor, - fontWeight: FontWeight.bold), + Container( + width: 0.5, + color: Colors.black.withOpacity(0.2), + height: 50.0, + ), + Expanded( + child: FlatButton( + height: 50, + onPressed: () { + streamChannel.channel.sendAction(message, { + 'image_action': 'send', + }); + }, + child: Text( + 'Send', + style: TextStyle( + color: StreamChatTheme.of(context).accentColor, + fontWeight: FontWeight.bold), + ), ), ), - ), - ], - ), - ], + ], + ), + ], + ), ), ), SizedBox( diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 9c9cf67f..7959901a 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -483,13 +483,6 @@ class MessageInputState extends State { child: Container( constraints: BoxConstraints.loose(Size.fromHeight(400)), decoration: BoxDecoration( - // boxShadow: [ - // BoxShadow( - // spreadRadius: -8, - // blurRadius: 5.0, - // offset: Offset(0, -4), - // ), - // ], color: StreamChatTheme.of(context).primaryColor, borderRadius: BorderRadius.circular(8.0)), child: ListView( @@ -606,13 +599,6 @@ class MessageInputState extends State { child: Container( constraints: BoxConstraints.loose(Size.fromHeight(400)), decoration: BoxDecoration( - boxShadow: [ - BoxShadow( - spreadRadius: -8, - blurRadius: 5.0, - offset: Offset(0, -4), - ), - ], color: StreamChatTheme.of(context).primaryColor, ), child: FutureBuilder>( @@ -625,6 +611,12 @@ class MessageInputState extends State { children: snapshot.data .map((m) => ListTile( leading: UserAvatar( + constraints: BoxConstraints.tight( + Size( + 40, + 40, + ), + ), user: m.user, ), title: Text( From 0de05143f4c427d71c5a16c3293726cf69926c00 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Thu, 5 Nov 2020 19:15:19 +0530 Subject: [PATCH 0300/1140] feat: Images and video are now dsplayed --- lib/src/message_input.dart | 138 ++++++++++++++++++++++--------------- 1 file changed, 83 insertions(+), 55 deletions(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 85878a40..3a8132e2 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -176,7 +176,6 @@ class MessageInputState extends State { bool _sendAsDm = false; bool _openFilePickerSection = false; int _filePickerIndex = 0; - Album _selectedAlbum; /// The editing controller passed to the input TextField TextEditingController textEditingController; @@ -598,59 +597,23 @@ class MessageInputState extends State { Widget _buildPickerSection() { switch (_filePickerIndex) { case 0: - if (_selectedAlbum != null) { - return FutureBuilder( - future: _selectedAlbum.listMedia(), - builder: (context, snapshot) { - if (!snapshot.hasData) { - return Center( - child: CircularProgressIndicator(), - ); - } - return GridView.builder( - itemCount: snapshot.data.total, - gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( - crossAxisCount: 3), - itemBuilder: (context, position) { - return FutureBuilder( - future: snapshot.data.items[position].getFile(), - builder: (context, snapshot) { - if (!snapshot.hasData) { - return Center( - child: CircularProgressIndicator(), - ); - } - - return InkWell( - onTap: () { - - }, - child: AspectRatio( - child: Image.file(snapshot.data), - aspectRatio: 1.0, - ), - ); - }); - }, - ); - }); - } - - return FutureBuilder>( - future: PhotoGallery.listAlbums(mediumType: MediumType.image), - builder: (context, albumData) { - if (!albumData.hasData) { + return FutureBuilder>( + future: _getAllMedia(MediumType.image), + builder: (context, mediaData) { + if (!mediaData.hasData) { return Center( child: CircularProgressIndicator(), ); } + return GridView.builder( - itemCount: albumData.data.length, + itemCount: mediaData.data.length, gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: 3), itemBuilder: (context, position) { - return FutureBuilder>( - future: albumData.data[position].getThumbnail(), + return FutureBuilder>( + future: PhotoGallery.getThumbnail( + mediumId: mediaData.data[position].id), builder: (context, snapshot) { if (!snapshot.hasData) { return Center( @@ -658,16 +621,22 @@ class MessageInputState extends State { ); } - return InkWell( - child: AspectRatio( - child: Image.memory(snapshot.data), - aspectRatio: 1.0, + return Padding( + padding: const EdgeInsets.symmetric( + horizontal: 1.0, vertical: 1.0), + child: InkWell( + child: AspectRatio( + child: Image.memory( + snapshot.data, + fit: mediaData.data[position].height > + mediaData.data[position].width + ? BoxFit.fitWidth + : BoxFit.fitHeight, + ), + aspectRatio: 1.0, + ), + onTap: () {}, ), - onTap: () { - setState(() { - _selectedAlbum = albumData.data[position]; - }); - }, ); }); }, @@ -675,12 +644,71 @@ class MessageInputState extends State { }); break; case 1: + return FutureBuilder>( + future: _getAllMedia(MediumType.video), + builder: (context, mediaData) { + if (!mediaData.hasData) { + return Center( + child: CircularProgressIndicator(), + ); + } + + return GridView.builder( + itemCount: mediaData.data.length, + gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: 3), + itemBuilder: (context, position) { + return FutureBuilder>( + future: PhotoGallery.getThumbnail( + mediumId: mediaData.data[position].id), + builder: (context, snapshot) { + if (!snapshot.hasData) { + return Center( + child: CircularProgressIndicator(), + ); + } + + return Padding( + padding: const EdgeInsets.symmetric( + horizontal: 1.0, vertical: 1.0), + child: InkWell( + child: AspectRatio( + child: Image.memory( + snapshot.data, + fit: mediaData.data[position].height > + mediaData.data[position].width + ? BoxFit.fitWidth + : BoxFit.fitHeight, + ), + aspectRatio: 1.0, + ), + onTap: () {}, + ), + ); + }); + }, + ); + }); break; case 2: break; } } + Future> _getAllMedia(MediumType type) async { + var allAlbums = await PhotoGallery.listAlbums(mediumType: type); + List resultList = []; + + for (var album in allAlbums) { + var data = await album.listMedia(); + resultList.addAll(data.items); + } + + resultList.sort((a, b) => a.modifiedDate.compareTo(b.modifiedDate)); + + return resultList; + } + OverlayEntry _buildMentionsOverlayEntry() { final splits = textEditingController.text .substring(0, textEditingController.value.selection.start) From d485c96f81bd856910ac5603358c5d1a44cae144 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Thu, 5 Nov 2020 15:16:16 +0100 Subject: [PATCH 0301/1140] use svg icon --- lib/src/message_input.dart | 116 ++++++++++++++++++++++++++++++------- pubspec.yaml | 4 +- svgs/giphy_icon.svg | 8 +++ 3 files changed, 107 insertions(+), 21 deletions(-) create mode 100644 svgs/giphy_icon.svg diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 7959901a..aff98b41 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -6,6 +6,7 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_keyboard_visibility/flutter_keyboard_visibility.dart'; +import 'package:flutter_svg/flutter_svg.dart'; import 'package:http_parser/http_parser.dart'; import 'package:image_picker/image_picker.dart'; import 'package:mime/mime.dart'; @@ -220,16 +221,72 @@ class MessageInputState extends State { } Widget _buildDmCheckbox() { + return Container( + height: 36, + padding: const EdgeInsets.only( + left: 12, + bottom: 12, + top: 8, + ), + child: Row( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Center( + child: Container( + height: 16, + width: 16, + child: Material( + borderRadius: BorderRadius.circular(3), + color: _sendAsDm + ? StreamChatTheme.of(context).accentColor + : Colors.white, + child: InkWell( + onTap: () { + setState(() { + _sendAsDm = !_sendAsDm; + }); + }, + child: AnimatedCrossFade( + duration: Duration(milliseconds: 300), + reverseDuration: Duration(milliseconds: 300), + crossFadeState: _sendAsDm + ? CrossFadeState.showFirst + : CrossFadeState.showSecond, + firstChild: Icon( + Icons.check, + size: 16.0, + color: Colors.white, + ), + secondChild: SizedBox( + height: 16, + width: 16, + ), + ), + ), + ), + ), + ), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 8.0), + child: Text('Send also as direct message'), + ), + ], + ), + ); return Row( children: [ - Checkbox( - value: _sendAsDm, - onChanged: (val) => setState( - () { - _sendAsDm = val; - }, + ClipRRect( + clipBehavior: Clip.hardEdge, + borderRadius: BorderRadius.circular(1), + child: Checkbox( + value: _sendAsDm, + onChanged: (val) => setState( + () { + _sendAsDm = val; + }, + ), + activeColor: StreamChatTheme.of(context).accentColor, ), - activeColor: StreamChatTheme.of(context).accentColor, ), Padding( padding: const EdgeInsets.symmetric(horizontal: 8.0), @@ -500,25 +557,19 @@ class MessageInputState extends State { child: Icon(StreamIcons.lightning, color: StreamChatTheme.of(context).accentColor), ), - Text('Instant Commands') + Text( + 'Instant Commands', + style: TextStyle( + color: Colors.black.withOpacity(.5), + ), + ) ], ), ), ...commands .map( (c) => ListTile( - leading: c.name == 'giphy' - ? CircleAvatar( - backgroundColor: Colors.black, - child: Image.asset( - 'images/giphy_icon.png', - package: 'stream_chat_flutter', - width: 16.0, - height: 16.0, - ), - maxRadius: 12.0, - ) - : null, + leading: c.name == 'giphy' ? _buildGiphyIcon() : null, title: Text.rich( TextSpan( text: '${c.name.capitalize()}', @@ -559,6 +610,31 @@ class MessageInputState extends State { }); } + CircleAvatar _buildGiphyIcon() { + if (kIsWeb) { + return CircleAvatar( + backgroundColor: Colors.black, + child: Image.asset( + 'images/giphy_icon.png', + package: 'stream_chat_flutter', + width: 24.0, + height: 24.0, + ), + radius: 12, + ); + } else { + return CircleAvatar( + child: SvgPicture.asset( + 'svgs/giphy_icon.svg', + package: 'stream_chat_flutter', + width: 24.0, + height: 24.0, + ), + radius: 12, + ); + } + } + OverlayEntry _buildMentionsOverlayEntry() { final splits = textEditingController.text .substring(0, textEditingController.value.selection.start) diff --git a/pubspec.yaml b/pubspec.yaml index 452eb69a..a2d92d69 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -15,6 +15,7 @@ dependencies: photo_view: ^0.10.1 rxdart: ^0.24.1 jiffy: ^3.0.1 + flutter_svg: ^0.19.1 flutter_portal: ^0.3.0 cached_network_image: ^2.2.0+1 flutter_markdown: ^0.5.0 @@ -35,7 +36,8 @@ dependencies: flutter: assets: - - images/giphy_icon.png + - images/ + - svgs/ fonts: - family: stream-icons fonts: diff --git a/svgs/giphy_icon.svg b/svgs/giphy_icon.svg new file mode 100644 index 00000000..e1a1d4bb --- /dev/null +++ b/svgs/giphy_icon.svg @@ -0,0 +1,8 @@ + + + + + + + + From 38fb9460711e8bdafad0c2a191889f273e2ed1bd Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Thu, 5 Nov 2020 15:26:48 +0100 Subject: [PATCH 0302/1140] modify checkbox to have 3 radius --- lib/src/message_input.dart | 59 ++++++++++++++++++++++---------------- 1 file changed, 35 insertions(+), 24 deletions(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index aff98b41..f2b3ccd0 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -235,31 +235,42 @@ class MessageInputState extends State { child: Container( height: 16, width: 16, - child: Material( + foregroundDecoration: BoxDecoration( + border: _sendAsDm + ? null + : Border.all( + color: Colors.black.withOpacity(.5), + width: 2, + ), borderRadius: BorderRadius.circular(3), - color: _sendAsDm - ? StreamChatTheme.of(context).accentColor - : Colors.white, - child: InkWell( - onTap: () { - setState(() { - _sendAsDm = !_sendAsDm; - }); - }, - child: AnimatedCrossFade( - duration: Duration(milliseconds: 300), - reverseDuration: Duration(milliseconds: 300), - crossFadeState: _sendAsDm - ? CrossFadeState.showFirst - : CrossFadeState.showSecond, - firstChild: Icon( - Icons.check, - size: 16.0, - color: Colors.white, - ), - secondChild: SizedBox( - height: 16, - width: 16, + ), + child: Center( + child: Material( + borderRadius: BorderRadius.circular(3), + color: _sendAsDm + ? StreamChatTheme.of(context).accentColor + : Colors.white, + child: InkWell( + onTap: () { + setState(() { + _sendAsDm = !_sendAsDm; + }); + }, + child: AnimatedCrossFade( + duration: Duration(milliseconds: 300), + reverseDuration: Duration(milliseconds: 300), + crossFadeState: _sendAsDm + ? CrossFadeState.showFirst + : CrossFadeState.showSecond, + firstChild: Icon( + StreamIcons.check, + size: 16.0, + color: Colors.white, + ), + secondChild: SizedBox( + height: 16, + width: 16, + ), ), ), ), From d51584e3ca205ba6d4ff98fce3bf72939690f4ef Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Thu, 5 Nov 2020 15:27:32 +0100 Subject: [PATCH 0303/1140] cleanup --- lib/src/message_input.dart | 99 +++++++++++++++----------------------- 1 file changed, 38 insertions(+), 61 deletions(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index f2b3ccd0..32e812e7 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -231,46 +231,44 @@ class MessageInputState extends State { child: Row( crossAxisAlignment: CrossAxisAlignment.center, children: [ - Center( - child: Container( - height: 16, - width: 16, - foregroundDecoration: BoxDecoration( - border: _sendAsDm - ? null - : Border.all( - color: Colors.black.withOpacity(.5), - width: 2, - ), + Container( + height: 16, + width: 16, + foregroundDecoration: BoxDecoration( + border: _sendAsDm + ? null + : Border.all( + color: Colors.black.withOpacity(.5), + width: 2, + ), + borderRadius: BorderRadius.circular(3), + ), + child: Center( + child: Material( borderRadius: BorderRadius.circular(3), - ), - child: Center( - child: Material( - borderRadius: BorderRadius.circular(3), - color: _sendAsDm - ? StreamChatTheme.of(context).accentColor - : Colors.white, - child: InkWell( - onTap: () { - setState(() { - _sendAsDm = !_sendAsDm; - }); - }, - child: AnimatedCrossFade( - duration: Duration(milliseconds: 300), - reverseDuration: Duration(milliseconds: 300), - crossFadeState: _sendAsDm - ? CrossFadeState.showFirst - : CrossFadeState.showSecond, - firstChild: Icon( - StreamIcons.check, - size: 16.0, - color: Colors.white, - ), - secondChild: SizedBox( - height: 16, - width: 16, - ), + color: _sendAsDm + ? StreamChatTheme.of(context).accentColor + : Colors.white, + child: InkWell( + onTap: () { + setState(() { + _sendAsDm = !_sendAsDm; + }); + }, + child: AnimatedCrossFade( + duration: Duration(milliseconds: 300), + reverseDuration: Duration(milliseconds: 300), + crossFadeState: _sendAsDm + ? CrossFadeState.showFirst + : CrossFadeState.showSecond, + firstChild: Icon( + StreamIcons.check, + size: 16.0, + color: Colors.white, + ), + secondChild: SizedBox( + height: 16, + width: 16, ), ), ), @@ -278,33 +276,12 @@ class MessageInputState extends State { ), ), Padding( - padding: const EdgeInsets.symmetric(horizontal: 8.0), + padding: const EdgeInsets.symmetric(horizontal: 16.0), child: Text('Send also as direct message'), ), ], ), ); - return Row( - children: [ - ClipRRect( - clipBehavior: Clip.hardEdge, - borderRadius: BorderRadius.circular(1), - child: Checkbox( - value: _sendAsDm, - onChanged: (val) => setState( - () { - _sendAsDm = val; - }, - ), - activeColor: StreamChatTheme.of(context).accentColor, - ), - ), - Padding( - padding: const EdgeInsets.symmetric(horizontal: 8.0), - child: Text('Send also as direct message'), - ), - ], - ); } AnimatedCrossFade _animateSendButton(BuildContext context) { From 3a5ae9af019870edc957f9d083370d32005d02d1 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Thu, 5 Nov 2020 16:05:39 +0100 Subject: [PATCH 0304/1140] hide overlay if there is no match --- lib/src/message_input.dart | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 8da205b9..2be0cf6a 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -682,6 +682,10 @@ class MessageInputState extends State { .where((e) => e != null) .toList(); + if (emojis.isEmpty) { + return null; + } + RenderBox renderBox = context.findRenderObject(); final size = renderBox.size; From 7de9206e60362ed0e660cba40b9620782a947efc Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Thu, 5 Nov 2020 16:12:54 +0100 Subject: [PATCH 0305/1140] use listview.builder --- lib/src/message_input.dart | 77 ++++++++++++++++++++------------------ 1 file changed, 41 insertions(+), 36 deletions(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 2be0cf6a..1acdd64b 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -714,44 +714,49 @@ class MessageInputState extends State { ], color: StreamChatTheme.of(context).primaryColor, ), - child: ListView( - padding: const EdgeInsets.all(0), - shrinkWrap: true, - children: [ - Padding( - padding: const EdgeInsets.only(left: 8.0, top: 8.0), - child: Row( - children: [ - Padding( - padding: const EdgeInsets.symmetric(horizontal: 8.0), - child: Icon( - StreamIcons.smile, - color: StreamChatTheme.of(context).accentColor, - ), + child: ListView.builder( + padding: const EdgeInsets.all(0), + shrinkWrap: true, + itemCount: emojis.length + 1, + itemBuilder: (context, i) { + if (i == 0) { + return Padding( + padding: const EdgeInsets.only(left: 8.0, top: 8.0), + child: Row( + children: [ + Padding( + padding: + const EdgeInsets.symmetric(horizontal: 8.0), + child: Icon( + StreamIcons.smile, + color: StreamChatTheme.of(context).accentColor, + ), + ), + Text( + 'Emoji matching "$query"', + style: TextStyle( + color: Colors.black.withOpacity(.5), + ), + ) + ], ), - Text( - 'Emoji matching "$query"', - style: TextStyle( - color: Colors.black.withOpacity(.5), - ), - ) - ], - ), - ), - ...emojis.map((emoji) => ListTile( - title: Text( - "${emoji.char} ${emoji.name.replaceAll('_', ' ')}", - style: TextStyle( - fontWeight: FontWeight.bold, - fontSize: 14.5, - ), + ); + } + + final emoji = emojis[i - 1]; + return ListTile( + title: Text( + "${emoji.char} ${emoji.name.replaceAll('_', ' ')}", + style: TextStyle( + fontWeight: FontWeight.bold, + fontSize: 14.5, ), - onTap: () { - _chooseEmoji(splits, emoji); - }, - )) - ], - ), + ), + onTap: () { + _chooseEmoji(splits, emoji); + }, + ); + }), ), ), ); From 4865f93ce34f48b154efab1747d976f18da1a727 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Fri, 6 Nov 2020 09:42:41 +0100 Subject: [PATCH 0306/1140] fix empty list error --- lib/src/message_list_view.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/message_list_view.dart b/lib/src/message_list_view.dart index 6c23ea4b..946ad66f 100644 --- a/lib/src/message_list_view.dart +++ b/lib/src/message_list_view.dart @@ -306,7 +306,7 @@ class _MessageListViewState extends State { valueListenable: _itemPositionListener.itemPositions, builder: (context, values, _) { final items = _itemPositionListener.itemPositions?.value; - if (items.isEmpty) { + if (items.isEmpty || messages.isEmpty) { return SizedBox(); } From 0428119c8ab61847576f848abaf80294fb9d6e18 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Fri, 6 Nov 2020 10:31:39 +0100 Subject: [PATCH 0307/1140] fix performance and highlight text --- example/ios/Flutter/.last_build_id | 2 +- example/pubspec.yaml | 2 +- lib/src/message_input.dart | 38 +++++++++++++----------------- pubspec.yaml | 2 +- 4 files changed, 20 insertions(+), 24 deletions(-) diff --git a/example/ios/Flutter/.last_build_id b/example/ios/Flutter/.last_build_id index 5d3809be..8aba7787 100644 --- a/example/ios/Flutter/.last_build_id +++ b/example/ios/Flutter/.last_build_id @@ -1 +1 @@ -bdf1751976c4ee1e2ef7638eabcfd1ea \ No newline at end of file +bb5f9103d9045cd6244bcae1f5f343e5 \ No newline at end of file diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 842f471c..97971445 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -1,6 +1,6 @@ name: example description: A new Flutter project. -version: 1.0.39+41 +version: 1.0.40+42 environment: sdk: ">=2.2.2 <3.0.0" diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 1acdd64b..b2d124da 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -7,7 +7,6 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_keyboard_visibility/flutter_keyboard_visibility.dart'; -import 'package:fuzzy/fuzzy.dart'; import 'package:http_parser/http_parser.dart'; import 'package:image_picker/image_picker.dart'; import 'package:mime/mime.dart'; @@ -15,6 +14,7 @@ import 'package:stream_chat/stream_chat.dart'; import 'package:stream_chat_flutter/src/message_list_view.dart'; import 'package:stream_chat_flutter/src/stream_chat_theme.dart'; import 'package:stream_chat_flutter/src/user_avatar.dart'; +import 'package:substring_highlight/substring_highlight.dart'; import '../stream_chat_flutter.dart'; import 'stream_channel.dart'; @@ -170,7 +170,7 @@ class MessageInputState extends State { bool _typingStarted = false; bool _commandEnabled = false; OverlayEntry _commandsOverlay, _mentionsOverlay, _emojiOverlay; - Fuzzy _emojiFuse; + Iterable _emojiNames; Command _chosenCommand; bool _actionsShrunk = false; @@ -403,8 +403,6 @@ class MessageInputState extends State { 0, textEditingController.selection.start, ) - .split(' ') - .last .contains(':'))) { final textToSelection = textEditingController.text .substring(0, textEditingController.value.selection.start); @@ -676,11 +674,8 @@ class MessageInputState extends State { return null; } - final emojis = _emojiFuse - .search(query) - .map((e) => Emoji.byName(e.item)) - .where((e) => e != null) - .toList(); + final emojis = + _emojiNames.where((e) => e.contains(query)).map((e) => Emoji.byName(e)); if (emojis.isEmpty) { return null; @@ -743,14 +738,19 @@ class MessageInputState extends State { ); } - final emoji = emojis[i - 1]; + final emoji = emojis.elementAt(i - 1); return ListTile( - title: Text( - "${emoji.char} ${emoji.name.replaceAll('_', ' ')}", - style: TextStyle( - fontWeight: FontWeight.bold, - fontSize: 14.5, - ), + title: SubstringHighlight( + text: "${emoji.char} ${emoji.name.replaceAll('_', ' ')}", + term: query, + textStyleHighlight: + Theme.of(context).textTheme.headline6.copyWith( + fontSize: 14.5, + fontWeight: FontWeight.bold, + ), + textStyle: Theme.of(context).textTheme.headline6.copyWith( + fontSize: 14.5, + ), ), onTap: () { _chooseEmoji(splits, emoji); @@ -1334,11 +1334,7 @@ class MessageInputState extends State { void initState() { super.initState(); - _emojiFuse = Fuzzy(Emoji.all().map((e) => e.name).toList(), - options: FuzzyOptions( - matchAllTokens: true, - tokenize: true, - )); + _emojiNames = Emoji.all().map((e) => e.name); if (!kIsWeb) { _keyboardListener = KeyboardVisibility.onChange.listen((visible) { diff --git a/pubspec.yaml b/pubspec.yaml index 6aa8aff3..eb9f0545 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -27,9 +27,9 @@ dependencies: stream_chat: ^0.2.10+1 emojis: ^0.9.3 mime: ^0.9.6+3 - fuzzy: ^0.2.3 visibility_detector: ^0.1.5 http_parser: ^3.1.4 + substring_highlight: ^0.1.2 flutter_slidable: ^0.5.4 carousel_slider: ^2.2.1 clipboard: ^0.1.2+8 From 5371eb3aae8f5faa4c3d1b8ac61629ded5b14387 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Fri, 6 Nov 2020 15:26:34 +0530 Subject: [PATCH 0308/1140] feat: Attachments are now supported --- lib/src/message_input.dart | 192 +++++++++++++++++++++++-------------- 1 file changed, 121 insertions(+), 71 deletions(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 3a8132e2..be06eb10 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -1,5 +1,4 @@ import 'dart:async'; -import 'dart:io'; import 'dart:math'; import 'package:file_picker/file_picker.dart'; @@ -176,6 +175,7 @@ class MessageInputState extends State { bool _sendAsDm = false; bool _openFilePickerSection = false; int _filePickerIndex = 0; + double _filePickerSize = 250.0; /// The editing controller passed to the input TextField TextEditingController textEditingController; @@ -539,7 +539,8 @@ class MessageInputState extends State { Widget _buildFilePickerSection() { return Container( - height: 200.0, + color: Color(0xFFF2F2F2), + height: _filePickerSize, child: Column( children: [ Row( @@ -566,9 +567,7 @@ class MessageInputState extends State { : Colors.black.withOpacity(0.5), ), onPressed: () { - setState(() { - _filePickerIndex = 1; - }); + pickFile(DefaultAttachmentTypes.file, false); }, ), IconButton( @@ -579,15 +578,54 @@ class MessageInputState extends State { : Colors.black.withOpacity(0.5), ), onPressed: () { - setState(() { - _filePickerIndex = 2; - }); + pickFile(DefaultAttachmentTypes.image, true); }, ), ], ), + Container( + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.only( + topLeft: Radius.circular(8.0), + topRight: Radius.circular(8.0), + ), + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + GestureDetector( + onVerticalDragUpdate: (update) { + setState(() { + _filePickerSize -= update.delta.dy; + if (_filePickerSize < 100) { + _filePickerSize = 100.0; + } + }); + }, + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Container( + width: 40.0, + height: 4.0, + decoration: BoxDecoration( + color: Color(0xFFF2F2F2), + borderRadius: BorderRadius.circular(4.0), + ), + ), + ), + ), + ], + ), + ), Expanded( - child: _buildPickerSection(), + child: Container( + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(8.0), + ), + child: _buildPickerSection(), + ), ), ], ), @@ -598,7 +636,7 @@ class MessageInputState extends State { switch (_filePickerIndex) { case 0: return FutureBuilder>( - future: _getAllMedia(MediumType.image), + future: _getAllMedia(), builder: (context, mediaData) { if (!mediaData.hasData) { return Center( @@ -635,7 +673,9 @@ class MessageInputState extends State { ), aspectRatio: 1.0, ), - onTap: () {}, + onTap: () { + _addAttachment(mediaData.data[position]); + }, ), ); }); @@ -644,59 +684,70 @@ class MessageInputState extends State { }); break; case 1: - return FutureBuilder>( - future: _getAllMedia(MediumType.video), - builder: (context, mediaData) { - if (!mediaData.hasData) { - return Center( - child: CircularProgressIndicator(), - ); - } - - return GridView.builder( - itemCount: mediaData.data.length, - gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( - crossAxisCount: 3), - itemBuilder: (context, position) { - return FutureBuilder>( - future: PhotoGallery.getThumbnail( - mediumId: mediaData.data[position].id), - builder: (context, snapshot) { - if (!snapshot.hasData) { - return Center( - child: CircularProgressIndicator(), - ); - } - - return Padding( - padding: const EdgeInsets.symmetric( - horizontal: 1.0, vertical: 1.0), - child: InkWell( - child: AspectRatio( - child: Image.memory( - snapshot.data, - fit: mediaData.data[position].height > - mediaData.data[position].width - ? BoxFit.fitWidth - : BoxFit.fitHeight, - ), - aspectRatio: 1.0, - ), - onTap: () {}, - ), - ); - }); - }, - ); - }); break; case 2: break; } } - Future> _getAllMedia(MediumType type) async { - var allAlbums = await PhotoGallery.listAlbums(mediumType: type); + void _addAttachment(Medium medium) async { + var mediaFile = await PhotoGallery.getFile(mediumId: medium.id); + + var file = PlatformFile( + path: mediaFile.path, + bytes: mediaFile.readAsBytesSync(), + ); + + setState(() { + _inputEnabled = true; + }); + + if (file == null) { + return; + } + + final channel = StreamChannel.of(context).channel; + final attachment = _SendingAttachment( + file: file, + attachment: Attachment( + localUri: file.path != null ? Uri.parse(file.path) : null, + type: medium.mediumType == MediumType.image ? 'image' : 'video', + ), + ); + + setState(() { + _attachments.add(attachment); + }); + + final url = await _uploadAttachment( + file, + medium.mediumType == MediumType.image + ? DefaultAttachmentTypes.image + : DefaultAttachmentTypes.video, + channel); + + var fileType = medium.mediumType == MediumType.image + ? DefaultAttachmentTypes.image + : DefaultAttachmentTypes.video; + + if (fileType == DefaultAttachmentTypes.image) { + attachment.attachment = attachment.attachment.copyWith( + imageUrl: url, + ); + } else { + attachment.attachment = attachment.attachment.copyWith( + assetUrl: url, + ); + } + + setState(() { + attachment.uploaded = true; + }); + } + + Future> _getAllMedia() async { + var allAlbums = await PhotoGallery.listAlbums(mediumType: MediumType.image); + //var allVideoAlbums = await PhotoGallery.listAlbums(mediumType: MediumType.video); List resultList = []; for (var album in allAlbums) { @@ -704,6 +755,11 @@ class MessageInputState extends State { resultList.addAll(data.items); } + // for (var album in allVideoAlbums) { + // var data = await album.listMedia(); + // resultList.addAll(data.items); + // } + resultList.sort((a, b) => a.modifiedDate.compareTo(b.modifiedDate)); return resultList; @@ -819,19 +875,6 @@ class MessageInputState extends State { _commandsOverlay = null; } - Gradient _getGradient(BuildContext context) { - if (_typingStarted) { - if (widget.editMessage == null) { - return StreamChatTheme.of(context).channelTheme.inputGradient; - } - return LinearGradient( - colors: [Colors.lightGreen, Colors.green], - ); - } else { - return null; - } - } - Widget _buildAttachments() { return _attachments.isEmpty ? Container() @@ -985,6 +1028,7 @@ class MessageInputState extends State { if (_openFilePickerSection) { setState(() { _openFilePickerSection = false; + _filePickerSize = 250.0; }); } else { showAttachmentModal(); @@ -1410,6 +1454,12 @@ class MessageInputState extends State { if (widget.editMessage != null || widget.initialMessage != null) { _parseExistingMessage(widget.editMessage ?? widget.initialMessage); } + + _focusNode.addListener(() { + if (_focusNode.hasFocus) { + _openFilePickerSection = false; + } + }); } void _parseExistingMessage(Message message) { From 24eeb337edb7055876188384bb1c9fcbab1d0e67 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Fri, 6 Nov 2020 15:30:39 +0530 Subject: [PATCH 0309/1140] feat: Attachments are now supported --- lib/src/message_input.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index be06eb10..5e4c7104 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -587,8 +587,8 @@ class MessageInputState extends State { decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.only( - topLeft: Radius.circular(8.0), - topRight: Radius.circular(8.0), + topLeft: Radius.circular(16.0), + topRight: Radius.circular(16.0), ), ), child: Row( From df9b5100b8c6e4b45d912df8593abb2b3594296a Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Fri, 6 Nov 2020 11:25:51 +0100 Subject: [PATCH 0310/1140] filter null emojis --- lib/src/message_input.dart | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index b2d124da..e8e5900a 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -674,8 +674,10 @@ class MessageInputState extends State { return null; } - final emojis = - _emojiNames.where((e) => e.contains(query)).map((e) => Emoji.byName(e)); + final emojis = _emojiNames + .where((e) => e.contains(query)) + .map((e) => Emoji.byName(e)) + .where((e) => e != null); if (emojis.isEmpty) { return null; From 7463b4f7258168588d67bd479f5d38257d00e1db Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Fri, 6 Nov 2020 11:31:23 +0100 Subject: [PATCH 0311/1140] fix text overflow --- lib/src/message_input.dart | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index e8e5900a..5cfff4e1 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -729,10 +729,12 @@ class MessageInputState extends State { color: StreamChatTheme.of(context).accentColor, ), ), - Text( - 'Emoji matching "$query"', - style: TextStyle( - color: Colors.black.withOpacity(.5), + Flexible( + child: Text( + 'Emoji matching "$query"', + style: TextStyle( + color: Colors.black.withOpacity(.5), + ), ), ) ], From b4646231fc4faba0872dd6d206e20aeb37341f64 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Fri, 6 Nov 2020 12:02:23 +0100 Subject: [PATCH 0312/1140] fix emoji picker with multiple : --- lib/src/message_input.dart | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 5cfff4e1..90fcfd11 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -768,8 +768,7 @@ class MessageInputState extends State { } void _chooseEmoji(List splits, Emoji emoji) { - splits[1] = emoji.char; - final rejoin = splits.join(''); + final rejoin = splits.sublist(0, splits.length - 1).join(':') + emoji.char; textEditingController.value = TextEditingValue( text: rejoin + From 7d45feafbb7c145c09088f2f974c3affd97af3a9 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Fri, 6 Nov 2020 12:12:35 +0100 Subject: [PATCH 0313/1140] remove dark theme for now --- example/lib/main.dart | 4 +++- example/pubspec.yaml | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/example/lib/main.dart b/example/lib/main.dart index 667b1e0f..ca727cf7 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -98,7 +98,9 @@ class MyApp extends StatelessWidget { return MaterialApp( theme: ThemeData.light(), darkTheme: ThemeData.dark(), - themeMode: ThemeMode.system, + themeMode: ThemeMode.light, + + ///TODO change to system once dark theme is implemented builder: (context, widget) { return StreamChat( child: widget, diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 97971445..d87454dc 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -1,6 +1,6 @@ name: example description: A new Flutter project. -version: 1.0.40+42 +version: 1.0.41+43 environment: sdk: ">=2.2.2 <3.0.0" From 3aababa282ed18063302d8f4cb7feda92689d3ad Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Fri, 6 Nov 2020 12:20:21 +0100 Subject: [PATCH 0314/1140] automatically replace emoji --- lib/src/message_input.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 90fcfd11..7ef2ebd6 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -407,11 +407,11 @@ class MessageInputState extends State { final textToSelection = textEditingController.text .substring(0, textEditingController.value.selection.start); final splits = textToSelection.split(':'); - final query = splits[1]?.toLowerCase(); + final query = splits[splits.length - 2]?.toLowerCase(); final emoji = Emoji.byName(query); if (textToSelection.endsWith(':') && emoji != null) { - _chooseEmoji(splits, emoji); + _chooseEmoji(splits.sublist(0, splits.length - 1), emoji); } else { _emojiOverlay = _buildEmojiOverlay(); From 73f5b33489e08beea91bb3055862484fd5ae8ef7 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Fri, 6 Nov 2020 13:41:24 +0100 Subject: [PATCH 0315/1140] update app name and icon --- .../android/app/src/main/AndroidManifest.xml | 2 +- .../src/main/res/mipmap-hdpi/ic_launcher.png | Bin 544 -> 2988 bytes .../src/main/res/mipmap-mdpi/ic_launcher.png | Bin 442 -> 1840 bytes .../src/main/res/mipmap-xhdpi/ic_launcher.png | Bin 721 -> 4096 bytes .../main/res/mipmap-xxhdpi/ic_launcher.png | Bin 1031 -> 6422 bytes .../main/res/mipmap-xxxhdpi/ic_launcher.png | Bin 1443 -> 8762 bytes example/assets/icon.png | Bin 0 -> 40617 bytes .../Icon-App-1024x1024@1x.png | Bin 10932 -> 52126 bytes .../AppIcon.appiconset/Icon-App-20x20@1x.png | Bin 564 -> 572 bytes .../AppIcon.appiconset/Icon-App-20x20@2x.png | Bin 1283 -> 1472 bytes .../AppIcon.appiconset/Icon-App-20x20@3x.png | Bin 1588 -> 2358 bytes .../AppIcon.appiconset/Icon-App-29x29@1x.png | Bin 1025 -> 990 bytes .../AppIcon.appiconset/Icon-App-29x29@2x.png | Bin 1716 -> 2338 bytes .../AppIcon.appiconset/Icon-App-29x29@3x.png | Bin 1920 -> 3744 bytes .../AppIcon.appiconset/Icon-App-40x40@1x.png | Bin 1283 -> 1472 bytes .../AppIcon.appiconset/Icon-App-40x40@2x.png | Bin 1895 -> 3342 bytes .../AppIcon.appiconset/Icon-App-40x40@3x.png | Bin 2665 -> 5281 bytes .../AppIcon.appiconset/Icon-App-60x60@2x.png | Bin 2665 -> 5281 bytes .../AppIcon.appiconset/Icon-App-60x60@3x.png | Bin 3831 -> 8289 bytes .../AppIcon.appiconset/Icon-App-76x76@1x.png | Bin 1888 -> 3132 bytes .../AppIcon.appiconset/Icon-App-76x76@2x.png | Bin 3294 -> 6964 bytes .../Icon-App-83.5x83.5@2x.png | Bin 3612 -> 7597 bytes example/ios/Runner/Info.plist | 2 +- example/pubspec.yaml | 8 +++++++- 24 files changed, 9 insertions(+), 3 deletions(-) create mode 100644 example/assets/icon.png diff --git a/example/android/app/src/main/AndroidManifest.xml b/example/android/app/src/main/AndroidManifest.xml index c5f1e85b..a90d828e 100644 --- a/example/android/app/src/main/AndroidManifest.xml +++ b/example/android/app/src/main/AndroidManifest.xml @@ -8,7 +8,7 @@ 0~>o!IOQseeG> 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 MrZy&3M(*+d0pjzbVgLXD literal 544 zcmeAS@N?(olHy`uVBq!ia0vp^9w5xY3?!3`olAj~WQl7;NpOBzNqJ&XDuZK6ep0G} zXKrG8YEWuoN@d~6R2!h8bpbvhu0Wd6uZuB!w&u2PAxD2eNXD>P5D~Wn-+_Wa#27Xc zC?Zj|6r#X(-D3u$NCt}(Ms06KgJ4FxJVv{GM)!I~&n8Bnc94O7-Hd)cjDZswgC;Qs zO=b+9!WcT8F?0rF7!Uys2bs@gozCP?z~o%U|N3vA*22NaGQG zlg@K`O_XuxvZ&Ks^m&R!`&1=spLvfx7oGDKDwpwW`#iqdw@AL`7MR}m`rwr|mZgU`8P7SBkL78fFf!WnuYWm$5Z0 zNXhDbCv&49sM544K|?c)WrFfiZvCi9h0O)B3Pgg&ebxsLQ05GG~ AQ2+n{ diff --git a/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png index 17987b79bb8a35cc66c3c1fd44f5a5526c1b78be..2f7fdaa7e0c24641edac586d68e910dd7b916345 100644 GIT binary patch delta 1836 zcmV+{2h;ev1F#N|8Gi-<00374`G)`i2KPxsK~#7F?O1zI6;&Aj?cUwH7e&Oh%)(b% ziuRCvkdnq9fvMP_S%?!6k)@WY&BQ2b20bp3sibMC3E5PpAlPK7sp(|NG?ghh6`~T; zgVYifk-d9&Pv1FLxDkj#(9IcsGdue{=X}5K`_A`RrB`AV!+#YF#n%G-TeK1IHQEUH z8f^r8jWz>Zr@)QR3M}|LB=qfOV#070E2rD>=yDfKtK~>ENPv;r_y(-f z0o@?Mq)RWz$1IqvV9XE&1tlh)c*BJWcPQZfYEqVgYdc8@zeT}|aSU_cHU!}lk*hpKNxIXVMyg`W!Q%`a+XEfjNeFB&d9LXk*v@<1i4H%_Gtbj+>B!x0 zT^@nr-z?HRBY&m|>=KlY5E{IcB~Dk8@XK`kakl=uGekIknG2ieX_z|N-sn7B^QOf^ zuxCBP&3{nzOMT%lO5n(^z{@!Qz<6DE~w1h>u6)Vp(47x!=WQYwzZ?p+3a4i4G zz~Rz{=e+19&fIBYM1ME#9;67tcN{P=akzq6<9}srr|X3*L7sg(GWI3!HTUqX`9g|R}g-)Ox9;Kw~6d8OiUlE3Q{XScH?4urjaNl z;h9X*&~viz+r5P*327jJVtmvv8P1377|>mYsz_Lpr(@T_%m2N!|3`)wHn@=bpoSbu zc7ORlm{`5t4d*5U7V`?a{eVljQ)8~%Xc*;YP0DhKMC5!(!+~SfC_4?jx7WhEdvx@> zUc!B03Z~qp;BO_~@8$i_o;!zNPjzCeMH5BOSo1%8@h=0igS}2ujCj)uxJXK z3n#1ilw2$?->kKI{~!qWR6dY&w$PyB=L+#q1}hPE*4Cd$(UMS_}JK3 zNtDe6SHsaB~ui! zVf5|fA|)0!?>8}%2*-?6$RZL}ZzC5QC<`}Q6suxVnvP%pWN^l7aM-=V>$;AZm>6u? zvPIlGoleZ1JGb_I?`vhu7-PfYJg)~dsTTTRpGlf@lP@cHDNezm5{5}(Hh)Sqz{W2; zE>eE3u8VN++UK(ZMu$PQ5kqA)Fr=?c8{by@4cB~Q!q;F*xPql0x@+sHCKhuNlGhuQ zY-9?hD#i_E_^QYhQKaWJGG>mK>wFy?B#T<6OMrJ7ZlSz<3nK@5zpZhb8sWLyG$cGn zCx00?_mo8`(hLF+H4u*=8-JeBM5+(%r_j;(n8AI$n$Fy52m(E>_Gqvnw~3FBM@B}5 zxcBq(Lqb9VR8_5=gO6=C0gi8q8SY+CO`EgnV^3UYFWH5>rzi>n0s?A<20r^M zvFDJ5+4p*`If>}#Xr!d12;n)RqM{HH5m9g4$qI}19Is59wTW8}-yOF^0N~wQ4Hhn3 zh|G%d0$W6hd1;+m6K zym+yAmX?<0DP4Xsv43_)-OALbKemdgw0?Yrj+HYsk?=TbNF*mG*M4W3CW^}>JVKpb zwNbZL^7)^+ecv;TO{vEG`&H4%$g(6z^y$+_ysy$3)=)8-LCH%uF0&{8ukrIKVEQWF z_!}7BPe!+^B&xqa<+Me;f`xOUzix6v^WTH_8oBxZ?0p;W!zKS$1e$|30=`BY0bk>a aC-4`Zb=ksdcbl{T0000i*pfB zP2drbID<_#qf;rPZx^FqH)F_D#*k@@q03KywUtLX8Ua?`H+NMzkczFPK3lFz@i_kW%1NOn0|D2I9n9wzH8m|-tHjsw|9>@K=iMBhxvkv6m8Y-l zytQ?X=U+MF$@3 zt`~i=@j|6y)RWMK--}M|=T`o&^Ni>IoWKHEbBXz7?A@mgWoL>!*SXo`SZH-*HSdS+ yn*9;$7;m`l>wYBC5bq;=U}IMqLzqbYCidGC!)_gkIk_C@UQP%cef?eO60y%8O5k_UB~}

mD4Zu(e0Mh*}>&rSpSgS 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 literal 721 zcmeAS@N?(olHy`uVBq!ia0vp^2_VeD3?#3*wSy!iOI#yLg7ec#$`gxH85~pclTsBt za}(23gHjVyDhp4h+5i=O3-AeX1=1l$e`s#|#^}+&7(N@w0CIr{$Oe+Uk^K-ZP~83C zcc@hG6rikF&NPT(23>y!y&wkt5C($~2D>~)O*cj@FGjOCM)M>_ixfudOh)?xMu#Fs z#}Y=@YDTwOM)x{K_j*Q;dPdJ?Mz0n|pLRx{4n|)f>SXlmV)XB04CrSJn#dS5nK2lM zrZ9#~WelCp7&e13Y$jvaEXHskn$2V!!DN-nWS__6T*l;H&Fopn?A6HZ-6WRLFP=R` zqG+CE#d4|IbyAI+rJJ`&x9*T`+a=p|0O(+s{UBcyZdkhj=yS1>AirP+0R;mf2uMgM zC}@~JfByORAh4SyRgi&!(cja>F(l*O+nd+@4m$|6K6KDn_&uvCpV23&>G9HJp{xgg zoq1^2_p9@|WEo z*X_Uko@K)qYYv~>43eQGMdbiGbo>E~Q& zrYBH{QP^@Sti!`2)uG{irBBq@y*$B zi#&(U-*=fp74j)RyIw49+0MRPMRU)+a2r*PJ$L5roHt2$UjExCTZSbq%V!HeS7J$N zdG@vOZB4v_lF7Plrx+hxo7(fCV&}fHq)$ diff --git a/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png index d5f1c8d34e7a88e3f88bea192c3a370d44689c3c..89492aaa6155a2ab0e3f37c2cc737315565016f6 100644 GIT binary patch literal 6422 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 literal 1031 zcmeAS@N?(olHy`uVBq!ia0vp^6F``Q8Ax83A=Cw=BuiW)N`mv#O3D+9QW+dm@{>{( zJaZG%Q-e|yQz{EjrrIztFa`(sgt!6~Yi|1%a`XoT0ojZ}lNrNjb9xjc(B0U1_% zz5^97Xt*%oq$rQy4?0GKNfJ44uvxI)gC`h-NZ|&0-7(qS@?b!5r36oQ}zyZrNO3 zMO=Or+<~>+A&uN&E!^Sl+>xE!QC-|oJv`ApDhqC^EWD|@=#J`=d#Xzxs4ah}w&Jnc z$|q_opQ^2TrnVZ0o~wh<3t%W&flvYGe#$xqda2bR_R zvPYgMcHgjZ5nSA^lJr%;<&0do;O^tDDh~=pIxA#coaCY>&N%M2^tq^U%3DB@ynvKo}b?yu-bFc-u0JHzced$sg7S3zqI(2 z#Km{dPr7I=pQ5>FuK#)QwK?Y`E`B?nP+}U)I#c1+FM*1kNvWG|a(TpksZQ3B@sD~b zpQ2)*V*TdwjFOtHvV|;OsiDqHi=6%)o4b!)x$)%9pGTsE z-JL={-Ffv+T87W(Xpooq<`r*VzWQcgBN$$`u}f>-ZQI1BB8ykN*=e4rIsJx9>z}*o zo~|9I;xof diff --git a/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png index 4d6372eebdb28e45604e46eeda8dd24651419bc0..dd30e06e2861798f277a9e4e444417f0f444e3f4 100644 GIT binary patch literal 8762 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

<>5{8FHRmJLp8Fp#2t+eq`i$^Rvu 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 diff --git a/example/assets/icon.png b/example/assets/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..314eb1db06c8771bc18c08234ab84940adfb033a GIT binary patch literal 40617 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 c8n=6E0@B?vz@U^!Nq0y$44pIY zGk(r{zURFE!h3$<8Ln&3X6^N?b+3EfYZIZOB#r&(`6Cbrge@y0p#}nB03R_x4<7&z z2n9$7cv%?lsK_a2YkVES$)Ll=l){-vp=jURA1z$#GMoS|j7cr{aQ4qN0P#Yj7CZn1!X zCBXxb*aqrrCIzK;chjb4{?2^NgrX6v{$}rPud&$R1%z{}<%O>i;|Yj}?Qq11obT=p z7u*o(PT%fxVKPz4qlw&&QuBFR$5VK20|K2W059iRHH635mD<>P4Q|N2E zum6?3MA zczV)4>hAO0iz3UdtUW4$O;y@6_K-jvWV;SCDL4I{U$w)Rz%eNm6C)$WSs+l61;DO~ zTyA=3=pXnK!CVgD@a+rMjH$!6Ra~8wSV;SeMYnyUQ{_e}hvM(IAdpHSK+04K6R{8v zda2E&Aw+S0SKm4Xc971C{@y0h3pLyV?4+@QImKJs)=}m(4?#tO?n|gIY`|XC^3u0E z9e=!S9m$Y~4~q!lUkJS$<5Xg92AT_5D`NB@4gt(#K-nnWLtok$ z7-rJTFeFnS3!j^kyxCabG1IggZw&+G&U1XH-q!vrm-rhkqlrSuf4n66>35US+gcg||ujAH06aXE|}2_?+S zquaLz1*D>mA!+YjFnfDQ7QW=)`%7}-mLVnOQT6I-VRy5p5NUV&*+>KJek8D#8nxCI zY1_4Yq<%^DmX@7l|yx~KhIK7F*}A?Q*Y@RC+A;Bv?}f{+;tlRcIw=#}W!*r8Q~ zkH=Z}9d4|ogNF~dHYFa2_$d%Ltm1D?@I#sdXBBSF)}T`jlD+r2IA018uB(}FKe`7p z8Ubi|2X(E3kg@x10x5FVW{iFP{j;`aqWuhy-sR~UEgd=NbI>vsYAfozBz(d<(da`1 zh}>*GdCJ;A$YkR@A$qss$XtT^Ymk^Y5bsf4m+D=XNE&!?zfyFPCdnB4W|iW+mrh;V zT@ERGMWmW8%JZmGV9*!Pgx*|q0WWAJm#da51d%FIBQk{ijhmO#^kSA|lQ|R=PX?@% znHfh|pNL+%`fmNGhyQWO7-P3EXxl&SnfCtUYlKGPR*4KT1PI>mIQnnP|rY`Hn$qvxZHNS&9uuP zex0PR9_aUWH6rZ!A{R18Y%$P4kB1IOKx*;a$UB;3#(}fmtwEbnc8fRj{@U`ctv=Kb zq|I~ntfPBE>sZhNeDQ%M=Mj)Vk7|8P_8MMWrPh3vg8e46vp9@IB&@3*us#I5eh&)- zG77|wl^Tc@A|>?5N_S@}CWZOw*JYo0K8Z=rtNaAGGaiick{Ask{=0u=gjH%{Nwuz~ z#I7!q^Za#1T!pPN1n_t$aAxA40ABGNIqqF{Jp=wGqtJObq49dNhjeERVea1mrn&*L zq6+k1S+Va==$9FCIlj)&OP77?M07JLHJ6AwhAkJ`y#N|pX8~i+Wq6Zuf6J`1XX|n< zSH?<2Ahy%~zXF(&62xZ=?COZ2I4rR@$4i8~&Mf6da{P%Ka)@OJ)96<8*o!e%=1<|y z*T)B$CINQF#;47Me^0nmwY7^JZk@W?=hz%O)Fv>5mGWjS2;#Rbl#iHtiGed28p{0oytyh zXG*JDCA8>5fdIDOZr&hyB*<|ZwG0>K?i+A~vc9|Vm)4fg?)+(vlf^OBZv8z?2R#d_ zjFsUUrHp7DAAqpw_<+KpgQa(N8oXVS7CK%2BKmIrE<*fGuMoGfg}J|7)a!uYS$xR(7PGf{x90jA#?I?rgYdS@-kwIJ|I0|>g%Mj*bPz|MJpss|XU(<#3hYS@ zREma4+nUSy>Uug2SS8E(L1yG)1>N7!y+l=?BZ2}8>T_(|UI#=^bvjbg{=#A|cRy3P zr{m`_P|5OC0h%Ey4Y&u^F#r^ap9sbV?k-IZ-a%hsQsl2|%cWMq2fZoXqiO(HcC4UE zM0NrSe_ZfuhkLeS-K%cjdD1L^Vh3NiJaNnxP^+V zN@<^VPqi|EiwaUZK2Cuzt@l8~sPKt;5+g~p@xWR-u~=DNK4cmWA6uDcp^P?Oy0+9! zbe9BG@c|Yt^8@6;ycZk+uWaMlSL0K#$ebnBZM2QvwV$U5IgYe^9YzB}5hhNaXPlfz zd6x$k$_h}TjlTDryuI(Is1O2|*#-QQ6 zAmP;AOpq#L8;?%<*UJ|^0lxIdj*-u;zPRK& zEXm~b?}eY-5{^1eTn(zSmPOg|icoeh0xXG)ffv-#4}e4bV}L0n4I`-N5yxj%sjn($ zhrNW-e-)0$8sjRHr)8_MO6{v(rOiy#XY;!6M$()F5o^^PcP>C1 z1EOn7(Wy@UE0NPQ`)b^iL-R)_h^2k)ZVGlT4(*jUl()(e^U_={Sl#=n^%A{MhJPU& z4T29%EFEx}sm|yv?!{q5xh{{XIRR8+P7qw-zTTfVudP*8@cN3sZ+I8XF5P>-lhfP9 z>Vy9gKF@VXmZhMN=4l-3-YOR8u_Evi%@vh^7z<=riDa{}DfF@EF1d)6=Khq|SlhHb zXnlO*Eg!@AlA9QI9=4jME#-83?pEJV7TWV`BsE449poPiB(XwzR>U-~5IO9Mtk=Bc z3WD4$SeYq&kXzWOC&(s>UEhCCZr=%s?o)ck8l?u3pcYJq5+T z2Egr=g*gv!LI{!W^Oe$6i#&csJ->d}dC!}yE#^uYzaK4hium~l`4irhQ6@ebyj*nsSv?{On9 z_OqgF8j&vrZg|*RLb;1ADq4BiuP$*{qOl9R`bwj$QeCGLsaF4wQB+%^k%0L0P)9Ve z1gZuvo=Ic567-YTS?H4AOC29xsT*oxI${3z{td0g8k?6>1{v=BCoBKWHk#f0&_UyZ z0M?|v6f&?AXE^V=r0C5Df?CeJz`;@%y2X$$zcVLV+o0j_D$Rh{_gYwfW!K}Zr`Crd zw-NffUY6vZQ9E#&A|I0^{8eB*`jki#Kz({9V18d2(y7E9&;VQu-vvg1E_m9h~o zH>~P3ruk1aCU08Me4BwsaQ&?}q3vf;_Oeo-OEZ+Kl2Jgb@KeLqF80s>`m?Y{6eAmX zj%YH!8Dcyu9~@{o={w|{s-F&8q_R zGwgba5Ivqu_GC#^E#ikBBzm!xe&2ax@B*9}B`<;q+R|!aa*KcIXBz>(9ln-?&mu|tGs(S}zgFXOL&s=y4a{Ev; zdpjJ9VC2GHd((I9jJ>~`$0Df7bt}HGkMCo_JL$hWmG!w(j@JCOJ+^aL4%ahc$zhgme&lHPU7 z=dCUTaRMksTb;aW@#Huz)$KL0Hx}@Q z&bf@;f+ebm&;@Uv~hjGUi$fJ^H;p05jKl0CV@4=uKGTU*do&TG`tG%FX}N!V*9nn2_8ds&?b?t(jEsPJznxtl zh*~R4KHL}LX}`M&Qr+9G&_4#w8K_SHiuw__0V4Rj%tY$dzrXU({H zRc-7`N5k@F?`lQ1dS@PLT=z%9!Hoc4_=;p{m~DCyW>4TBVwZGv3kJxNmHWK z4kO?`z=Vz7>}SW2KBtUIQre0dZs!o(6i0TqaaG&hyd9Zo{64bal_(UOd^~&E(Tik? zJrH>@Bv6hBV?zla%Gl-683&&9k;3vOvUi)$LE{P6OG#)dy#LYZL8r`3J~jsN7}et zVgl7v%PujE%%r>1&8SUIbVK(QoT;^PM>@q0isEb$r5%bl7%c$`~!&3A!&Aq7BO{RaQz#FsSuwI9AV6%#uH zvuRqO$q9d+8U1+=LUlgx>^+-5P#WtYOg8eHWPK=itdT_KnC~Lxxrvb_wMLtV(79fA zj2CTU|MR~PMxr^v?g0v*0lKaZd@i7`nMKN=c#+NSSBq}g-L3k7;$B=&>uY9pY}>%8+Z-c7-F8cCbc z-rd{LEm#emJD2eAlH{I?DxlUDs2tY^D(n(r?|E4)ZuZm{ciFIgyF%Wc$;WX~yY|yh zLyoQGWzifZNLxTJ5C0Qc%^sxJ28mp+Z%=F3{g#_}P);WZ)6lmr7eOR1K1Bs%b?fHq zw1;UG0xw=pKDkY3G7L!sW*-rVxm9(95c zuFHD8Q(rFx&%&0E?r(SZtuv+7{9w^d!FTsCG;exgo0Sl>k-YFoluo-4s@9gB5jAai z=ZPE$9473WfGSR~732uCGi!)433)`3-1+UdJ1!&d9W!|0J|mw2cc+A2?yS$W#9y_R zQpPqIOj&U7P)ux^G_*1S)fl(u|K)?{{W`g;3xpF>qY9toV>Z$P$TP}g`&fptdvIg> zvXQOMMleB5uMbbMqkEH_F28g7ykd7aru-2FDB5iwXdA1Gckae5)z1%0{a=!ISGYOd z?$Fi4BDFuSZRl8yIQ8M#F~O8v_}KhcS-uUfVU3hFw! zfdAP1h+bsa=Oc-far^e_2I$eXPzAZ1X`8l!pbI%6*55LpsMZc zt0X{Y0s0a=G_g!UzAUBN8YzEsc7D>-+XV86(#4H)O=RWT$#xO>t&Vd>W~A}3(?q3m z58P(f2FdfxMzqa=Jv7U!M4%u$T>PD;8NKie!=Y^$k`nwt8E5GIlFB1M1gV7&{MLICtqyCbBnZj_ zRDB^$sM1NuveA;un>S;DM_-AF9^!mmq_9M=s21@cO&TrAt^n;;A*Qn`;S zwI>XG+BkOYqZea)v=-lok4=);5bkEFwi(X8k8a3@wp6T=sJFDAZ|YA}U-sH(#|pv( ziC1Y>tG~5Xy3=P+QNb`k{K*Qx>mBN@drt}BVX#_}3ZcVs%`?B*R0&%x|F1U&@axpM zFa832GD4?adUb3}>Pw$7FjWpidrB&cn**&^>jnNI3eYjO=kTHF;wEk~cx7FO^^Z7x zZ%1ik`-vNp&QfpxrO8%iZi5Emf?{qt1fFMeAN3VqU^;Lt{8WA~S{_@-(&u$OR$oct z!=r&5F)cHk!7nVc36Iz|u6Ht2Ym4(-2sPeE{CF zYtiWlq)hg}&+V>gKtFT-z{BA=3r?f5r7PfyxlcM2y%a9MX|##S#f0S--@U$2koXuZGRm73tm@-=Xx@hzta^Uj0Fu@c zDG~mBgb^2VUiEU5?8^F`q2+eukHoC4J=@6k9g*d_GgwoCsGS|>B*j_OgOJR}@KSJ% zY4ZpmPxnk6rbR%i?WpJ(p68a<4o1@O0|qC|uIZUf@OD&(t%61FX8DShEaZvFJ62HA zkw_I+yRV}6hn0jQ#IRz|9qwMtK~}y}QW;lY*_D3&P}7N^a(8$BIy~)S64E&ogNi@J^Py2>`u)w(GYA4eT-2MJYo z_-AkAVjqH>S3-7OE_%AAAawiAYA^T#u9EfQ_yA3+!N5~*zerr;U){9H$a@3$tCO6n z&veqY%)-*$iiTdS8mASpxE4nIzoLe0BN-m>bk*}7#EQGk*_I;>Bc5EFaZTE+k)*D% z7ROa+q+aX9lhh*_uiW0S;OnXmBp`rpB?;n%d0Kcjqk!3 zb9*`vWl;thaXU`F8-5M1eSRg$IuoYJY_mE`Mj0W##C+2Z+`?MxIFjID*wopJm2h;t z7;3gG#<|QY^Y=4#<=M!(a;on)JkDMI>Pf{aBOYXY;&Ks2OirtJIMAOqYv^bAY?cgm z7Yp=hh{HKyl2qSY%#mu>q&%u;2|{uIfd4^Mts%s_ytv3C+kZIm@>;(QzPA{$wQuhh z@rYwrWilSpEkFDo=KnR}Fy=hAz;hwp_|)ySRC6t7Yz5CzTPA+LPh@qOI*{tG$9vdV z?PZ&^SSw=ec!i&0x5?Y2swL=WEk?^Ljbu`KQqi}cwE*JoQ*X2H-`^C9B2@{(&Y|{2W$HtE9mSs5Ywph|cPHDiV z$^0+ATe3O4>eK0=9p1EE0@6Vr*K~uRNqDO9|7K=+7mMV4)G@aoIE1BBd@tuWnh+U& za9gAT`9z-Nz^h^VP&)Lpgg-e=D{Tz<`i~wj8#z{aTOC_)F8W{h-z{-akdwCx{W;Kg zf$ureozokF{Z$>0R^*>XVsq#fQ1Sh2H8o1(Chy*PaJ*nsTTiK7GwJmWk0rV%7D`v^Lh{_4 z%Po@qXW#@$#s5khiP{hHvdzzB({Z-6kf(`3ZQ-0l2H@Nq*_ zw0zdmn%4o?;5o%1Wi&7V{-!_Lit1o2{l=DhWjdK+r`sNJ)Su3OkHh6T?rYk)dbW$J zw$zJ~K&(XRZgFV5xf+9{*UwpcQ zMt(PnG!kkJ-8?@Y<~=4WMOwa^tlSHKH`(^m#IJ_n*Deo{%|&53+vK^8sPct`-?am* zk#-2VT4(~Xsf>`~lJWTbrccSy+1AkaEH4(3MDa1mHCjnZ;S~82fv7D+Ii$tB*Y$Qe z&>|Ol!5EbBMOMjbpE-GD2zDi_S8H$PyET6eQ#dGlM`p5{665sGI9YY7-*eE1MwCN- z*p0ob5+|xhHwiu5g@&`u5EL(o7VxA*@g-M1@1pDIah-hNI9ty$71o3F=eWU`eaF!u zKUM%p;)?k9sH%ouaF_ExTb5XFrFwP4{`^Igm7RU4vAw;%o|iv`$G~uN$+h5rj;QuM z6#8?@UcjnigpTC&eHUjh2Q&+F7X)I{fFkg;myu$y6jspWz)t8-{kCckL5J>0$o6WeIySpP$a?td-g!T#6+T&sI52;Gtg^Xy2jl6s za2F!HvAFqiKc4dp*0{Qsfl# zA2a?Hcn?&kAlPampJlX5sHVe{bQo7SLcYHW4%zI(wce6b?s?^T~*sKMN2 zwfp?XOh-Jpd$eTs&ArrqvnZ4qfrvec)_phmG4}gfph}*9v#KtAT<}Aj2U66OWJO&U zV5^8qyFrcAc|cO-cC{@lzmF@*GQ)m8WM5{-@K^H%=&=7y%jHsKdiYcYYY*o_N)|fK z!nH|i*8#&=#m6gpAees5BN#o#kyg+|Z*KH3Up=OoIp=KkcSDR+1>Wy)T zg!b8llW$%_A7NLklXdc-o$2D;sOppIwNqn1$rMwc@zl5VHrLFxZfzKN9lqP17e?xl z>%fps&G3C-H`|QJugvZ(@Ie%+EzC3AlZVm|_xWyClQ?-f zDTEi;(jf*3rh?nswvpd+B4*EBZp>y{h#oAf+?pD(M@kZUn#Z8r)c^4{cQ4KGK=-Vf zL6w+@eyxc>`&DMPgvZtAPJ>4=zOoIe6>7x|cY3w{K)UM{j^Degb10i-wPtwLTg7N% z-HV8lUkQtQ3<~hQ-byVrnFB6Cs2fnQdGi{Cm_nJ(CvH?+R z_T2UQTJgMC>_GioxjC3UXm9XUk(unf+o{8Wu53i?2=Ltujy9IrI03p@{gy!?nTEWX zMQo?V_qe@(Rd<|@kIg<)dPM0h)~O^(Yyb{fTSb!kI$NCOB>^#F^c^KoX^ncwx$0a+ zd#PJTeNNMTztDaV5h1874KftJ=Kvjh-TP@;|7?A+XH zx~LDMi0@*ARVuopM15vk>2;5X`e{R|@hqqds?as|J^ntdr>@O+?c(i00I)PU?IZMvD*eWDa<;RRT z2{GsvbEifBL}ounxUl|o#8$ZnO|GG_q9W^ZatT3OVE`M|6BH}ZJDKsxtGlI@Msf{Q zF?A-=80Qb2Py6@BtqMDM+x@+#APWlH{}0);ZmUh^P0d2GcU*)`!(nuuk0BvR`$)dK z*qx0}Z(MHi1!^xPP`p#0HfT(EcXetJDW>4t85|(yche*MZ=nhlqE0twnBU4Has-D& z=0TN#V$AgoZD;DWU;)h|iu!!zJ|3S^a?45_HG18tuJowh)sbP(_vmN4e>?s~?2&^} z8{$Ay!7uv@S_|wRJwS}1UUKR2K)alt-<_zG)eLh(Zl!73T#PRmY`;%4d=pzI3HB`Y23(ENLWEk`yGK77@^h{d7Y?^sbfHGb!R<*Blk zh1gz?O1JVyRZVw@LU&1@#;0z_QlNOQzAnmqH49tV`X9dC@fdTq2gKzU5c^jL5F-cI z3)a_6_--#|l%Vqa_50^{*}BBp{&6$Rf!)RX6u6SrZf>puXQCdi5dKfB*iA4CyDt~g zxZRgiN-{udX1koRjXACE$4P2>N!sBM7LoLw>+Bfl%=yRdYg2$lhI3vUIq_Gm85VlE zIm?0K-}U)|2;Y^O?02ui!-1nnt|_+*QA{mXvB<4Y)OQfy!^>)=42jisjKcrzr{QPDLJpgaVG}L-@U+(XYvSSkG_ub)N?4`$8 zgtEZLmjTU3LWom6!lE?$a6vNy>ORyx@RN{}_f&a;b9&6_m<;(|&)+=>wEVQ?{Msk) zq$o+DED98WZbRacsW-7gogy*=Vmo`2&E@{d0-gQfYdw7UG zixYx!Q0kA8jQl1ryqRm>L24Hxc*!_<^>3P9rTXgKVY<9iwPcdaX%>t%9Mid>ly&^A z$=tR55#6~2z~&;Ne&8}4AM+b}x;eKRzYAQBm{E6oDUKGF(-a3)Hstuq@cgp*bQA@tQv+Ls_ zYn(TwEJ+@t^-jAN<}1e;1*>o{^5vuQ{=Dk^MxMv6uV#$@NNPS-XU2D#nA_9q>WrH( z{^)rcu`^|Eu@Z}HZ0RiYnqIPOf`q*;Y<3H~eayhQLVLQ0b%sKQGrh9w`^MrHf6Ofw>N$kn zU24^iPp?f}?;yWKkU1YQ9(g#tJ07}jQd=e?5cR= z@riN%UIGmZf3d1UnpRV%q)k14v#4pCC9b<#xODZ`iN1R;%RAhd+nn?)en&DgvZ!B| zSz11~1(zNU`%yrM4BR5Ve(}C=3mO@1t8mv~CZ`207mlYqV0G(N6r_w6t>#|-psmf` z#Re{OzXi{0$s2J%tsr{{cwFx924)>y9qXWu4KMHelsb;_du5lo zBIa&P=Cb#rhmLi2@si~GjC?CBBvE|sOZA6$x0A)8CSHl%QV5m3N*uC+(zl@_5otvV zBJU_fqkF)J3`Mx~W_F5!>a)6y75Ho-gd%nm&b8-s$=^3*`D--bWQU^Crfh*)DfYtO z{S{))@E{8AM^i74A-9iRKUPD0eZBd1>FO~KpRZ3C3n2dkRN0K-b9A_#d;?N$DRkO* zM!4Fd_gQrvtz#vxm%|#aq;rAsD;^mocy=0j$-#y6iXGDT{cRWoa7#z_yV|Og@2|5~%cHyVNF$S!yMc)>HM_u=;7?z9f-J>h=aPs_gsKya#8{lN5%jbHQF}- z|I^&GH12LUH*Mm__@?71ZSf{5Z1EyY-LeIrgS`&n@WUl{oQSX6kN)2mZj{g4m z)KA=B?EnGv5HXeqjD=8xHU*zutC)J-E?IcPF8yldA!Q8wPr^=;qq=K7g%+7`WuYS$ zPEF3gC$W%Ae&LBJU>NZqw*#Vne3ueQam@k2QO;+=Um>1W8!0PyQHR6h z8;C6{j;;k<*sPSum3OC$^e$O$aW!7Kynz27f#bejz}}PFVE@%IOeOeI6Fs|^&ENmM z7-eVkNW>~^Tsn4iWz)Cm6E#TD_-I&CDr{`jBJA&RqkfzESaGIJ#Q>H=x^$H^xg%ZJ z%X^p+<05kGsqjP*=s!MN+E|qgK3&H4N3i)i#?LEHJWvV=jUa`cOl@wGXwwcME=>m% z6{M9tqBg(=QpeX@+qTi)bKrcNgh@`j`7?Zwi@A&8uEGi!*P{gn&6|rM^cdg$pSLUy zYlMrU#Bn6qE26w`bvIF-XC#@m?Ec98-tP2#g48;4tz(CMs-1@n8aoA>I|%es0$t7koRk!&h>B$8(D$?fXdz9y*J=$bwcRkH}AR#z|j zsqoV{qzpRWK7W_JMEFtc4OKIAGmByAV%P1#<77kUi`$Khn;W?Uyg&&`J5YSTag;*d zNPy-frTEOnjfo?%+d;MaiP8ORvR}lBCe0Cl=Ae3xg8C{&H%F;5XB$L;o+FttL9r^- zyb*E|Ha=*k)->}DzFf~02?sv9`L~|EK_6&nCu$b|`P67QqR+Cc;exD+iUB5~J`%@6fW!(L?N&D!Y{=cm@v?@TZ&lgTpj1ReX*>hDz~j7+qm@TXiiz;zQE^ zc;|_2ZAcKYys2}Pd>Y+Q)>LWxMn>qvaMZ{w$q7pd-lO$pc*F`MAghTBA6m)9x=ZtI^4-%@MQm#{Pm zW4R)Ei7|KK`qk9{UC2(vpG&M#m6|h94PzyhjC z6tBSXvHvm2%38)3@W-pW$*kzI&?ebs{3k2ds%svmMr~+MA>ZWFmBV8v!!|atpMk~s z?gQjWajcKvaf0f{ae8dROT)nt1#&FgNYoz%&#m#uDLuH+YPn~B<4@)vfpICikHK~A4T80!kRf& z5wJ-$y^fe&*V#IJlskhTJXrK?>=$3B`0Y&py7P;@ijcMmKs%kawtGH}Yna(O$j$4b= zeNw{+-aK}$+@R5FG;R8=7{NDKo-Llq9e<366#>$SVED`(45<*B3w^ZkCEOA+_)y;p zTSu>N%Y>-q^_p!sj3K=0f(XyPw=*e{(_`f&%9J4en#au%sF;zGzvnzL&7POK&y%9j zS^wrX|K8mE2ZXzOsew-F^!&LZ9TM$9o^2Wl1mQzAZ>J<8*-`ZF=ufKaHG$6_8l8m; z_J#s`hYVKmSyq(d&eKrp&u-$4!Fbz7>*8c@C2vo<*@KeN&iyRy7h=r4IC;+>Eu=4o zg`1n_6>~>PcBzVY`6*@8`bF`TrvAHE<`u^|$AfM0 zR@ZNGYK|D{U1fD`J?{eYnknNHhQ6;7emi?R6}i z(L&B1UWxo}C6<7Z@kU9NE?DB8Pes}M$;7<*+ettBan_`sNUy$Bb+DKXsDR z>62XZw~2+_@Znkaw$@N9fQ40#SB0VR=OJtqMFNiTH!qqv??^6I7?z$Q@7~YO;fPh# zkM%s;=7|u!rcKxCYYym+#d5)Qe7to}oVTzS(Xgf4bW-i7vU6O${#KL+riJ;Yjxk#>O z`bC0;?rE_KT({y8NZPJ07^~;NC0Oi{_2e0p1jtCQ)7NsXd{9wJE$4?dv?b38WcR*h z2^dj1#e^4*~S1{2+KvX-K@cZm%BI%1zaunk`g~$HJ`pf#+E>;xz?jMRpsqk?nG3 z#pEY5V;7gG>@owZTCEpOhD=HIN!8O@jhiZ$UJ(&Vv2rdrnXsBDT{wNirGs;5KM zVJeNQ3w5NTgobTV$V`e-HomxVfUpI9(z7|_NWfL|GfxGy5s9)~mACIGiOb6Zqj%-G zSCA#$R;?2(DZ~<9ee1PE4>%>&r6p6~DKlsUD=+Yq_R%|W zL@to+|DHeP)Wgbjdk+==GxLq*YwdS%)rS)pdXaA-j&nUu+HfdsOoFKv*|E+q6u>&pnw9~Dwq9A`J!Zk_i2o!_h%b)Okp-<9jK$1a4C6il zjVyI`-og!@Htf}`{8MvyGB|=3SUO97T?*|#^x26|c^6C(RVyiq2_+|9L6(OJ^ZBpI z|E$|qDT%J4okLoTg-gDz<6j{4GkNe!zDrb^3>lr85x0Fg`Zf6U)1~wi0+MOdE*qv` zKQ&>XCI#Co#kE}?y;SgN57b>Q_`+LMg@xs_JuYW|q`2vkO47R1ahv))KG~3}kLcbr z-qdMsD3_$sDmx*i4u#nMcXVI=H*)w*+zgGE7ukp>S&fw>Ell{D0yZSBOmDYF*~Kxs zvS2ti_vmkT9?mC+i1RW~Tc_IOz*xe~rSW+35_!@%91X%@7Z`PY+n--g1~VM&(V#+d z9uM-EroS z^zUR!$t134JV9ks4rs0+mr&n%O^3&L&PLY76kNS)G^MFwmxhm`qK_JVBhp{LH5vQO zm;o1m>S`|6NR#lE3`A=@O=ZVpU1f2|SusWo`8hF?uVX275F($9IX1OtaXLv9nE2*V z)1*ai1yl4ki{JFMKO5DUcuoVH2@UJlkRY`;84ui%XUb@34K13Sxtv`?Qzxh@7Z)}o z{V)PoL-;o-^G3FE@i($&9@CSIm~wWq#AxwGDN@$1>^41ik{<^;(@~M|p`w7jh z0?CQwP?WuijsiMIKiih#B?K@GkCl@oGY)8Tzr7Zu`)EQ@H#DERRL;u5M9{)7+^`yl z{xa7WOpx5H>B7*@~K{1iEW)(X$2GOv8}b>sIN`{kivsqzh8 zDR22m5Y%pZL@!R7eskFgYktU&eScrN3D<);^Cvz*7^}e7z7HV?c1*}e_WKoQ+rMK0 z_4ifn)VQE1*~%dn^`7wk;5qowH{*d!#+a>G`E8|eWPV*s6C^luo|F|4lX!m@;DZsd z2Cvu{s=M5o7TOiIAk!buVOpple=?M4avbbiR%9DAYTQ(EbRL!eP{DVF2$lqyD}Q?w zjqwgci%If)#ow7xccVKSx%j{%BS{(mrA^O5qnV67JX?F?0TGWD zwsT)QBslz;4|};3UAnID?a43a?R=yED~pM3F2Nxe9>GnLuzwiHW*YYo^1eZQcJ7Nx zf7{z8^ssYqh(eNk_X|Yo%5rE)JoNd&;0ni;M+sZ>RX_5vi8E)uMq+p#Hi+OUaoZC% zHiJ(b7skc3a_B9;H(t525W(k(0*%7%-%GlmjKo=v@z{AWMS7H%p`hiT-2{;$>1<~> zFR_v98F(+E-rk%_wtR!4DNJZ;zsyVudDw8kiE6A`^wk%~g&bFo*AiT;8f1#%4`!aBICz%_%1?x2KCt)gr-z)%ERdRp}qNF?XG-i{exW+B8h?=v|446Pzm|!Zz3nO z{=Xl9A|ADKe;tW_zk9wa8}aGE_@ev6q2N=>^$%`#4=f3^BgI7hJG{@>a1nKX0=~V& zm>gIp?&bSU;xL;1606y*hLfxU{ke>PCYaUj8zYEZiNDLb8_Wp{g ze>pQMc}Iyqs#}E^w`_n9+lk5(QznUV6F@&T<}l$#X-tasoJndX#*$RFu%EhkH^1og zBY#+LVxWy*5J$iH9#Sx&*}CMp1exGT zah$KTDbN0K=WEusd8DAD-9?XH{e#|FapQsqsxC8}FuRaI`n+P0fM zdEQW9@}~R4H=Se7Gar1?Dh!_gtcAJ~Jc$;=rf&qY}ST;vfERw5EzAv_=%_3E)>dKmsQGyCxfA%+CS z+^kF8N9js8AGqkG%1q38*I5XB3?n->`1gF&Og2BTn3tb_*o^h_jSSGSSYfC#=EMGw zirptZnAq$E?caR;g0&Y%ZxzU-&ck_rLJmg1PfC0bpl8poyaEWCIfKe<^GRsBu;ibx`AwxV9pyTTL_^@DF zVgTs4LM6B7V1Youxw;oFzH41 zRP|$@dE6h_d-%g#y=MVyyZHs;#V{7t-ha>y7?umu2o4-ZgF?QwNR&JS z4=Mk_q*{riH$gNU(wKgyu*tE6Y2y4rPwM}n>n$9r>b7@bN<7dcnd96bE=Eo~(ZC}xx+$^ea zGRH96+Tv;zPY8{ivi$ChXhw?_yQu!}ef^6ZGeMlYkmckTkki z&VuvGc8$~67qUfT?x!mSVJ4vGixcN;Vak^0`~|HTqK4Ta9V2{}7jz=N<7 zW^AVgK_TSVqRT$tP+DVLs8;AhrwC*vGWgd55t(0}y;gMjrtnlCwL$wCZB?yI#)M@T zvkmUoqx%OL2$R~qG0S+&!q{`co^2b~LQIl3;b#XIw}k%Z7b@p`*lVJn@luvq+yB84 z_LHgMEkztf)t9D+_l?FfYh62&WT)rlI@x=|>c*OUJJTpp^MkJtM}IyyL*EE{sc}-gN)Gy) z&@pkZxYb2q1B0&2A}tpm2=T3$zuH8&M(LUK>r=BVP4}^FOYkov2cd}bcR`X%u{juu zyUS9|O}=AG)&GGZEW!-^CEh=?-1A#aI-OA)C{KulA`u-oFPU} za1Q{D&`6Z;-5ieQ%#+%ERIwW}i4#6=Om`?$8TEZWQAmO2#@h~=JXtr(1%?xoE8EE*>msQ2CQ^R!*4i|4`Ec_p+pCjNot?#>5 zZNzSjPM0yf+lt9Abecgpx6OQOPu>SSYyR>QdW|Gdw4CPG)A2VF4}a|X3@d$A7l7xl5k^^<Rjatdell{^sV(agP z0%kbd_dQI8KVMz0?We2AVnk)n9ncZyMm(aG3OzXwY;e)UVOF!&f8bDmZl?Zz@FHh* z1?H3-Zq%^j&B?q|32ON&?&jLPB)@@cmVRGIbAN|_=EGrA$C{tCA@%lW`z$F~?xoyP z@C`=onD{OiwOf|`gtszSXlA==)#9sb+rx>Z>VOfN?A4bA8&5}5&eTAWb)JC zqH&qyMI67KH(xYq(YA3HRg}?DzgKQU@3A9F8DUyOoni?8_vVFy8USKHn6K_ww!+~) zah-#b78otZR5J0-##+c%r-3082MCQ|{O7i$Cg}VjmeHXjoIj zvYB_&a?CV|_GNfVqfh{JE|uKF${9A4GU6Qp^% zP$UkPG{x!+*My*?A<76YbUx=Y8FN4Dn4qM2_R-^m!6w2M(-uw}mV6l7H9g3-AdiKQ zDBzi5$nSL%%k&Wxez(yZ31)xZRG}1o+*--MFz-*B2)6z)A@{4938h1v%~<2drA{j4Bid|!~HPEk&BQkU)f=lb^x%1|r7Vs?UJx_W5C1?TtXHc>;IOHBV-^3B+%OZxFdl`R znpM)2RZviUO!g_v>cT0gJ-X(GGE8oO88~~|_0i(?aor=4mhynOoc!lV;F79IzZW*K zCfnmclS_XR`{7ERwc%UmI#HZJ{hq%)(`n7&2`|YIpstWkKJhBfO|Q8DVDXDO9Q0x6uI%G*HNg24#Uy?GBFJj6T)8#Cql(MV zFn1RGN?o$3j+$DHE<^FYAcFj^hEgPR&Q11dNz<+7>rUz}Fxsyi2dRa62}>8kJ5_+= zm?4Ts`;J9gGtX&yg51Q13;3JJ_nmM_CGR6D{G`pLjfdAV;>Zw=N}U4CWnta!U1+@` zWB|4p>5gzE5koj3@2pVQ@ttyAx;Ij@{Kyso(FEazTwzogTYkRu2W}u*A|hq>=w+nu zTd*zd=OYSWr)D?Y3*Kcpx~wZFgQwqJ^6nIg8dK2U=RZMrrl*`#Wq_SWw(}X1p>)TL zX1kL@-U`RfD&>R`wc>Vd4F|L@kL2b@F6`MPrEyUcS8INku;L7Jb3CzQLg9L^6XEyf zv*{R*eK;}o$@7M^=WlMQf?&9_?7G+r4Gk@~aI*)Nb2*<{(Up6+{MXD0JJpJF^J6)3 ze%K$0j*3e4k3j;BV%dKq3EM4ba~|74EEbnvX7ARwYh`~MXGRRthuvQ$uUOQW)nnoO zK;{h`uiS55O#xHUVa?vw9zUR`+4*c;e^!tTJJUs&aFGJ*NvNPxkh7mS=|=6qXJW5} z1RXz!>0jRbA$sskOT@CAP{j;q%)m)#>dxiOyff)m1nzY5J(r0H>%Ah;UJ!Sl8g!(S zFCMjVPy*rA7aQG}Z$!K%v3qav8UHEu_N1k z_0N+9GfESidhFG&^djQ9OL3~M(jUoeBX19qB9XPO=bKEhr!7eaf->tQRpb+tiYMCV zsmCDGnzw&?{*j?_OFt@MQl}2yMb_|O0UV);hY_d!O9hR7dGjAPV){S}N>+y43{q$e zW;>?|>chS|pgkdZQ}HHG8~;m~hP_gkhE0M~+4&?-c;Wg#)WFNu>)`X1eV(||=Zr6_ zcGu+6n@|O%E$$M=@>E|krtc9*${*GE(tH?}+OIG?Yx8LzABm6p0=d`Bpw zuXWs_zf33&K1ZQ$A9(O>(}AI`;Dqk!W9iJDS=Fy9q?jVC@Tb%(eY{(NZ>6B{zIwZo z@exqv;uQ67-9Lk~xChWF-{b*Io6qzsLz0*vY*#T_wpwB7Yyom^qY^;niXR`@uO)}P z@&o<3Z$cK+aVbP@JuD~mM}uB2ct>>2Hz$Gd>{=#C8L?%&?HnXA_n$^mSYp38e|W~6 zs!+8|hIqOOv@5SfTnM@B1TP0%MAcQw;{Af~&H>R3|Hu4(;8H46cuQYk{dSr#H6^pO z5ot{;qYM>qgL!$Ak;oHmJs5!`xUc7mL3xzc(m@R6rpVxHCc({4^~cm|3N*q`jMKcj z3H5aD7s+U%$R5&e{+ga(q@ZQfr5az}d>`?Z z4C5bH%IxD24O+GwD096(-_8zk%Zr;P0> zEhWsH*H-M3t2ny9pEf`lf}~&R|I~|m{U*n<|F|>7d`fC_H7=GgWeqVrKI|!70`w)EZC81VCf8?u3qRh4aFPHdKer#O&#Mb zleXcEAt(%4nK+!W=Krt~tiqK@aWKk&WTrzh0raiklhC1O?(CF z&of&!OJ3Uiedtq`l~q;JLS%;rY&Na0+rVfFv5@lHahD=Y==1kyQ2!-LF&QQl3)}lQ zVZkpjOyqxUeft0`L!=8K`2NZ1VaykM_&8Rrw_pvI(&p)wP;5@?S#jh8CiN!WgHfhD zI+<f?sGSU#G7jD6LUX2^9#lC{$vCM5`>vd1H9pbGAC6J``=S2!DsnJAopdwgY!tHHm zQr+9RluwWdc}oycQ&;!$S!DX(AJs^Om@XN27?j)eLa-RYH%}%_rkR)!NqG3K-8fy8 zXjwUUJvm#;i1C=>*}F5CYJocwRjcvG?qAka)Gv3oy%p-gLGtLV0%3b;uHyA;e)r7Y z-c}-<_r01gv^&eC6un58KJDk^N%!_^ppk;EbHqPMQ0H_AA^*Tl{X~3o$KE`2&3^Hy zi~ozEB<4~U#OL`WDx9iPf=M0UL-asSowqXlu(0SiB)U|8;nO-bWq?O?2V30aWVavsy3fW{9pE-?^sAEc@Ko9Xv_e) zJ#U8gFBvl7dmxjv9%fNKET0PisyXIL7KN9+9!?SBdyIa?RpHbU1wXrt_*|$eX#P5$Qh%*H z(4eqq;L8JTCfIQpk1ngaj_rYrqAhU zU;K*T@VOL!>p;Iayuz=hkCn`c<*B?Yfl3`DpB&Wc40aWKu|Bf{&LnGEsJt^9C?l=# z;Ct?c>tVueWBHW`dAAS~ZOTjQkQQ1RNWNHL)V#YNub;z2y(6H)?V zQ{&Onebu z+i;Isq86urI<%gfD@=k{j5lW$!4 z=BJJ}stR%x%3796LP^wiyS9+RjAwIO95Yfm1(;8QYIaGL2!p*HnUUHQ4tmk8{$j6K zWG>buYi^dIW|vJ>%>85_U5DkUJol&!%ww($u?aMMjGMZ*AzlN-rdKIMjHPc(G!5Bg zOol|BHXUb9dZV_eqx~CVW26_c7h>Xp)&4IDSwXlD@pA}o)`zgKI^`5&+Y`Xa9BFrd zw_e-10oLQT8nu60Z9a`MB1%qCa<(B8pNejvS2O@HSipMNhJaF!q3V_s6W!7sv+D~U zA@sMo*oLmZ)%M&Z6_r`X5tYd!;<6J1gw!Okcvx8W^K1O92-Cs}#&&irJ|B9lisEl7aKQqx4DKL3+X4Ueqz z(hBR8%tR05OqPTJSdGh)RE{=y1!MjE<2jE{Io&(bvym~bnul+0jK2k+8554{FrlEM zMF+QY$*fn7331pPi3nFxz&nsqz+JpWd(LmeICR50b6H_4aBgb&0wLfW)Z2A{cgR1( zx~V52q#QVxz%Uj-hsG|X6T8qt3 zJ-DJs-$fu%bDoJ&!%f+XVurh;ID`N7+z0^r#=mk?x8b;#r*2su;#ke%z?Y%uC@R|7FOZiXDg zULV3}EZ`)F`=hyM`zPTbK9sDhT8$QR<+z|`q;`Siv&I>4B3A^_lCRH; z2EC9n>|cc9n6%W*&F1!>JL^?3@#y=pcXOQKosBqw4K+`9bLw;3b1lRaaEssfp$sTa zMRK0=g%-Y571VF&r*2Qd#6C1nU{?dzIC+tW{1%Qf(b82JZhWuA0-~}Gan^ugMSSMi z)8or&`<6W^Wuv8Z9_z4+4h5&hN*4;~NK4;NKG&y=_m%Lbl&z>bA8efLEW|*sCswfl z*9kwxR7B+32$F#+5pL(5n15rnXBBmN+t03sJfYr=VZqEGEUmW)RIAO@I83R4{pr}m z?OX;D0@coMfBI2Ti7~^Pki;|SRK}_?mpCr>@wAmRZf0-O$nZJ6tVn;w$i;7RIo;5x z7}iO5nGMpo7j5qLP8+6t=6vuZ`P2V>@-NAWG2y^KEDRG0~b{ z&~#WNfdbL-{+ow3&021y`d&c~xCDIQwul@03R|=)>vlR@| ziXX78>!l*Xh~gzt($-aJY~>*(BSQD+jHhr!_IsmPf!CVtR)NrG+99?W4m~JcfZy`! zI;->TxVv96_zn8~=KVX?cVzKKdak}qmQ?}NoNsadV%)ry?lh|>+#}n*Nu?X*!nd2e zr)xC~@Lrj{Up5{|?Ob_q74eo>&xXjIpIi$b2^+*FVz?`?)3amCmbY=lr6tiKj0^~= zDmULmy#fBlvMBO0jmv?Z{*qbUlYiv_0lGe4vF5#BJY7Wi=k(NfBjZd_|at1gzwWz)i*+jjof_utYBMg}a-`H`EeHm~hOH}L+3(p8j@t;m7MUi}n*VC5R;gozPw{dVYV0+H zh1wc3ZNBwg5Vj?DHQ#RDdbz0*-$B8)|M^#8;U>jL?PpfV#7OcN(oEu1Sx*MZlS{s= zlwUe#6!Hrpn}-nReQOr^m?j6no1@ER%|kYm@&IDeh=<46q^i;EQG3(>r$QS zSp8WRpG=dIgHwjZ$sK?B?PTKEH=|D;W6dl|zVq=^1_P;j1E`l-_ zJEa;Q8DIoT^nsH(NWdiC8WbVMsWD&Y+|)h8%G@(AM_ZJA9p2-G6>L)G%AMB-H}W?* zw_ctoqz9T{n&|1y1j{|D}#OzCNn;uYN@|9O~|a zKE(3&KtQggbHByqRrq8wbtP0AQR450(*RoVa7wkM@y`Mv123H z-&yfGq+=?5vpQ(NOC`(CnCzN{NH7E~lQ=e3q5tRUm$=NLm3tMd&Acwkt2d@|!XTBa z?ynIf^sIz*_B>~~!c6R#j+}m*AP2e07pX58ahE16JdyNw%I+B-YWZk4pMFQ5t|+2I z$=<%)m|K0i8O!WGM29jKqauwcZ@j@IPRALhOaj9(B5Mw|7>n3T`~5{)O>5i&W`KLD za{Tf69?td=5N%T(VUaQsbi;2enOX%{3 z0XEb%5BFO!lc@X#B%;0wE`f0p7e!U!Z@2jVX2P{B0nOE^H1D)}@sT3{7<~>oipJEo zEA7q6zW+lA31tY)?dJub2*j_Rij_O}^-38|iVWt7t!DYGj@(8fA8*u={Tah19+rP< zfJC(dDzA1^l^bb5XED@^`VCqtM5>Jgyh^2kl8c@v2~+y8t;E%<_6}iv{vAgFje1_2J9+a}A+JNvmI8h2ci+XP zOQ>A!!XkCD*D6J`7};Ew@au=Gw`px`Cp~-8=3O?*lg8m)b)}Qi*4EUka2-Ni)=%L` zjiT}PtZbc~K#KlR!hCX?8}am^VTt!RfC;{D*gQWgt8#js+p;UT{bD0fK)~{J!svTy zPMG`rB-5mjt%8H?JZb+=i=Gk|A;#S7jk?UV7vgpSQ?!$nA+vtI%lBn3JIO4xfh-ID zf$qH&n&?ZsSn4Gb*ntXE`>?x%5Yod7MKr)icC0ftA(Eow4g-5t9#Ks2=?LlZQ!Er$ ziT#&Gr@b`au+H}!?be(<>2UBWd`E(GE0{yX$a-3$pT9>Y@{-a<5_6u`14?uY9SVKw zQeeWzd>#|rFARnwC=RY6cI#|V{Q7Ndj7iEA%r{AxO7C9{WL)W+)_m-?y#7Up5?&Ni zjXP0jAlxseGqpd9ST&A~R}FRCQv@Pk=7W62Ti~I+V_riDCLxldH_)9|YT&igm904^;Ehu0u8GP`cT?4kHeW{rNQKq7`uyy^-+$9ECdqSSJQ?37qIkac; zu|}iBX3Y>e55>c%9-{<}germZH%FhSJ`Br^2KjlHb!3EBp?4aj#QY@y6*MLChtn(s zE1-pp5YnN9Ixba;oLw3&vVchDhiQ%TrA=VW)Uf@P*Jx$lpM~gwo$V7MObBb=rDts- zB5MuLFHHLta4WS&^hmoM=4Qa}+)BQFd)#6cCQK^7qjLabTFY!Y?^T<3?Dtcl7U5_^ zN1U9!0E|@W8qZ#f5;vES;rPB_Bx_zaq_~rzN@Q~Sq_=7lJ<8b}*XXVe*{N(b-J%VI z9VV~aa0=z5&bKA$P#h5TL=No?3TVqs=cEj)IaMS0$ZB^~Rlqknuu?E}`M*v+0eQ^K zC`v%&3!u4Z2R$;Cr5HL|-!(9B94+TxF#WJS?DPhsB}IJQnkJzP98CVTVw zQ<5_r55~KUNWeZJd~NrXnnKT-@We-YqgU>CvHK9;$>3vv6p_NsIT5nBK|r{K+UiKN-1HK zI+`{u_JrWh^_{0>We5}eJkVdP5v@6Sy}{;jxdAJj2`0DwW>SR{Werk9mq1#y|{}X&9nKv4GwQfLy{` ze2r@;YU5lq=H^UxpkO76al@%G=_2T0Y99ZxYC)ECjDkNz6cu9qy$B0A_v_-q6N=Dy z3$ckGMH@O)6Mvi+{32?|Z&UKW@};R> zXb^|idInk!PKVQ>ymmHs(`g;+{(*SW-_Q?K$9pVb^{4SppC>7$ zD(?7~#GW=X>*w;GO%LE$QaK8@%@zVbEiY?$RpZ6)kH2$RAhQvR zHnV=Jh&C-g#{_4-K}N@jN+AUH;2%;!u%A=08rx7|`$~6Kai2PVz|Qwq1mu*x?}mX= z`Xd!Gk(^L7Eb+aV3uo2CeHjeZKX%wSoGMJLSjE8k$GQf+klMM+Cn@KWnL= zz?hx4gAe0XlWDeNyZ1j|ykcyjdfo{R?+|L{$>WjZu0&Skb?u5Vlqm41z}78!-v>@; z%GbuVJ`~oyiq)&|zTv>HU|XIa{t6Vy5wA86UpqpF$|amY9@Mv!a}r85O--}Bql)Kp znET|D=NkbA4RemA8i|AueWD6&b{3WDB4WX5>8gvHCwP(G(QB}ZcfP0iOcE@5_o;OhAQ4*O?*PJ`htDUxo}bnoFF31|F-3hHw(As7>}h2`&O7tR7igPP4FI=R3CMf z&zD%Fb zI1c+YypV+aO_smp0o^Eu?!#L)U*TeuKh!h^Dr8IO_{2zIY%*Czq$(#NZ4-rO)juEG z3$PyQDo+I_#K0M)Xq)gvUA^2S97z!^L-FX6yFV8Qdj-*zPT2|-@*W4upMyKVHrwbo3_0*-%*TvQT(C>10O8Rl8SSwKx;Q%rDw$6hA5(s?mI?dhEkrHo#&%Tcaz z!KGsuTcjnKE-zeRJ8CgDBJYVxYUs*_bRAqDuv>>&OCn|mYw;#01z#nDCmXnZ=9nd)@BNZ0=LVkwW)Em9_rGvpnY zCOh;M3{P;su|WskJ4)f#K3jwHrccrYYcK_l8{Ea-cz%A5)@g7V{OXeIcPY?B`PaKY z$XJj!j-kqTO7mKpXtCwQ~U_cek)_z(Zt_I@V^J)piz>3e2H#iG1?QX&nc zs>0AI7F5r44mS@`qROg(p~LN8?2XL>D-MbY$nln50*u}kifG^UZ>Txxu!f7$C#rS5 zsu|<=&u$hbd(qn2biq_aWR1`-giLS{2#NtNR);xrly(vm+!Zp5G-yxJ_KS5tN$ejc zguDRVRPb+fem4^`%5vfvC~G6bn`rLanBDX)569}&Z8~BO5@|jn%p+LLGz2w*t9$)^ z{lcSX!8C%t8yF#t<;602SBMtw@>*WGWY90Oo*lilksdK_ylG-3jQa zFUoKU#}vST&RrId3^SIo^?#NwDZf;Czvp7v__@8XHzLjp%d>Gen605sjiq ziCv3U)bQk&w#)yjAuhy!QX>9Q21&*J87}5DM@L2&TcQV5NSk4t&>bF(nd=dwg-;K> z?G(UHAwWtMvx9>jf2C|AAf-mxXqOlD@xC7$=gss zAjn5vGtMj~(AlkNLxYfEaq0H1Ry7mcSzDUpUaJUd^Og}s^H%!OIJhf=If()%KEDsy zAGK;f=2Xn%)gMuYglu%twKuX}-1PapRP-wpsV|n?Uv+WSCb#;FlVboLhlt_-)~?7%_RsXRbQm`K z7XefIe+WVnbVWgyNvTp^QYma!vaq>9Dnv&|9I?QG zI@x&$6b~SvkHpAnknHDXFZmOegm`yr;o;=Tsd~%M;@7og=y+Ognp7c-SD`SNQ zWc7@V|LUzakI5GsY+9!8)7(O z|H@z%>)2p%#E9CuYAu?ZW+XYk_@h`}J)|-ifpcGtbPs5yX?2M%A)R zk;Fn!iR?u+Q+l!o21u3f5?)1kOOP^oq3O-`0B{=WSX(FqSb$~!1~ zR#4>SX8;pGLGd1lHc94TA%2rk-5A23MF(QoX~*PT4`BGhp%PpR!MfgPJQsPPHn z*Q>%6QpXqpUsxvzEPJHxcv&NHZzTf~tcYOC=d2Ti% z@OoG5-TXPsvOY^)brGx%+pVnZT{SfBF**K82+1ye`c~&w=ke-UY_v&(&@@=LRJqvOg%eBM4R`o;RV?duGh>!YFj|8@2U&;@2Qu zgeltLD!WX;LX;M_kX4Zk1%rSE)-Y zA78k2SDz~M*|p!cXa)l8)(tJQRT zK>^g#Z7$Z@g)Zm9ee1!a6tR1%63>}ofx zkf^6y#;<8mhenOr@&D0mfNxM#Z#d4VeJs_%CJux6{``G}ke0ZqZpexgROb`3$SbfR z-p6Y4wiS+}jmi?mWAq;_u|1Q*Y)E*GDDmn?p9N|y7bv0-8!s3~Ro;2ZkEma?5P$a< z+Q9l$&qK98%9o5OEb9B;_8#pO!buE<4`zzCSCEmTlYY+8Ce4|$UYpT%!# zdP=)c1B8>c48UgE#L(-Zs_dl(B`A~EnCsv%Q82qN$1PYGb0))r_Dy_)xakG zk%^O>cb-*AJcAR7oCbU%Vdln^iN2q#0r^dD zVxbb5*zO>R^R>hCrjJ#Y&vj!C@{&sprHg;kp~yNRmF&BOcloeuZmu@V>4F{8N0ra{ z76rTZt;c|KUv{K6z&vXsDySrx=R10v!wK)@=?vDsy=yTBVCIQ_AhA1w z4-R_p{T;%Y;FpFRP=*KxGf)?=BXJpiod<`>s|^$+H8Q+P1?CT9LF( zS8K?NjaVC%uB5CUUVUleF5nT@SEYmqt|I7^d)IodJUN_;o05idfm&oKavsc~;&`Ak zE!($$`@)ngM3lTI!s@^mrGslVAUcz3y<>OS=`>5d;DdYb zt1kp0xkScCU`jg$@SD9fqe|@s~6aC9@~)&9uj`X zyvg1$GKbEG@2@*4P`%P?{_3o7ei%?8QUCi#nNytzuO4_ZOVEx9yX(qWbVw(8R5DSzQy%bpQU{$KEeU zi0t6qlaq+wgg#F=I!Q8Ujk|8nN52bVXMe#=o{=D_AUCb2{WS(+Lmw}k4)Qa(C7y4~ zE1s14stpc6WZJg?hU|-ePR6^wlj)%CNiuQ`4Wp$c`Fo~0giNB&we7Z0fc+SwoNCYT zFfF>Bz4X?tR8lMU#yUu8KZ#9 z%C>A^n>6*qoYUlNin{HlmeT)#l!V2~@%>oVH}Prtq_OFw)84kwmT&y}_b<6U`_?;4 z-B-V0JltJrc#^R0Ol-X6S5FV`FCUIuw_~8ZR-kV!n*z9`7FSDhS?B#u^l_LNFH&^YQiA{Uog+tboXF-fNFD$WB(uf{u) zjJ>kDKa|p&&Eg5|dy&s&j11v~5lBGI;xJdTh-!`J3nJo#Iw;t5L%yY+)~>I4Y1H}@ zQw~uG@x>B$JwXCL2}``lX2T_7UkhLOK|IWGSiZ2DptKzYMf26*qd1XlarTXX@C-a3 z>Yw&+{%JpG_-mN+5w7|f&DZcm#E%83y?4Vy*Jo&!7H2`Lxd?-YDP@$EC6c)66H$JF8 zQ{A;E-|tB$gov5>2mWL|_(g~yqQ!|W`-hr61h6Y9TA7cZ0J(jpKOKr7HPPH_A2nKe z_L1AIFQ3zh9@CkVctz^Kqq)_k&5Yk`H`!L_375P5f;#R zhH&Nqx}AeaV7-lAq%KLv|a|7^I(XLqL-_QLOOyrZnaHWZL&-m%$AM(`(O^jc8Io%!V;4M& z?lvGZGkI;oQ10$@p-P+<ct#+W| z4k?%=Nl=!Y%i!^PFF{q<92Gi3nG-6uwT?n|B=yU2GIvx8S^uSRptO^ul7gWvKdU-ip$y!y#*GA8Vi zD1A-Ba{P!=q*pqrwS#eU{=OC=v^K?tXPTWsL;*-SkACdW&M7q-Q#jlG1Sy{%{C`vX z?fhHTN@h0V5j4u`Fey1x#o?}oZu{RY?ZA}6H|=R%@H@Snh|{%6#jCM!) z&LqZ>kSK#2wJb4OA6e$_G*Ej=z;9Ti0KdV8v!67FFQmbGkZDP|O-%9Mm9GPJF{?Jy zKaQ1BfB@xh>76z2b%?ZZ_pDz*O=L0j5fEE&X<+LL%0xhmF9#M?zoqG^N1}SU^_mO^ z%$UV9WCBcZ2*2Z$&KES?HRog?LlX_GcQT!S)PF$#HOWAV8r1X}VW0<2lx3twkqz@)r%IQSQ#{)=%P>agK5GkND922Uqq0$ulV z3fo`mK2n@d2+jX37;xxL0=keccs!&J#W0!O51G%U=Xd<_-zofm&J^LME%L$N$MU7O zgir#xLaeM85S4_X(k*Sh*)ieHqW$w^)49*yw=|HX(|o5H()>B=H(i!d0L6&S%VWd{ zta9BN5^BiaM9kEBvLHAj27T{wFPpAA&nA{rm~+}rs3{K~LOC5ie?1_kW&hNz%JNrB zFDHZvIE{MW@~jsCkoc}fj)wh|x=nybX8-FuEWoD;0};dZKWGUAXhi+jrlT$1HgY^V zG}C#_e_&q%4AK}1qad-0D!++C(+Jkak^w@9F=h!a#S=4XfquxZF1DW&9uWvwH0Za! zerS8^O}B}CD4LG@haWZzsM7V5BlD0N5&HIbG2xwp5fwdb9-f+DKpt(!tz!gvXt06y zB4=`?IgfE!K$do!RHO2Li1}-hN)dWJ|2jAJ6}zs-37U9dd;A>(VVh~g=$b*tO%A5I z_Laq-@*6i2l-)FE`{GX2+(S_#Z~^LV`bw^MChQ5$S1Df|+nmg){QcAOy}cols!WQ$ z+Ui(|SGE>)9_z}(!4h{iI(PZ3Ip6IS;;Lvfy}`~t?PPKVV%LN9ohiQR|AS;lKCf5s z0Dx!v5#!=&>)?Vg!S(PU%zca*IO~{%EI!t(%TF2eNDCo`K#qd%zU>DDvIsZ*` z&7^H2paI$90jRS282pCEe^&O2kUKY~XX^SkCAUU@%s;7aEdD>JxJaEgt=GAJw2Jk?R&z6G9Zd z_!F?U$D${N#x}=@Q&-F+X)^$3qUkhPVOi)VY)26-ML8J^FAes%H&zpFfNF;OH4;>4 z3n`+p1qk6_wbkeN3Bc$_q}1N#`2`ro$Z26jMcUBNMFZdw`ALZcBF_8j zFn2nPV#KwSdnKO(>y~m}K?Xc#A8eikB8o_0KUg^3vs%H~g-EPH05E#(=w{O;lPNgF zqh|g6W7YHPuYXE#^cGfwGXT=`6c+Z()kF->JfY_pGAQ~TQC^lRl zLlIdI2Y{}c`L#UjKF&YBLaL4a?w449uck#^p!q=^H~)m!HP=CYgx2kzMvZ9?7uD52 zBzr4;E0SZg1-xB&$k@NO2y%1qH7J1c%{9}Ze8oH)o+~@wKE(wDI=r#v>@ei^2EHet z|L+{bO6xX6KXQaA)n&h3T3qF!8iw5+J;w;t2jqY1!&-|G^u4I>b&u)3NP5-1g_ZM} zqFezO5TE&*$^Ocw_H=?30Y8c4KmYPSq8))g>VZlkA!7XPerHhJDm6JJ+s_%92*k}N zwDT(+<1Uk7zoDZ9fJ@Yyo7V-Ka4&&ei8jwTO}1GksyO|S=PWiB)E;G77-FH7fP;DX z{$#7Oeq_O7hl7KA9f|uWFHDhOXz5ycD?paxWJkf12fa3A){-pM(ny0Q{H_IG2cZ_!67q;S1 zF_I0)*~4u*XysPC{#Iae*~Fdaq(6bo@um6E{&7waTMKvf3%-FPwqj!9wKPW@mc%v@=>k(C zVzb>R`bNY3oK+|_lK7HXeSwD6Gs|tH@&7xg3AuP_U4}J5Hgo3_Xy9G zc`%-h7R$o=J}Zjs7JH}Hx0Dsp(G&G?)gTCS4`N)=1mwaRlV?J5@*%C)UozK89kXN`JPmfQ$i$4(!eo0s=@BOrveHiIf@H8 z+q?K^=&|(akK2uhTVz*NRh^2cRRaT=kgp{42N<@rrGJsHSLfYWCz7andNN#V+pR(3 z$h2km<-0|cI^~j8hm1S7dBnzGCwZk@?vZ*4=YFY7^%{x8-3aQ#ZxBNHAWit~Tm}uC z=9tay-Afv{vEln^5$4&_lyy%zn10dSrv@*oS4}c`nxiH2aTC9c39r_-GOZ!GRuB8{ zpX*&RxjT3XX1!+!`R#1TqK|e>qVtTmT=WFaiZaj*nHf#J9IkE~15AngXv)s^loj7L zw&p8W85$a^8cG^cB)`ay>d42->2oldFV14^nIdNkX$i!3Iu>k0Gk$F5M~Cc$g;fS` zXJBp@p4DSxnPvKHIi~Jbfun+(VhW`LZYK~*q^$3yw zA633R{aC`QZFb{|2V3&pMOKu;2Mk2Er90CeMo;I9jWyo^3-Kl3*KiA?{(ghMK2p*k z;e230o4Sf_alf_pIseA}JMn78c4czHy7TD$M;eW0((#Q|o=xNZWv~2ue$^No%Dsi> zFAUu*j53W(`yh-*OW?SueoduYi^#72;>Q@&eAsTTV{5TX{M`DveNJY8W@p3S-b9#& zA3C;ziO>#$>_V%Twn!1R#7VKLAF%d0^N^96vOq}}=|cx;t#4PDWtR+9Ivd`gT{bhT zj+5WmX?e_J&b9CVMeU4%c7DGhM67}kL6Ya6WMQGYjJo$_Ld!({=-KBORw5qtit6W_ zf?l%nD>t!Pjjs(IEsSCxTJlc3b(Q!1zCqwo`+44TnR*>2Nh^ixB4C(42%g=~ud&x_ zp)wf@N!Mti-r3vznpo3@F5ERw)AEg>bjp78U|(q2hxAuv>a5lNR&V3+NL>hD5O6c( zs1ed9rvI*Sm(@5L$_|x~So3HqIl5Nf*|3d*3iWpDqeT(yPeB(jNc(KeNx)R{ocL zZb3g?9?zn52~nB8;zCvGlQK09T1v|Y0PiL@$0y7MdMTBp9R zMu$NuTpzsJSN>cMXKD0ixDR=-zHipwP|Aoul=wh?zE)+zQkp3$YGB-SN!Y4L=3)#p zm4Mtl{Lmb7pF`2&rh!v9&9kCV`pRq+;jp$+m({C&KE>bbS>k0*d9^XWlLUOo&ZTMw z!kS_4&crYK&rZBxovJG1IvvA=;>JxkQ~#^IH~)tE4gbfVL!}gweOF4^6J<-ZQDhB6 zb`lYjEMp%f*{Ni!?AiBy84O{RecyN48N0E}@_EkG>wMnle7=9d_q_YTIdR?Becg|1 zdtCQ(7P|V2dnPo)d8nGJD@RXbP%>iKX*tzpSHI~!9mUwzSWN{YpeBNg@Yv%cPi0(- zr%w~H!8FQwuJ&PV-NKcV7c3bgtQl3US+}s6loh9U8C$-=drc4gr8@2li+%S_$(NVP zjboT7c{W~|nysP{F-wct!e9h#_TwVkDXXWs$tEGa2%lxW=f|Evc2Bl()mw)8J9ytu zjTV*2KXqHHu@7V7>oPT!d|;rFBljld^JMH~*+2sy!IEEXAU>vIg%2^k9^r@QBVY?+ zC9tbvb=n6}%yd{dR5QyWsW+G~dj<&5#h9~k-6)m?v_GZ!K7&RDeJNGjY`VUIb;`CtgacBiW2H3& zEj~-f*`#K8g8NAA@!JE(aCZQX1B8Ke=_2y(LJ(N6JyDV z^oVos`RwUq_v*grjk7+jM;q%7iHQg@c1Z7AduXV$-*iZsuu6&`BLy>~o?fy60PYvU z&l&des`pnpoafmvreEaux?1cOa4fnk++72{RE41jixq-BOjxoeMQI(f{g;>i+V31ds1xMF+bz7PSt59tCLBf~3!G7(KrG^_ntbdHa}`i9DZ{#q2r9!gAa?`opE+FN~(?uygn*d>Q%%ROqD zLX`C@`5T?=RdZe8B}hijlVmWAE863e#1QZZi%*wV-}`j~fLFcSQxns~!OvE9E(39W z?NZAQFP_}Ee5Y71{?jd|pAD;E=vIk*l}K$F`ZQ!HKq>#i+O+yPeO8l zk5+EpTdsr6QhEf3Zv?n6dQ2W9xsEvv?}#=%;T6=jwwXIm;6rYaHbxWBm623i*GQ%C z#FY?w#2n4y9(LbmfT2LOq4Z~w(oUg-5^jc{3P$g?@NiiJQBuV`8HpbSS)7EiO1}@? z)f@SQvrXEvi_fFKs6Qk%lj9cS#LT{Iq7m$tb?rg%Qtj+ZnuA|*P)dis&xza_Lh5jA z-|M-Q_aG_Kv397uA%M(r-)NVzK~EB1MH~*k9{)jWEFqVASn_O5)V|w531``%ax?Tr z6Hh+2llko^YD1@l?Q@3+MTyik*09yLC+%fdo9gf%zs(UxjDz{(M}S`o)UvCRJZsHw z1jvQJ6n&1)w*8=JwAfe@pjD&ln1Mu4!BN++V%rPhf6I7|1rI@Gs$gk&D zjGXI|#V28$->o>8pq&o7Nuzo0EE@fLi)!XgJe%iJPS8C@?b*jmwCa3&8I*^LV3$d?xSXG8i4N zYkWlKE`R)!S>U5t6Hi@fK~GdDcg;iIG$(b{6+5R?_KD}-%+l_-DYxjbIO!hDjn}8i z#TF3{K1LUeUlHg9hFcm`tpLB@((=T=6A=uf>QdqlZQh-@YB4&Zs~bY;w@aWWV!me| z=7CxHO%kCOKaoZwX!&!-E{FQ)XG%=FHy&-+?%a4y0-!&du?_%3;#cHJd0dmy$y6=* z%4z9%arx)BXmSokmBWb~U1e_wYIyurr4eIlS~Aa{D_2PTF@{;!5&mq3zX!W+Mp%)hO^sF6n`SMSdg7omBZng86?o;Pws&pHp5HK}2d@^%g z#84@UUW|N%dV2lx(_cp0MJN{W9fsM=u6F&yJu0`P;W&l!YOnVa8_$!5vFo_K@3P+J zGt5z|SG$4pV5uAmt(9Pa!byXDzptWHOAjTj1uq4*4+$ABcurHpFGsmydjn3mdWdjo6 zgYR4Ax4*%jw%~FHkvLmL%V6_m4doU87$;lXP&$K6FY6|SG0$Mc`h7GVAECe@$L28d zinn=>tw5|r6Avq|IuTp4v5BIBEo>@e@RE3~W1-!P0OyGc*UVU(UAzGx2>{n3X- za~<`kBoXEX1L_=BQZqKL=bsu+manS(Kr`Ex<;_QkuL{mSv_DqHDM(mX^R>88^@3i$ zxe9)as&1A!Lq~Y^l!7J%bv^w%`prS2B^fYj#<{e17dSjy^9KZc|D&L9-F5J3aq{CS z1MnRLM@#2+o_kAivX}P!Pt|$o_PqhXr zOk37UF}xZG(AeMK>7pUGYt9bi80E6<3_~5^h}}I#fCd1L2U^m&t-hq5x6P-Jr_nN;J@yCuBh$v68?J@-2u(+T;kQb9+0c*Hle`A)1C++!* z+k6BdJX_*w2d@5%Ys`!xIbSA2iugk1lVx_A=|C??EAlgScg9Z~wRxr-We8DiUi0Sg zax&3Th0d2E;NYZBTy&DD-C9wlzC6kpKKPA~ zptMQln<`F66k6-2S(G5a$U`y@eg z`NT7eOs$QL0U!&M7Pjp2s&o82x>%Qtna7yyhP9s99sb$3r~I^rIE>soJ}JNHY+wh4 zY4YCr3~Ix_;0%{_Xnl@s+vFk#4`s5wzT(@_ubKMWi=)4eh0FoG#doU0)Q>vA41Lc{GIYQ;)i^S7#^z-f6woK^y*g;GL6?KRRXXj(&h_+mc@m zBwkBnAJc6CZMxh0^vk;-{^lhj?HTeB{mcouvfc|hW4ieuH}k!Jqnu)waqLT_S#2?$ z^RRLF#%*MBN*ku#u1|<$#j_DF11G|DdpKJixw~3kKN-o_ekx;XP#bjTuEGCgnRmt| zZ#J2bit0un;$E^FI2!^Vbc$Z#idChIr!jtJ6J)Qom?14(l|rENx`~@ZF1{o+apD&L zgCR;WZtR4W8#9UEMkL=_e*bc` z@L}+w4GXD&wX}mCWg6V?7%Tmg(Xt%e=k4mDqTsz1a1uX(ozlKCm8V!52L@aCa|}^z zy(bZGN(*qFBX7L6soX+U=6XMWKOWIpo&o`;<;B&XsNF1GT9HfWTYIXZt9rj4^O#Hp>y^S^C^F-&n+j7(Bc5!iIDq>Wb0NN^YS(G=cb* zjCG^>M&fy$vO?9U*3-YQ+DWhjz|j@1n90tT-Q{NaBYr65SBL5XWw@B9v94v4!eFjq z&4gDU54Fm?%0^64;i*%fx61YAzf-5Zo%kFnrlTv!+#eSrSfAA8dxIbwhU$AX9H(}7 z4jiMD-;A{>lCP3xPBiG)t(TO*s|V;n*DkSG_Ka#K4$jW6y8K*n{HoBVoRP^n9iYMN z(lPtaHP1VD|LzT?w>FU!%jnUSx^g$#Kf2e3^bW0%Iqx%c!)O&_-uS$hPx%_MUCrQUZ&|5^)np%*q>mbhi-_VCn{b~yE0Bx_qlFM6S7H^P$+63tFR{+8 zr3Do|)Tp7W8&iz@439NbP>Da9F6Bq6Zk-^fr22NtQ_5;$kV91KOVjb655T77o2l`r zDxqg3HgUis|I`WJJI5m%t<)#u_ZG5VJrQPdwY|40jZ}4%|GVC4|8dzPBaEIdp>pf} zDZm#J`8c4|zKzz~R!fukh6$@gsc5?9;q+~V0~}jE_!nJCc5G)vw!QwhyuXK2r>s&r zN+m~(mf{BlFso-hhW62@9d&LG9Q7(&XMz_}km<~9{~Gs4nUSvnGa|WNy)HJh{Q>*C zLh(vUnZMRP_cC-RYNm1WZQ(47a;isi6BAqiZc?PgF6%MB%r7T^AbY0$lP0k;kD8GD5 zw##6epQE;<(=B%Vl8^L^U+9|U6#%5aEDk~$Ps`*y20x?Zbid=r)uO*4$S-l#Uq{5M z<5cDlSZ}Y}^g0TRNhoDStm_P6Z@9)#0^xmeQI}{vj$umzDo^>#MvOn?kW=w>+6}Ng zELA)aOp2G=`HH$$;BQ288eq;boy>GjEunoP5}l?qju9O9BaQ9>h9_5BzIG`TOq~G7 zrTU~B1*dXh{k3h-)e!QkfqR2mP#{|9MvGaOjDS5{AfH^18$0e?mru^{xteyHP!|kB zd)L~CX1H;{7ceW5GrS1{PRnLO%)(L8PO`_(%k8=T0V3z)tck+e*X_rbbXu|5kPtaD zciWfC-y^I}FefaelKnj3>a53fTE=d${}*vUrNQgP+$Px@ZVml&6xwOZX>a0F9bWuf z3sMy4c-NXDUF_}2bfK=-gDEV)htW>VsMy=W@1^3lQzzgS-4UeJ+$*gyA<`Txi_8Bc|EI1P@80jz>u4w;YcT65jf&5r8-@}@Wagf*G@ z<?#23^T&^Xa3`|GmhNv=sJKgB*0hhIE-+dsm5HwGG%8*4GPKLdpJ&IVr)=v1r!c zsH_Xdjai6Wyw0!Cp?1_k?Hf9c3M41M`UdTEeW@^JeLzL)s>}7bGCFdw7O3*y7o13;eVrnPW=_# z%JS5Raq~3TPU>$h4ESahmcu5~n-%2Mchs?)HB11fFsoDl3E!%XGVSi)bHmZ(8-zx& zuN?0Lp(cbLZ&X54nS{K=su0X_Sx*z7Z8KCUpDF*9ogN>jY0-kt~7r zr2O}Psr|w4&7)DV7nJn|RHd|+!QSvHCiL;4`Bg#p84s5!@D2{}y2Pqi|Iz^YOxvlp zFPL4H>`z?!h>h=Hg5SJK{5@_i3KFfRUt#DSlYi{(;TTZ|KEDBQywkZHz_|exgFLo~ ze2<8CWO#YvZ``p-@SmN}0bYVM=)E_TQq*KWyHno%bEmw23j+{wR(e&&TGTDa>Pn5= zp@%-WUB-Lj7z|~6=w8&u(=(AwHfdB&fpsHZ=P2G;RuE!>{%m>Zm_EA!A^ z+TL5jHn;B8;wscA0pC>CMaUlybhf3B-f9*5d0*w)nl$E8KYFSJh-NAB-9-@kH!24T zi{G8VQH&Qy7ax5pjs_4*1yRrnrG(yC{#b55lB^*@y<(a_d&d@-w0z}BEe(FC6pld> zOh)xH#J#<}m9@1}222cZ6 zZzt4R18$x(NHE-51!kt=)Wna^69OhP&F}79*CFry>4KKP|D68-Uj;X>-2rll$uZ1K zaW7oVM6&_hgw+ht(xR2Q-tdGU>PVTKjE(8rV4gfld$v#af`7~yo%HvKP|zk!3P!~D zf&5B;=3~D;&(Mz8tDet^;XO*1|<@95AEVmKEv0H@mR5y zO7oW0wMe&Dkb1LB?#-MbBgbZ@XVuPG6IRlvz$2U{vQp>%fJi4eaw}RLTsD5)2R^*r zNbfrVOw+$lOxDiQSrcs#KTYg>aL}S@&O}qsq>Z-s_B0e=2;q0H%Mwxg_LWW6P=#)}e>5t9*&YG<=M-MwRzD z{G{KDDFOm@3-WIdk_UA|*MVen5f4|F$6F-{z3*}~daT9Fz*`rjv^XUjRe@eP%IFxQ zgH&ac^s%QnPXJH8p)*O4Ndwoqg!(}YZrq1>-?vgq|5E@kbR!+I@>76GMIi6!p_UNO z)DN@b#}XOM&gk8boibN)XI^Htk7xj#KlOFkXNXlaWmHe4^8)?0%d4jMwzIK-&&z*$ zjnEP!s|p2Rr>OiYUTo`iCB>XcrDdS*M~3N_1h0J6im7jT-mTHJ2e6&DXY18HS)$P2 zh|dnX`dijS7C+X28S`=I8}J@s4LzHUVM= zzvveTN&&!r0_41QIqwxO*Q#LX*S}jMmB+pI-I4Svlq89C#p^%vFVX4g+{CRf&; zQ6zaAg~T1{&M^Zp<>xTsGAPy!e_L3-k!5QXGT}emn5PE(L`l#SCa%8V^t*66j_Qdg z6Br%f6oYZ6d0&>=HA~fZQ3|(x0avJ{ScT-@aDf*{ zVRe|!xgYGIz?KF8ik>hH@p9n6i^7a2L+YPQMSOgj@7flhCRrp2dOf#7Ze8@J%=gg~ zyf{));s;-~3u&>GAVcpy{Cm1b(wU1x&^6IUt?z^Xgg69|g90~575tnaSfjx`?=PCQAlwxFEk=cD%&WZXF3u zk+bZS1OMPXmJJgE_-Lrzy@;r{e}hn>fI@fy^nuIK*gqj2lSv~jUdA094RGqOx~^Y{ zx39HVE1>;7Yj}Ji<#O%6LV}G@Mi_p+cjj;=ku+)oz?yYF;{Id&k8<7wg*NaFgLI{q z|K*67f_r|hqO`fXqC3}L*&$B`#e2j(i-$YwU1|CKL;uc0D0!j!uqcqO_iwaK^VUj1 zzO0Kj4ut;~C5f)JbSKRrrNyUx10YvcHwDuDMC>+PRyE%;yP=i)JVzfp?;O8Ewq3;Wyx-h_Y2fO#RhxfL?r3=Vk|7mt_kS&& zMs&|=z3WT)XNs^s1r~QQ#hbGh`@)p7(*p7R3#?nr1IbJ(f;ITj+8wSj?;zw$@Ww*x z9d@f{8NNNdZC~XOIyy=DTIPxCL@9Dm)tj@O{qtHf4|ZE;5NF^D_46Z-l}jO}^2gP^VU}Rh zFoW#|BzF&fXOO&O1eGZ3#pk=-cqljj2?`tPFzUhWGB z^ThwXA2c;a{%9E={8O>RO(dEoFM@nZyW2{dv^$P)GH+Tf4XXl5H=_!=X19IQ6(#F9%R zjZ|h%j;iSaaed;<$4RUB>8+_TICiXMtcu~D?98LnN!Rj`hK!a2*P58V>weD7$6)k3 zL)8Zx@RYG>S)8-|L=XRq8gdR#LVN;0py~`M9 zEOLWrKO1tciF3j|VsS?RSuOW5J0r+_)w_GYuof{-WHWY#H7`!ji_;F&D-mUTr$bGFq0Hw_zo(!CRA2+YA)SkHu%=DN8~JgBN3(pI5-`*8Dq zT7i1rzNVW$S(8WIPDCnw6~@LcZ~sxY1}Hb}Yn21MF+OY2p~mOfpaL59SMnL+P2=SD z#q<&L^ehHYPTI@>__erGwBN-Od{!?(dwph8@RFkc>G~Y|(M=o17b5xl*KOaCHop53 z7Uou!bv0qcAXMfgL+7(g6gq*x^TB+MAfrXCdAA_4P-}G0EqF&*U*{Nu2Cg9AmM&oE zJVfvTAbNbXzqGc-0GM0^5uJBe6z;sEmy10=T%-7g6Vz~aPpB7AO zU%&E=>-DeP*H@TmDRUo^Z2FkKJ%flZ;Ur)MDL^Gu>oEZk6XZp`0_m*L#u=JGk{*v+ z_QU7>4O*a{tT!KmLen3g2S6|mmWeAZwiA9H87mq$z_Z2^}J z^~QR8cucFkh4n;o_HBlFNDg?^XgalLw%Z|7HQJadLl(?M^34X(e6twqydpjn<$F`@ zMCN%2yW!yq3U|qqXc_=2tH0P*4v~b@HNn24u5up-3qkDSNsf{fg%WGUNvCV<9b?4;286_GnT9qZO& zYYpk=AR&{fkwD;KC7tDQ$%Zf>MbS?NEK>~pwKVzHb4tEP{N#=1{Ol69c8S0lP}LK` z9AM=e361``5MtLO#+I*_rnEq>Q;`=%q@}cPyr{RF-{EuG9Km4}60qI;HtA)vNj2*5NgD#`{m4ce#uw zZJQeCNoUpe$1J!x?4-L9(yoY?44o)W0PVLsFIo<709D5#pbIjE33yUIfTWBo< zn5Mpb)-%}+zxHYcsz*r(UI9g~&lhL7$k+N;{%Jj)tC@!t?7xmZL5hy+d!%^na+qYs zOBe}xNRy5i9=Mh@kv|zZJFIaIJ!k63YsN=Pf8VUV2C!~fPu->>a`BV=%$JUmV;Q@p zzybB%$UGQkoBS9l!H3BvWF~Y5Hq4yt!6$QVZA%^H$aC@skwAEofbcxr zUs~b_q_qxErzTq=I!0Y+d5qC_dU{7xe>vVem27PzeDu&WMS7Bbf@^^L@!WaP4(ZwA zJV4&N&vIQ?AuJ;Pa4>elx_9{617B+T>26~@zIH3}xFT8uU$KkWJ`Kw2JaiSR*Ch5z zFQk66#CDtoUBUl}?24}%CO#U@UG5=IiC5!5NyUNZi;!15E8rX1*}}z$`FwR8WOF&c z=OgeorRs=~G~!c5P%z2%**Cr;56{`JE*j|H$~+7?(K2*NpU6494hVayA~r$Bud`F$*oJu!WR2oX@vOS*c^ZUkY<` zzUy4OvBipOvm~JwN3yr3h|Xx&#(7UHSpDqV^iWV#QSI6vzVeOrka_62<_^U39at(o z$;Sx65QLg>h%i3Uf>bhYCVO!!YTUsbG%Qpu*q@z)Pc0v8DDjc%0n?(9xXvUt@u6aR zG)ZB{uTILPzy@xy|Ljyt8(!KtVd1tx6rA zh1=-kq9u4j(8TJ3o~QH^2z}C}`O}+`VRMcn0}2rdajLCb5m{G3X-y{&IX)lp(M8Sr zQy>68*dgk~#>LcH#ABHw$LAzx^?#3E2z)7DHC$JsK$v&;bHvW8pR#*!N%5gAJujjY zeeG7)o24mwev-1tVtl>-WT)G7Mi+Y2WyfNV+U`9E=-E#yCzc4^``2!%MJ&r#**IkH z+w@){Ehrf^g2<1ZKQa1dv$iA&sUANJXJaYI+0sR6*gSbeFOi z{=hz#=BmVF_jZx*jMnihBCq%^Km^%uQsh>>yqu5Uf2tLGM`09qGoP9`0s%7JM=qLM z_A$4#hHytT7{=&;SkQx5gaF|Cd94qf_7A+Do=71Cd2Z}XYy7@vcY+X;~+E?WiYqaA$le|s@xK?o@c93fe zchLJQu|&WX;hFSr?S}V;=iJY;Vxg*{RX;}W%Us6Vb4Fl^Ti!kLtCxrH0{|)As(TY7 z4x01hE-Cu8T>|ztN}YIuI@zv1toV&kBPCg;(8%wZkv;QEK!15>2_~X^vbkqScl}f0 z-<|0pN#$17E~WdTBCxS!SF-1>fFFtSbRSz(W&M(Idw}~)0jXqZRy+VQMGof;Q-*I# zq(|`+JJdiz_4iLh;Gbwl5{L_!=K0@=J9E{B6)iMVu!tCxc;4v!ch#Rw>tuqf z2uotS555^ZpV(HW0u(P4UyWA7`wth{_1}E^+Ly30*`x2?GuJa-#Y=q{v~x4llw|Dh zUkOI)8}>o*Nb83~F!>9_xyTTUfg5&lGkebi@Of1$pO(J58tqmu6kH@Z^|I9z4MeO= zIFNYc-(qo`KR1hGx&+jWzKftkpY5tSUn>#eG;B&qYL1Vz_aBs$S!v}~5vnTJ(nS|3 z>V=9$ZZsR2G9FngA;%;*NbOp&Sa$5v*9^4?E+qOA%EIpU;i8kJo@xGQa`Rqptq=6vWbqGh0|D%KNVEQKkBFA=LMj4%Tb01^ z9n=pL{Gye!iy!2XgJYG4JQ3WhqQ;yX?l~3hlIglc&ujUn*w>|4v7iKXRl?KhfpY+0 zl2#^p=Bq*76*DbiQ@s9ne5b!-AI~!eHOpnfrmA?ICw#Z_+3XkMdy+kyvc-lJqt8yw z7WkCPZNpKlQ?dw;@7~!JUHug~D3lbTk3~u;-`i&w%hGCX_K_Ab4z4*RJE{VUJ!`zR zt=ZIiHuqFg9oKPC!*Kaw)zV75smZp62Pr3pBVL(0U*r+*uZG>MS9P2_?3)$Nfn+j} zm_&?`JK~RrMlfNyM1D^rR>1>ooIrsIP2ud%F!AFh_oA&~=v!bA@Q^+(*T1jKmas5YeY`j^2JJ<@!$S zb}Q3xix4CDx|)<%k6l(v@2z#xo+%aa6>N<@ro-){11&uNoIRVG>SEDMUGo)G4g@6c zLCa4vraFxrN!yJ)F6y+0a6$~>jB{K$*rq;?#Nho&NE?1cjARLaLsPl0(b}@CIOZT= zX6g1$-9bCgcXkBM$F4Ar#A+DfUK>3&D>8SEtZBax6;2DUfu;9Y_d}%#yw*c+pI0jV)aNxGct^1DY6G5?u?v zH}s4Bm_cY?*A#@wA+?{FWl10M2+JT$q+0q!~6zr8uK{MA_QV z?%cda;2s^zTqSW+U$U&C1ul9=u+yugr7q0D0zv$+eS^3VzMQ{fsY0r`nv}&EwOsa9 ztjh^Jo=TS{;WJKJ<0V%nu?bSmOsENNWsM5KB(2*eC9E0o6<0~q>Yr-n2X(KXxc5$F zW3M-pj+}YXUW9??aR1&Kmr#?4!Z-)wu(qS8f0E6V@MrB{3FZNQw*O%^%r?hjz;F-L7Zgw>Rl7>VhSCrKwIAGU5(Nwe;T(VAb^2xGl#$ zg`2VQnhUVp8oodB1EF48ijCITu4qbpHX8-T_e!^qW&P&a9(io6zWX!P?{IZH;n*IX z^_g4WzY(Ww#&_q64myoB9uy5TSC!u@Er-YLJ_VmBfe<+rgh4Fl{8`zY#a5NQ$ZZqTwGcrUxu)FwdY&3pSV}jK5lHOWnbW~srxw;3qnwP?B zQ?+O*?CQ#e28}9&g8Af9UhmFI`#3!H`XgmH8-G=*CBU)0H8Y`jiyIcF?xBJ3U76+Y7d zMyvAp&U9z5f}2dRr)jv6ohPT~c+Xa+lvHzX>YFW0MQOha>w(tG6ykJxk=xR;1#XH8 zJy+CH@x`aJHZ8G4E+tFi>u7Z<5?24&hn>WxfgoGaj`=pHacKFuT_x8K^-Y3rEyRyy zXS3|-q4GC5#c$~x4Rba3Or)K0vSxhI5p=IkU=lx=zSOliyH-)wRN8ynLkaeD*I8$A z@$fhRZLw%3&OI*8jfJsCu)ta7Hh5S=w_K2We1^cVo}^^{5||qL=jT7*jJiPodGNH5O)V`GEzKvYg^~E+pbZ zk^^UL7+bK>sEDl@8$n@FZ|-0Q<^{{j-L{gm^iCN!qv}M_V-fa(R3A*GqC3Vyw#GXx zB&8Nxg;)j^ZgGpPu}2sq_mv#oloiJx(w0-FPV)h7x+V zC>$UA=i5>w>3#w@C^M0JiFq}K9eBVQ_)B>!%Jlc8hB~GbbIo42>ttGqujU4Ov2&?u zF!bC$PnbGR6@@b{i1M6&x+BC>wOvqF{wJj>3mlY3Q>!f1C7Bj*Z{DCb;8vzmLmTQR zV{ed%&ujh3r67;;yy-++kNMQJn$Kp4C$r{nNYzJCH+H)56N#+?isYdNc;rj^4{(M= z9synmX+3aRk@VB|1gWP3A4wz{050&7e*W*G{{`ZIBjW#WsWDBYd~)Nfn@H>*3sRCl NeyIK+|DM^q{{wI=gKz)< literal 10932 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 JPDHLkV1fsgxb*-4 delta 1264 zcmV7ip7{`C_J2TxPmfw%h$|%acrYHt)Re^PB%O&&=~ahS(%I#+V>J-vjIic7FmrfXn)08SZW zzL?HZgo}SSNcu|m&n`&XRLWEe_q?Rh_`)DQ!Ucc|OZ-XFn511rB_$bP9dH@wh-Ggo zqynVM3)3?_gVf#>E5u8iY)EMfQ#c-AONh%-O{IL)jaDpDp>fGZ;* z&NNa1u7PwxJb%(=S<`N2yPs}=Qd>tT)H6o27G=V5iPc4VS!_#@l|b>qnm9t zrveTdNw3GcyxNRs+YhS;I5HWpo!3ygInT3 zP$EweZn5FmW{(G2OmSWnlaVUrTdi!)jr#2-s*s1Y*W_xKW$+MV)+W zCJONO)jWe^^@a6LPGuFcfUl@%=t@<;i?RwP48wWx&VbMLbZu~j*zqUV3tSiqXmuv* zLdA3PVSjYZn;Sj4Qq`Z+ib)a*a^cJc%E9^JB;4s+K@rARbcBLT5P=@r;IVnBMKvT* z)ew*R;&8vu%?Z&S>s?8?)3*YawM0P4!q$KvMmKh3lgE~&w&v%wVzH3Oe=jeNT=n@Y z6J6TdHWTjXfX~-=1A1Bw`EW8rn}MqeI34nhet(}(@b2R=TnMg(!~JoOB@~U_c{58&x0vLE`&u6Jl1aUEMx=WS<^6F&44hq+zu3- z_YL@*xZ%^Cib8GTu|*xK0`9Mn-Pm>9AUJNoFl&j-KxEN_kAlACY{ z$$uG-fx8)AdpOV5PKzI?;TLyZ)r=v66R`IomuI>x!+GH*&chH~4;$pUapo+qzkiN9 z<5@h%5QL2t?hTdv#T`vf9JrKYa7=W%A%T-Zg*<e+2=O{vx$^4} zFC06^KjT>(Tk|t13k)ZJ8iKTjKw?FACl`;u#Kx8F_~|Syo`Y)*u46%BQD+-het*Bi z?&DuFlF8#(Lxtca1NV%iv%qemMnJ6c{JImlNL(npL!W|Gr_kxl1GVmF5&^$^YherS7+~q$pt}{a=*RiD2Ikv6o=IM1kgc7zq zpaZ;OB)P!1zz*i3{U()Dq#jG)erW`rGV!8YiTcE;xq_^g1lF2L%K5-fW6V#bE#SS9 zvT+;sezt(~lJ><+Gy2p|Ncw&Opk}j6l6FjiD+x;i=}0=DsM|lR`BgEDeVmu{s-k?D a0{1_&;gnn2jcRKE0000tiPUY+iMC<^G> zQ9;%ovsK^Us)R=k5b)wO7g>h+kJ|CoMFl(m*?OPVT8;34UO?6?I~+CvmgOSI-1#q4 z9jLgh;P9!|A%EQ}gd@U$oH-733K4Pcl8L<^83=I*xTm*(0g)0i$q>nZR&cuf_Rr39V-GP4L5^vY47A{qpsH_4i$pDqr?q93HHH(bn zIe$LQhLQbc9<%e-DmZYWah#Tt0j857*a{EnBjNR5+c7U&MJFm-p&jUG4{r3(_OA0V z_S=E3g@3s33kaiM79tE6Doy-gK^@JvY0|z4Q-7!3^H4iFZ`VaauP#1~=M&5FRctS@ ze0s-0GQ{uKC|L1J2kwuSQL_BTBh6t$vtHr1q_O^dG%kg zPDM>KA zC4sDNVA`uH6#e>jGBeQJ)f!JkV+PB3g=DBn>T}ycoxAHtUsw%-RKU_L2Ad^ceSbX3 zuk3J+%E$a16&W*}Bo-uEMH%TE4W0?N9yDnaV4`Fw>689uGDyvQW;|*+wO|%} zK3Bs?is!o{BrKb3M{If>uGCyRx_~33i;tYr@h6I@*kLZ0pAl!n2d52ed7sHjSNVt= zL901h#@Hbe{`IMWReN;2b;Ka?;Bi@ofsx>wjzLjUlXGLCHZexT1WIJg^?#q+s8JTb z&N|!_n1Y#|sbbp#CzTKpOCPskW`^d|q^$q;5|buj(#mNxDGAT~%tmEQgYjo=tV&CnIb~8EYcqGP z5)szx+c!m+ts0YaBdG4)*;ArKB+$A4L-y__dbNv>xhBTqKRndq5pJ^8)z!T1CVTSa zNt{3LNgmPB(FhL@_Zl;*`z=UX4Z(IM(_U6-H6=)5%l(@}=~-8{x5k zjpbx_?b?Nulz$Xxn#QkBm@omkxw(zTba*?_t@*^mGW4R&M#~-jM0Fjj;a2^AJS!`U zyE3b}`T6-i$=dDqMq_<_#k<`m|MS3BmzA+$ce&zNmSt?%umP&7qPV!&Z?X(*oQ7zV zgc+Egb`xe`q}j1!$Bufk45_K9KFPA=x98|Bsl&G)Z-4AFF*DBMb-p1oGBQwGTZ{GU z*YkE-S{nalt9~usq4N0YIdApWW(i-Z1y^E=ANMXhk|ZHJJDZ;~(uQGR(xgfJdUA4d zeZLyT!lGQQk<4$igc&yOGcfc{jr6*As&$i&ii$#6SsA}pP*8xFm>5JxMv~aEFn5)L zvWmuIwts2DOoq;1r_mPF!nB8NUZskWUb19KqbFG3xvLd&=cfO4)5ZzAKKU%BlK0Ms zCgvr|7}kWoX3%sCI}YnuzE#J$O5fwPdBO~AVGq#`Dsicb0lhSg9xS3ycM(pTz`u5| zFQ@xHHt75oebZ_yU@m>C9CWbSdhH(k7Jt(U6eR=+2Red;106xafsSt-;r{~zucsQm SrJ%e30000c)UfJ<2uenUn3ARN>mf|M z+(eagCX~wv_9N9Br6dE4W@{R1X8yU75JVAXqB_2?1W&7xoYHg zkR5NEVWsUG^?wLzRHH9Aa#eCDK9NvdPE(De9-HaQc(6~^lpTe2pm3&x9G1K5Xawdi z4F*DRWI%>vgEBPFqaRR51|&E>B!fiay027YsK+Vrn=1PqDKdi{m<&P1nQ3_Gw<%cH zHU+slT8moWCbIKH=(W3t1j5BNfsIKQ#Mzi(J59kx zT!xVJ&SKqb4XjdxWQV7$IrZ-{l-x3`7M}qzHsPzP1S_$c=96h(q%b9ZXPvcV z;D5oPsau6Q(U`-YLD*G41z_cgz)a99av0W_U=aHAj?mj@2KZI50efIA zO8^kn_?FjaZ_hfbhSh@3^GzxJx*P{Jc7Hi*OHPZ!wvEV2a9XKq###zPPeRs75i0(W zU?doBGb9yqT58~qn?wQ4oCi3oWdc^W%JAgTVR)*l33@Ky3ip4Rqz14Wx_gwsGYGq) zMY~B;*z8j>WF8xV`^#!USYHDVZf}I{OZGzBnutHA1D(}!4{};5>;)mO27l7F zHh@r23lDAk8oF(C+P0rsBpv85EP>4CVMx#04MOfG;P%vktHcXwTj~+IE(~px)3*MY z77e}p#|c>TD?sMatC0Tu4iKKJ0(X8jxQY*gYtxsC(zYC$g|@+I+kY;dg_dE>scBf& zbP1Nc@Hz<3R)V`=AGkc;8CXqdi+`PV3Vc;#lxQO~AoO*}pfE+=*r3ffZ_YMC zflq>i%a-`Xw)YRuK;MUtq{SGa7vtY^gg0bKSp&F>y|A>h5qhqSvgdtV{(lh0c$xz5 z;*U?KQl%W)htLmD=yhL!@aldLHW(=H00^&qu7J0mA5v0IaX@pn_bKobsC(e>(nAjI zzjyto3Dmc!oOxjlw&JZqeL%+vsN0Zy8@1@rs~rRNAqO?umG&QV WYK#ibz}*4>0000B8us0F~tW_Y#5{ z>Y&A^-v(oCn%nrY;bMBSWI_B}lR!&W%Jp~c1%E5o>6|4ED=kr^k%pttL$78z zTaIaxu=l6oKL5u>dLw2qXS%_?^Ia?oXB=PH@XE_o9`L(p>oVBYXAb(y;?naJZn|0} zvCrazT?RX(ar3THxKk=-t7NMsFtHH%p|*4nzn0~lM?Ea5bV>gi#J;v<)j6dAxuGh@ zRW2%4rGG!+vmT3Q-_<$%2VCM6Y<bGKKP~_N}#WsV2QYTTGuK_+h``%kL~+x=*8cl0rJ2rnIN6MS=FXH z@}GH{z&}eJ0@l>j5RFD@Z*P~t3TM9?%3b)pIz372*vVn_7M)o>m8Cbjo&Ftj-NW85 zt;+RpZyI36)Ev<7_dCGW)>cxf6tP%r2t4CLF*?-FtqY${bLxa+=h%Mvn>Bx?bb+Q( zR)1DTeSJNlP>5tQNk>P=&^&!Gaz;&qx&$BieY9DE?R!jaog-*$Y^1rlnRq--Lqh{T zpU;_L%A5ZA9`pF1$6K~^nbcJoGK5qDfdGj_f?zO+*XyOWww4Va>HPRBV+*yVyGzFP znq?YSPE!eo!_Gw01{XvNDI|MgBm1gF}3YSf>vy&o|gF){v<`8hq qp}8XH+H1*b0sYywyRT@!HH?E|j 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 literal 1716 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 R{*OF~bU=ohwa=ij{{u=RJS+eJ delta 1906 zcmV-&2aWik9e@vzBYy`+Nkl^fDmF(5(5$|?Cx}D zKEJa&XZP%OyE`*GvvYQ4PV&!g2|L^Q?YG}tx;sY@GzV#^0C$Z`m}blr)&(OPMHT6T@%AxHOWYGG zm>@=0?<)?0r0XK9>leRXyD^j4O4bXT!@LESVI<~>`yB+S2b_f__vvyMHkwGyyXedq3usx&X*}E{O;}+nJ#G_xm zJbQX5 zuFrVK*|x9RQeZ1J@1v9MX;>n34(i>=YE@Iur`0Vah(inE3VUFZNqf~ ztSz{1fz3Fsn_x4F>o(Yo;kpqvBe-sbwH(*Yuz!}~S^-;|MX;9Py1im8!}VY-!u4P+ z!nLEvx?+Rogo+Kw9OBXy&lGIvJ51_7Hl6Q>*MAJa!lMDGGML530`Te&0ciU({DC7` z;RKg{uC>($*mdXnVQQBjiVyqYC7mf!Z%e-Q!?Oo{ufu`G3CAC=UjiTpU<94UTFz2KEDuNS@KKkg)K8!v1L8RUP$_! z({LG$Dy&JLEVpiNVe^G(HCbA*SpsX?292)#=JVQDUMp-cOJPl`+yTHTD!AOit-zAD zptXYa!q%OVLa^mo25b7^Z>kE`3rqgr-G4i;Lw<+P(8khESW8aaBmxfY`WS#6j<92Q z-++&Y z$gbH4#2sT0cU0SdFs=*W*4hKGpuR1QGacHFy;`# zR&NJkbTNp}Ee5f08HmLzK%D(q3@lH;Tzx$?VT;&xJq-KyHV__o3dD)?KrE<6*iXV0 z8;6<{IKw@dyDwJ90H5^3h;|9?twz{UGr|>1Pzhdn6W(r0ifeZd=JI+AAz<~yL(QJk zAWW))+=`8mGj|J!70oF@d4B;WxB=jBM1bWWRBb&1!ie3BUzOdm}yC-xA%SY``k$rbfk;CHqifhU*jfGM@DkYCec zD9&E@F9*za0?~OQZiDE|Cf;;0 z`uZ%H=IeGyG^H0ruev{yIVARgwZUG)j7>F#3~dh+8DOtPByR=(VDhz2enf#EjcXCI z=NUPYr4@S)GhX!?s(0Eh(nGe!y$#$r1B$||I~`wPhUuCQEo;#Xb$EXk=6HgBBRd#c ziK|jN$e~{zV~|;*E@Ij-Z(+tI^B8RW51ptE!nMnPyZ`_I07*qoM6N<$f^^1=6#xJL diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png index 2ccbfd967d9697cd4b83225558af2911e9571c9b..5ad80187a2b9d75d67946055753881cefd525c76 100644 GIT binary patch delta 1455 zcmV;g1yK5f3cw4HBYy>lNklWoUqHR^*Ry6wOA> zoEp%`|jtSbMCq4SstBx!^Ax-%YT0j(3ZLZ{Z%)hzv>3` zSKWaAsvFQ>bt>S@XGH`C2-tQ=hahy$Gdm4%$_NpwX3G#o0jlQ0&LX2zp4%yaW1bMO zE>=c86-Ml{B1*=UIt2$S{fG1$@W~JXY46x@{*r+mg*t3jW=#nj=gEj#>%y_~{#A3$ z0D}U6mq$uyY=1IQ*Jz^l22k5T-|1dQ7BURM6JL)61KSqK{QuaE3PwC8@wR!J736(j zL;6A)(^t9h`xSS8lUPN;#Qi-4^b7lU@7=m`hgu zf&hnwizq&+;iq4jR~U#1`+dNK!4e$(M6$Yol2aP?AJb{1FMKmVlR7Nfs$$;?5t0aG z9@Oys5Pu0hY`{0=Iu2CoST|ROZkSkk zTq17(oAzj!I8?;YFp} zkD#C+-nNoXp&zQ7=pixnGhjHQ$4TfO~&Y^O3y3<(vn=oJ~4YYo1_ z1(QX(te##hN3t9|Yn=PBe_k~x&8UccT=Kxh#Kd^u3JVK;;BG0>!TNUy5U8g_9iOIP z;S>v6IS6pI&iD7F8h0%9c6$$5S$|o`&d%m=1qB62OiV;sSs4Zn9EiNUJlO4a-Y?kh zeMX0hh2u^WZ*5XLGKA~eb@x3sHWp5&lUp$%Ap!aM`3MgWM|yg?2af6Xbkijjb?GUc zaw%C}6p@^qjI^{g4#$*{k%9jG`}_7kt#>UTJ1r7kGw^V4_eP0}i$i5)C4UEvii*PF z!-wH;IC$Ijn+(&2DVjEa?B)Of002ov JPDHLkV1fsgxb*-4 delta 1264 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 delta 2657 zcmV-n3ZC_$Dd`lDBYz4oNkloFh3q0M zFesq&64WThn3$;G69TfjsAv=f2G9}pgSx99+!YO}2Uveik)GA5ewEg1Va|1@=x;Pyj3t}zC)T-c zzoz+u9TyK|)jteh(` z;D6}gLagCR0hn*76kN#wCv*`b8GyswI1s7kNaT!{fEXv;5ofK|nu3vU_1cRKLBd@TQ@Ei6F6QJ?HM!O!+{x(L<6rNAv)=55QOzlPWhqI{ zjSR5c$#aW1xy}c;$06La(Y*xlX>0w3EDGGn02k}7*%ZplRLFsw%E3MJO@BuPkU#Ja zcbp(_BL!RxGHHe;wff^+2G>u>ah(dq7O)#K0ekx={yBF*$P%aJSOMmjHHmAxvW0cp zt8@K;ETVH`1(=8Ie(Z;Hy+9V#xv>Mxz*+%0w;aeKJ2#eqVJL7nrpksp7|5bKS2)0a zId?FSYb0>4P=MLsl6(J^Q-5;@54jg=+fq2sO~Hz-hVXEO0L<$0j+BKdGX;Npqt{os zJmk~Y_Q1L83|RfW)5G^!;(u>i7{EI*HIqAp9`Cbzna*hHhI2Lm9I{{?%y{Hgdzxli z7Fd?00Ed;L$qk&zI`y$@{Dn;5j(iW`=!aXNV*G=kjb8%Qi`UtJMSq7ZT$4qCb{TaXHjb$QA{y0EYy*+b1XI;6Ah-w13P)xT`>~eFoJC!>{2X zL(a_#upp3gaR1#5+L(Jmzp4TBnx{~WHedpJ1ch8JFk~Sw>F+gN+i+VD?gMXwcIhn8 zrz`>e>J^TI3E-MW>VM=sWZual)ns9B%8_$25BcpOz+KP;+J(1(UiAp*Q=dc!FQL}*R43bTaVm7wy#IrC-VD&k-4FWYMd;wg6!1z8a3SP;O>P#-$->_l zEAM2>hI~v3$Y(TlIdJE^0@|6AK_7#uc{~E1^f2gGJ^}i)rGJ>FDPRt4F~}m-WGQZK zw?8N6;NJH#XeW;Webf!0kG=!+v2#G5xX^L14Y#o*Tz9&z7NjOib92f(6aq==Ntoo74a!u6w~r!$mq|FDi7h6+6fTa4$$0Y>@Y*O}J#< z8ic&ucAQ^e_cw)#3uFTLcly|p7IMmPAXha6205mSA%EQja0eR?DV=N%;eS$2zHI*MpiObUuA|j7`m5?j`@^G6SO!-;(G1aCOu{sGli$ zGck~Eqx{gt?U$`9P3JRJO>}Ku- zRew#6AKb$jGi@lro`A;#P%m@cnyJP&(r%f}Zq^V3mIc=hnLfVXHRn=pj;2#4v8WiM zav|%So5|ksmkM-bV7H;F_%f>b72G`eFJ!d@wTC-#ALO^GRCtHl=K|Y}dX%fTm0A$N zzc4;N3AGsYM~OOND&T_#%8wZzWYfL@by`|620=mAU7(LZ-At!cdlWCvu@AK#bt~#< z9;~k^d5}}7VXmK@h?&@_rUHYJ9zD=M%4AFQ`}k8OC$9ssPq=LnkwKG P00000NkvXXu0mjfs#qFw diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png index a6d6b8609df07bf62e5100a53a01510388bd2b22..f049762f057fca745ca451c25a3f1052195be542 100644 GIT binary patch literal 5281 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 delta 2657 zcmV-n3ZC_$Dd`lDBYz4oNkloFh3q0M zFesq&64WThn3$;G69TfjsAv=f2G9}pgSx99+!YO}2Uveik)GA5ewEg1Va|1@=x;Pyj3t}zC)T-c zzoz+u9TyK|)jteh(` z;D6}gLagCR0hn*76kN#wCv*`b8GyswI1s7kNaT!{fEXv;5ofK|nu3vU_1cRKLBd@TQ@Ei6F6QJ?HM!O!+{x(L<6rNAv)=55QOzlPWhqI{ zjSR5c$#aW1xy}c;$06La(Y*xlX>0w3EDGGn02k}7*%ZplRLFsw%E3MJO@BuPkU#Ja zcbp(_BL!RxGHHe;wff^+2G>u>ah(dq7O)#K0ekx={yBF*$P%aJSOMmjHHmAxvW0cp zt8@K;ETVH`1(=8Ie(Z;Hy+9V#xv>Mxz*+%0w;aeKJ2#eqVJL7nrpksp7|5bKS2)0a zId?FSYb0>4P=MLsl6(J^Q-5;@54jg=+fq2sO~Hz-hVXEO0L<$0j+BKdGX;Npqt{os zJmk~Y_Q1L83|RfW)5G^!;(u>i7{EI*HIqAp9`Cbzna*hHhI2Lm9I{{?%y{Hgdzxli z7Fd?00Ed;L$qk&zI`y$@{Dn;5j(iW`=!aXNV*G=kjb8%Qi`UtJMSq7ZT$4qCb{TaXHjb$QA{y0EYy*+b1XI;6Ah-w13P)xT`>~eFoJC!>{2X zL(a_#upp3gaR1#5+L(Jmzp4TBnx{~WHedpJ1ch8JFk~Sw>F+gN+i+VD?gMXwcIhn8 zrz`>e>J^TI3E-MW>VM=sWZual)ns9B%8_$25BcpOz+KP;+J(1(UiAp*Q=dc!FQL}*R43bTaVm7wy#IrC-VD&k-4FWYMd;wg6!1z8a3SP;O>P#-$->_l zEAM2>hI~v3$Y(TlIdJE^0@|6AK_7#uc{~E1^f2gGJ^}i)rGJ>FDPRt4F~}m-WGQZK zw?8N6;NJH#XeW;Webf!0kG=!+v2#G5xX^L14Y#o*Tz9&z7NjOib92f(6aq==Ntoo74a!u6w~r!$mq|FDi7h6+6fTa4$$0Y>@Y*O}J#< z8ic&ucAQ^e_cw)#3uFTLcly|p7IMmPAXha6205mSA%EQja0eR?DV=N%;eS$2zHI*MpiObUuA|j7`m5?j`@^G6SO!-;(G1aCOu{sGli$ zGck~Eqx{gt?U$`9P3JRJO>}Ku- zRew#6AKb$jGi@lro`A;#P%m@cnyJP&(r%f}Zq^V3mIc=hnLfVXHRn=pj;2#4v8WiM zav|%So5|ksmkM-bV7H;F_%f>b72G`eFJ!d@wTC-#ALO^GRCtHl=K|Y}dX%fTm0A$N zzc4;N3AGsYM~OOND&T_#%8wZzWYfL@by`|620=mAU7(LZ-At!cdlWCvu@AK#bt~#< z9;~k^d5}}7VXmK@h?&@_rUHYJ9zD=M%4AFQ`}k8OC$9ssPq=LnkwKG P00000NkvXXu0mjfs#qFw diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png index 75b2d164a5a98e212cca15ea7bf2ab5de5108680..b51e00a7e59da211b022b622a91217b0dab107fb 100644 GIT binary patch literal 8289 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 literal 3831 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 diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png index c4df70d39da7941ef3f6dcb7f06a192d8dcb308d..8c4973081f22d5f81b781442cb0eb6b18514317a 100644 GIT binary patch literal 3132 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 delta 1874 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

wfbU}SOG#?y4 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 iW8CFBundleInfoDictionaryVersion 6.0 CFBundleName - example + ChatSample CFBundlePackageType APPL CFBundleShortVersionString diff --git a/example/pubspec.yaml b/example/pubspec.yaml index b7f2709c..1e527964 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -1,7 +1,7 @@ name: example description: A new Flutter project. -version: 1.0.41+43 +version: 1.0.42+44 environment: sdk: ">=2.2.2 <3.0.0" @@ -19,7 +19,13 @@ dev_dependencies: sdk: flutter flutter_driver: sdk: flutter + flutter_launcher_icons: ^0.8.0 test: any flutter: uses-material-design: true + +flutter_icons: + android: true + ios: true + image_path: "assets/icon.png" From c8bbd59732f1e11d2a104f15632a23f86560b608 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Fri, 6 Nov 2020 17:09:29 +0100 Subject: [PATCH 0316/1140] add choose user pages --- example/assets/logo.svg | 3 + example/lib/advanced_options_page.dart | 266 +++++++++++++++++++++++++ example/lib/choose_user_page.dart | 227 +++++++++++++++++++++ example/lib/main.dart | 77 +------ example/pubspec.yaml | 5 +- lib/src/stream_chat_theme.dart | 1 + lib/src/user_avatar.dart | 4 +- pubspec.yaml | 3 +- 8 files changed, 507 insertions(+), 79 deletions(-) create mode 100644 example/assets/logo.svg create mode 100644 example/lib/advanced_options_page.dart create mode 100644 example/lib/choose_user_page.dart diff --git a/example/assets/logo.svg b/example/assets/logo.svg new file mode 100644 index 00000000..49eecf7c --- /dev/null +++ b/example/assets/logo.svg @@ -0,0 +1,3 @@ + + + diff --git a/example/lib/advanced_options_page.dart b/example/lib/advanced_options_page.dart new file mode 100644 index 00000000..4d1de2ae --- /dev/null +++ b/example/lib/advanced_options_page.dart @@ -0,0 +1,266 @@ +import 'dart:io'; + +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_apns/flutter_apns.dart'; +import 'package:flutter_local_notifications/flutter_local_notifications.dart' + hide Message; +import 'package:stream_chat_flutter/stream_chat_flutter.dart'; + +import 'main.dart'; + +void showLocalNotification(Message message, ChannelModel channel) async { + FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin = + FlutterLocalNotificationsPlugin(); + final initializationSettingsAndroid = + AndroidInitializationSettings('launch_background'); + final initializationSettingsIOS = IOSInitializationSettings(); + final initializationSettings = InitializationSettings( + android: initializationSettingsAndroid, + iOS: initializationSettingsIOS, + ); + await flutterLocalNotificationsPlugin.initialize(initializationSettings); + await flutterLocalNotificationsPlugin.show( + message.id.hashCode, + '${message.user.name} @ ${channel.name}', + message.text, + NotificationDetails( + android: AndroidNotificationDetails( + 'message channel', + 'Message channel', + 'Channel used for showing messages', + priority: Priority.high, + importance: Importance.high, + ), + iOS: IOSNotificationDetails(), + ), + ); +} + +Future backgroundHandler(Map notification) async { + final messageId = notification['data']['message_id']; + + final notificationData = + await NotificationService.getAndStoreMessage(messageId); + + showLocalNotification( + notificationData.message, + notificationData.channel, + ); +} + +void _initNotifications(Client client) { + final connector = createPushConnector(); + connector.configure( + onBackgroundMessage: backgroundHandler, + ); + + connector.requestNotificationPermissions(); + connector.token.addListener(() { + if (connector.token.value != null) { + client.addDevice( + connector.token.value, + Platform.isAndroid ? 'firebase' : 'apn', + ); + } + }); +} + +class AdvancedOptionsPage extends StatelessWidget { + final _formKey = GlobalKey(); + final TextEditingController _apiKeyController = TextEditingController(); + final TextEditingController _userIdController = TextEditingController(); + final TextEditingController _userTokenController = TextEditingController(); + final TextEditingController _usernameController = TextEditingController(); + + @override + Widget build(BuildContext context) { + return Scaffold( + resizeToAvoidBottomPadding: false, + appBar: AppBar( + backgroundColor: StreamChatTheme.of(context).primaryColor, + elevation: 1, + centerTitle: true, + title: Text( + 'Advanced Options', + style: Theme.of(context).textTheme.subtitle1.copyWith( + fontWeight: FontWeight.bold, + ), + ), + leading: IconButton( + icon: Icon( + StreamIcons.left, + color: Colors.black, + ), + onPressed: () { + Navigator.pop(context); + }, + ), + ), + body: Padding( + padding: const EdgeInsets.symmetric( + horizontal: 16, + vertical: 16, + ), + child: Form( + key: _formKey, + onChanged: () {}, + child: Column( + children: [ + TextFormField( + controller: _apiKeyController, + validator: (value) { + if (value.isEmpty) { + return 'Please enter the user Chat API Key'; + } + return null; + }, + decoration: InputDecoration( + labelStyle: TextStyle( + fontSize: 14, + color: Colors.black.withOpacity(.5), + ), + border: UnderlineInputBorder( + borderRadius: BorderRadius.circular(8), + borderSide: BorderSide.none, + ), + fillColor: Color(0xffF5F5F5), + filled: true, + labelText: 'Chat API Key', + ), + textInputAction: TextInputAction.next, + ), + Padding( + padding: const EdgeInsets.only(top: 8.0), + child: TextFormField( + controller: _userIdController, + validator: (value) { + if (value.isEmpty) { + return 'Please enter the User ID'; + } + return null; + }, + textInputAction: TextInputAction.next, + decoration: InputDecoration( + labelStyle: TextStyle( + fontSize: 14, + color: Colors.black.withOpacity(.5), + ), + border: UnderlineInputBorder( + borderRadius: BorderRadius.circular(8), + borderSide: BorderSide.none, + ), + fillColor: Color(0xffF5F5F5), + filled: true, + labelText: 'User ID', + ), + ), + ), + Padding( + padding: const EdgeInsets.only(top: 8.0), + child: TextFormField( + controller: _userTokenController, + validator: (value) { + if (value.isEmpty) { + return 'Please enter the user token'; + } + return null; + }, + textInputAction: TextInputAction.next, + decoration: InputDecoration( + labelStyle: TextStyle( + fontSize: 14, + color: Colors.black.withOpacity(.5), + ), + border: UnderlineInputBorder( + borderRadius: BorderRadius.circular(8), + borderSide: BorderSide.none, + ), + fillColor: Color(0xffF5F5F5), + filled: true, + labelText: 'User Token', + ), + ), + ), + Padding( + padding: const EdgeInsets.only(top: 8.0), + child: TextFormField( + controller: _usernameController, + textInputAction: TextInputAction.done, + decoration: InputDecoration( + labelStyle: TextStyle( + fontSize: 14, + color: Colors.black.withOpacity(.5), + ), + border: UnderlineInputBorder( + borderRadius: BorderRadius.circular(8), + borderSide: BorderSide.none, + ), + fillColor: Color(0xffF5F5F5), + filled: true, + labelText: 'Username (optional)', + ), + ), + ), + Expanded( + child: Align( + alignment: Alignment.bottomCenter, + child: FlatButton( + color: StreamChatTheme.of(context).accentColor, + minWidth: double.infinity, + height: 48, + child: Text( + 'Login', + style: TextStyle( + color: Colors.white, + fontSize: 16, + ), + ), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(26), + ), + onPressed: () async { + if (_formKey.currentState.validate()) { + final apiKey = _apiKeyController.text; + final userId = _userIdController.text; + final userToken = _userTokenController.text; + final username = _usernameController.text; + + final client = StreamChat.of(context).client; + client.apiKey = apiKey; + + await client.setUser( + User(id: userId, extraData: { + 'name': username, + }), + userToken, + ); + + if (!kIsWeb) { + _initNotifications(client); + } + + Navigator.pop(context); + await Navigator.pushReplacement( + context, + MaterialPageRoute( + builder: (context) { + return StreamChat( + client: client, + child: ChannelListPage(), + ); + }, + ), + ); + } + }, + ), + ), + ) + ], + ), + ), + ), + ); + } +} diff --git a/example/lib/choose_user_page.dart b/example/lib/choose_user_page.dart new file mode 100644 index 00000000..2d9f1c7a --- /dev/null +++ b/example/lib/choose_user_page.dart @@ -0,0 +1,227 @@ +import 'dart:io'; + +import 'package:example/advanced_options_page.dart'; +import 'package:example/main.dart'; +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_apns/flutter_apns.dart'; +import 'package:flutter_local_notifications/flutter_local_notifications.dart' + hide Message; +import 'package:flutter_svg/flutter_svg.dart'; +import 'package:stream_chat_flutter/stream_chat_flutter.dart'; + +void showLocalNotification(Message message, ChannelModel channel) async { + FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin = + FlutterLocalNotificationsPlugin(); + final initializationSettingsAndroid = + AndroidInitializationSettings('launch_background'); + final initializationSettingsIOS = IOSInitializationSettings(); + final initializationSettings = InitializationSettings( + android: initializationSettingsAndroid, + iOS: initializationSettingsIOS, + ); + await flutterLocalNotificationsPlugin.initialize(initializationSettings); + await flutterLocalNotificationsPlugin.show( + message.id.hashCode, + '${message.user.name} @ ${channel.name}', + message.text, + NotificationDetails( + android: AndroidNotificationDetails( + 'message channel', + 'Message channel', + 'Channel used for showing messages', + priority: Priority.high, + importance: Importance.high, + ), + iOS: IOSNotificationDetails(), + ), + ); +} + +Future backgroundHandler(Map notification) async { + final messageId = notification['data']['message_id']; + + final notificationData = + await NotificationService.getAndStoreMessage(messageId); + + showLocalNotification( + notificationData.message, + notificationData.channel, + ); +} + +void _initNotifications(Client client) { + final connector = createPushConnector(); + connector.configure( + onBackgroundMessage: backgroundHandler, + ); + + connector.requestNotificationPermissions(); + connector.token.addListener(() { + if (connector.token.value != null) { + client.addDevice( + connector.token.value, + Platform.isAndroid ? 'firebase' : 'apn', + ); + } + }); +} + +class ChooseUserPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + final users = { + 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoidmlzaGFsIn0._JHWzo92fpTWZMZriJHXqOng6ShYVmWrdaIaPwEPKBg': + User( + id: 'vishal', + extraData: { + 'name': 'Vishal', + }, + ), + 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoic3VwZXItYmFuZC05In0.0L6lGoeLwkz0aZRUcpZKsvaXtNEDHBcezVTZ0oPq40A': + User( + id: 'super-band-9', + extraData: { + 'name': 'John Doe', + }, + ), + 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoic2FsdmF0b3JlIn0.GMEKyEhONmFnqtkf1TR1A3oUOSIWhjfQv5RpI906dAM': + User( + id: 'salvatore', + extraData: { + 'name': 'Salvatore', + }, + ), + 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoidG9tbWFzbyJ9.GTalMeZHaBdpIM5w-KWrVIDSy-ODkHTRkf1GZbWAveM': + User( + id: 'tommaso', + extraData: { + 'name': 'Tommaso', + }, + ), + 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoiamFhcCJ9.xpGE2lu4OoYS7-2yy6PbF0gJnxOaxeGO4EU6xo4EdMU': + User( + id: 'jaap', + extraData: { + 'name': 'Jaap', + }, + ), + }; + return Scaffold( + body: Column( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Padding( + padding: const EdgeInsets.only( + top: 34, + bottom: 20, + ), + child: Center( + child: SvgPicture.asset( + 'assets/logo.svg', + height: 40, + ), + ), + ), + Padding( + padding: const EdgeInsets.only(bottom: 13.0), + child: Text( + 'Welcome to Stream Chat', + style: TextStyle( + fontSize: 22, + color: Colors.black, + fontWeight: FontWeight.bold, + ), + ), + ), + Text( + 'Select a user to try the Flutter SDK:', + style: TextStyle( + fontSize: 14.5, + color: Colors.black, + ), + ), + Expanded( + child: ListView( + children: [ + ...users.entries.map((entry) { + final token = entry.key; + final user = entry.value; + return ListTile( + onTap: () async { + final client = StreamChat.of(context).client; + + await client.setUser( + User(id: user.id, extraData: { + 'name': user.name, + }), + token, + ); + + if (!kIsWeb) { + _initNotifications(client); + } + + await Navigator.pushReplacement( + context, + MaterialPageRoute( + builder: (context) { + return StreamChat( + client: client, + child: ChannelListPage(), + ); + }, + ), + ); + }, + leading: UserAvatar( + user: user, + constraints: BoxConstraints.tight( + Size.fromRadius(20), + ), + ), + title: Text( + user.name, + style: TextStyle(fontWeight: FontWeight.bold), + ), + subtitle: Text('Stream test account'), + trailing: Icon( + StreamIcons.arrow_right, + color: StreamChatTheme.of(context).accentColor, + ), + ); + }), + ListTile( + onTap: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => AdvancedOptionsPage(), + ), + ); + }, + leading: CircleAvatar( + child: Icon( + StreamIcons.settings, + color: Colors.black, + ), + backgroundColor: StreamChatTheme.of(context).secondaryColor, + ), + title: Text( + 'Advanced Options', + style: TextStyle(fontWeight: FontWeight.bold), + ), + subtitle: Text('Custom settings'), + trailing: Icon( + StreamIcons.arrow_right, + color: StreamChatTheme.of(context).accentColor, + ), + ), + ], + ), + ), + ], + ), + ); + } +} diff --git a/example/lib/main.dart b/example/lib/main.dart index ca727cf7..8218f203 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -1,70 +1,11 @@ import 'dart:io'; +import 'package:example/choose_user_page.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; -import 'package:flutter_apns/apns.dart'; -import 'package:flutter_local_notifications/flutter_local_notifications.dart' - hide Message; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; -void showLocalNotification(Message message, ChannelModel channel) async { - FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin = - FlutterLocalNotificationsPlugin(); - final initializationSettingsAndroid = - AndroidInitializationSettings('launch_background'); - final initializationSettingsIOS = IOSInitializationSettings(); - final initializationSettings = InitializationSettings( - android: initializationSettingsAndroid, - iOS: initializationSettingsIOS, - ); - await flutterLocalNotificationsPlugin.initialize(initializationSettings); - await flutterLocalNotificationsPlugin.show( - message.id.hashCode, - '${message.user.name} @ ${channel.name}', - message.text, - NotificationDetails( - android: AndroidNotificationDetails( - 'message channel', - 'Message channel', - 'Channel used for showing messages', - priority: Priority.high, - importance: Importance.high, - ), - iOS: IOSNotificationDetails(), - ), - ); -} - -Future backgroundHandler(Map notification) async { - final messageId = notification['data']['message_id']; - - final notificationData = - await NotificationService.getAndStoreMessage(messageId); - - showLocalNotification( - notificationData.message, - notificationData.channel, - ); -} - -void _initNotifications(Client client) { - final connector = createPushConnector(); - connector.configure( - onBackgroundMessage: backgroundHandler, - ); - - connector.requestNotificationPermissions(); - connector.token.addListener(() { - if (connector.token.value != null) { - client.addDevice( - connector.token.value, - Platform.isAndroid ? 'firebase' : 'apn', - ); - } - }); -} - void main() async { final client = Client( 's2dxdhpxd94g', @@ -74,17 +15,6 @@ void main() async { persistenceEnabled: true, ); - await client.setUser( - User(id: 'super-band-9', extraData: { - 'name': 'Jonathan Doe', - }), - 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoic3VwZXItYmFuZC05In0.0L6lGoeLwkz0aZRUcpZKsvaXtNEDHBcezVTZ0oPq40A', - ); - - if (!kIsWeb) { - _initNotifications(client); - } - runApp(MyApp(client)); } @@ -98,16 +28,15 @@ class MyApp extends StatelessWidget { return MaterialApp( theme: ThemeData.light(), darkTheme: ThemeData.dark(), + //TODO change to system once dark theme is implemented themeMode: ThemeMode.light, - - ///TODO change to system once dark theme is implemented builder: (context, widget) { return StreamChat( child: widget, client: client, ); }, - home: ChannelListPage(), + home: ChooseUserPage(), ); } } diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 1e527964..e4604f44 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -1,7 +1,7 @@ name: example description: A new Flutter project. -version: 1.0.42+44 +version: 1.0.43+45 environment: sdk: ">=2.2.2 <3.0.0" @@ -13,6 +13,7 @@ dependencies: path: ../ flutter_apns: ^1.3.1 flutter_local_notifications: ^2.0.0 + flutter_svg: ^0.19.1 dev_dependencies: flutter_test: @@ -23,6 +24,8 @@ dev_dependencies: test: any flutter: + assets: + - assets/ uses-material-design: true flutter_icons: diff --git a/lib/src/stream_chat_theme.dart b/lib/src/stream_chat_theme.dart index cc959a35..1dfd42b7 100644 --- a/lib/src/stream_chat_theme.dart +++ b/lib/src/stream_chat_theme.dart @@ -218,6 +218,7 @@ class StreamChatThemeData { final accentColor = Color(0xff006cff); final isDark = theme.brightness == Brightness.dark; return StreamChatThemeData( + secondaryColor: Color(0xffEAEAEA), accentColor: accentColor, primaryColor: isDark ? Colors.black : Colors.white, primaryIconTheme: IconThemeData( diff --git a/lib/src/user_avatar.dart b/lib/src/user_avatar.dart index a86206eb..ce3d29ec 100644 --- a/lib/src/user_avatar.dart +++ b/lib/src/user_avatar.dart @@ -55,9 +55,7 @@ class UserAvatar extends StatelessWidget { errorWidget: (_, __, ___) { return Center( child: Text( - user.extraData?.containsKey('name') ?? false - ? user.extraData['name'][0] - : '', + user.name[0], style: TextStyle( color: Colors.white, fontWeight: FontWeight.bold, diff --git a/pubspec.yaml b/pubspec.yaml index 0e768587..e5c57193 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -26,7 +26,8 @@ dependencies: file_picker: ^2.0.8+1 image_picker: ^0.6.7+2 flutter_keyboard_visibility: ^3.2.1 - stream_chat: ^0.2.10+1 + stream_chat: + path: ../stream_chat_dart emojis: ^0.9.3 mime: ^0.9.6+3 visibility_detector: ^0.1.5 From 38c06d5de78b7e0be7c48c97aa0121ed9d85c10b Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Mon, 9 Nov 2020 13:02:46 +0530 Subject: [PATCH 0317/1140] fix: Fixed overflow bug --- lib/src/message_input.dart | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 5e4c7104..d3b568a6 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -600,6 +600,8 @@ class MessageInputState extends State { _filePickerSize -= update.delta.dy; if (_filePickerSize < 100) { _filePickerSize = 100.0; + } else if (_filePickerSize > 500) { + _filePickerSize = 500; } }); }, From 812f70284552d9827982c6b29d4ebd80f61d5826 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Mon, 9 Nov 2020 14:21:32 +0530 Subject: [PATCH 0318/1140] feat: Added selected image --- lib/src/message_input.dart | 467 +++++++++++++++++++++---------------- 1 file changed, 261 insertions(+), 206 deletions(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index d3b568a6..efb3af5e 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -20,9 +20,9 @@ import 'stream_channel.dart'; typedef FileUploader = Future Function(PlatformFile, Channel); typedef AttachmentThumbnailBuilder = Widget Function( - BuildContext, - _SendingAttachment, -); + BuildContext, + _SendingAttachment, + ); enum ActionsLocation { left, @@ -230,7 +230,7 @@ class MessageInputState extends State { Checkbox( value: _sendAsDm, onChanged: (val) => setState( - () { + () { _sendAsDm = val; }, ), @@ -247,7 +247,7 @@ class MessageInputState extends State { AnimatedCrossFade _animateSendButton(BuildContext context) { return AnimatedCrossFade( crossFadeState: ((_messageIsPresent || _attachments.isNotEmpty) && - _attachments.every((a) => a.uploaded == true)) + _attachments.every((a) => a.uploaded == true)) ? CrossFadeState.showFirst : CrossFadeState.showSecond, firstChild: _buildSendButton(context), @@ -260,7 +260,7 @@ class MessageInputState extends State { Widget _buildExpandActionsButton() { return AnimatedCrossFade( crossFadeState: - _actionsShrunk ? CrossFadeState.showFirst : CrossFadeState.showSecond, + _actionsShrunk ? CrossFadeState.showFirst : CrossFadeState.showSecond, firstChild: IconButton( onPressed: () { setState(() { @@ -353,7 +353,7 @@ class MessageInputState extends State { (s[textEditingController.selection.start - 1] == '@' || textEditingController.text .substring( - 0, textEditingController.selection.start) + 0, textEditingController.selection.start) .split(' ') .last .contains('@'))) { @@ -371,9 +371,9 @@ class MessageInputState extends State { textAlignVertical: TextAlignVertical.center, decoration: InputDecoration( hintText: - (_commandEnabled && _chosenCommand.name == 'giphy') - ? 'Search GIFs' - : 'Write a message', + (_commandEnabled && _chosenCommand.name == 'giphy') + ? 'Search GIFs' + : 'Write a message', prefixText: _commandEnabled ? null : ' ', border: OutlineInputBorder( borderSide: BorderSide(color: Colors.transparent)), @@ -388,31 +388,31 @@ class MessageInputState extends State { contentPadding: EdgeInsets.all(8), prefixIcon: _commandEnabled ? Padding( - padding: - const EdgeInsets.symmetric(horizontal: 8.0), - child: Chip( - backgroundColor: - StreamChatTheme.of(context).accentColor, - label: Text( - _chosenCommand?.name ?? "", - style: TextStyle(color: Colors.white), - ), - avatar: Icon( - StreamIcons.lightning, - color: Colors.white, - ), - ), - ) + padding: + const EdgeInsets.symmetric(horizontal: 8.0), + child: Chip( + backgroundColor: + StreamChatTheme.of(context).accentColor, + label: Text( + _chosenCommand?.name ?? "", + style: TextStyle(color: Colors.white), + ), + avatar: Icon( + StreamIcons.lightning, + color: Colors.white, + ), + ), + ) : null, suffixIcon: _commandEnabled ? IconButton( - icon: Icon(Icons.cancel_outlined), - onPressed: () { - setState(() { - _commandEnabled = false; - }); - }, - ) + icon: Icon(Icons.cancel_outlined), + onPressed: () { + setState(() { + _commandEnabled = false; + }); + }, + ) : null, ), textCapitalization: TextCapitalization.sentences, @@ -454,13 +454,13 @@ class MessageInputState extends State { child: Container( constraints: BoxConstraints.loose(Size.fromHeight(400)), decoration: BoxDecoration( - // boxShadow: [ - // BoxShadow( - // spreadRadius: -8, - // blurRadius: 5.0, - // offset: Offset(0, -4), - // ), - // ], + // boxShadow: [ + // BoxShadow( + // spreadRadius: -8, + // blurRadius: 5.0, + // offset: Offset(0, -4), + // ), + // ], color: StreamChatTheme.of(context).primaryColor, borderRadius: BorderRadius.circular(8.0)), child: ListView( @@ -474,7 +474,7 @@ class MessageInputState extends State { children: [ Padding( padding: - const EdgeInsets.symmetric(horizontal: 8.0), + const EdgeInsets.symmetric(horizontal: 8.0), child: Icon(StreamIcons.lightning, color: StreamChatTheme.of(context).accentColor), ), @@ -485,48 +485,48 @@ class MessageInputState extends State { ...commands .map( (c) => ListTile( - leading: c.name == 'giphy' - ? CircleAvatar( - backgroundColor: Colors.black, - child: Image.asset( - 'images/giphy_icon.png', - package: 'stream_chat_flutter', - width: 16.0, - height: 16.0, - ), - maxRadius: 12.0, - ) - : null, - title: Text.rich( - TextSpan( - text: '${c.name.capitalize()}', - style: TextStyle(fontWeight: FontWeight.bold), - children: [ - TextSpan( - text: ' /${c.name} ${c.args}', - style: TextStyle( - fontWeight: FontWeight.w300, - ), - ), - ], - ), - ), - trailing: CircleAvatar( - backgroundColor: - StreamChatTheme.of(context).accentColor, - child: Icon( - StreamIcons.lightning, - color: Colors.white, - size: 12.5, - ), - maxRadius: 12, - ), - //subtitle: Text(c.description), - onTap: () { - _setCommand(c); - }, + leading: c.name == 'giphy' + ? CircleAvatar( + backgroundColor: Colors.black, + child: Image.asset( + 'images/giphy_icon.png', + package: 'stream_chat_flutter', + width: 16.0, + height: 16.0, ), + maxRadius: 12.0, ) + : null, + title: Text.rich( + TextSpan( + text: '${c.name.capitalize()}', + style: TextStyle(fontWeight: FontWeight.bold), + children: [ + TextSpan( + text: ' /${c.name} ${c.args}', + style: TextStyle( + fontWeight: FontWeight.w300, + ), + ), + ], + ), + ), + trailing: CircleAvatar( + backgroundColor: + StreamChatTheme.of(context).accentColor, + child: Icon( + StreamIcons.lightning, + color: Colors.white, + size: 12.5, + ), + maxRadius: 12, + ), + //subtitle: Text(c.description), + onTap: () { + _setCommand(c); + }, + ), + ) .toList(), ], ), @@ -637,7 +637,7 @@ class MessageInputState extends State { Widget _buildPickerSection() { switch (_filePickerIndex) { case 0: - return FutureBuilder>( + return FutureBuilder( future: _getAllMedia(), builder: (context, mediaData) { if (!mediaData.hasData) { @@ -647,40 +647,46 @@ class MessageInputState extends State { } return GridView.builder( - itemCount: mediaData.data.length, + itemCount: mediaData.data.item2.length, gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: 3), itemBuilder: (context, position) { - return FutureBuilder>( - future: PhotoGallery.getThumbnail( - mediumId: mediaData.data[position].id), - builder: (context, snapshot) { - if (!snapshot.hasData) { - return Center( - child: CircularProgressIndicator(), - ); - } - - return Padding( - padding: const EdgeInsets.symmetric( - horizontal: 1.0, vertical: 1.0), - child: InkWell( - child: AspectRatio( - child: Image.memory( - snapshot.data, - fit: mediaData.data[position].height > - mediaData.data[position].width - ? BoxFit.fitWidth - : BoxFit.fitHeight, - ), - aspectRatio: 1.0, + return Padding( + padding: const EdgeInsets.symmetric( + horizontal: 1.0, vertical: 1.0), + child: InkWell( + child: Stack( + children: [ + AspectRatio( + aspectRatio: 1.0, + child: Image.memory( + mediaData.data.item2[position], + fit: mediaData.data.item1[position].height > + mediaData.data.item1[position].width + ? BoxFit.fitWidth + : BoxFit.fitHeight, ), - onTap: () { - _addAttachment(mediaData.data[position]); - }, ), - ); - }); + if (_attachments.any((element) => + element.id == + mediaData.data.item1[position].id)) + Container( + color: Colors.black.withOpacity(0.5), + child: Center( + child: Icon( + StreamIcons.check_send, + color: Colors.white, + size: 24.0, + ), + ), + ), + ], + ), + onTap: () { + _addAttachment(mediaData.data.item1[position]); + }, + ), + ); }, ); }); @@ -715,6 +721,7 @@ class MessageInputState extends State { localUri: file.path != null ? Uri.parse(file.path) : null, type: medium.mediumType == MediumType.image ? 'image' : 'video', ), + id: medium.id, ); setState(() { @@ -747,10 +754,11 @@ class MessageInputState extends State { }); } - Future> _getAllMedia() async { + Future, List>> _getAllMedia() async { var allAlbums = await PhotoGallery.listAlbums(mediumType: MediumType.image); //var allVideoAlbums = await PhotoGallery.listAlbums(mediumType: MediumType.video); List resultList = []; + List> resultThumbnailList = []; for (var album in allAlbums) { var data = await album.listMedia(); @@ -764,7 +772,11 @@ class MessageInputState extends State { resultList.sort((a, b) => a.modifiedDate.compareTo(b.modifiedDate)); - return resultList; + for (var e in resultList) { + resultThumbnailList.add(await PhotoGallery.getThumbnail(mediumId: e.id)); + } + + return Tuple2, List>(resultList, resultThumbnailList); } OverlayEntry _buildMentionsOverlayEntry() { @@ -784,8 +796,8 @@ class MessageInputState extends State { } final members = StreamChannel.of(context).channel.state.members?.where((m) { - return m.user.name.toLowerCase().contains(query); - })?.toList() ?? + return m.user.name.toLowerCase().contains(query); + })?.toList() ?? []; RenderBox renderBox = context.findRenderObject(); @@ -825,38 +837,38 @@ class MessageInputState extends State { shrinkWrap: true, children: snapshot.data .map((m) => ListTile( - leading: UserAvatar( - user: m.user, - ), - title: Text( - '${m.user.name}', - style: TextStyle(fontWeight: FontWeight.bold), - ), - subtitle: Text('@${m.userId}'), - trailing: Icon( - StreamIcons.at_mention, - color: StreamChatTheme.of(context).accentColor, - ), - onTap: () { - _mentionedUsers.add(m.user); + leading: UserAvatar( + user: m.user, + ), + title: Text( + '${m.user.name}', + style: TextStyle(fontWeight: FontWeight.bold), + ), + subtitle: Text('@${m.userId}'), + trailing: Icon( + StreamIcons.at_mention, + color: StreamChatTheme.of(context).accentColor, + ), + onTap: () { + _mentionedUsers.add(m.user); - splits[splits.length - 1] = m.user.name; - final rejoin = splits.join('@'); + splits[splits.length - 1] = m.user.name; + final rejoin = splits.join('@'); - textEditingController.value = TextEditingValue( - text: rejoin + - textEditingController.text.substring( - textEditingController - .selection.start), - selection: TextSelection.collapsed( - offset: rejoin.length, - ), - ); + textEditingController.value = TextEditingValue( + text: rejoin + + textEditingController.text.substring( + textEditingController + .selection.start), + selection: TextSelection.collapsed( + offset: rejoin.length, + ), + ); - _mentionsOverlay?.remove(); - _mentionsOverlay = null; - }, - )) + _mentionsOverlay?.remove(); + _mentionsOverlay = null; + }, + )) .toList(), ); }), @@ -881,44 +893,44 @@ class MessageInputState extends State { return _attachments.isEmpty ? Container() : LimitedBox( - maxHeight: 76.0, - child: ListView( - scrollDirection: Axis.horizontal, - children: _attachments - .map( - (attachment) => Padding( - padding: const EdgeInsets.all(8.0), - child: ClipRRect( - borderRadius: BorderRadius.circular(10), - child: Stack( - children: [ - AspectRatio( - aspectRatio: 1.0, - child: Container( - height: 50, - width: 50, - child: _buildAttachment(attachment), - ), - ), - _buildRemoveButton(attachment), - attachment.uploaded - ? SizedBox() - : Positioned.fill( - child: Center( - child: Padding( - padding: const EdgeInsets.all(16.0), - child: CircularProgressIndicator(), - ), - ), - ), - ], - ), + maxHeight: 76.0, + child: ListView( + scrollDirection: Axis.horizontal, + children: _attachments + .map( + (attachment) => Padding( + padding: const EdgeInsets.all(8.0), + child: ClipRRect( + borderRadius: BorderRadius.circular(10), + child: Stack( + children: [ + AspectRatio( + aspectRatio: 1.0, + child: Container( + height: 50, + width: 50, + child: _buildAttachment(attachment), + ), + ), + _buildRemoveButton(attachment), + attachment.uploaded + ? SizedBox() + : Positioned.fill( + child: Center( + child: Padding( + padding: const EdgeInsets.all(16.0), + child: CircularProgressIndicator(), ), ), - ) - .toList(), + ), + ], + ), ), - ); + ), + ) + .toList(), + ), + ); } Positioned _buildRemoveButton(_SendingAttachment attachment) { @@ -954,7 +966,7 @@ class MessageInputState extends State { Widget _buildAttachment(_SendingAttachment attachment) { if (widget.attachmentThumbnailBuilders - ?.containsKey(attachment.attachment.type) == + ?.containsKey(attachment.attachment.type) == true) { return widget.attachmentThumbnailBuilders[attachment.attachment.type]( context, @@ -967,14 +979,14 @@ class MessageInputState extends State { case 'giphy': return attachment.file != null ? Image.memory( - attachment.file.bytes, - fit: BoxFit.cover, - ) + attachment.file.bytes, + fit: BoxFit.cover, + ) : Image.network( - attachment.attachment.imageUrl ?? - attachment.attachment.thumbUrl, - fit: BoxFit.cover, - ); + attachment.attachment.imageUrl ?? + attachment.attachment.thumbUrl, + fit: BoxFit.cover, + ); break; case 'video': return Container( @@ -1020,7 +1032,7 @@ class MessageInputState extends State { child: InkWell( child: Padding( padding: - EdgeInsets.only(left: 8.0, right: padding, top: 8.0, bottom: 8.0), + EdgeInsets.only(left: 8.0, right: padding, top: 8.0, bottom: 8.0), child: Icon( StreamIcons.attach, color: Color(0xFF000000).withAlpha(128), @@ -1220,10 +1232,10 @@ class MessageInputState extends State { } Future _uploadAttachment( - PlatformFile file, - DefaultAttachmentTypes type, - Channel channel, - ) async { + PlatformFile file, + DefaultAttachmentTypes type, + Channel channel, + ) async { String url; if (type == DefaultAttachmentTypes.image) { if (widget.doImageUploadRequest != null) { @@ -1270,19 +1282,19 @@ class MessageInputState extends State { Widget _buildIdleSendButton(BuildContext context) { return IconTheme( data: - StreamChatTheme.of(context).channelTheme.messageInputButtonIconTheme, + StreamChatTheme.of(context).channelTheme.messageInputButtonIconTheme, child: Padding( padding: const EdgeInsets.all(8.0), child: Center( child: InkWell( - onTap: () { - sendMessage(); - }, - child: Icon( - _getIdleSendIcon(), - color: Colors.grey, - ), - )), + onTap: () { + sendMessage(); + }, + child: Icon( + _getIdleSendIcon(), + color: Colors.grey, + ), + )), ), ); } @@ -1290,7 +1302,7 @@ class MessageInputState extends State { Widget _buildSendButton(BuildContext context) { return IconTheme( data: - StreamChatTheme.of(context).channelTheme.messageInputButtonIconTheme, + StreamChatTheme.of(context).channelTheme.messageInputButtonIconTheme, child: Center( child: Padding( padding: const EdgeInsets.all(8.0), @@ -1370,7 +1382,7 @@ class MessageInputState extends State { text: text, attachments: _getAttachments(attachments).toList(), mentionedUsers: - _mentionedUsers.where((u) => text.contains('@${u.name}')).toList(), + _mentionedUsers.where((u) => text.contains('@${u.name}')).toList(), ); } else { message = (widget.initialMessage ?? Message()).copyWith( @@ -1378,7 +1390,7 @@ class MessageInputState extends State { text: text, attachments: _getAttachments(attachments).toList(), mentionedUsers: - _mentionedUsers.where((u) => text.contains('@${u.name}')).toList(), + _mentionedUsers.where((u) => text.contains('@${u.name}')).toList(), showInChannel: widget.parentMessage != null ? _sendAsDm : null, ); } @@ -1392,9 +1404,9 @@ class MessageInputState extends State { sendingFuture = channel.sendMessage(message); } else { sendingFuture = StreamChat.of(context).client.updateMessage( - message, - channel.cid, - ); + message, + channel.cid, + ); } return sendingFuture.then((resp) { @@ -1501,11 +1513,13 @@ class _SendingAttachment { PlatformFile file; Attachment attachment; bool uploaded; + String id; _SendingAttachment({ this.file, this.attachment, this.uploaded = false, + this.id, }); } @@ -1514,3 +1528,44 @@ extension StringExtension on String { return "${this[0].toUpperCase()}${this.substring(1)}"; } } + +/// Represents a 2-tuple, or pair. +class Tuple2 { + /// Returns the first item of the tuple + final T1 item1; + + /// Returns the second item of the tuple + final T2 item2; + + /// Creates a new tuple value with the specified items. + const Tuple2(this.item1, this.item2); + + /// Create a new tuple value with the specified list [items]. + factory Tuple2.fromList(List items) { + if (items.length != 2) { + throw ArgumentError('items must have length 2'); + } + + return Tuple2(items[0] as T1, items[1] as T2); + } + + /// Returns a tuple with the first item set to the specified value. + Tuple2 withItem1(T1 v) => Tuple2(v, item2); + + /// Returns a tuple with the second item set to the specified value. + Tuple2 withItem2(T2 v) => Tuple2(item1, v); + + /// Creates a [List] containing the items of this [Tuple2]. + /// + /// The elements are in item order. The list is variable-length + /// if [growable] is true. + List toList({bool growable = false}) => + List.from([item1, item2], growable: growable); + + @override + String toString() => '[$item1, $item2]'; + + @override + bool operator ==(Object other) => + other is Tuple2 && other.item1 == item1 && other.item2 == item2; +} From a06b7c2cd88d7264b769027bfcde506143ad03b5 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Mon, 9 Nov 2020 14:38:25 +0530 Subject: [PATCH 0319/1140] feat: Added remove image --- lib/src/message_input.dart | 360 +++++++++++++++++++------------------ 1 file changed, 183 insertions(+), 177 deletions(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index efb3af5e..72066008 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -20,9 +20,9 @@ import 'stream_channel.dart'; typedef FileUploader = Future Function(PlatformFile, Channel); typedef AttachmentThumbnailBuilder = Widget Function( - BuildContext, - _SendingAttachment, - ); + BuildContext, + _SendingAttachment, +); enum ActionsLocation { left, @@ -230,7 +230,7 @@ class MessageInputState extends State { Checkbox( value: _sendAsDm, onChanged: (val) => setState( - () { + () { _sendAsDm = val; }, ), @@ -247,7 +247,7 @@ class MessageInputState extends State { AnimatedCrossFade _animateSendButton(BuildContext context) { return AnimatedCrossFade( crossFadeState: ((_messageIsPresent || _attachments.isNotEmpty) && - _attachments.every((a) => a.uploaded == true)) + _attachments.every((a) => a.uploaded == true)) ? CrossFadeState.showFirst : CrossFadeState.showSecond, firstChild: _buildSendButton(context), @@ -260,7 +260,7 @@ class MessageInputState extends State { Widget _buildExpandActionsButton() { return AnimatedCrossFade( crossFadeState: - _actionsShrunk ? CrossFadeState.showFirst : CrossFadeState.showSecond, + _actionsShrunk ? CrossFadeState.showFirst : CrossFadeState.showSecond, firstChild: IconButton( onPressed: () { setState(() { @@ -353,7 +353,7 @@ class MessageInputState extends State { (s[textEditingController.selection.start - 1] == '@' || textEditingController.text .substring( - 0, textEditingController.selection.start) + 0, textEditingController.selection.start) .split(' ') .last .contains('@'))) { @@ -371,9 +371,9 @@ class MessageInputState extends State { textAlignVertical: TextAlignVertical.center, decoration: InputDecoration( hintText: - (_commandEnabled && _chosenCommand.name == 'giphy') - ? 'Search GIFs' - : 'Write a message', + (_commandEnabled && _chosenCommand.name == 'giphy') + ? 'Search GIFs' + : 'Write a message', prefixText: _commandEnabled ? null : ' ', border: OutlineInputBorder( borderSide: BorderSide(color: Colors.transparent)), @@ -388,31 +388,31 @@ class MessageInputState extends State { contentPadding: EdgeInsets.all(8), prefixIcon: _commandEnabled ? Padding( - padding: - const EdgeInsets.symmetric(horizontal: 8.0), - child: Chip( - backgroundColor: - StreamChatTheme.of(context).accentColor, - label: Text( - _chosenCommand?.name ?? "", - style: TextStyle(color: Colors.white), - ), - avatar: Icon( - StreamIcons.lightning, - color: Colors.white, - ), - ), - ) + padding: + const EdgeInsets.symmetric(horizontal: 8.0), + child: Chip( + backgroundColor: + StreamChatTheme.of(context).accentColor, + label: Text( + _chosenCommand?.name ?? "", + style: TextStyle(color: Colors.white), + ), + avatar: Icon( + StreamIcons.lightning, + color: Colors.white, + ), + ), + ) : null, suffixIcon: _commandEnabled ? IconButton( - icon: Icon(Icons.cancel_outlined), - onPressed: () { - setState(() { - _commandEnabled = false; - }); - }, - ) + icon: Icon(Icons.cancel_outlined), + onPressed: () { + setState(() { + _commandEnabled = false; + }); + }, + ) : null, ), textCapitalization: TextCapitalization.sentences, @@ -454,13 +454,13 @@ class MessageInputState extends State { child: Container( constraints: BoxConstraints.loose(Size.fromHeight(400)), decoration: BoxDecoration( - // boxShadow: [ - // BoxShadow( - // spreadRadius: -8, - // blurRadius: 5.0, - // offset: Offset(0, -4), - // ), - // ], + // boxShadow: [ + // BoxShadow( + // spreadRadius: -8, + // blurRadius: 5.0, + // offset: Offset(0, -4), + // ), + // ], color: StreamChatTheme.of(context).primaryColor, borderRadius: BorderRadius.circular(8.0)), child: ListView( @@ -474,7 +474,7 @@ class MessageInputState extends State { children: [ Padding( padding: - const EdgeInsets.symmetric(horizontal: 8.0), + const EdgeInsets.symmetric(horizontal: 8.0), child: Icon(StreamIcons.lightning, color: StreamChatTheme.of(context).accentColor), ), @@ -485,48 +485,48 @@ class MessageInputState extends State { ...commands .map( (c) => ListTile( - leading: c.name == 'giphy' - ? CircleAvatar( - backgroundColor: Colors.black, - child: Image.asset( - 'images/giphy_icon.png', - package: 'stream_chat_flutter', - width: 16.0, - height: 16.0, - ), - maxRadius: 12.0, - ) - : null, - title: Text.rich( - TextSpan( - text: '${c.name.capitalize()}', - style: TextStyle(fontWeight: FontWeight.bold), - children: [ + leading: c.name == 'giphy' + ? CircleAvatar( + backgroundColor: Colors.black, + child: Image.asset( + 'images/giphy_icon.png', + package: 'stream_chat_flutter', + width: 16.0, + height: 16.0, + ), + maxRadius: 12.0, + ) + : null, + title: Text.rich( TextSpan( - text: ' /${c.name} ${c.args}', - style: TextStyle( - fontWeight: FontWeight.w300, - ), + text: '${c.name.capitalize()}', + style: TextStyle(fontWeight: FontWeight.bold), + children: [ + TextSpan( + text: ' /${c.name} ${c.args}', + style: TextStyle( + fontWeight: FontWeight.w300, + ), + ), + ], ), - ], + ), + trailing: CircleAvatar( + backgroundColor: + StreamChatTheme.of(context).accentColor, + child: Icon( + StreamIcons.lightning, + color: Colors.white, + size: 12.5, + ), + maxRadius: 12, + ), + //subtitle: Text(c.description), + onTap: () { + _setCommand(c); + }, ), - ), - trailing: CircleAvatar( - backgroundColor: - StreamChatTheme.of(context).accentColor, - child: Icon( - StreamIcons.lightning, - color: Colors.white, - size: 12.5, - ), - maxRadius: 12, - ), - //subtitle: Text(c.description), - onTap: () { - _setCommand(c); - }, - ), - ) + ) .toList(), ], ), @@ -662,14 +662,13 @@ class MessageInputState extends State { child: Image.memory( mediaData.data.item2[position], fit: mediaData.data.item1[position].height > - mediaData.data.item1[position].width + mediaData.data.item1[position].width ? BoxFit.fitWidth : BoxFit.fitHeight, ), ), if (_attachments.any((element) => - element.id == - mediaData.data.item1[position].id)) + element.id == mediaData.data.item1[position].id)) Container( color: Colors.black.withOpacity(0.5), child: Center( @@ -683,7 +682,14 @@ class MessageInputState extends State { ], ), onTap: () { - _addAttachment(mediaData.data.item1[position]); + if (!_attachments.any((element) => + element.id == mediaData.data.item1[position].id)) { + _addAttachment(mediaData.data.item1[position]); + } else { + _attachments.removeWhere((element) => + element.id == mediaData.data.item1[position].id); + setState(() {}); + } }, ), ); @@ -796,8 +802,8 @@ class MessageInputState extends State { } final members = StreamChannel.of(context).channel.state.members?.where((m) { - return m.user.name.toLowerCase().contains(query); - })?.toList() ?? + return m.user.name.toLowerCase().contains(query); + })?.toList() ?? []; RenderBox renderBox = context.findRenderObject(); @@ -837,38 +843,38 @@ class MessageInputState extends State { shrinkWrap: true, children: snapshot.data .map((m) => ListTile( - leading: UserAvatar( - user: m.user, - ), - title: Text( - '${m.user.name}', - style: TextStyle(fontWeight: FontWeight.bold), - ), - subtitle: Text('@${m.userId}'), - trailing: Icon( - StreamIcons.at_mention, - color: StreamChatTheme.of(context).accentColor, - ), - onTap: () { - _mentionedUsers.add(m.user); + leading: UserAvatar( + user: m.user, + ), + title: Text( + '${m.user.name}', + style: TextStyle(fontWeight: FontWeight.bold), + ), + subtitle: Text('@${m.userId}'), + trailing: Icon( + StreamIcons.at_mention, + color: StreamChatTheme.of(context).accentColor, + ), + onTap: () { + _mentionedUsers.add(m.user); - splits[splits.length - 1] = m.user.name; - final rejoin = splits.join('@'); + splits[splits.length - 1] = m.user.name; + final rejoin = splits.join('@'); - textEditingController.value = TextEditingValue( - text: rejoin + - textEditingController.text.substring( - textEditingController - .selection.start), - selection: TextSelection.collapsed( - offset: rejoin.length, - ), - ); + textEditingController.value = TextEditingValue( + text: rejoin + + textEditingController.text.substring( + textEditingController + .selection.start), + selection: TextSelection.collapsed( + offset: rejoin.length, + ), + ); - _mentionsOverlay?.remove(); - _mentionsOverlay = null; - }, - )) + _mentionsOverlay?.remove(); + _mentionsOverlay = null; + }, + )) .toList(), ); }), @@ -893,44 +899,44 @@ class MessageInputState extends State { return _attachments.isEmpty ? Container() : LimitedBox( - maxHeight: 76.0, - child: ListView( - scrollDirection: Axis.horizontal, - children: _attachments - .map( - (attachment) => Padding( - padding: const EdgeInsets.all(8.0), - child: ClipRRect( - borderRadius: BorderRadius.circular(10), - child: Stack( - children: [ - AspectRatio( - aspectRatio: 1.0, - child: Container( - height: 50, - width: 50, - child: _buildAttachment(attachment), - ), - ), - _buildRemoveButton(attachment), - attachment.uploaded - ? SizedBox() - : Positioned.fill( - child: Center( - child: Padding( - padding: const EdgeInsets.all(16.0), - child: CircularProgressIndicator(), + maxHeight: 76.0, + child: ListView( + scrollDirection: Axis.horizontal, + children: _attachments + .map( + (attachment) => Padding( + padding: const EdgeInsets.all(8.0), + child: ClipRRect( + borderRadius: BorderRadius.circular(10), + child: Stack( + children: [ + AspectRatio( + aspectRatio: 1.0, + child: Container( + height: 50, + width: 50, + child: _buildAttachment(attachment), + ), + ), + _buildRemoveButton(attachment), + attachment.uploaded + ? SizedBox() + : Positioned.fill( + child: Center( + child: Padding( + padding: const EdgeInsets.all(16.0), + child: CircularProgressIndicator(), + ), + ), + ), + ], + ), ), ), - ), - ], - ), + ) + .toList(), ), - ), - ) - .toList(), - ), - ); + ); } Positioned _buildRemoveButton(_SendingAttachment attachment) { @@ -966,7 +972,7 @@ class MessageInputState extends State { Widget _buildAttachment(_SendingAttachment attachment) { if (widget.attachmentThumbnailBuilders - ?.containsKey(attachment.attachment.type) == + ?.containsKey(attachment.attachment.type) == true) { return widget.attachmentThumbnailBuilders[attachment.attachment.type]( context, @@ -979,14 +985,14 @@ class MessageInputState extends State { case 'giphy': return attachment.file != null ? Image.memory( - attachment.file.bytes, - fit: BoxFit.cover, - ) + attachment.file.bytes, + fit: BoxFit.cover, + ) : Image.network( - attachment.attachment.imageUrl ?? - attachment.attachment.thumbUrl, - fit: BoxFit.cover, - ); + attachment.attachment.imageUrl ?? + attachment.attachment.thumbUrl, + fit: BoxFit.cover, + ); break; case 'video': return Container( @@ -1032,7 +1038,7 @@ class MessageInputState extends State { child: InkWell( child: Padding( padding: - EdgeInsets.only(left: 8.0, right: padding, top: 8.0, bottom: 8.0), + EdgeInsets.only(left: 8.0, right: padding, top: 8.0, bottom: 8.0), child: Icon( StreamIcons.attach, color: Color(0xFF000000).withAlpha(128), @@ -1232,10 +1238,10 @@ class MessageInputState extends State { } Future _uploadAttachment( - PlatformFile file, - DefaultAttachmentTypes type, - Channel channel, - ) async { + PlatformFile file, + DefaultAttachmentTypes type, + Channel channel, + ) async { String url; if (type == DefaultAttachmentTypes.image) { if (widget.doImageUploadRequest != null) { @@ -1282,19 +1288,19 @@ class MessageInputState extends State { Widget _buildIdleSendButton(BuildContext context) { return IconTheme( data: - StreamChatTheme.of(context).channelTheme.messageInputButtonIconTheme, + StreamChatTheme.of(context).channelTheme.messageInputButtonIconTheme, child: Padding( padding: const EdgeInsets.all(8.0), child: Center( child: InkWell( - onTap: () { - sendMessage(); - }, - child: Icon( - _getIdleSendIcon(), - color: Colors.grey, - ), - )), + onTap: () { + sendMessage(); + }, + child: Icon( + _getIdleSendIcon(), + color: Colors.grey, + ), + )), ), ); } @@ -1302,7 +1308,7 @@ class MessageInputState extends State { Widget _buildSendButton(BuildContext context) { return IconTheme( data: - StreamChatTheme.of(context).channelTheme.messageInputButtonIconTheme, + StreamChatTheme.of(context).channelTheme.messageInputButtonIconTheme, child: Center( child: Padding( padding: const EdgeInsets.all(8.0), @@ -1382,7 +1388,7 @@ class MessageInputState extends State { text: text, attachments: _getAttachments(attachments).toList(), mentionedUsers: - _mentionedUsers.where((u) => text.contains('@${u.name}')).toList(), + _mentionedUsers.where((u) => text.contains('@${u.name}')).toList(), ); } else { message = (widget.initialMessage ?? Message()).copyWith( @@ -1390,7 +1396,7 @@ class MessageInputState extends State { text: text, attachments: _getAttachments(attachments).toList(), mentionedUsers: - _mentionedUsers.where((u) => text.contains('@${u.name}')).toList(), + _mentionedUsers.where((u) => text.contains('@${u.name}')).toList(), showInChannel: widget.parentMessage != null ? _sendAsDm : null, ); } @@ -1404,9 +1410,9 @@ class MessageInputState extends State { sendingFuture = channel.sendMessage(message); } else { sendingFuture = StreamChat.of(context).client.updateMessage( - message, - channel.cid, - ); + message, + channel.cid, + ); } return sendingFuture.then((resp) { From 909587a127d5d5e2caa25d7e0a83de60e7ff6849 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Mon, 9 Nov 2020 14:50:09 +0530 Subject: [PATCH 0320/1140] fix: Fixed picture flickering --- lib/src/message_input.dart | 111 ++++++++++++++++++------------------- 1 file changed, 53 insertions(+), 58 deletions(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 72066008..74ed535a 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -177,6 +177,8 @@ class MessageInputState extends State { int _filePickerIndex = 0; double _filePickerSize = 250.0; + Tuple2, List> _mediaData = Tuple2([], []); + /// The editing controller passed to the input TextField TextEditingController textEditingController; @@ -637,65 +639,55 @@ class MessageInputState extends State { Widget _buildPickerSection() { switch (_filePickerIndex) { case 0: - return FutureBuilder( - future: _getAllMedia(), - builder: (context, mediaData) { - if (!mediaData.hasData) { - return Center( - child: CircularProgressIndicator(), - ); - } - - return GridView.builder( - itemCount: mediaData.data.item2.length, - gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( - crossAxisCount: 3), - itemBuilder: (context, position) { - return Padding( - padding: const EdgeInsets.symmetric( - horizontal: 1.0, vertical: 1.0), - child: InkWell( - child: Stack( - children: [ - AspectRatio( - aspectRatio: 1.0, - child: Image.memory( - mediaData.data.item2[position], - fit: mediaData.data.item1[position].height > - mediaData.data.item1[position].width - ? BoxFit.fitWidth - : BoxFit.fitHeight, - ), - ), - if (_attachments.any((element) => - element.id == mediaData.data.item1[position].id)) - Container( - color: Colors.black.withOpacity(0.5), - child: Center( - child: Icon( - StreamIcons.check_send, - color: Colors.white, - size: 24.0, - ), - ), - ), - ], + return GridView.builder( + itemCount: _mediaData.item2.length, + gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: 3), + itemBuilder: (context, position) { + return Padding( + padding: const EdgeInsets.symmetric( + horizontal: 1.0, vertical: 1.0), + child: InkWell( + child: Stack( + children: [ + AspectRatio( + aspectRatio: 1.0, + child: Image.memory( + _mediaData.item2[position], + fit: _mediaData.item1[position].height > + _mediaData.item1[position].width + ? BoxFit.fitWidth + : BoxFit.fitHeight, ), - onTap: () { - if (!_attachments.any((element) => - element.id == mediaData.data.item1[position].id)) { - _addAttachment(mediaData.data.item1[position]); - } else { - _attachments.removeWhere((element) => - element.id == mediaData.data.item1[position].id); - setState(() {}); - } - }, ), - ); + if (_attachments.any((element) => + element.id == _mediaData.item1[position].id)) + Container( + color: Colors.black.withOpacity(0.5), + child: Center( + child: Icon( + StreamIcons.check_send, + color: Colors.white, + size: 24.0, + ), + ), + ), + ], + ), + onTap: () { + if (!_attachments.any((element) => + element.id == _mediaData.item1[position].id)) { + _addAttachment(_mediaData.item1[position]); + } else { + _attachments.removeWhere((element) => + element.id == _mediaData.item1[position].id); + setState(() {}); + } }, - ); - }); + ), + ); + }, + ); break; case 1: break; @@ -760,7 +752,7 @@ class MessageInputState extends State { }); } - Future, List>> _getAllMedia() async { + void _getAllMedia() async { var allAlbums = await PhotoGallery.listAlbums(mediumType: MediumType.image); //var allVideoAlbums = await PhotoGallery.listAlbums(mediumType: MediumType.video); List resultList = []; @@ -782,7 +774,9 @@ class MessageInputState extends State { resultThumbnailList.add(await PhotoGallery.getThumbnail(mediumId: e.id)); } - return Tuple2, List>(resultList, resultThumbnailList); + setState(() { + _mediaData = Tuple2, List>(resultList, resultThumbnailList); + }); } OverlayEntry _buildMentionsOverlayEntry() { @@ -1051,6 +1045,7 @@ class MessageInputState extends State { _filePickerSize = 250.0; }); } else { + _getAllMedia(); showAttachmentModal(); } }, From 5c2de165810e04466bad9218e7033817e1d70a48 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Mon, 9 Nov 2020 11:17:39 +0100 Subject: [PATCH 0321/1140] move gesture detector --- lib/src/message_input.dart | 44 +++++++++++++++++++------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 2ba93347..ad70f148 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -657,28 +657,28 @@ class MessageInputState extends State { ), ], ), - Container( - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.only( - topLeft: Radius.circular(16.0), - topRight: Radius.circular(16.0), + GestureDetector( + onVerticalDragUpdate: (update) { + setState(() { + _filePickerSize -= update.delta.dy; + if (_filePickerSize < 100) { + _filePickerSize = 100.0; + } else if (_filePickerSize > 500) { + _filePickerSize = 500; + } + }); + }, + child: Container( + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.only( + topLeft: Radius.circular(16.0), + topRight: Radius.circular(16.0), + ), ), - ), - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - GestureDetector( - onVerticalDragUpdate: (update) { - setState(() { - _filePickerSize -= update.delta.dy; - if (_filePickerSize < 100) { - _filePickerSize = 100.0; - } else if (_filePickerSize > 500) { - _filePickerSize = 500; - } - }); - }, + child: Container( + width: double.infinity, + child: Center( child: Padding( padding: const EdgeInsets.all(8.0), child: Container( @@ -691,7 +691,7 @@ class MessageInputState extends State { ), ), ), - ], + ), ), ), Expanded( From 27c3447c2eaa62f70eb2703e9681b9ece8353364 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Mon, 9 Nov 2020 11:20:21 +0100 Subject: [PATCH 0322/1140] fix remove attachment indicator color --- lib/src/message_input.dart | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index ad70f148..ff243bbe 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -1169,11 +1169,12 @@ class MessageInputState extends State { _attachments.remove(attachment); }); }, - fillColor: Colors.white.withOpacity(.5), + fillColor: Colors.black.withOpacity(.5), child: Center( child: Icon( - Icons.close, + StreamIcons.close, size: 15, + color: Colors.white, ), ), ), From 0867d7a4dba8d93c217cc941ce5f8dd866aea463 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Mon, 9 Nov 2020 17:19:34 +0530 Subject: [PATCH 0323/1140] fix: Fixed issues --- lib/src/message_input.dart | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index ff243bbe..38ae6eb6 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -737,10 +737,13 @@ class MessageInputState extends State { Container( color: Colors.black.withOpacity(0.5), child: Center( - child: Icon( - StreamIcons.check_send, - color: Colors.white, - size: 24.0, + child: CircleAvatar( + maxRadius: 12.0, + backgroundColor: Colors.white, + child: Icon( + StreamIcons.check, + color: Colors.black, + ), ), ), ), @@ -826,7 +829,7 @@ class MessageInputState extends State { void _getAllMedia() async { var allAlbums = await PhotoGallery.listAlbums(mediumType: MediumType.image); - //var allVideoAlbums = await PhotoGallery.listAlbums(mediumType: MediumType.video); + var allVideoAlbums = await PhotoGallery.listAlbums(mediumType: MediumType.video); List resultList = []; List> resultThumbnailList = []; @@ -835,12 +838,13 @@ class MessageInputState extends State { resultList.addAll(data.items); } - // for (var album in allVideoAlbums) { - // var data = await album.listMedia(); - // resultList.addAll(data.items); - // } + for (var album in allVideoAlbums) { + var data = await album.listMedia(); + resultList.addAll(data.items); + } resultList.sort((a, b) => a.modifiedDate.compareTo(b.modifiedDate)); + resultList = resultList.toSet().toList(); for (var e in resultList) { resultThumbnailList.add(await PhotoGallery.getThumbnail(mediumId: e.id)); From 58e66ee28ff4ae3920cc08215df4087212739dfc Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Mon, 9 Nov 2020 13:33:29 +0100 Subject: [PATCH 0324/1140] fix overlay issues --- lib/src/message_input.dart | 44 ++++++-------------------------------- 1 file changed, 6 insertions(+), 38 deletions(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 38ae6eb6..de5f9c6a 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -377,7 +377,7 @@ class MessageInputState extends State { _emojiOverlay?.remove(); _emojiOverlay = null; - _checkCommands(s.trimLeft(), context); + _checkCommands(s, context); _checkMentions(s, context); @@ -829,7 +829,8 @@ class MessageInputState extends State { void _getAllMedia() async { var allAlbums = await PhotoGallery.listAlbums(mediumType: MediumType.image); - var allVideoAlbums = await PhotoGallery.listAlbums(mediumType: MediumType.video); + var allVideoAlbums = + await PhotoGallery.listAlbums(mediumType: MediumType.video); List resultList = []; List> resultThumbnailList = []; @@ -1659,42 +1660,9 @@ class MessageInputState extends State { if (!kIsWeb) { _keyboardListener = KeyboardVisibility.onChange.listen((visible) { if (visible) { - if (_commandsOverlay != null) { - if (textEditingController.text.trimLeft().startsWith('/')) { - WidgetsBinding.instance.addPostFrameCallback((_) { - _commandsOverlay = _buildCommandsOverlayEntry(); - Overlay.of(context).insert(_commandsOverlay); - }); - } - } - - if (_mentionsOverlay != null) { - if (textEditingController.text.contains('@')) { - WidgetsBinding.instance.addPostFrameCallback((_) { - _mentionsOverlay = _buildCommandsOverlayEntry(); - Overlay.of(context).insert(_mentionsOverlay); - }); - } - } - - if (_emojiOverlay != null) { - if (textEditingController.text.contains(':')) { - WidgetsBinding.instance.addPostFrameCallback((_) { - _emojiOverlay = _buildEmojiOverlay(); - Overlay.of(context).insert(_emojiOverlay); - }); - } - } - } else { - if (_commandsOverlay != null) { - _commandsOverlay.remove(); - } - if (_mentionsOverlay != null) { - _mentionsOverlay.remove(); - } - if (_emojiOverlay != null) { - _emojiOverlay.remove(); - } + _checkCommands(textEditingController.text, context); + _checkMentions(textEditingController.text, context); + _checkEmoji(textEditingController.text, context); } }); } From 9399e28869ccf8b29e76db2bc05c69ac9038c089 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Mon, 9 Nov 2020 18:11:45 +0530 Subject: [PATCH 0325/1140] feat, fix: Added animation, fixed modal issues --- lib/src/message_input.dart | 37 +++++++++++++++++++++++-------------- 1 file changed, 23 insertions(+), 14 deletions(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 38ae6eb6..70444ce9 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -663,8 +663,9 @@ class MessageInputState extends State { _filePickerSize -= update.delta.dy; if (_filePickerSize < 100) { _filePickerSize = 100.0; - } else if (_filePickerSize > 500) { - _filePickerSize = 500; + } else if (_filePickerSize > + MediaQuery.of(context).size.height / 1.7) { + _filePickerSize = MediaQuery.of(context).size.height / 1.7; } }); }, @@ -732,21 +733,28 @@ class MessageInputState extends State { : BoxFit.fitHeight, ), ), - if (_attachments.any((element) => - element.id == _mediaData.item1[position].id)) - Container( - color: Colors.black.withOpacity(0.5), - child: Center( - child: CircleAvatar( - maxRadius: 12.0, - backgroundColor: Colors.white, - child: Icon( - StreamIcons.check, - color: Colors.black, + IgnorePointer( + child: AnimatedOpacity( + duration: Duration(milliseconds: 300), + opacity: _attachments.any((element) => + element.id == _mediaData.item1[position].id) + ? 1.0 + : 0.0, + child: Container( + color: Colors.black.withOpacity(0.5), + child: Center( + child: CircleAvatar( + maxRadius: 12.0, + backgroundColor: Colors.white, + child: Icon( + StreamIcons.check, + color: Colors.black, + ), ), ), ), ), + ), ], ), onTap: () { @@ -829,7 +837,8 @@ class MessageInputState extends State { void _getAllMedia() async { var allAlbums = await PhotoGallery.listAlbums(mediumType: MediumType.image); - var allVideoAlbums = await PhotoGallery.listAlbums(mediumType: MediumType.video); + var allVideoAlbums = + await PhotoGallery.listAlbums(mediumType: MediumType.video); List resultList = []; List> resultThumbnailList = []; From 815b0120bf2eaf58d3d290e98244c494ce0be539 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Mon, 9 Nov 2020 14:45:12 +0100 Subject: [PATCH 0326/1140] fix iconbuttons splash animation --- lib/src/message_input.dart | 160 +++++++++++++++++++------------------ 1 file changed, 81 insertions(+), 79 deletions(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 61866612..f2f60652 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -613,98 +613,100 @@ class MessageInputState extends State { Widget _buildFilePickerSection() { return Container( - color: Color(0xFFF2F2F2), height: _filePickerSize, - child: Column( - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.start, - children: [ - IconButton( - icon: Icon( - StreamIcons.picture, - color: _filePickerIndex == 0 - ? StreamChatTheme.of(context).accentColor - : Colors.black.withOpacity(0.5), + child: Material( + color: Color(0xFFF2F2F2), + child: Column( + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + IconButton( + icon: Icon( + StreamIcons.picture, + color: _filePickerIndex == 0 + ? StreamChatTheme.of(context).accentColor + : Colors.black.withOpacity(0.5), + ), + onPressed: () { + setState(() { + _filePickerIndex = 0; + }); + }, ), - onPressed: () { - setState(() { - _filePickerIndex = 0; - }); - }, - ), - IconButton( - icon: Icon( - StreamIcons.folder, - color: _filePickerIndex == 1 - ? StreamChatTheme.of(context).accentColor - : Colors.black.withOpacity(0.5), + IconButton( + icon: Icon( + StreamIcons.folder, + color: _filePickerIndex == 1 + ? StreamChatTheme.of(context).accentColor + : Colors.black.withOpacity(0.5), + ), + onPressed: () { + pickFile(DefaultAttachmentTypes.file, false); + }, ), - onPressed: () { - pickFile(DefaultAttachmentTypes.file, false); - }, - ), - IconButton( - icon: Icon( - StreamIcons.camera, - color: _filePickerIndex == 2 - ? StreamChatTheme.of(context).accentColor - : Colors.black.withOpacity(0.5), + IconButton( + icon: Icon( + StreamIcons.camera, + color: _filePickerIndex == 2 + ? StreamChatTheme.of(context).accentColor + : Colors.black.withOpacity(0.5), + ), + onPressed: () { + pickFile(DefaultAttachmentTypes.image, true); + }, ), - onPressed: () { - pickFile(DefaultAttachmentTypes.image, true); - }, - ), - ], - ), - GestureDetector( - onVerticalDragUpdate: (update) { - setState(() { - _filePickerSize -= update.delta.dy; - if (_filePickerSize < 100) { - _filePickerSize = 100.0; - } else if (_filePickerSize > - MediaQuery.of(context).size.height / 1.7) { - _filePickerSize = MediaQuery.of(context).size.height / 1.7; - } - }); - }, - child: Container( - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.only( - topLeft: Radius.circular(16.0), - topRight: Radius.circular(16.0), - ), - ), + ], + ), + GestureDetector( + onVerticalDragUpdate: (update) { + setState(() { + _filePickerSize -= update.delta.dy; + if (_filePickerSize < 100) { + _filePickerSize = 100.0; + } else if (_filePickerSize > + MediaQuery.of(context).size.height / 1.7) { + _filePickerSize = MediaQuery.of(context).size.height / 1.7; + } + }); + }, child: Container( - width: double.infinity, - child: Center( - child: Padding( - padding: const EdgeInsets.all(8.0), - child: Container( - width: 40.0, - height: 4.0, - decoration: BoxDecoration( - color: Color(0xFFF2F2F2), - borderRadius: BorderRadius.circular(4.0), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.only( + topLeft: Radius.circular(16.0), + topRight: Radius.circular(16.0), + ), + ), + child: Container( + width: double.infinity, + child: Center( + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Container( + width: 40.0, + height: 4.0, + decoration: BoxDecoration( + color: Color(0xFFF2F2F2), + borderRadius: BorderRadius.circular(4.0), + ), ), ), ), ), ), ), - ), - Expanded( - child: Container( - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(8.0), + Expanded( + child: Container( + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(8.0), + ), + child: _buildPickerSection(), ), - child: _buildPickerSection(), ), - ), - ], + ], + ), ), ); } From ae0316fe4f969e9ae4da360db4985e63067760bd Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Mon, 9 Nov 2020 15:15:15 +0100 Subject: [PATCH 0327/1140] add animation --- lib/src/message_input.dart | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index f2f60652..9fd4e746 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -207,7 +207,7 @@ class MessageInputState extends State { padding: const EdgeInsets.symmetric(horizontal: 8.0), child: _buildDmCheckbox(), ), - if (_openFilePickerSection) _buildFilePickerSection(), + _buildFilePickerSection(), ], ), ), @@ -612,8 +612,9 @@ class MessageInputState extends State { } Widget _buildFilePickerSection() { - return Container( - height: _filePickerSize, + return AnimatedContainer( + duration: Duration(milliseconds: 300), + height: _openFilePickerSection ? _filePickerSize : 0, child: Material( color: Color(0xFFF2F2F2), child: Column( From bb6ba72b1a00912a4475c0af4d7e55902cab37b2 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Mon, 9 Nov 2020 18:39:16 +0100 Subject: [PATCH 0328/1140] refactoring --- example/lib/advanced_options_page.dart | 67 +-------- example/lib/choose_user_page.dart | 189 +++++++++---------------- example/lib/main.dart | 2 + example/lib/notifications_service.dart | 62 ++++++++ example/pubspec.yaml | 2 +- 5 files changed, 138 insertions(+), 184 deletions(-) create mode 100644 example/lib/notifications_service.dart diff --git a/example/lib/advanced_options_page.dart b/example/lib/advanced_options_page.dart index 4d1de2ae..b6062c30 100644 --- a/example/lib/advanced_options_page.dart +++ b/example/lib/advanced_options_page.dart @@ -1,70 +1,9 @@ -import 'dart:io'; - import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; -import 'package:flutter_apns/flutter_apns.dart'; -import 'package:flutter_local_notifications/flutter_local_notifications.dart' - hide Message; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; import 'main.dart'; - -void showLocalNotification(Message message, ChannelModel channel) async { - FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin = - FlutterLocalNotificationsPlugin(); - final initializationSettingsAndroid = - AndroidInitializationSettings('launch_background'); - final initializationSettingsIOS = IOSInitializationSettings(); - final initializationSettings = InitializationSettings( - android: initializationSettingsAndroid, - iOS: initializationSettingsIOS, - ); - await flutterLocalNotificationsPlugin.initialize(initializationSettings); - await flutterLocalNotificationsPlugin.show( - message.id.hashCode, - '${message.user.name} @ ${channel.name}', - message.text, - NotificationDetails( - android: AndroidNotificationDetails( - 'message channel', - 'Message channel', - 'Channel used for showing messages', - priority: Priority.high, - importance: Importance.high, - ), - iOS: IOSNotificationDetails(), - ), - ); -} - -Future backgroundHandler(Map notification) async { - final messageId = notification['data']['message_id']; - - final notificationData = - await NotificationService.getAndStoreMessage(messageId); - - showLocalNotification( - notificationData.message, - notificationData.channel, - ); -} - -void _initNotifications(Client client) { - final connector = createPushConnector(); - connector.configure( - onBackgroundMessage: backgroundHandler, - ); - - connector.requestNotificationPermissions(); - connector.token.addListener(() { - if (connector.token.value != null) { - client.addDevice( - connector.token.value, - Platform.isAndroid ? 'firebase' : 'apn', - ); - } - }); -} +import 'notifications_service.dart'; class AdvancedOptionsPage extends StatelessWidget { final _formKey = GlobalKey(); @@ -111,7 +50,7 @@ class AdvancedOptionsPage extends StatelessWidget { controller: _apiKeyController, validator: (value) { if (value.isEmpty) { - return 'Please enter the user Chat API Key'; + return 'Please enter the Chat API Key'; } return null; }, @@ -237,7 +176,7 @@ class AdvancedOptionsPage extends StatelessWidget { ); if (!kIsWeb) { - _initNotifications(client); + initNotifications(client); } Navigator.pop(context); diff --git a/example/lib/choose_user_page.dart b/example/lib/choose_user_page.dart index 2d9f1c7a..ef710e53 100644 --- a/example/lib/choose_user_page.dart +++ b/example/lib/choose_user_page.dart @@ -1,71 +1,11 @@ -import 'dart:io'; - import 'package:example/advanced_options_page.dart'; import 'package:example/main.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; -import 'package:flutter_apns/flutter_apns.dart'; -import 'package:flutter_local_notifications/flutter_local_notifications.dart' - hide Message; import 'package:flutter_svg/flutter_svg.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; -void showLocalNotification(Message message, ChannelModel channel) async { - FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin = - FlutterLocalNotificationsPlugin(); - final initializationSettingsAndroid = - AndroidInitializationSettings('launch_background'); - final initializationSettingsIOS = IOSInitializationSettings(); - final initializationSettings = InitializationSettings( - android: initializationSettingsAndroid, - iOS: initializationSettingsIOS, - ); - await flutterLocalNotificationsPlugin.initialize(initializationSettings); - await flutterLocalNotificationsPlugin.show( - message.id.hashCode, - '${message.user.name} @ ${channel.name}', - message.text, - NotificationDetails( - android: AndroidNotificationDetails( - 'message channel', - 'Message channel', - 'Channel used for showing messages', - priority: Priority.high, - importance: Importance.high, - ), - iOS: IOSNotificationDetails(), - ), - ); -} - -Future backgroundHandler(Map notification) async { - final messageId = notification['data']['message_id']; - - final notificationData = - await NotificationService.getAndStoreMessage(messageId); - - showLocalNotification( - notificationData.message, - notificationData.channel, - ); -} - -void _initNotifications(Client client) { - final connector = createPushConnector(); - connector.configure( - onBackgroundMessage: backgroundHandler, - ); - - connector.requestNotificationPermissions(); - connector.token.addListener(() { - if (connector.token.value != null) { - client.addDevice( - connector.token.value, - Platform.isAndroid ? 'firebase' : 'apn', - ); - } - }); -} +import 'notifications_service.dart'; class ChooseUserPage extends StatelessWidget { @override @@ -142,82 +82,93 @@ class ChooseUserPage extends StatelessWidget { ), ), Expanded( - child: ListView( - children: [ - ...users.entries.map((entry) { - final token = entry.key; - final user = entry.value; - return ListTile( - onTap: () async { - final client = StreamChat.of(context).client; + child: ListView.separated( + separatorBuilder: (context, i) { + return Container( + width: double.infinity, + color: Colors.black12, + height: 1, + ); + }, + itemCount: users.length + 1, + itemBuilder: (context, i) { + return [ + ...users.entries.map((entry) { + final token = entry.key; + final user = entry.value; + return ListTile( + onTap: () async { + final client = StreamChat.of(context).client; - await client.setUser( - User(id: user.id, extraData: { - 'name': user.name, - }), - token, - ); + await client.setUser( + User(id: user.id, extraData: { + 'name': user.name, + }), + token, + ); - if (!kIsWeb) { - _initNotifications(client); - } + if (!kIsWeb) { + initNotifications(client); + } - await Navigator.pushReplacement( + await Navigator.pushReplacement( + context, + MaterialPageRoute( + builder: (context) { + return StreamChat( + client: client, + child: ChannelListPage(), + ); + }, + ), + ); + }, + leading: UserAvatar( + user: user, + constraints: BoxConstraints.tight( + Size.fromRadius(20), + ), + ), + title: Text( + user.name, + style: TextStyle(fontWeight: FontWeight.bold), + ), + subtitle: Text('Stream test account'), + trailing: Icon( + StreamIcons.arrow_right, + color: StreamChatTheme.of(context).accentColor, + ), + ); + }), + ListTile( + onTap: () { + Navigator.push( context, MaterialPageRoute( - builder: (context) { - return StreamChat( - client: client, - child: ChannelListPage(), - ); - }, + builder: (context) => AdvancedOptionsPage(), ), ); }, - leading: UserAvatar( - user: user, - constraints: BoxConstraints.tight( - Size.fromRadius(20), + leading: CircleAvatar( + child: Icon( + StreamIcons.settings, + color: Colors.black, ), + backgroundColor: + StreamChatTheme.of(context).secondaryColor, ), title: Text( - user.name, + 'Advanced Options', style: TextStyle(fontWeight: FontWeight.bold), ), - subtitle: Text('Stream test account'), + subtitle: Text('Custom settings'), trailing: Icon( StreamIcons.arrow_right, color: StreamChatTheme.of(context).accentColor, ), - ); - }), - ListTile( - onTap: () { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => AdvancedOptionsPage(), - ), - ); - }, - leading: CircleAvatar( - child: Icon( - StreamIcons.settings, - color: Colors.black, - ), - backgroundColor: StreamChatTheme.of(context).secondaryColor, ), - title: Text( - 'Advanced Options', - style: TextStyle(fontWeight: FontWeight.bold), - ), - subtitle: Text('Custom settings'), - trailing: Icon( - StreamIcons.arrow_right, - color: StreamChatTheme.of(context).accentColor, - ), - ), - ], + ][i]; + }, ), ), ], diff --git a/example/lib/main.dart b/example/lib/main.dart index 8218f203..5af7f134 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -6,6 +6,8 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; +import 'notifications_service.dart'; + void main() async { final client = Client( 's2dxdhpxd94g', diff --git a/example/lib/notifications_service.dart b/example/lib/notifications_service.dart new file mode 100644 index 00000000..c5b77c0e --- /dev/null +++ b/example/lib/notifications_service.dart @@ -0,0 +1,62 @@ +import 'dart:io'; + +import 'package:flutter_apns/flutter_apns.dart'; +import 'package:flutter_local_notifications/flutter_local_notifications.dart' + hide Message; +import 'package:stream_chat_flutter/stream_chat_flutter.dart'; + +void showLocalNotification(Message message, ChannelModel channel) async { + final flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin(); + final initializationSettingsAndroid = + AndroidInitializationSettings('launch_background'); + final initializationSettingsIOS = IOSInitializationSettings(); + final initializationSettings = InitializationSettings( + android: initializationSettingsAndroid, + iOS: initializationSettingsIOS, + ); + await flutterLocalNotificationsPlugin.initialize(initializationSettings); + await flutterLocalNotificationsPlugin.show( + message.id.hashCode, + '${message.user.name} @ ${channel.name}', + message.text, + NotificationDetails( + android: AndroidNotificationDetails( + 'message channel', + 'Message channel', + 'Channel used for showing messages', + priority: Priority.high, + importance: Importance.high, + ), + iOS: IOSNotificationDetails(), + ), + ); +} + +Future backgroundHandler(Map notification) async { + final messageId = notification['data']['message_id']; + + final notificationData = + await NotificationService.getAndStoreMessage(messageId); + + showLocalNotification( + notificationData.message, + notificationData.channel, + ); +} + +void initNotifications(Client client) { + final connector = createPushConnector(); + connector.configure( + onBackgroundMessage: backgroundHandler, + ); + + connector.requestNotificationPermissions(); + connector.token.addListener(() { + if (connector.token.value != null) { + client.addDevice( + connector.token.value, + Platform.isAndroid ? 'firebase' : 'apn', + ); + } + }); +} diff --git a/example/pubspec.yaml b/example/pubspec.yaml index e4604f44..8917cc07 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -1,7 +1,7 @@ name: example description: A new Flutter project. -version: 1.0.43+45 +version: 1.0.44+46 environment: sdk: ">=2.2.2 <3.0.0" From 89fdb47e0eaa2f9c9175bb18188c5fca516452e8 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Tue, 10 Nov 2020 10:07:28 +0100 Subject: [PATCH 0329/1140] show unread indicator only for members --- example/lib/multiple_conversation.dart | 6 ++--- example/pubspec.yaml | 2 +- lib/src/channel_preview.dart | 10 +++++---- lib/src/message_list_view.dart | 31 +++++++++++++++++--------- 4 files changed, 31 insertions(+), 18 deletions(-) diff --git a/example/lib/multiple_conversation.dart b/example/lib/multiple_conversation.dart index 647ae7dd..b5fdd5af 100644 --- a/example/lib/multiple_conversation.dart +++ b/example/lib/multiple_conversation.dart @@ -56,9 +56,9 @@ class ChannelListPage extends StatelessWidget { body: ChannelsBloc( child: ChannelListView( filter: { - 'members': { - '\$in': [StreamChat.of(context).user.id], - } + // 'members': { + // '\$in': [StreamChat.of(context).user.id], + // } }, sort: [SortOption('last_message_at')], pagination: PaginationParams( diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 1e527964..0cba8d30 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -1,7 +1,7 @@ name: example description: A new Flutter project. -version: 1.0.42+44 +version: 1.0.43+45 environment: sdk: ">=2.2.2 <3.0.0" diff --git a/lib/src/channel_preview.dart b/lib/src/channel_preview.dart index 8ed15657..cd1a0910 100644 --- a/lib/src/channel_preview.dart +++ b/lib/src/channel_preview.dart @@ -70,9 +70,11 @@ class ChannelPreview extends StatelessWidget { StreamChatTheme.of(context).channelPreviewTheme.title, ), ), - UnreadIndicator( - channel: channel, - ), + if (channel.state.members.contains( + (Member e) => e.userId == channel.client.state.user.id)) + UnreadIndicator( + channel: channel, + ), ], ), subtitle: Row( @@ -92,7 +94,7 @@ class ChannelPreview extends StatelessWidget { .isAfter(channel .state.lastMessage.createdAt)) .length == - channel.memberCount - 1, + (channel.memberCount ?? 0) - 1, ), ); } diff --git a/lib/src/message_list_view.dart b/lib/src/message_list_view.dart index 946ad66f..2a60b75b 100644 --- a/lib/src/message_list_view.dart +++ b/lib/src/message_list_view.dart @@ -289,7 +289,9 @@ class _MessageListViewState extends State { return messageWidget; }, ), - if (widget.showScrollToBottom) + if (streamChannel.channel.state.members.contains((Member e) => + e.userId == streamChannel.channel.client.state.user.id) && + widget.showScrollToBottom) StreamBuilder( stream: streamChannel.channel.state.unreadCountStream, builder: (context, snapshot) { @@ -374,8 +376,16 @@ class _MessageListViewState extends State { left: 10, top: -10, child: CircleAvatar( - radius: 20, - child: Text(unreadCount.toString()), + child: Padding( + padding: const EdgeInsets.all(3.0), + child: Text( + unreadCount.toString(), + style: TextStyle( + fontSize: 11, + fontWeight: FontWeight.bold, + ), + ), + ), ), ), ], @@ -555,13 +565,14 @@ class _MessageListViewState extends State { final channel = StreamChannel.of(context).channel; final readList = channel.state?.read - ?.where((element) => element.user.id != userId) - ?.where((read) => - (read.lastRead.isAfter(message.createdAt) || - read.lastRead.isAtSameMomentAs(message.createdAt)) && - (index == 0 || - read.lastRead.isBefore(messages[index - 1].createdAt))) - ?.toList(); + ?.where((element) => element.user.id != userId) + ?.where((read) => + (read.lastRead.isAfter(message.createdAt) || + read.lastRead.isAtSameMomentAs(message.createdAt)) && + (index == 0 || + read.lastRead.isBefore(messages[index - 1].createdAt))) + ?.toList() ?? + []; final allRead = readList.length >= (channel.memberCount ?? 0) - 1; From 755dd511edfc77c0640a5abef837e38c3bceedc6 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Tue, 10 Nov 2020 19:32:46 +0530 Subject: [PATCH 0330/1140] feat: Added url attachments --- lib/src/message_widget.dart | 194 ++++++++++++++++++++++++++++++------ 1 file changed, 165 insertions(+), 29 deletions(-) diff --git a/lib/src/message_widget.dart b/lib/src/message_widget.dart index 476217f3..0affe079 100644 --- a/lib/src/message_widget.dart +++ b/lib/src/message_widget.dart @@ -1,6 +1,7 @@ import 'dart:math'; import 'dart:ui'; +import 'package:cached_network_image/cached_network_image.dart'; import 'package:emojis/emoji.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/foundation.dart'; @@ -343,6 +344,83 @@ class _MessageWidgetState extends State { ); } + Widget _buildUrlAttachment() { + var urlAttachment = widget.message.attachments + .firstWhere((element) => element.ogScrapeUrl != null); + + var host = Uri.parse(urlAttachment.ogScrapeUrl).host; + var splitList = host.split('.'); + var hostName = splitList.length == 3 ? splitList[1] : splitList[0]; + var hostDisplayName = + _getWebsiteName(hostName.toLowerCase()) ?? hostName.capitalize(); + + return Column( + children: [ + SizedBox( + height: 16.0, + ), + Container( + margin: EdgeInsets.symmetric(horizontal: 8.0), + child: Stack( + clipBehavior: Clip.antiAlias, + children: [ + CachedNetworkImage(imageUrl: urlAttachment.imageUrl), + Positioned( + left: 0.0, + bottom: 0.0, + child: Container( + child: Padding( + padding: + const EdgeInsets.only(top: 8.0, left: 8.0, right: 8.0), + child: Text( + hostDisplayName, + style: TextStyle( + fontWeight: FontWeight.w700, + color: Color(0xFF006CFF), + ), + ), + ), + decoration: BoxDecoration( + borderRadius: + BorderRadius.only(topRight: Radius.circular(16.0)), + color: Color(0xFFE9F2FF), + ), + ), + ), + ], + ), + clipBehavior: Clip.antiAlias, + decoration: BoxDecoration(borderRadius: BorderRadius.circular(8.0)), + ), + Padding( + padding: widget.textPadding, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + if (urlAttachment.title != null) + Text( + urlAttachment.title, + maxLines: 1, + style: TextStyle( + fontWeight: FontWeight.w700, + fontSize: 12.0, + ), + ), + if (urlAttachment.text != null) + Text( + urlAttachment.text, + style: TextStyle( + fontWeight: FontWeight.w400, + fontSize: 12.0, + ), + ), + ], + ), + ), + ], + ); + } + Padding _buildBottomRow(double leftPadding) { return Padding( padding: EdgeInsets.only( @@ -525,7 +603,8 @@ class _MessageWidgetState extends State { List _parseAttachments(BuildContext context) { final images = widget.message.attachments - ?.where((element) => element.type == 'image') + ?.where((element) => + element.type == 'image' && element.ogScrapeUrl == null) ?.toList() ?? []; @@ -548,7 +627,9 @@ class _MessageWidgetState extends State { ]; } - return widget.message.attachments?.map((attachment) { + return widget.message.attachments + ?.where((element) => element.ogScrapeUrl == null) + ?.map((attachment) { final attachmentBuilder = widget.attachmentBuilders[attachment.type]; if (attachmentBuilder == null) { @@ -757,28 +838,35 @@ class _MessageWidgetState extends State { Widget child = Transform( transform: Matrix4.rotationY(widget.reverse ? pi : 0), alignment: Alignment.center, - child: Padding( - padding: widget.textPadding, - child: Column( - crossAxisAlignment: CrossAxisAlignment.end, - children: [ - getFailedMessageWidget(context), - widget.textBuilder != null - ? widget.textBuilder(context, widget.message) - : MessageText( - onLinkTap: widget.onLinkTap, - message: widget.message, - onMentionTap: widget.onMentionTap, - messageTheme: isOnlyEmoji - ? widget.messageTheme.copyWith( - messageText: - widget.messageTheme.messageText.copyWith( - fontSize: 40, - )) - : widget.messageTheme, - ), - ], - ), + child: Column( + children: [ + Padding( + padding: widget.textPadding, + child: Column( + crossAxisAlignment: CrossAxisAlignment.end, + children: [ + getFailedMessageWidget(context), + widget.textBuilder != null + ? widget.textBuilder(context, widget.message) + : MessageText( + onLinkTap: widget.onLinkTap, + message: widget.message, + onMentionTap: widget.onMentionTap, + messageTheme: isOnlyEmoji + ? widget.messageTheme.copyWith( + messageText: + widget.messageTheme.messageText.copyWith( + fontSize: 40, + )) + : widget.messageTheme, + ), + ], + ), + ), + if (widget.message.attachments + .any((element) => element.ogScrapeUrl != null)) + _buildUrlAttachment(), + ], ), ); @@ -796,11 +884,18 @@ class _MessageWidgetState extends State { } Color _getBackgroundColor() { - return (widget.message.status == MessageSendingStatus.FAILED || - widget.message.status == MessageSendingStatus.FAILED_UPDATE || - widget.message.status == MessageSendingStatus.FAILED_DELETE) - ? Color(0xffd0021B).withOpacity(.1) - : widget.messageTheme.messageBackgroundColor; + if ((widget.message.status == MessageSendingStatus.FAILED || + widget.message.status == MessageSendingStatus.FAILED_UPDATE || + widget.message.status == MessageSendingStatus.FAILED_DELETE)) { + return Color(0xffd0021B).withOpacity(.1); + } + + if (widget.message.attachments + .any((element) => element.ogScrapeUrl != null)) { + return Color(0xFFE9F2FF); + } + + return widget.messageTheme.messageBackgroundColor; } void retryMessage(BuildContext context) { @@ -825,4 +920,45 @@ class _MessageWidgetState extends State { return; } } + + String _getWebsiteName(String hostName) { + switch (hostName) { + case 'reddit': + return 'Reddit'; + case 'youtube': + return 'Youtube'; + case 'wikipedia': + return 'Wikipedia'; + case 'twitter': + return 'Twitter'; + case 'facebook': + return 'Facebook'; + case 'amazon': + return 'Amazon'; + case 'yelp': + return 'Yelp'; + case 'imdb': + return 'IMDB'; + case 'pinterest': + return 'Pinterest'; + case 'tripadvisor': + return 'TripAdvisor'; + case 'instagram': + return 'Instagram'; + case 'walmart': + return 'Walmart'; + case 'craigslist': + return 'Craigslist'; + case 'ebay': + return 'eBay'; + case 'linkedin': + return 'LinkedIn'; + case 'google': + return 'Google'; + case 'apple': + return 'Apple'; + default: + return null; + } + } } From 477673aa28eb65ee51bf221b71513cdfb62bc888 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Tue, 10 Nov 2020 19:38:05 +0530 Subject: [PATCH 0331/1140] fix: Fix case when image is null --- lib/src/message_widget.dart | 58 +++++++++++++++++++------------------ 1 file changed, 30 insertions(+), 28 deletions(-) diff --git a/lib/src/message_widget.dart b/lib/src/message_widget.dart index 0affe079..4291e00e 100644 --- a/lib/src/message_widget.dart +++ b/lib/src/message_widget.dart @@ -356,42 +356,44 @@ class _MessageWidgetState extends State { return Column( children: [ + if (urlAttachment.imageUrl != null) SizedBox( height: 16.0, ), - Container( - margin: EdgeInsets.symmetric(horizontal: 8.0), - child: Stack( - clipBehavior: Clip.antiAlias, - children: [ - CachedNetworkImage(imageUrl: urlAttachment.imageUrl), - Positioned( - left: 0.0, - bottom: 0.0, - child: Container( - child: Padding( - padding: - const EdgeInsets.only(top: 8.0, left: 8.0, right: 8.0), - child: Text( - hostDisplayName, - style: TextStyle( - fontWeight: FontWeight.w700, - color: Color(0xFF006CFF), + if (urlAttachment.imageUrl != null) + Container( + margin: EdgeInsets.symmetric(horizontal: 8.0), + child: Stack( + clipBehavior: Clip.antiAlias, + children: [ + CachedNetworkImage(imageUrl: urlAttachment.imageUrl), + Positioned( + left: 0.0, + bottom: 0.0, + child: Container( + child: Padding( + padding: const EdgeInsets.only( + top: 8.0, left: 8.0, right: 8.0), + child: Text( + hostDisplayName, + style: TextStyle( + fontWeight: FontWeight.w700, + color: Color(0xFF006CFF), + ), ), ), - ), - decoration: BoxDecoration( - borderRadius: - BorderRadius.only(topRight: Radius.circular(16.0)), - color: Color(0xFFE9F2FF), + decoration: BoxDecoration( + borderRadius: + BorderRadius.only(topRight: Radius.circular(16.0)), + color: Color(0xFFE9F2FF), + ), ), ), - ), - ], + ], + ), + clipBehavior: Clip.antiAlias, + decoration: BoxDecoration(borderRadius: BorderRadius.circular(8.0)), ), - clipBehavior: Clip.antiAlias, - decoration: BoxDecoration(borderRadius: BorderRadius.circular(8.0)), - ), Padding( padding: widget.textPadding, child: Column( From b1401a5f0ced55840eb6e7a76cce196872b096b3 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Tue, 10 Nov 2020 16:05:51 +0100 Subject: [PATCH 0332/1140] create a new app and client for advanced options --- example/lib/advanced_options_page.dart | 393 +++++++++++++++---------- example/lib/choose_user_page.dart | 19 ++ example/pubspec.yaml | 2 +- 3 files changed, 253 insertions(+), 161 deletions(-) diff --git a/example/lib/advanced_options_page.dart b/example/lib/advanced_options_page.dart index b6062c30..4fb801c9 100644 --- a/example/lib/advanced_options_page.dart +++ b/example/lib/advanced_options_page.dart @@ -1,3 +1,5 @@ +import 'dart:io'; + import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; @@ -5,13 +7,24 @@ import 'package:stream_chat_flutter/stream_chat_flutter.dart'; import 'main.dart'; import 'notifications_service.dart'; -class AdvancedOptionsPage extends StatelessWidget { +class AdvancedOptionsPage extends StatefulWidget { + @override + _AdvancedOptionsPageState createState() => _AdvancedOptionsPageState(); +} + +class _AdvancedOptionsPageState extends State { final _formKey = GlobalKey(); + final TextEditingController _apiKeyController = TextEditingController(); + final TextEditingController _userIdController = TextEditingController(); + final TextEditingController _userTokenController = TextEditingController(); + final TextEditingController _usernameController = TextEditingController(); + bool loading = false; + @override Widget build(BuildContext context) { return Scaffold( @@ -36,169 +49,229 @@ class AdvancedOptionsPage extends StatelessWidget { }, ), ), - body: Padding( - padding: const EdgeInsets.symmetric( - horizontal: 16, - vertical: 16, - ), - child: Form( - key: _formKey, - onChanged: () {}, - child: Column( - children: [ - TextFormField( - controller: _apiKeyController, - validator: (value) { - if (value.isEmpty) { - return 'Please enter the Chat API Key'; - } - return null; - }, - decoration: InputDecoration( - labelStyle: TextStyle( - fontSize: 14, - color: Colors.black.withOpacity(.5), + body: Builder( + builder: (context) { + return Padding( + padding: const EdgeInsets.symmetric( + horizontal: 16, + vertical: 16, + ), + child: Form( + key: _formKey, + child: Column( + children: [ + TextFormField( + controller: _apiKeyController, + validator: (value) { + if (value.isEmpty) { + return 'Please enter the Chat API Key'; + } + return null; + }, + decoration: InputDecoration( + labelStyle: TextStyle( + fontSize: 14, + color: Colors.black.withOpacity(.5), + ), + border: UnderlineInputBorder( + borderRadius: BorderRadius.circular(8), + borderSide: BorderSide.none, + ), + fillColor: Color(0xffF5F5F5), + filled: true, + labelText: 'Chat API Key', + ), + textInputAction: TextInputAction.next, ), - border: UnderlineInputBorder( - borderRadius: BorderRadius.circular(8), - borderSide: BorderSide.none, - ), - fillColor: Color(0xffF5F5F5), - filled: true, - labelText: 'Chat API Key', - ), - textInputAction: TextInputAction.next, - ), - Padding( - padding: const EdgeInsets.only(top: 8.0), - child: TextFormField( - controller: _userIdController, - validator: (value) { - if (value.isEmpty) { - return 'Please enter the User ID'; - } - return null; - }, - textInputAction: TextInputAction.next, - decoration: InputDecoration( - labelStyle: TextStyle( - fontSize: 14, - color: Colors.black.withOpacity(.5), - ), - border: UnderlineInputBorder( - borderRadius: BorderRadius.circular(8), - borderSide: BorderSide.none, - ), - fillColor: Color(0xffF5F5F5), - filled: true, - labelText: 'User ID', - ), - ), - ), - Padding( - padding: const EdgeInsets.only(top: 8.0), - child: TextFormField( - controller: _userTokenController, - validator: (value) { - if (value.isEmpty) { - return 'Please enter the user token'; - } - return null; - }, - textInputAction: TextInputAction.next, - decoration: InputDecoration( - labelStyle: TextStyle( - fontSize: 14, - color: Colors.black.withOpacity(.5), - ), - border: UnderlineInputBorder( - borderRadius: BorderRadius.circular(8), - borderSide: BorderSide.none, - ), - fillColor: Color(0xffF5F5F5), - filled: true, - labelText: 'User Token', - ), - ), - ), - Padding( - padding: const EdgeInsets.only(top: 8.0), - child: TextFormField( - controller: _usernameController, - textInputAction: TextInputAction.done, - decoration: InputDecoration( - labelStyle: TextStyle( - fontSize: 14, - color: Colors.black.withOpacity(.5), - ), - border: UnderlineInputBorder( - borderRadius: BorderRadius.circular(8), - borderSide: BorderSide.none, - ), - fillColor: Color(0xffF5F5F5), - filled: true, - labelText: 'Username (optional)', - ), - ), - ), - Expanded( - child: Align( - alignment: Alignment.bottomCenter, - child: FlatButton( - color: StreamChatTheme.of(context).accentColor, - minWidth: double.infinity, - height: 48, - child: Text( - 'Login', - style: TextStyle( - color: Colors.white, - fontSize: 16, + Padding( + padding: const EdgeInsets.only(top: 8.0), + child: TextFormField( + controller: _userIdController, + validator: (value) { + if (value.isEmpty) { + return 'Please enter the User ID'; + } + return null; + }, + textInputAction: TextInputAction.next, + decoration: InputDecoration( + labelStyle: TextStyle( + fontSize: 14, + color: Colors.black.withOpacity(.5), + ), + border: UnderlineInputBorder( + borderRadius: BorderRadius.circular(8), + borderSide: BorderSide.none, + ), + fillColor: Color(0xffF5F5F5), + filled: true, + labelText: 'User ID', ), ), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(26), - ), - onPressed: () async { - if (_formKey.currentState.validate()) { - final apiKey = _apiKeyController.text; - final userId = _userIdController.text; - final userToken = _userTokenController.text; - final username = _usernameController.text; - - final client = StreamChat.of(context).client; - client.apiKey = apiKey; - - await client.setUser( - User(id: userId, extraData: { - 'name': username, - }), - userToken, - ); - - if (!kIsWeb) { - initNotifications(client); - } - - Navigator.pop(context); - await Navigator.pushReplacement( - context, - MaterialPageRoute( - builder: (context) { - return StreamChat( - client: client, - child: ChannelListPage(), - ); - }, - ), - ); - } - }, ), - ), - ) - ], - ), - ), + Padding( + padding: const EdgeInsets.only(top: 8.0), + child: TextFormField( + controller: _userTokenController, + validator: (value) { + if (value.isEmpty) { + return 'Please enter the user token'; + } + return null; + }, + textInputAction: TextInputAction.next, + decoration: InputDecoration( + labelStyle: TextStyle( + fontSize: 14, + color: Colors.black.withOpacity(.5), + ), + border: UnderlineInputBorder( + borderRadius: BorderRadius.circular(8), + borderSide: BorderSide.none, + ), + fillColor: Color(0xffF5F5F5), + filled: true, + labelText: 'User Token', + ), + ), + ), + Padding( + padding: const EdgeInsets.only(top: 8.0), + child: TextFormField( + controller: _usernameController, + textInputAction: TextInputAction.done, + decoration: InputDecoration( + labelStyle: TextStyle( + fontSize: 14, + color: Colors.black.withOpacity(.5), + ), + border: UnderlineInputBorder( + borderRadius: BorderRadius.circular(8), + borderSide: BorderSide.none, + ), + fillColor: Color(0xffF5F5F5), + filled: true, + labelText: 'Username (optional)', + ), + ), + ), + Expanded( + child: Align( + alignment: Alignment.bottomCenter, + child: FlatButton( + color: StreamChatTheme.of(context).accentColor, + minWidth: double.infinity, + height: 48, + child: Text( + 'Login', + style: TextStyle( + color: Colors.white, + fontSize: 16, + ), + ), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(26), + ), + onPressed: () async { + if (loading) { + return; + } + loading = true; + if (_formKey.currentState.validate()) { + final apiKey = _apiKeyController.text; + final userId = _userIdController.text; + final userToken = _userTokenController.text; + final username = _usernameController.text; + + showDialog( + barrierDismissible: false, + context: context, + builder: (context) => Center( + child: Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(16), + color: Colors.white, + ), + height: 100, + width: 100, + child: Center( + child: CircularProgressIndicator(), + ), + ), + ), + ); + + print('CREATE CLIENT'); + final client = Client( + apiKey, + logLevel: Level.INFO, + showLocalNotification: + (!kIsWeb && Platform.isAndroid) + ? showLocalNotification + : null, + persistenceEnabled: true, + ); + + try { + await client.setUser( + User(id: userId, extraData: { + 'name': username, + }), + userToken, + ); + } catch (e) { + var errorText = 'Error connecting, retry'; + if (e is Map) { + errorText = e['message'] ?? errorText; + } + Navigator.pop(context); + Scaffold.of(context).showSnackBar( + SnackBar( + content: Text(errorText), + ), + ); + loading = false; + await client.disconnect(); + return; + } + + if (!kIsWeb) { + initNotifications(client); + } + + Navigator.pop(context); + Navigator.pop(context); + await Navigator.pushReplacement( + context, + MaterialPageRoute( + builder: (context) { + return MaterialApp( + theme: ThemeData.light(), + darkTheme: ThemeData.dark(), + //TODO change to system once dark theme is implemented + themeMode: ThemeMode.light, + builder: (context, widget) { + return StreamChat( + child: widget, + client: client, + ); + }, + home: ChannelListPage(), + ); + }, + ), + ); + loading = false; + } + }, + ), + ), + ) + ], + ), + ), + ); + }, ), ); } diff --git a/example/lib/choose_user_page.dart b/example/lib/choose_user_page.dart index ef710e53..35fe2d0d 100644 --- a/example/lib/choose_user_page.dart +++ b/example/lib/choose_user_page.dart @@ -98,6 +98,24 @@ class ChooseUserPage extends StatelessWidget { final user = entry.value; return ListTile( onTap: () async { + showDialog( + barrierDismissible: false, + context: context, + builder: (context) => Center( + child: Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(16), + color: Colors.white, + ), + height: 100, + width: 100, + child: Center( + child: CircularProgressIndicator(), + ), + ), + ), + ); + final client = StreamChat.of(context).client; await client.setUser( @@ -111,6 +129,7 @@ class ChooseUserPage extends StatelessWidget { initNotifications(client); } + Navigator.pop(context); await Navigator.pushReplacement( context, MaterialPageRoute( diff --git a/example/pubspec.yaml b/example/pubspec.yaml index b94a312a..4a950698 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -1,7 +1,7 @@ name: example description: A new Flutter project. -version: 1.0.45+47 +version: 1.0.46+48 environment: sdk: ">=2.2.2 <3.0.0" From 1ef232c2a98878420b48f89cae07dad0989111ce Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Tue, 10 Nov 2020 16:14:58 +0100 Subject: [PATCH 0333/1140] fix dep --- pubspec.yaml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pubspec.yaml b/pubspec.yaml index e5c57193..11a79617 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -26,8 +26,7 @@ dependencies: file_picker: ^2.0.8+1 image_picker: ^0.6.7+2 flutter_keyboard_visibility: ^3.2.1 - stream_chat: - path: ../stream_chat_dart + stream_chat: ^0.2.10+2 emojis: ^0.9.3 mime: ^0.9.6+3 visibility_detector: ^0.1.5 From 3cfe5efd0956834c18f00cd19f1b9f59bda507ea Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Tue, 10 Nov 2020 16:46:25 +0100 Subject: [PATCH 0334/1140] fix tests --- lib/src/channel_preview.dart | 19 ++++++++++++++----- test/src/channel_preview_test.dart | 15 ++++++++++++++- 2 files changed, 28 insertions(+), 6 deletions(-) diff --git a/lib/src/channel_preview.dart b/lib/src/channel_preview.dart index cd1a0910..c23d7732 100644 --- a/lib/src/channel_preview.dart +++ b/lib/src/channel_preview.dart @@ -70,11 +70,20 @@ class ChannelPreview extends StatelessWidget { StreamChatTheme.of(context).channelPreviewTheme.title, ), ), - if (channel.state.members.contains( - (Member e) => e.userId == channel.client.state.user.id)) - UnreadIndicator( - channel: channel, - ), + StreamBuilder>( + stream: channel.state.membersStream, + initialData: channel.state.members, + builder: (context, snapshot) { + if (!snapshot.hasData || + snapshot.data.isEmpty || + !snapshot.data.any((Member e) => + e.user.id == channel.client.state.user.id)) { + return SizedBox(); + } + return UnreadIndicator( + channel: channel, + ); + }), ], ), subtitle: Row( diff --git a/test/src/channel_preview_test.dart b/test/src/channel_preview_test.dart index 94c45ac2..578d4b28 100644 --- a/test/src/channel_preview_test.dart +++ b/test/src/channel_preview_test.dart @@ -19,6 +19,7 @@ void main() { when(clientState.user).thenReturn(OwnUser(id: 'user-id')); when(channel.lastMessageAt).thenReturn(lastMessageAt); when(channel.state).thenReturn(channelState); + when(channel.client).thenReturn(client); when(channel.isMuted).thenReturn(false); when(channel.isMutedStream).thenAnswer((i) => Stream.value(false)); when(channel.extraDataStream).thenAnswer((i) => Stream.value({ @@ -28,7 +29,19 @@ void main() { 'name': 'test name', }); when(channelState.unreadCount).thenReturn(1); - when(channelState.members).thenReturn([]); + when(channelState.unreadCountStream).thenAnswer((i) => Stream.value(1)); + when(channelState.membersStream).thenAnswer((i) => Stream.value([ + Member( + userId: 'user-id', + user: User(id: 'user-id'), + ) + ])); + when(channelState.members).thenReturn([ + Member( + userId: 'user-id', + user: User(id: 'user-id'), + ), + ]); when(channelState.lastMessage).thenReturn(Message( text: 'hello', user: User(id: 'other-user'), From f87fa8ae8fd361c71e6e0cdfa468de8e19f1c16a Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Tue, 10 Nov 2020 17:12:48 +0100 Subject: [PATCH 0335/1140] add inkwell --- lib/src/message_widget.dart | 135 +++++++++++++++++++++--------------- 1 file changed, 78 insertions(+), 57 deletions(-) diff --git a/lib/src/message_widget.dart b/lib/src/message_widget.dart index 4291e00e..1f3a12dd 100644 --- a/lib/src/message_widget.dart +++ b/lib/src/message_widget.dart @@ -16,6 +16,7 @@ import 'package:stream_chat_flutter/stream_chat_flutter.dart'; import 'image_group.dart'; import 'message_text.dart'; +import 'utils.dart'; typedef AttachmentBuilder = Widget Function(BuildContext, Message, Attachment); @@ -354,69 +355,89 @@ class _MessageWidgetState extends State { var hostDisplayName = _getWebsiteName(hostName.toLowerCase()) ?? hostName.capitalize(); - return Column( + return Stack( children: [ - if (urlAttachment.imageUrl != null) - SizedBox( - height: 16.0, - ), - if (urlAttachment.imageUrl != null) - Container( - margin: EdgeInsets.symmetric(horizontal: 8.0), - child: Stack( - clipBehavior: Clip.antiAlias, - children: [ - CachedNetworkImage(imageUrl: urlAttachment.imageUrl), - Positioned( - left: 0.0, - bottom: 0.0, - child: Container( - child: Padding( - padding: const EdgeInsets.only( - top: 8.0, left: 8.0, right: 8.0), - child: Text( - hostDisplayName, - style: TextStyle( - fontWeight: FontWeight.w700, - color: Color(0xFF006CFF), + Column( + children: [ + if (urlAttachment.imageUrl != null) + SizedBox( + height: 16.0, + ), + if (urlAttachment.imageUrl != null) + Container( + margin: EdgeInsets.symmetric(horizontal: 8.0), + child: Stack( + clipBehavior: Clip.antiAlias, + children: [ + CachedNetworkImage(imageUrl: urlAttachment.imageUrl), + Positioned( + left: 0.0, + bottom: 0.0, + child: Container( + child: Padding( + padding: const EdgeInsets.only( + top: 8.0, + left: 8.0, + right: 8.0, + ), + child: Text( + hostDisplayName, + style: TextStyle( + fontWeight: FontWeight.w700, + color: Color(0xFF006CFF), + ), + ), + ), + decoration: BoxDecoration( + borderRadius: BorderRadius.only( + topRight: Radius.circular(16.0), + ), + color: Color(0xFFE9F2FF), ), ), ), - decoration: BoxDecoration( - borderRadius: - BorderRadius.only(topRight: Radius.circular(16.0)), - color: Color(0xFFE9F2FF), + ], + ), + clipBehavior: Clip.antiAlias, + decoration: + BoxDecoration(borderRadius: BorderRadius.circular(8.0)), + ), + Padding( + padding: widget.textPadding, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + if (urlAttachment.title != null) + Text( + urlAttachment.title, + maxLines: 1, + style: TextStyle( + fontWeight: FontWeight.w700, + fontSize: 12.0, + ), ), - ), - ), - ], + if (urlAttachment.text != null) + Text( + urlAttachment.text, + style: TextStyle( + fontWeight: FontWeight.w400, + fontSize: 12.0, + ), + ), + ], + ), + ), + ], + ), + Positioned.fill( + child: Material( + color: Colors.transparent, + child: InkWell( + onTap: () => launchURL( + context, + urlAttachment.ogScrapeUrl, + ), ), - clipBehavior: Clip.antiAlias, - decoration: BoxDecoration(borderRadius: BorderRadius.circular(8.0)), - ), - Padding( - padding: widget.textPadding, - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - if (urlAttachment.title != null) - Text( - urlAttachment.title, - maxLines: 1, - style: TextStyle( - fontWeight: FontWeight.w700, - fontSize: 12.0, - ), - ), - if (urlAttachment.text != null) - Text( - urlAttachment.text, - style: TextStyle( - fontWeight: FontWeight.w400, - fontSize: 12.0, - ), - ), - ], ), ), ], From 24c44520e610eef8af2f2b5c985368248639307d Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Tue, 10 Nov 2020 17:16:40 +0100 Subject: [PATCH 0336/1140] fix alignment --- lib/src/message_widget.dart | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/src/message_widget.dart b/lib/src/message_widget.dart index 1f3a12dd..d1be132d 100644 --- a/lib/src/message_widget.dart +++ b/lib/src/message_widget.dart @@ -862,6 +862,7 @@ class _MessageWidgetState extends State { transform: Matrix4.rotationY(widget.reverse ? pi : 0), alignment: Alignment.center, child: Column( + crossAxisAlignment: CrossAxisAlignment.start, children: [ Padding( padding: widget.textPadding, From 2d125ea83692dbb65a80047c748cacb2494a8c09 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Tue, 10 Nov 2020 17:25:25 +0100 Subject: [PATCH 0337/1140] use hostname if not null --- lib/src/message_widget.dart | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/src/message_widget.dart b/lib/src/message_widget.dart index d1be132d..55d08424 100644 --- a/lib/src/message_widget.dart +++ b/lib/src/message_widget.dart @@ -352,8 +352,9 @@ class _MessageWidgetState extends State { var host = Uri.parse(urlAttachment.ogScrapeUrl).host; var splitList = host.split('.'); var hostName = splitList.length == 3 ? splitList[1] : splitList[0]; - var hostDisplayName = - _getWebsiteName(hostName.toLowerCase()) ?? hostName.capitalize(); + var hostDisplayName = urlAttachment.authorName?.capitalize() ?? + _getWebsiteName(hostName.toLowerCase()) ?? + hostName.capitalize(); return Stack( children: [ From a91f1c500044e0c07bb225fa3247f0f47458fb47 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Tue, 10 Nov 2020 17:28:10 +0100 Subject: [PATCH 0338/1140] fix image alignent --- lib/src/message_widget.dart | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/src/message_widget.dart b/lib/src/message_widget.dart index 55d08424..6f81f149 100644 --- a/lib/src/message_widget.dart +++ b/lib/src/message_widget.dart @@ -359,6 +359,7 @@ class _MessageWidgetState extends State { return Stack( children: [ Column( + crossAxisAlignment: CrossAxisAlignment.stretch, children: [ if (urlAttachment.imageUrl != null) SizedBox( @@ -370,7 +371,11 @@ class _MessageWidgetState extends State { child: Stack( clipBehavior: Clip.antiAlias, children: [ - CachedNetworkImage(imageUrl: urlAttachment.imageUrl), + Center( + child: CachedNetworkImage( + imageUrl: urlAttachment.imageUrl, + ), + ), Positioned( left: 0.0, bottom: 0.0, From 10017099976a815be35f855eca58379d01bfda63 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Wed, 11 Nov 2020 10:33:04 +0100 Subject: [PATCH 0339/1140] update llc dependency --- pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pubspec.yaml b/pubspec.yaml index 9dd2fd95..a3cb6d18 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -26,7 +26,7 @@ dependencies: file_picker: ^2.0.8+1 image_picker: ^0.6.7+2 flutter_keyboard_visibility: ^3.2.1 - stream_chat: ^0.2.10+1 + stream_chat: ^0.2.11 emojis: ^0.9.3 mime: ^0.9.6+3 visibility_detector: ^0.1.5 From 269ad0b99bed3a9817b81db7590bb6fa80aaa62f Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Wed, 11 Nov 2020 12:03:39 +0100 Subject: [PATCH 0340/1140] add drawer --- example/lib/choose_user_page.dart | 22 +++++++ example/lib/main.dart | 103 +++++++++++++++++++++++++++++- example/pubspec.yaml | 3 +- lib/src/channel_list_view.dart | 6 +- 4 files changed, 129 insertions(+), 5 deletions(-) diff --git a/example/lib/choose_user_page.dart b/example/lib/choose_user_page.dart index 35fe2d0d..beea6b1b 100644 --- a/example/lib/choose_user_page.dart +++ b/example/lib/choose_user_page.dart @@ -2,11 +2,17 @@ import 'package:example/advanced_options_page.dart'; import 'package:example/main.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_secure_storage/flutter_secure_storage.dart'; import 'package:flutter_svg/flutter_svg.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; import 'notifications_service.dart'; +const kStreamApiKey = 'STREAM_API_KEY'; +const kStreamUserId = 'STREAM_USER_ID'; +const kStreamToken = 'STREAM_TOKEN'; +const kDefaultStreamApiKey = 's2dxdhpxd94g'; + class ChooseUserPage extends StatelessWidget { @override Widget build(BuildContext context) { @@ -116,6 +122,7 @@ class ChooseUserPage extends StatelessWidget { ), ); + final secureStorage = FlutterSecureStorage(); final client = StreamChat.of(context).client; await client.setUser( @@ -125,6 +132,21 @@ class ChooseUserPage extends StatelessWidget { token, ); + await Future.wait([ + secureStorage.write( + key: kStreamApiKey, + value: kDefaultStreamApiKey, + ), + secureStorage.write( + key: kStreamUserId, + value: user.id, + ), + secureStorage.write( + key: kStreamToken, + value: token, + ), + ]); + if (!kIsWeb) { initNotifications(client); } diff --git a/example/lib/main.dart b/example/lib/main.dart index 5af7f134..1da02072 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -4,19 +4,34 @@ import 'package:example/choose_user_page.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_secure_storage/flutter_secure_storage.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; import 'notifications_service.dart'; void main() async { + WidgetsFlutterBinding.ensureInitialized(); + final secureStorage = FlutterSecureStorage(); + + final apiKey = await secureStorage.read(key: kStreamApiKey); + final userId = await secureStorage.read(key: kStreamUserId); + final client = Client( - 's2dxdhpxd94g', + apiKey ?? kDefaultStreamApiKey, logLevel: Level.INFO, showLocalNotification: (!kIsWeb && Platform.isAndroid) ? showLocalNotification : null, persistenceEnabled: true, ); + if (userId != null) { + final token = await secureStorage.read(key: kStreamToken); + await client.setUser( + User(id: userId), + token, + ); + } + runApp(MyApp(client)); } @@ -38,7 +53,7 @@ class MyApp extends StatelessWidget { client: client, ); }, - home: ChooseUserPage(), + home: client.state.user == null ? ChooseUserPage() : ChannelListPage(), ); } } @@ -46,7 +61,89 @@ class MyApp extends StatelessWidget { class ChannelListPage extends StatelessWidget { @override Widget build(BuildContext context) { + final user = StreamChat.of(context).user; return Scaffold( + drawer: Drawer( + 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, + ), + ), + ), + ], + ), + ), + ListTile( + leading: Icon(StreamIcons.edit), + title: Text( + 'New direct message', + style: TextStyle( + fontSize: 14.5, + ), + ), + ), + ListTile( + leading: Icon(StreamIcons.group), + title: Text( + 'New group', + style: TextStyle( + fontSize: 14.5, + ), + ), + ), + Expanded( + child: Container( + alignment: Alignment.bottomCenter, + child: ListTile( + onTap: () async { + await StreamChat.of(context).client.disconnect(); + + final secureStorage = FlutterSecureStorage(); + await secureStorage.deleteAll(); + Navigator.pop(context); + await Navigator.pushReplacement( + context, + MaterialPageRoute( + builder: (context) => ChooseUserPage(), + ), + ); + }, + leading: Icon(StreamIcons.user), + title: Text( + 'Sign out', + style: TextStyle( + fontSize: 14.5, + ), + ), + ), + ), + ), + ], + ), + ), + ), floatingActionButton: FloatingActionButton( child: Icon(Icons.add), onPressed: () { @@ -60,7 +157,7 @@ class ChannelListPage extends StatelessWidget { swipeToAction: true, filter: { 'members': { - '\$in': [StreamChat.of(context).user.id], + '\$in': [user.id], } }, options: { diff --git a/example/pubspec.yaml b/example/pubspec.yaml index e36c3751..f8bfcfe9 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -1,6 +1,6 @@ name: example description: A new Flutter project. -version: 1.0.47+49 +version: 1.0.48+50 environment: sdk: ">=2.2.2 <3.0.0" @@ -13,6 +13,7 @@ dependencies: flutter_apns: ^1.3.1 flutter_local_notifications: ^2.0.0 flutter_svg: ^0.19.1 + flutter_secure_storage: ^3.3.5 dev_dependencies: flutter_test: diff --git a/lib/src/channel_list_view.dart b/lib/src/channel_list_view.dart index 3b698782..9f09235b 100644 --- a/lib/src/channel_list_view.dart +++ b/lib/src/channel_list_view.dart @@ -1,3 +1,4 @@ +import 'dart:async'; import 'dart:convert'; import 'package:flutter/foundation.dart'; @@ -482,6 +483,8 @@ class _ChannelListViewState extends State } } + StreamSubscription _subscription; + @override void initState() { super.initState(); @@ -506,7 +509,7 @@ class _ChannelListViewState extends State final client = StreamChat.of(context).client; - client + _subscription = client .on( EventType.connectionRecovered, EventType.notificationAddedToChannel, @@ -544,6 +547,7 @@ class _ChannelListViewState extends State @override void dispose() { + _subscription.cancel(); WidgetsBinding.instance.removeObserver(this); super.dispose(); } From d24a74be78c203be5916ce94fb5d1bee245393c5 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Wed, 11 Nov 2020 12:16:05 +0100 Subject: [PATCH 0341/1140] use random pngs --- lib/src/stream_chat_theme.dart | 8 +++++--- lib/src/user_avatar.dart | 25 ++++++------------------- lib/src/utils.dart | 5 +++++ 3 files changed, 16 insertions(+), 22 deletions(-) diff --git a/lib/src/stream_chat_theme.dart b/lib/src/stream_chat_theme.dart index 1dfd42b7..3b3725ed 100644 --- a/lib/src/stream_chat_theme.dart +++ b/lib/src/stream_chat_theme.dart @@ -1,3 +1,4 @@ +import 'package:cached_network_image/cached_network_image.dart'; import 'package:flutter/material.dart'; import 'package:stream_chat/stream_chat.dart'; import 'package:stream_chat_flutter/src/channel_header.dart'; @@ -5,6 +6,7 @@ import 'package:stream_chat_flutter/src/channel_preview.dart'; import 'package:stream_chat_flutter/src/message_input.dart'; import 'package:stream_chat_flutter/src/reaction_icon.dart'; import 'package:stream_chat_flutter/src/stream_icons.dart'; +import 'package:stream_chat_flutter/src/utils.dart'; /// Inherited widget providing the [StreamChatThemeData] to the widget tree class StreamChatTheme extends InheritedWidget { @@ -226,9 +228,9 @@ class StreamChatThemeData { defaultChannelImage: (context, channel) => SizedBox(), backgroundColor: isDark ? Colors.black : Colors.white, defaultUserImage: (context, user) => Center( - child: Text( - user.name?.substring(0, 1) ?? '', - style: TextStyle(color: Colors.white), + child: CachedNetworkImage( + imageUrl: getRandomPicUrl(user), + fit: BoxFit.cover, ), ), channelPreviewTheme: ChannelPreviewTheme( diff --git a/lib/src/user_avatar.dart b/lib/src/user_avatar.dart index 41c830e2..86bf7abd 100644 --- a/lib/src/user_avatar.dart +++ b/lib/src/user_avatar.dart @@ -27,6 +27,7 @@ class UserAvatar extends StatelessWidget { final hasImage = user.extraData?.containsKey('image') == true && user.extraData['image'] != null && user.extraData['image'] != ''; + final streamChatTheme = StreamChatTheme.of(context); return GestureDetector( onTap: onTap != null ? () { @@ -39,36 +40,22 @@ class UserAvatar extends StatelessWidget { children: [ ClipRRect( borderRadius: borderRadius ?? - StreamChatTheme.of(context) - .ownMessageTheme - .avatarTheme - .borderRadius, + streamChatTheme.ownMessageTheme.avatarTheme.borderRadius, child: Container( constraints: constraints ?? - StreamChatTheme.of(context) - .ownMessageTheme - .avatarTheme - .constraints, + streamChatTheme.ownMessageTheme.avatarTheme.constraints, decoration: BoxDecoration( - color: StreamChatTheme.of(context).accentColor, + color: streamChatTheme.accentColor, ), child: hasImage ? CachedNetworkImage( imageUrl: user.extraData['image'], errorWidget: (_, __, ___) { - return Center( - child: Text( - user.name[0], - style: TextStyle( - color: Colors.white, - fontWeight: FontWeight.bold, - ), - ), - ); + return streamChatTheme.defaultUserImage(context, user); }, fit: BoxFit.cover, ) - : StreamChatTheme.of(context).defaultUserImage(context, user), + : streamChatTheme.defaultUserImage(context, user), ), ), if (showOnlineStatus && user.online == true) diff --git a/lib/src/utils.dart b/lib/src/utils.dart index b20e5f59..20e3ce1f 100644 --- a/lib/src/utils.dart +++ b/lib/src/utils.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:stream_chat/stream_chat.dart'; import 'package:url_launcher/url_launcher.dart'; Future launchURL(BuildContext context, String url) async { @@ -42,3 +43,7 @@ Future showConfirmationDialog( }, ); } + +/// Get random png with initials +String getRandomPicUrl(User user) => + 'https://getstream.io/random_png/?id=${user.id}&name=${user.name}'; From 09dc280f6de9128446ffe9d3bc31e389bb9f0c04 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Wed, 11 Nov 2020 12:21:17 +0100 Subject: [PATCH 0342/1140] use random png on default users --- example/lib/choose_user_page.dart | 8 +++++--- example/pubspec.yaml | 2 +- lib/stream_chat_flutter.dart | 1 + 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/example/lib/choose_user_page.dart b/example/lib/choose_user_page.dart index beea6b1b..943a66a1 100644 --- a/example/lib/choose_user_page.dart +++ b/example/lib/choose_user_page.dart @@ -53,6 +53,10 @@ class ChooseUserPage extends StatelessWidget { }, ), }; + + users.updateAll( + (_, value) => value..extraData['image'] = getRandomPicUrl(value)); + return Scaffold( body: Column( crossAxisAlignment: CrossAxisAlignment.center, @@ -126,9 +130,7 @@ class ChooseUserPage extends StatelessWidget { final client = StreamChat.of(context).client; await client.setUser( - User(id: user.id, extraData: { - 'name': user.name, - }), + user, token, ); diff --git a/example/pubspec.yaml b/example/pubspec.yaml index f8bfcfe9..87a45b01 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -1,6 +1,6 @@ name: example description: A new Flutter project. -version: 1.0.48+50 +version: 1.0.49+51 environment: sdk: ">=2.2.2 <3.0.0" diff --git a/lib/stream_chat_flutter.dart b/lib/stream_chat_flutter.dart index 4c5760bf..e433e58e 100644 --- a/lib/stream_chat_flutter.dart +++ b/lib/stream_chat_flutter.dart @@ -28,4 +28,5 @@ export 'src/system_message.dart'; export 'src/thread_header.dart'; export 'src/typing_indicator.dart'; export 'src/user_avatar.dart'; +export 'src/utils.dart'; export 'src/video_attachment.dart'; From d4da4870a245b67abdb9f48322587431f37a6b6c Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Wed, 11 Nov 2020 12:52:37 +0100 Subject: [PATCH 0343/1140] add package version --- example/lib/choose_user_page.dart | 28 ++++++++++++++++++++++++++++ example/pubspec.yaml | 4 +++- 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/example/lib/choose_user_page.dart b/example/lib/choose_user_page.dart index 943a66a1..42952e99 100644 --- a/example/lib/choose_user_page.dart +++ b/example/lib/choose_user_page.dart @@ -2,9 +2,11 @@ import 'package:example/advanced_options_page.dart'; import 'package:example/main.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; import 'package:flutter_secure_storage/flutter_secure_storage.dart'; import 'package:flutter_svg/flutter_svg.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; +import 'package:yaml/yaml.dart'; import 'notifications_service.dart'; @@ -214,6 +216,32 @@ class ChooseUserPage extends StatelessWidget { }, ), ), + Container( + padding: const EdgeInsets.symmetric(vertical: 16), + alignment: Alignment.bottomCenter, + child: FutureBuilder( + future: rootBundle.loadString('pubspec.lock'), + builder: (context, snapshot) { + if (!snapshot.hasData) { + return SizedBox(); + } + + final pubspec = snapshot.data; + final yaml = loadYaml(pubspec); + final streamChatDep = + yaml['packages']['stream_chat_flutter']['version']; + + print('streamChatDep: ${streamChatDep}'); + return Text( + 'Stream SDK v ${streamChatDep}', + style: TextStyle( + fontSize: 14.5, + color: Colors.black.withOpacity(.13), + ), + ); + }, + ), + ), ], ), ); diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 87a45b01..8f9e849e 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -1,6 +1,6 @@ name: example description: A new Flutter project. -version: 1.0.49+51 +version: 1.0.50+52 environment: sdk: ">=2.2.2 <3.0.0" @@ -14,6 +14,7 @@ dependencies: flutter_local_notifications: ^2.0.0 flutter_svg: ^0.19.1 flutter_secure_storage: ^3.3.5 + yaml: ^2.2.1 dev_dependencies: flutter_test: @@ -26,6 +27,7 @@ dev_dependencies: flutter: assets: - assets/ + - pubspec.lock uses-material-design: true flutter_icons: From 49f792bceb273a15d467ba53a51b2e4f7bd38dc0 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Wed, 11 Nov 2020 17:23:51 +0530 Subject: [PATCH 0344/1140] rfac, fix: Separated URL attachment to widget, fixed clipping --- lib/src/message_widget.dart | 96 ++----------------------------- lib/src/url_attachment.dart | 110 ++++++++++++++++++++++++++++++++++++ 2 files changed, 115 insertions(+), 91 deletions(-) create mode 100644 lib/src/url_attachment.dart diff --git a/lib/src/message_widget.dart b/lib/src/message_widget.dart index 6f81f149..a41bc97f 100644 --- a/lib/src/message_widget.dart +++ b/lib/src/message_widget.dart @@ -12,6 +12,7 @@ import 'package:jiffy/jiffy.dart'; import 'package:stream_chat_flutter/src/message_actions_modal.dart'; import 'package:stream_chat_flutter/src/message_reactions_modal.dart'; import 'package:stream_chat_flutter/src/reaction_bubble.dart'; +import 'package:stream_chat_flutter/src/url_attachment.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; import 'image_group.dart'; @@ -356,97 +357,10 @@ class _MessageWidgetState extends State { _getWebsiteName(hostName.toLowerCase()) ?? hostName.capitalize(); - return Stack( - children: [ - Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - if (urlAttachment.imageUrl != null) - SizedBox( - height: 16.0, - ), - if (urlAttachment.imageUrl != null) - Container( - margin: EdgeInsets.symmetric(horizontal: 8.0), - child: Stack( - clipBehavior: Clip.antiAlias, - children: [ - Center( - child: CachedNetworkImage( - imageUrl: urlAttachment.imageUrl, - ), - ), - Positioned( - left: 0.0, - bottom: 0.0, - child: Container( - child: Padding( - padding: const EdgeInsets.only( - top: 8.0, - left: 8.0, - right: 8.0, - ), - child: Text( - hostDisplayName, - style: TextStyle( - fontWeight: FontWeight.w700, - color: Color(0xFF006CFF), - ), - ), - ), - decoration: BoxDecoration( - borderRadius: BorderRadius.only( - topRight: Radius.circular(16.0), - ), - color: Color(0xFFE9F2FF), - ), - ), - ), - ], - ), - clipBehavior: Clip.antiAlias, - decoration: - BoxDecoration(borderRadius: BorderRadius.circular(8.0)), - ), - Padding( - padding: widget.textPadding, - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - if (urlAttachment.title != null) - Text( - urlAttachment.title, - maxLines: 1, - style: TextStyle( - fontWeight: FontWeight.w700, - fontSize: 12.0, - ), - ), - if (urlAttachment.text != null) - Text( - urlAttachment.text, - style: TextStyle( - fontWeight: FontWeight.w400, - fontSize: 12.0, - ), - ), - ], - ), - ), - ], - ), - Positioned.fill( - child: Material( - color: Colors.transparent, - child: InkWell( - onTap: () => launchURL( - context, - urlAttachment.ogScrapeUrl, - ), - ), - ), - ), - ], + return UrlAttachment( + urlAttachment: urlAttachment, + hostDisplayName: hostDisplayName, + textPadding: widget.textPadding, ); } diff --git a/lib/src/url_attachment.dart b/lib/src/url_attachment.dart new file mode 100644 index 00000000..4b296a6a --- /dev/null +++ b/lib/src/url_attachment.dart @@ -0,0 +1,110 @@ +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:flutter/material.dart'; +import 'package:stream_chat_flutter/src/utils.dart'; +import 'package:stream_chat_flutter/stream_chat_flutter.dart'; + +class UrlAttachment extends StatelessWidget { + Attachment urlAttachment; + String hostDisplayName; + EdgeInsets textPadding; + + UrlAttachment({ + @required this.urlAttachment, + @required this.hostDisplayName, + @required this.textPadding, + }); + + @override + Widget build(BuildContext context) { + return Stack( + children: [ + Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + if (urlAttachment.imageUrl != null) + SizedBox( + height: 16.0, + ), + if (urlAttachment.imageUrl != null) + Container( + margin: EdgeInsets.symmetric(horizontal: 8.0), + child: Stack( + children: [ + Center( + child: CachedNetworkImage( + imageUrl: urlAttachment.imageUrl, + ), + ), + Positioned( + left: 0.0, + bottom: -1, + child: Container( + child: Padding( + padding: const EdgeInsets.only( + top: 8.0, + left: 8.0, + right: 8.0, + ), + child: Text( + hostDisplayName, + style: TextStyle( + fontWeight: FontWeight.w700, + color: Color(0xFF006CFF), + ), + ), + ), + decoration: BoxDecoration( + borderRadius: BorderRadius.only( + topRight: Radius.circular(16.0), + ), + color: Color(0xFFE9F2FF), + ), + ), + ), + ], + ), + decoration: + BoxDecoration(borderRadius: BorderRadius.circular(8.0)), + ), + Padding( + padding: textPadding, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + if (urlAttachment.title != null) + Text( + urlAttachment.title, + maxLines: 1, + style: TextStyle( + fontWeight: FontWeight.w700, + fontSize: 12.0, + ), + ), + if (urlAttachment.text != null) + Text( + urlAttachment.text, + style: TextStyle( + fontWeight: FontWeight.w400, + fontSize: 12.0, + ), + ), + ], + ), + ), + ], + ), + Positioned.fill( + child: Material( + color: Colors.transparent, + child: InkWell( + onTap: () => launchURL( + context, + urlAttachment.ogScrapeUrl, + ), + ), + ), + ), + ], + ); + } +} From 80d04016437b76a6233f2175a808d8ce6c7fc369 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Wed, 11 Nov 2020 12:56:00 +0100 Subject: [PATCH 0345/1140] add package version in advanced options --- example/lib/advanced_options_page.dart | 12 +++++--- example/lib/choose_user_page.dart | 30 ++------------------ example/lib/stream_version.dart | 39 ++++++++++++++++++++++++++ example/pubspec.yaml | 2 +- 4 files changed, 50 insertions(+), 33 deletions(-) create mode 100644 example/lib/stream_version.dart diff --git a/example/lib/advanced_options_page.dart b/example/lib/advanced_options_page.dart index 4fb801c9..f0373345 100644 --- a/example/lib/advanced_options_page.dart +++ b/example/lib/advanced_options_page.dart @@ -1,5 +1,6 @@ import 'dart:io'; +import 'package:example/stream_version.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; @@ -52,9 +53,11 @@ class _AdvancedOptionsPageState extends State { body: Builder( builder: (context) { return Padding( - padding: const EdgeInsets.symmetric( - horizontal: 16, - vertical: 16, + padding: const EdgeInsets.fromLTRB( + 16, + 16, + 16, + 0, ), child: Form( key: _formKey, @@ -266,7 +269,8 @@ class _AdvancedOptionsPageState extends State { }, ), ), - ) + ), + StreamVersion(), ], ), ), diff --git a/example/lib/choose_user_page.dart b/example/lib/choose_user_page.dart index 42952e99..b5296f8a 100644 --- a/example/lib/choose_user_page.dart +++ b/example/lib/choose_user_page.dart @@ -1,12 +1,11 @@ import 'package:example/advanced_options_page.dart'; import 'package:example/main.dart'; +import 'package:example/stream_version.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; import 'package:flutter_secure_storage/flutter_secure_storage.dart'; import 'package:flutter_svg/flutter_svg.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; -import 'package:yaml/yaml.dart'; import 'notifications_service.dart'; @@ -216,32 +215,7 @@ class ChooseUserPage extends StatelessWidget { }, ), ), - Container( - padding: const EdgeInsets.symmetric(vertical: 16), - alignment: Alignment.bottomCenter, - child: FutureBuilder( - future: rootBundle.loadString('pubspec.lock'), - builder: (context, snapshot) { - if (!snapshot.hasData) { - return SizedBox(); - } - - final pubspec = snapshot.data; - final yaml = loadYaml(pubspec); - final streamChatDep = - yaml['packages']['stream_chat_flutter']['version']; - - print('streamChatDep: ${streamChatDep}'); - return Text( - 'Stream SDK v ${streamChatDep}', - style: TextStyle( - fontSize: 14.5, - color: Colors.black.withOpacity(.13), - ), - ); - }, - ), - ), + StreamVersion(), ], ), ); diff --git a/example/lib/stream_version.dart b/example/lib/stream_version.dart new file mode 100644 index 00000000..ee340f89 --- /dev/null +++ b/example/lib/stream_version.dart @@ -0,0 +1,39 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:yaml/yaml.dart'; + +class StreamVersion extends StatelessWidget { + const StreamVersion({ + Key key, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + return Container( + padding: const EdgeInsets.symmetric(vertical: 16), + alignment: Alignment.bottomCenter, + child: FutureBuilder( + future: rootBundle.loadString('pubspec.lock'), + builder: (context, snapshot) { + if (!snapshot.hasData) { + return SizedBox(); + } + + final pubspec = snapshot.data; + final yaml = loadYaml(pubspec); + final streamChatDep = + yaml['packages']['stream_chat_flutter']['version']; + + print('streamChatDep: ${streamChatDep}'); + return Text( + 'Stream SDK v ${streamChatDep}', + style: TextStyle( + fontSize: 14.5, + color: Colors.black.withOpacity(.13), + ), + ); + }, + ), + ); + } +} diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 8f9e849e..855373bf 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -1,6 +1,6 @@ name: example description: A new Flutter project. -version: 1.0.50+52 +version: 1.0.51+53 environment: sdk: ">=2.2.2 <3.0.0" From 36d7ad060a911f5e457a976c83eaba36b9c1c360 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Wed, 11 Nov 2020 13:03:46 +0100 Subject: [PATCH 0346/1140] update sending indicator color --- lib/src/sending_indicator.dart | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/src/sending_indicator.dart b/lib/src/sending_indicator.dart index e93984e2..ce8915c3 100644 --- a/lib/src/sending_indicator.dart +++ b/lib/src/sending_indicator.dart @@ -18,6 +18,7 @@ class SendingIndicator extends StatelessWidget { return Icon( Icons.done_all, size: 8, + color: StreamChatTheme.of(context).accentColor, ); } if (message.status == MessageSendingStatus.SENT || message.status == null) { From e07c865c676b2a7dfcb4689f97508c04b48e6666 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Wed, 11 Nov 2020 14:16:00 +0100 Subject: [PATCH 0347/1140] fix url attachment image border radius --- lib/src/url_attachment.dart | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/src/url_attachment.dart b/lib/src/url_attachment.dart index 4b296a6a..c6b0b3f7 100644 --- a/lib/src/url_attachment.dart +++ b/lib/src/url_attachment.dart @@ -27,6 +27,7 @@ class UrlAttachment extends StatelessWidget { ), if (urlAttachment.imageUrl != null) Container( + clipBehavior: Clip.antiAliasWithSaveLayer, margin: EdgeInsets.symmetric(horizontal: 8.0), child: Stack( children: [ @@ -63,8 +64,9 @@ class UrlAttachment extends StatelessWidget { ), ], ), - decoration: - BoxDecoration(borderRadius: BorderRadius.circular(8.0)), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(8.0), + ), ), Padding( padding: textPadding, From 7b151dfb613b7a6f640753c9a08e598e9b5664af Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Wed, 11 Nov 2020 14:22:33 +0100 Subject: [PATCH 0348/1140] update podfile --- example/ios/Podfile.lock | 10 ++++++++-- example/ios/Runner.xcodeproj/project.pbxproj | 2 ++ example/pubspec.yaml | 2 +- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock index d20eaee6..f23764fa 100644 --- a/example/ios/Podfile.lock +++ b/example/ios/Podfile.lock @@ -38,7 +38,7 @@ PODS: - Firebase/Messaging (6.33.0): - Firebase/CoreOnly - FirebaseMessaging (~> 4.7.0) - - firebase_core (0.5.1): + - firebase_core (0.5.2): - Firebase/CoreOnly (~> 6.33.0) - Flutter - firebase_messaging (7.0.3): @@ -82,6 +82,8 @@ PODS: - Flutter - flutter_local_notifications (0.0.1): - Flutter + - flutter_secure_storage (3.3.1): + - Flutter - FMDB (2.7.5): - FMDB/standard (= 2.7.5) - FMDB/standard (2.7.5) @@ -161,6 +163,7 @@ DEPENDENCIES: - 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`) + - flutter_secure_storage (from `.symlinks/plugins/flutter_secure_storage/ios`) - image_picker (from `.symlinks/plugins/image_picker/ios`) - path_provider (from `.symlinks/plugins/path_provider/ios`) - shared_preferences (from `.symlinks/plugins/shared_preferences/ios`) @@ -210,6 +213,8 @@ EXTERNAL SOURCES: :path: ".symlinks/plugins/flutter_keyboard_visibility/ios" flutter_local_notifications: :path: ".symlinks/plugins/flutter_local_notifications/ios" + flutter_secure_storage: + :path: ".symlinks/plugins/flutter_secure_storage/ios" image_picker: :path: ".symlinks/plugins/image_picker/ios" path_provider: @@ -232,7 +237,7 @@ SPEC CHECKSUMS: DKPhotoGallery: fdfad5125a9fdda9cc57df834d49df790dbb4179 file_picker: 3e6c3790de664ccf9b882732d9db5eaf6b8d4eb1 Firebase: 8db6f2d1b2c5e2984efba4949a145875a8f65fe5 - firebase_core: aa25a5dc6b492ecab37587c53d8420135f0cac90 + firebase_core: 350ba329d1641211bc6183a3236893cafdacfea7 firebase_messaging: 0aea2cd5885b65e19ede58ee3507f485c992cc75 FirebaseCore: d889d9e12535b7f36ac8bfbf1713a0836a3012cd FirebaseCoreDiagnostics: 770ac5958e1372ce67959ae4b4f31d8e127c3ac1 @@ -244,6 +249,7 @@ SPEC CHECKSUMS: flutter_app_badger: 65de4d6f0c34a891df49e6cfb8a1c0496426fa68 flutter_keyboard_visibility: 0339d06371254c3eb25eeb90ba8d17dca8f9c069 flutter_local_notifications: 0c0b1ae97e741e1521e4c1629a459d04b9aec743 + flutter_secure_storage: 7953c38a04c3fdbb00571bcd87d8e3b5ceb9daec FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a GoogleDataTransport: f56af7caa4ed338dc8e138a5d7c5973e66440833 GoogleUtilities: 7f2f5a07f888cdb145101d6042bc4422f57e70b3 diff --git a/example/ios/Runner.xcodeproj/project.pbxproj b/example/ios/Runner.xcodeproj/project.pbxproj index 6d377561..1baa240f 100644 --- a/example/ios/Runner.xcodeproj/project.pbxproj +++ b/example/ios/Runner.xcodeproj/project.pbxproj @@ -325,6 +325,7 @@ "${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}/flutter_secure_storage/flutter_secure_storage.framework", "${BUILT_PRODUCTS_DIR}/image_picker/image_picker.framework", "${BUILT_PRODUCTS_DIR}/nanopb/nanopb.framework", "${BUILT_PRODUCTS_DIR}/path_provider/path_provider.framework", @@ -354,6 +355,7 @@ "${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}/flutter_secure_storage.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/image_picker.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/nanopb.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/path_provider.framework", diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 855373bf..894bc679 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -1,6 +1,6 @@ name: example description: A new Flutter project. -version: 1.0.51+53 +version: 1.0.52+54 environment: sdk: ">=2.2.2 <3.0.0" From aa478bfef5b26695b47169d8e2bfb09a0d16065f Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Wed, 11 Nov 2020 14:54:22 +0100 Subject: [PATCH 0349/1140] use bold fontweight --- example/lib/advanced_options_page.dart | 4 ++++ example/pubspec.yaml | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/example/lib/advanced_options_page.dart b/example/lib/advanced_options_page.dart index f0373345..8a4c79c0 100644 --- a/example/lib/advanced_options_page.dart +++ b/example/lib/advanced_options_page.dart @@ -74,6 +74,7 @@ class _AdvancedOptionsPageState extends State { decoration: InputDecoration( labelStyle: TextStyle( fontSize: 14, + fontWeight: FontWeight.bold, color: Colors.black.withOpacity(.5), ), border: UnderlineInputBorder( @@ -99,6 +100,7 @@ class _AdvancedOptionsPageState extends State { textInputAction: TextInputAction.next, decoration: InputDecoration( labelStyle: TextStyle( + fontWeight: FontWeight.bold, fontSize: 14, color: Colors.black.withOpacity(.5), ), @@ -125,6 +127,7 @@ class _AdvancedOptionsPageState extends State { textInputAction: TextInputAction.next, decoration: InputDecoration( labelStyle: TextStyle( + fontWeight: FontWeight.bold, fontSize: 14, color: Colors.black.withOpacity(.5), ), @@ -146,6 +149,7 @@ class _AdvancedOptionsPageState extends State { decoration: InputDecoration( labelStyle: TextStyle( fontSize: 14, + fontWeight: FontWeight.bold, color: Colors.black.withOpacity(.5), ), border: UnderlineInputBorder( diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 894bc679..c6743cd4 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -1,6 +1,6 @@ name: example description: A new Flutter project. -version: 1.0.52+54 +version: 1.0.53+55 environment: sdk: ">=2.2.2 <3.0.0" From e32902d5aa3fe96922ea2852903883b0510aebe6 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Wed, 11 Nov 2020 15:21:00 +0100 Subject: [PATCH 0350/1140] add unread indicator in backbutton --- lib/src/back_button.dart | 65 ++++++++++++++++----------- lib/src/channel_header.dart | 5 ++- lib/src/channel_preview.dart | 4 +- lib/src/channel_unread_indicator.dart | 48 ++++++++++++++++++++ lib/src/unread_indicator.dart | 61 +++++++++++++------------ 5 files changed, 123 insertions(+), 60 deletions(-) create mode 100644 lib/src/channel_unread_indicator.dart diff --git a/lib/src/back_button.dart b/lib/src/back_button.dart index 657a44ef..78b86ae5 100644 --- a/lib/src/back_button.dart +++ b/lib/src/back_button.dart @@ -1,44 +1,57 @@ import 'package:flutter/material.dart'; +import 'package:stream_chat_flutter/src/stream_icons.dart'; +import 'package:stream_chat_flutter/src/unread_indicator.dart'; +import 'package:stream_chat_flutter/stream_chat_flutter.dart'; class StreamBackButton extends StatelessWidget { const StreamBackButton({ Key key, this.onPressed, this.icon = Icons.arrow_back_ios_outlined, + this.showUnreads = false, }) : super(key: key); final VoidCallback onPressed; final IconData icon; + final bool showUnreads; @override Widget build(BuildContext context) { - return Padding( - padding: const EdgeInsets.all(14.0), - child: RawMaterialButton( - shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(4)), - elevation: 0, - highlightElevation: 0, - focusElevation: 0, - disabledElevation: 0, - hoverElevation: 0, - onPressed: () { - if (onPressed != null) { - onPressed(); - } else { - Navigator.of(context).pop(); - } - }, - fillColor: Theme.of(context).brightness == Brightness.dark - ? Colors.white.withOpacity(.1) - : Colors.black.withOpacity(.1), - child: Icon( - icon ?? Icons.arrow_back_ios_outlined, - size: 15, - color: Theme.of(context).brightness == Brightness.dark - ? Colors.white - : Colors.black, + return Stack( + children: [ + Padding( + padding: const EdgeInsets.all(14.0), + child: RawMaterialButton( + shape: + RoundedRectangleBorder(borderRadius: BorderRadius.circular(4)), + elevation: 0, + highlightElevation: 0, + focusElevation: 0, + disabledElevation: 0, + hoverElevation: 0, + onPressed: () { + if (onPressed != null) { + onPressed(); + } else { + Navigator.of(context).pop(); + } + }, + child: Icon( + icon ?? StreamIcons.left, + size: 24, + color: Theme.of(context).brightness == Brightness.dark + ? Colors.white + : Colors.black, + ), + ), ), - ), + if (showUnreads) + Positioned( + top: 7, + right: 7, + child: UnreadIndicator(), + ), + ], ); } } diff --git a/lib/src/channel_header.dart b/lib/src/channel_header.dart index 81f95a87..ee0fd179 100644 --- a/lib/src/channel_header.dart +++ b/lib/src/channel_header.dart @@ -81,7 +81,10 @@ class ChannelHeader extends StatelessWidget implements PreferredSizeWidget { brightness: Theme.of(context).brightness, elevation: 1, leading: showBackButton - ? StreamBackButton(onPressed: onBackPressed) + ? StreamBackButton( + onPressed: onBackPressed, + showUnreads: true, + ) : SizedBox(), backgroundColor: StreamChatTheme.of(context).channelTheme.channelHeaderTheme.color, diff --git a/lib/src/channel_preview.dart b/lib/src/channel_preview.dart index c23d7732..ba3090c2 100644 --- a/lib/src/channel_preview.dart +++ b/lib/src/channel_preview.dart @@ -2,10 +2,10 @@ import 'package:flutter/material.dart'; import 'package:flutter/widgets.dart'; import 'package:jiffy/jiffy.dart'; import 'package:stream_chat/stream_chat.dart'; -import 'package:stream_chat_flutter/src/unread_indicator.dart'; import '../stream_chat_flutter.dart'; import 'channel_name.dart'; +import 'channel_unread_indicator.dart'; /// ![screenshot](https://raw.githubusercontent.com/GetStream/stream-chat-flutter/master/screenshots/channel_preview.png) /// ![screenshot](https://raw.githubusercontent.com/GetStream/stream-chat-flutter/master/screenshots/channel_preview_paint.png) @@ -80,7 +80,7 @@ class ChannelPreview extends StatelessWidget { e.user.id == channel.client.state.user.id)) { return SizedBox(); } - return UnreadIndicator( + return ChannelUnreadIndicator( channel: channel, ); }), diff --git a/lib/src/channel_unread_indicator.dart b/lib/src/channel_unread_indicator.dart new file mode 100644 index 00000000..8080b1e9 --- /dev/null +++ b/lib/src/channel_unread_indicator.dart @@ -0,0 +1,48 @@ +import 'package:flutter/material.dart'; +import 'package:stream_chat/stream_chat.dart'; +import 'package:stream_chat_flutter/src/stream_chat_theme.dart'; + +class ChannelUnreadIndicator extends StatelessWidget { + const ChannelUnreadIndicator({ + Key key, + @required this.channel, + }) : super(key: key); + + final Channel channel; + + @override + Widget build(BuildContext context) { + return StreamBuilder( + stream: channel.state.unreadCountStream, + initialData: channel.state.unreadCount, + builder: (context, snapshot) { + if (!snapshot.hasData || snapshot.data == 0) { + return SizedBox(); + } + return Material( + borderRadius: BorderRadius.circular(8), + color: StreamChatTheme.of(context) + .channelPreviewTheme + .unreadCounterColor, + child: Padding( + padding: const EdgeInsets.only( + left: 5.0, + right: 5.0, + top: 2, + bottom: 1, + ), + child: Center( + child: Text( + '${snapshot.data}', + style: TextStyle( + fontSize: 11, + color: Colors.white, + ), + ), + ), + ), + ); + }, + ); + } +} diff --git a/lib/src/unread_indicator.dart b/lib/src/unread_indicator.dart index 7e49e202..c9f42fad 100644 --- a/lib/src/unread_indicator.dart +++ b/lib/src/unread_indicator.dart @@ -1,47 +1,46 @@ import 'package:flutter/material.dart'; -import 'package:stream_chat/stream_chat.dart'; import 'package:stream_chat_flutter/src/stream_chat_theme.dart'; +import 'package:stream_chat_flutter/stream_chat_flutter.dart'; class UnreadIndicator extends StatelessWidget { const UnreadIndicator({ Key key, - @required this.channel, }) : super(key: key); - final Channel channel; - @override Widget build(BuildContext context) { + final client = StreamChat.of(context).client; return StreamBuilder( - stream: channel.state.unreadCountStream, - initialData: channel.state.unreadCount, - builder: (context, snapshot) { - if (!snapshot.hasData || snapshot.data == 0) { - return SizedBox(); - } - return Material( - borderRadius: BorderRadius.circular(8), - color: StreamChatTheme.of(context) - .channelPreviewTheme - .unreadCounterColor, - child: Padding( - padding: const EdgeInsets.only( - left: 5.0, - right: 5.0, - top: 2, - bottom: 1, - ), - child: Center( - child: Text( - '${snapshot.data}', - style: TextStyle( - fontSize: 11, - color: Colors.white, - ), + stream: client.state.totalUnreadCountStream, + initialData: client.state.totalUnreadCount, + builder: (context, snapshot) { + if (!snapshot.hasData || snapshot.data == 0) { + return SizedBox(); + } + return Material( + borderRadius: BorderRadius.circular(8), + color: StreamChatTheme.of(context) + .channelPreviewTheme + .unreadCounterColor, + child: Padding( + padding: const EdgeInsets.only( + left: 5.0, + right: 5.0, + top: 2, + bottom: 1, + ), + child: Center( + child: Text( + '${snapshot.data}', + style: TextStyle( + fontSize: 11, + color: Colors.white, ), ), ), - ); - }); + ), + ); + }, + ); } } From 42e746fed7c9049780bf8935b6dc9e4001b0839f Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Wed, 11 Nov 2020 16:35:58 +0100 Subject: [PATCH 0351/1140] use media_gallery plugin --- .../android/app/src/main/AndroidManifest.xml | 6 +- example/ios/Podfile.lock | 10 +- example/ios/Runner.xcodeproj/project.pbxproj | 2 + example/pubspec.yaml | 2 +- lib/src/message_input.dart | 117 ++++++++++-------- pubspec.yaml | 4 +- 6 files changed, 83 insertions(+), 58 deletions(-) diff --git a/example/android/app/src/main/AndroidManifest.xml b/example/android/app/src/main/AndroidManifest.xml index a90d828e..6fb8664b 100644 --- a/example/android/app/src/main/AndroidManifest.xml +++ b/example/android/app/src/main/AndroidManifest.xml @@ -6,10 +6,14 @@ additional functionality it is fine to subclass or reimplement FlutterApplication and put your custom class here. --> + + + android:icon="@mipmap/ic_launcher" + android:requestLegacyExternalStorage="true" + > 4.7.0) - - firebase_core (0.5.1): + - firebase_core (0.5.2): - Firebase/CoreOnly (~> 6.33.0) - Flutter - firebase_messaging (7.0.3): @@ -113,6 +113,8 @@ PODS: - nanopb/encode (1.30906.0) - path_provider (0.0.1): - Flutter + - photo_gallery (0.0.1): + - Flutter - PromisesObjC (1.2.11) - Protobuf (3.13.0) - SDWebImage (5.9.4): @@ -163,6 +165,7 @@ DEPENDENCIES: - flutter_local_notifications (from `.symlinks/plugins/flutter_local_notifications/ios`) - image_picker (from `.symlinks/plugins/image_picker/ios`) - path_provider (from `.symlinks/plugins/path_provider/ios`) + - photo_gallery (from `.symlinks/plugins/photo_gallery/ios`) - shared_preferences (from `.symlinks/plugins/shared_preferences/ios`) - sqflite (from `.symlinks/plugins/sqflite/ios`) - sqlite3_flutter_libs (from `.symlinks/plugins/sqlite3_flutter_libs/ios`) @@ -214,6 +217,8 @@ EXTERNAL SOURCES: :path: ".symlinks/plugins/image_picker/ios" path_provider: :path: ".symlinks/plugins/path_provider/ios" + photo_gallery: + :path: ".symlinks/plugins/photo_gallery/ios" shared_preferences: :path: ".symlinks/plugins/shared_preferences/ios" sqflite: @@ -232,7 +237,7 @@ SPEC CHECKSUMS: DKPhotoGallery: fdfad5125a9fdda9cc57df834d49df790dbb4179 file_picker: 3e6c3790de664ccf9b882732d9db5eaf6b8d4eb1 Firebase: 8db6f2d1b2c5e2984efba4949a145875a8f65fe5 - firebase_core: aa25a5dc6b492ecab37587c53d8420135f0cac90 + firebase_core: 350ba329d1641211bc6183a3236893cafdacfea7 firebase_messaging: 0aea2cd5885b65e19ede58ee3507f485c992cc75 FirebaseCore: d889d9e12535b7f36ac8bfbf1713a0836a3012cd FirebaseCoreDiagnostics: 770ac5958e1372ce67959ae4b4f31d8e127c3ac1 @@ -250,6 +255,7 @@ SPEC CHECKSUMS: image_picker: 9c3312491f862b28d21ecd8fdf0ee14e601b3f09 nanopb: 59317e09cf1f1a0af72f12af412d54edf52603fc path_provider: abfe2b5c733d04e238b0d8691db0cfd63a27a93c + photo_gallery: 9f95e57747cd22c10676ece3660d1ffe6c603ee5 PromisesObjC: 8c196f5a328c2cba3e74624585467a557dcb482f Protobuf: 3dac39b34a08151c6d949560efe3f86134a3f748 SDWebImage: b69257f4ab14e9b6a2ef53e910fdf914d8f757c1 diff --git a/example/ios/Runner.xcodeproj/project.pbxproj b/example/ios/Runner.xcodeproj/project.pbxproj index 6d377561..de8fcb9a 100644 --- a/example/ios/Runner.xcodeproj/project.pbxproj +++ b/example/ios/Runner.xcodeproj/project.pbxproj @@ -328,6 +328,7 @@ "${BUILT_PRODUCTS_DIR}/image_picker/image_picker.framework", "${BUILT_PRODUCTS_DIR}/nanopb/nanopb.framework", "${BUILT_PRODUCTS_DIR}/path_provider/path_provider.framework", + "${BUILT_PRODUCTS_DIR}/photo_gallery/photo_gallery.framework", "${BUILT_PRODUCTS_DIR}/shared_preferences/shared_preferences.framework", "${BUILT_PRODUCTS_DIR}/sqflite/sqflite.framework", "${BUILT_PRODUCTS_DIR}/sqlite3/sqlite3.framework", @@ -357,6 +358,7 @@ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/image_picker.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/nanopb.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/path_provider.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/photo_gallery.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/shared_preferences.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/sqflite.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/sqlite3.framework", diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 0cba8d30..79b9638e 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -1,7 +1,7 @@ name: example description: A new Flutter project. -version: 1.0.43+45 +version: 1.0.44+46 environment: sdk: ">=2.2.2 <3.0.0" diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 9fd4e746..c26cd152 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -8,15 +8,17 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_keyboard_visibility/flutter_keyboard_visibility.dart'; import 'package:flutter_svg/flutter_svg.dart'; -import 'package:http_parser/http_parser.dart'; +import 'package:http_parser/http_parser.dart' as httpParser; import 'package:image_picker/image_picker.dart'; +import 'package:media_gallery/media_gallery.dart'; import 'package:mime/mime.dart'; -import 'package:photo_gallery/photo_gallery.dart'; +import 'package:permission_handler/permission_handler.dart'; import 'package:stream_chat/stream_chat.dart'; import 'package:stream_chat_flutter/src/message_list_view.dart'; import 'package:stream_chat_flutter/src/stream_chat_theme.dart'; import 'package:stream_chat_flutter/src/user_avatar.dart'; import 'package:substring_highlight/substring_highlight.dart'; +import 'package:transparent_image/transparent_image.dart'; import '../stream_chat_flutter.dart'; import 'stream_channel.dart'; @@ -181,7 +183,7 @@ class MessageInputState extends State { int _filePickerIndex = 0; double _filePickerSize = 250.0; - Tuple2, List> _mediaData = Tuple2([], []); + Iterable _media = []; /// The editing controller passed to the input TextField TextEditingController textEditingController; @@ -716,7 +718,7 @@ class MessageInputState extends State { switch (_filePickerIndex) { case 0: return GridView.builder( - itemCount: _mediaData.item2.length, + itemCount: _media.length, gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 3), itemBuilder: (context, position) { @@ -728,24 +730,29 @@ class MessageInputState extends State { children: [ AspectRatio( aspectRatio: 1.0, - child: Image.memory( - _mediaData.item2[position], - fit: _mediaData.item1[position].height > - _mediaData.item1[position].width - ? BoxFit.fitWidth - : BoxFit.fitHeight, + child: FadeInImage( + placeholder: MemoryImage(kTransparentImage), + image: MediaThumbnailProvider( + media: _media.elementAt(position), + ), + fit: BoxFit.fill, ), ), - IgnorePointer( - child: AnimatedOpacity( - duration: Duration(milliseconds: 300), - opacity: _attachments.any((element) => - element.id == _mediaData.item1[position].id) - ? 1.0 - : 0.0, - child: Container( - color: Colors.black.withOpacity(0.5), - child: Center( + Positioned.fill( + child: IgnorePointer( + child: AnimatedOpacity( + duration: Duration(milliseconds: 300), + opacity: _attachments.any((element) => + element.id == _media.elementAt(position).id) + ? 1.0 + : 0.0, + child: Container( + color: Colors.black.withOpacity(0.5), + alignment: Alignment.topRight, + padding: const EdgeInsets.only( + top: 8, + right: 8, + ), child: CircleAvatar( maxRadius: 12.0, backgroundColor: Colors.white, @@ -762,11 +769,11 @@ class MessageInputState extends State { ), onTap: () { if (!_attachments.any((element) => - element.id == _mediaData.item1[position].id)) { - _addAttachment(_mediaData.item1[position]); + element.id == _media.elementAt(position).id)) { + _addAttachment(_media.elementAt(position)); } else { _attachments.removeWhere((element) => - element.id == _mediaData.item1[position].id); + element.id == _media.elementAt(position).id); setState(() {}); } }, @@ -782,10 +789,10 @@ class MessageInputState extends State { } } - void _addAttachment(Medium medium) async { - var mediaFile = await PhotoGallery.getFile(mediumId: medium.id); + void _addAttachment(Media medium) async { + final mediaFile = await medium.getFile(); - var file = PlatformFile( + final file = PlatformFile( path: mediaFile.path, bytes: mediaFile.readAsBytesSync(), ); @@ -803,7 +810,7 @@ class MessageInputState extends State { file: file, attachment: Attachment( localUri: file.path != null ? Uri.parse(file.path) : null, - type: medium.mediumType == MediumType.image ? 'image' : 'video', + type: medium.mediaType == MediaType.image ? 'image' : 'video', ), id: medium.id, ); @@ -814,12 +821,12 @@ class MessageInputState extends State { final url = await _uploadAttachment( file, - medium.mediumType == MediumType.image + medium.mediaType == MediaType.image ? DefaultAttachmentTypes.image : DefaultAttachmentTypes.video, channel); - var fileType = medium.mediumType == MediumType.image + final fileType = medium.mediaType == MediaType.image ? DefaultAttachmentTypes.image : DefaultAttachmentTypes.video; @@ -839,32 +846,28 @@ class MessageInputState extends State { } void _getAllMedia() async { - var allAlbums = await PhotoGallery.listAlbums(mediumType: MediumType.image); - var allVideoAlbums = - await PhotoGallery.listAlbums(mediumType: MediumType.video); - List resultList = []; - List> resultThumbnailList = []; + final List collections = + await MediaGallery.listMediaCollections(mediaTypes: [ + MediaType.image, + MediaType.video, + ]); - for (var album in allAlbums) { - var data = await album.listMedia(); - resultList.addAll(data.items); + if (collections.isEmpty) { + return; } - for (var album in allVideoAlbums) { - var data = await album.listMedia(); - resultList.addAll(data.items); - } - - resultList.sort((a, b) => a.modifiedDate.compareTo(b.modifiedDate)); - resultList = resultList.toSet().toList(); - - for (var e in resultList) { - resultThumbnailList.add(await PhotoGallery.getThumbnail(mediumId: e.id)); - } + final page = await collections + .firstWhere( + (element) => element.name == 'All', + orElse: () => collections.first, + ) + .getMedias( + take: 50, + ); + print('page.items.length: ${page.items.length}'); setState(() { - _mediaData = - Tuple2, List>(resultList, resultThumbnailList); + _media = page.items; }); } @@ -1271,13 +1274,21 @@ class MessageInputState extends State { color: Color(0xFF000000).withAlpha(128), ), ), - onTap: () { + onTap: () async { if (_openFilePickerSection) { setState(() { _openFilePickerSection = false; _filePickerSize = 250.0; }); } else { + final status = await Permission.storage.request(); + print('status: ${status}'); + if (status.isDenied || status.isPermanentlyDenied) { + final res = await openAppSettings(); + if (!res) { + return; + } + } _getAllMedia(); showAttachmentModal(); } @@ -1494,7 +1505,7 @@ class MessageInputState extends State { MultipartFile.fromBytes( bytes, filename: filename, - contentType: MediaType.parse(lookupMimeType(filename)), + contentType: httpParser.MediaType.parse(lookupMimeType(filename)), ), ); return res.file; @@ -1507,7 +1518,7 @@ class MessageInputState extends State { MultipartFile.fromBytes( bytes, filename: filename, - contentType: MediaType.parse(lookupMimeType(filename)), + contentType: httpParser.MediaType.parse(lookupMimeType(filename)), ), ); return res.file; diff --git a/pubspec.yaml b/pubspec.yaml index 6b2aeff1..ce0b3633 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -35,7 +35,9 @@ dependencies: flutter_slidable: ^0.5.4 carousel_slider: ^2.2.1 clipboard: ^0.1.2+8 - photo_gallery: ^0.3.0 + media_gallery: ^0.1.5 + permission_handler: ^5.0.1+1 + transparent_image: ^1.0.0 flutter: assets: From f756e6e5670c2b37b0d31d527fe2f15d5e9025ae Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Wed, 11 Nov 2020 17:29:45 +0100 Subject: [PATCH 0352/1140] extract media list view --- lib/src/media_list_view.dart | 161 +++++++++++++++++++++++++++++++++++ lib/src/message_input.dart | 125 ++++++--------------------- svgs/video_call_icon.svg | 3 + 3 files changed, 189 insertions(+), 100 deletions(-) create mode 100644 lib/src/media_list_view.dart create mode 100644 svgs/video_call_icon.svg diff --git a/lib/src/media_list_view.dart b/lib/src/media_list_view.dart new file mode 100644 index 00000000..5a2fc25f --- /dev/null +++ b/lib/src/media_list_view.dart @@ -0,0 +1,161 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_svg/flutter_svg.dart'; +import 'package:media_gallery/media_gallery.dart'; +import 'package:stream_chat_flutter/src/stream_icons.dart'; +import 'package:transparent_image/transparent_image.dart'; + +class MediaListView extends StatefulWidget { + final List selectedIds; + final void Function(Media media) onSelect; + + const MediaListView({ + Key key, + this.selectedIds = const [], + this.onSelect, + }) : super(key: key); + @override + _MediaListViewState createState() => _MediaListViewState(); +} + +class _MediaListViewState extends State { + final _media = []; + final ScrollController _scrollController = ScrollController(); + + @override + Widget build(BuildContext context) { + return GridView.builder( + itemCount: _media.length, + controller: _scrollController, + gridDelegate: + SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 3), + itemBuilder: ( + context, + position, + ) { + final media = _media.elementAt(position); + return Padding( + padding: const EdgeInsets.symmetric(horizontal: 1.0, vertical: 1.0), + child: InkWell( + child: Stack( + children: [ + AspectRatio( + aspectRatio: 1.0, + child: FadeInImage( + placeholder: MemoryImage(kTransparentImage), + image: MediaThumbnailProvider( + media: media, + ), + fit: BoxFit.cover, + ), + ), + Positioned.fill( + child: IgnorePointer( + child: AnimatedOpacity( + duration: Duration(milliseconds: 300), + opacity: widget.selectedIds.any((id) => id == media.id) + ? 1.0 + : 0.0, + child: Container( + color: Colors.black.withOpacity(0.5), + alignment: Alignment.topRight, + padding: const EdgeInsets.only( + top: 8, + right: 8, + ), + child: CircleAvatar( + maxRadius: 12.0, + backgroundColor: Colors.white, + child: Icon( + StreamIcons.check, + color: Colors.black, + ), + ), + ), + ), + ), + ), + if (media.mediaType == MediaType.video) + Positioned( + left: 8, + bottom: 10, + child: SvgPicture.asset( + 'svgs/video_call_icon.svg', + package: 'stream_chat_flutter', + ), + ), + ], + ), + onTap: () { + if (widget.onSelect != null) { + widget.onSelect(media); + } + }, + ), + ); + }, + ); + } + + @override + void initState() { + super.initState(); + + _scrollController.addListener(() { + if (_scrollController.offset > + _scrollController.position.maxScrollExtent - 100) { + _getMedia(); + } + }); + + _getMedia(); + } + + @override + void dispose() { + _scrollController.dispose(); + super.dispose(); + } + + void _getMedia() async { + final List collections = + await MediaGallery.listMediaCollections( + mediaTypes: [ + MediaType.video, + MediaType.image, + ], + ); + + if (collections.isEmpty) { + return; + } + final collection = collections.firstWhere( + (element) => element.isAllCollection, + orElse: () => collections.first, + ); + + final videoPage = await collection.getMedias( + mediaType: MediaType.video, + take: 500, + ); + final imagePage = await collection.getMedias( + mediaType: MediaType.image, + take: 500, + ); + + final allItems = [ + ...videoPage.items, + ...imagePage.items, + ]..sort(( + a, + b, + ) => + b.creationDate.compareTo(a.creationDate)); + + setState(() { + _media.addAll(allItems); + }); + + print( + '_media.where((element) => element.mediaType == MediaType.video).length: ${_media.where((element) => element.mediaType == MediaType.video).length}'); + } +} diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index c26cd152..7e8a40c4 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -14,11 +14,11 @@ import 'package:media_gallery/media_gallery.dart'; import 'package:mime/mime.dart'; import 'package:permission_handler/permission_handler.dart'; import 'package:stream_chat/stream_chat.dart'; +import 'package:stream_chat_flutter/src/media_list_view.dart'; import 'package:stream_chat_flutter/src/message_list_view.dart'; import 'package:stream_chat_flutter/src/stream_chat_theme.dart'; import 'package:stream_chat_flutter/src/user_avatar.dart'; import 'package:substring_highlight/substring_highlight.dart'; -import 'package:transparent_image/transparent_image.dart'; import '../stream_chat_flutter.dart'; import 'stream_channel.dart'; @@ -183,8 +183,6 @@ class MessageInputState extends State { int _filePickerIndex = 0; double _filePickerSize = 250.0; - Iterable _media = []; - /// The editing controller passed to the input TextField TextEditingController textEditingController; @@ -699,15 +697,16 @@ class MessageInputState extends State { ), ), ), - Expanded( - child: Container( - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(8.0), + if (_openFilePickerSection) + Expanded( + child: Container( + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(8.0), + ), + child: _buildPickerSection(), ), - child: _buildPickerSection(), ), - ), ], ), ), @@ -717,68 +716,15 @@ class MessageInputState extends State { Widget _buildPickerSection() { switch (_filePickerIndex) { case 0: - return GridView.builder( - itemCount: _media.length, - gridDelegate: - SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 3), - itemBuilder: (context, position) { - return Padding( - padding: - const EdgeInsets.symmetric(horizontal: 1.0, vertical: 1.0), - child: InkWell( - child: Stack( - children: [ - AspectRatio( - aspectRatio: 1.0, - child: FadeInImage( - placeholder: MemoryImage(kTransparentImage), - image: MediaThumbnailProvider( - media: _media.elementAt(position), - ), - fit: BoxFit.fill, - ), - ), - Positioned.fill( - child: IgnorePointer( - child: AnimatedOpacity( - duration: Duration(milliseconds: 300), - opacity: _attachments.any((element) => - element.id == _media.elementAt(position).id) - ? 1.0 - : 0.0, - child: Container( - color: Colors.black.withOpacity(0.5), - alignment: Alignment.topRight, - padding: const EdgeInsets.only( - top: 8, - right: 8, - ), - child: CircleAvatar( - maxRadius: 12.0, - backgroundColor: Colors.white, - child: Icon( - StreamIcons.check, - color: Colors.black, - ), - ), - ), - ), - ), - ), - ], - ), - onTap: () { - if (!_attachments.any((element) => - element.id == _media.elementAt(position).id)) { - _addAttachment(_media.elementAt(position)); - } else { - _attachments.removeWhere((element) => - element.id == _media.elementAt(position).id); - setState(() {}); - } - }, - ), - ); + return MediaListView( + selectedIds: _attachments.map((e) => e.id).toList(), + onSelect: (media) { + if (!_attachments.any((element) => element.id == media.id)) { + _addAttachment(media); + } else { + _attachments.removeWhere((element) => element.id == media.id); + setState(() {}); + } }, ); break; @@ -845,32 +791,6 @@ class MessageInputState extends State { }); } - void _getAllMedia() async { - final List collections = - await MediaGallery.listMediaCollections(mediaTypes: [ - MediaType.image, - MediaType.video, - ]); - - if (collections.isEmpty) { - return; - } - - final page = await collections - .firstWhere( - (element) => element.name == 'All', - orElse: () => collections.first, - ) - .getMedias( - take: 50, - ); - - print('page.items.length: ${page.items.length}'); - setState(() { - _media = page.items; - }); - } - CircleAvatar _buildGiphyIcon() { if (kIsWeb) { return CircleAvatar( @@ -1275,6 +1195,13 @@ class MessageInputState extends State { ), ), onTap: () async { + _emojiOverlay?.remove(); + _emojiOverlay = null; + _commandsOverlay?.remove(); + _commandsOverlay = null; + _mentionsOverlay?.remove(); + _mentionsOverlay = null; + if (_openFilePickerSection) { setState(() { _openFilePickerSection = false; @@ -1282,14 +1209,12 @@ class MessageInputState extends State { }); } else { final status = await Permission.storage.request(); - print('status: ${status}'); if (status.isDenied || status.isPermanentlyDenied) { final res = await openAppSettings(); if (!res) { return; } } - _getAllMedia(); showAttachmentModal(); } }, diff --git a/svgs/video_call_icon.svg b/svgs/video_call_icon.svg new file mode 100644 index 00000000..1c3832d6 --- /dev/null +++ b/svgs/video_call_icon.svg @@ -0,0 +1,3 @@ + + + From 43d7522b19059ec3f9cd124d85e38cc2a60f9ff0 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Wed, 11 Nov 2020 17:43:29 +0100 Subject: [PATCH 0353/1140] highligth attach icon --- lib/src/message_input.dart | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 7e8a40c4..8014ed89 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -1191,7 +1191,9 @@ class MessageInputState extends State { EdgeInsets.only(left: 8.0, right: padding, top: 8.0, bottom: 8.0), child: Icon( StreamIcons.attach, - color: Color(0xFF000000).withAlpha(128), + color: _openFilePickerSection + ? StreamChatTheme.of(context).accentColor + : Color(0xFF000000).withAlpha(128), ), ), onTap: () async { From 264b11362e35dbc05592b20da2bd8b3b57c6c937 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Wed, 11 Nov 2020 18:04:13 +0100 Subject: [PATCH 0354/1140] remove inkwell from url attachment --- lib/src/message_widget.dart | 2 - lib/src/url_attachment.dart | 155 +++++++++++++++++------------------- 2 files changed, 73 insertions(+), 84 deletions(-) diff --git a/lib/src/message_widget.dart b/lib/src/message_widget.dart index a41bc97f..f9871d69 100644 --- a/lib/src/message_widget.dart +++ b/lib/src/message_widget.dart @@ -1,7 +1,6 @@ import 'dart:math'; import 'dart:ui'; -import 'package:cached_network_image/cached_network_image.dart'; import 'package:emojis/emoji.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/foundation.dart'; @@ -17,7 +16,6 @@ import 'package:stream_chat_flutter/stream_chat_flutter.dart'; import 'image_group.dart'; import 'message_text.dart'; -import 'utils.dart'; typedef AttachmentBuilder = Widget Function(BuildContext, Message, Attachment); diff --git a/lib/src/url_attachment.dart b/lib/src/url_attachment.dart index c6b0b3f7..a873217f 100644 --- a/lib/src/url_attachment.dart +++ b/lib/src/url_attachment.dart @@ -16,97 +16,88 @@ class UrlAttachment extends StatelessWidget { @override Widget build(BuildContext context) { - return Stack( - children: [ - Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - if (urlAttachment.imageUrl != null) - SizedBox( - height: 16.0, - ), - if (urlAttachment.imageUrl != null) - Container( - clipBehavior: Clip.antiAliasWithSaveLayer, - margin: EdgeInsets.symmetric(horizontal: 8.0), - child: Stack( - children: [ - Center( - child: CachedNetworkImage( - imageUrl: urlAttachment.imageUrl, - ), - ), - Positioned( - left: 0.0, - bottom: -1, - child: Container( - child: Padding( - padding: const EdgeInsets.only( - top: 8.0, - left: 8.0, - right: 8.0, - ), - child: Text( - hostDisplayName, - style: TextStyle( - fontWeight: FontWeight.w700, - color: Color(0xFF006CFF), - ), - ), - ), - decoration: BoxDecoration( - borderRadius: BorderRadius.only( - topRight: Radius.circular(16.0), - ), - color: Color(0xFFE9F2FF), - ), - ), - ), - ], - ), - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(8.0), - ), - ), - Padding( - padding: textPadding, - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, + return GestureDetector( + onTap: () => launchURL( + context, + urlAttachment.ogScrapeUrl, + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + if (urlAttachment.imageUrl != null) + SizedBox( + height: 16.0, + ), + if (urlAttachment.imageUrl != null) + Container( + clipBehavior: Clip.antiAliasWithSaveLayer, + margin: EdgeInsets.symmetric(horizontal: 8.0), + child: Stack( children: [ - if (urlAttachment.title != null) - Text( - urlAttachment.title, - maxLines: 1, - style: TextStyle( - fontWeight: FontWeight.w700, - fontSize: 12.0, - ), + Center( + child: CachedNetworkImage( + imageUrl: urlAttachment.imageUrl, ), - if (urlAttachment.text != null) - Text( - urlAttachment.text, - style: TextStyle( - fontWeight: FontWeight.w400, - fontSize: 12.0, + ), + Positioned( + left: 0.0, + bottom: -1, + child: Container( + child: Padding( + padding: const EdgeInsets.only( + top: 8.0, + left: 8.0, + right: 8.0, + ), + child: Text( + hostDisplayName, + style: TextStyle( + fontWeight: FontWeight.w700, + color: Color(0xFF006CFF), + ), + ), + ), + decoration: BoxDecoration( + borderRadius: BorderRadius.only( + topRight: Radius.circular(16.0), + ), + color: Color(0xFFE9F2FF), ), ), + ), ], ), - ), - ], - ), - Positioned.fill( - child: Material( - color: Colors.transparent, - child: InkWell( - onTap: () => launchURL( - context, - urlAttachment.ogScrapeUrl, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(8.0), ), ), + Padding( + padding: textPadding, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + if (urlAttachment.title != null) + Text( + urlAttachment.title, + maxLines: 1, + style: TextStyle( + fontWeight: FontWeight.w700, + fontSize: 12.0, + ), + ), + if (urlAttachment.text != null) + Text( + urlAttachment.text, + style: TextStyle( + fontWeight: FontWeight.w400, + fontSize: 12.0, + ), + ), + ], + ), ), - ), - ], + ], + ), ); } } From 3ad6a25a828566b758c27d26eb9dff133cb722e6 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Thu, 12 Nov 2020 17:04:01 +0530 Subject: [PATCH 0355/1140] feat: Added new image detail screen --- lib/src/full_screen_image.dart | 110 +++++++++++++++++++++++---- lib/src/giphy_attachment.dart | 12 ++- lib/src/image_attachment.dart | 6 +- lib/src/image_footer.dart | 133 +++++++++++++++++++++++++++++++++ lib/src/image_group.dart | 32 ++------ lib/src/image_header.dart | 101 +++++++++++++++++++++++++ 6 files changed, 345 insertions(+), 49 deletions(-) create mode 100644 lib/src/image_footer.dart create mode 100644 lib/src/image_header.dart diff --git a/lib/src/full_screen_image.dart b/lib/src/full_screen_image.dart index 76953b1a..e0dd79a3 100644 --- a/lib/src/full_screen_image.dart +++ b/lib/src/full_screen_image.dart @@ -1,34 +1,112 @@ import 'package:cached_network_image/cached_network_image.dart'; import 'package:flutter/material.dart'; +import 'package:jiffy/jiffy.dart'; import 'package:photo_view/photo_view.dart'; +import 'package:stream_chat_flutter/src/image_footer.dart'; +import 'package:stream_chat_flutter/src/image_header.dart'; + +import '../stream_chat_flutter.dart'; /// A full screen image widget -class FullScreenImage extends StatelessWidget { +class FullScreenImage extends StatefulWidget { /// The url of the image - final String url; + final List urls; + + final int startIndex; + final String userName; + final DateTime sentAt; /// Instantiate a new FullScreenImage const FullScreenImage({ Key key, - @required this.url, + @required this.urls, + this.startIndex = 0, + this.userName = '', + this.sentAt, }) : super(key: key); + @override + _FullScreenImageState createState() => _FullScreenImageState(); +} + +class _FullScreenImageState extends State + with SingleTickerProviderStateMixin { + bool _optionsShown = true; + + AnimationController _controller; + PageController _pageController; + + int _currentPage; + + @override + void initState() { + super.initState(); + _controller = + AnimationController(vsync: this, duration: Duration(milliseconds: 300)); + _pageController = PageController(initialPage: widget.startIndex); + _currentPage = widget.startIndex; + } + @override Widget build(BuildContext context) { return Scaffold( - appBar: AppBar( - backgroundColor: Colors.black, - iconTheme: IconThemeData( - color: Colors.white, - ), - ), - body: PhotoView( - imageProvider: CachedNetworkImageProvider(url), - maxScale: PhotoViewComputedScale.covered, - minScale: PhotoViewComputedScale.contained, - heroAttributes: PhotoViewHeroAttributes( - tag: url, - ), + body: Stack( + children: [ + AnimatedBuilder( + animation: _controller, + builder: (context, snapshot) { + return PageView.builder( + controller: _pageController, + onPageChanged: (val) { + setState(() { + _currentPage = val; + }); + }, + itemBuilder: (context, position) { + return PhotoView( + imageProvider: CachedNetworkImageProvider(widget.urls[position]), + maxScale: PhotoViewComputedScale.covered, + minScale: PhotoViewComputedScale.contained, + heroAttributes: PhotoViewHeroAttributes( + tag: widget.urls, + ), + backgroundDecoration: BoxDecoration( + color: ColorTween( + begin: StreamChatTheme.of(context) + .channelTheme + .channelHeaderTheme + .color, + end: Colors.black).lerp(_controller.value), + ), + onTapUp: (a, b, c) { + setState(() { + _optionsShown = !_optionsShown; + }); + if(_controller.isCompleted) { + _controller.reverse(); + } else { + _controller.forward(); + } + }, + ); + }, + itemCount: widget.urls.length, + ); + } + ), + AnimatedOpacity( + opacity: _optionsShown ? 1.0 : 0.0, + duration: Duration(milliseconds: 300), + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + ImageHeader(userName: widget.userName, sentAt: 'Sent at${Jiffy(widget.sentAt.toLocal()) + .format(' HH:mm')}',), + ImageFooter(currentPage: _currentPage, totalPages: widget.urls.length,), + ], + ), + ), + ], ), ); } diff --git a/lib/src/giphy_attachment.dart b/lib/src/giphy_attachment.dart index bfa21239..f99ccb27 100644 --- a/lib/src/giphy_attachment.dart +++ b/lib/src/giphy_attachment.dart @@ -67,9 +67,11 @@ class GiphyAttachment extends StatelessWidget { Navigator.push(context, MaterialPageRoute(builder: (_) { return FullScreenImage( - url: attachment.imageUrl ?? + urls: [attachment.imageUrl ?? attachment.assetUrl ?? - attachment.thumbUrl, + attachment.thumbUrl], + userName: message.user.name, + sentAt: message.createdAt, ); })); }, @@ -299,9 +301,11 @@ class GiphyAttachment extends StatelessWidget { onTap: () { Navigator.push(context, MaterialPageRoute(builder: (_) { return FullScreenImage( - url: attachment.imageUrl ?? + urls: [attachment.imageUrl ?? attachment.assetUrl ?? - attachment.thumbUrl, + attachment.thumbUrl], + userName: message.user.name, + sentAt: message.createdAt, ); })); }, diff --git a/lib/src/image_attachment.dart b/lib/src/image_attachment.dart index ba11252a..d493fa66 100644 --- a/lib/src/image_attachment.dart +++ b/lib/src/image_attachment.dart @@ -44,9 +44,11 @@ class ImageAttachment extends StatelessWidget { MaterialPageRoute( builder: (_) { return FullScreenImage( - url: attachment.imageUrl ?? + urls: [attachment.imageUrl ?? attachment.assetUrl ?? - attachment.thumbUrl, + attachment.thumbUrl], + userName: message.user.name, + sentAt: message.createdAt, ); }, ), diff --git a/lib/src/image_footer.dart b/lib/src/image_footer.dart new file mode 100644 index 00000000..fade96bf --- /dev/null +++ b/lib/src/image_footer.dart @@ -0,0 +1,133 @@ +import 'package:flutter/material.dart'; +import 'package:stream_chat/stream_chat.dart'; +import 'package:stream_chat_flutter/src/back_button.dart'; +import 'package:stream_chat_flutter/src/channel_info.dart'; +import 'package:stream_chat_flutter/src/channel_name.dart'; +import 'package:stream_chat_flutter/src/stream_chat_theme.dart'; +import 'package:stream_chat_flutter/src/stream_icons.dart'; + +import './channel_name.dart'; +import 'channel_image.dart'; +import 'stream_channel.dart'; + +class ImageFooter extends StatelessWidget { + /// Callback to call when pressing the back button. + /// By default it calls [Navigator.pop] + final VoidCallback onBackPressed; + + /// Callback to call when the header is tapped. + final VoidCallback onTitleTap; + + /// Callback to call when the image is tapped. + final VoidCallback onImageTap; + + final int currentPage; + final int totalPages; + + /// Creates a channel header + ImageFooter({ + Key key, + this.onBackPressed, + this.onTitleTap, + this.onImageTap, + this.currentPage = 0, + this.totalPages = 0, + }) : preferredSize = Size.fromHeight(kToolbarHeight), + super(key: key); + + @override + Widget build(BuildContext context) { + return SafeArea( + child: Container( + color: StreamChatTheme.of(context).channelTheme.channelHeaderTheme.color, + padding: EdgeInsets.symmetric(vertical: 8.0), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + IconButton( + icon: Icon( + StreamIcons.share, + size: 24.0, + color: Colors.black, + ), + onPressed: onBackPressed, + ), + InkWell( + onTap: onTitleTap, + child: Container( + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.center, + mainAxisSize: MainAxisSize.min, + children: [ + Text( + '${currentPage + 1} of $totalPages', + style: TextStyle( + fontSize: 16.0, + fontWeight: FontWeight.w700, + color: Colors.black, + ), + ), + ], + ), + ), + ), + IconButton( + icon: Icon( + StreamIcons.grid, + color: Colors.black, + ), + onPressed: () {}, + ), + ], + ), + ), + ); + + return AppBar( + brightness: Theme.of(context).brightness, + elevation: 1, + leading: IconButton( + icon: Icon(StreamIcons.share), + onPressed: onBackPressed, + ), + backgroundColor: + StreamChatTheme.of(context).channelTheme.channelHeaderTheme.color, + actions: [ + IconButton( + icon: Icon(StreamIcons.grid), + onPressed: () {}, + ), + ], + centerTitle: true, + title: InkWell( + onTap: onTitleTap, + child: Container( + height: preferredSize.height, + width: preferredSize.width, + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.center, + mainAxisSize: MainAxisSize.min, + children: [ + Text( + 'Demo name', + style: StreamChatTheme.of(context) + .channelTheme + .channelHeaderTheme + .title, + ), + Text( + '1 of 1', + style: StreamChatTheme.of(context).channelPreviewTheme.subtitle, + ), + ], + ), + ), + ), + ); + } + + @override + final Size preferredSize; +} diff --git a/lib/src/image_group.dart b/lib/src/image_group.dart index 1a7144d8..4592d94d 100644 --- a/lib/src/image_group.dart +++ b/lib/src/image_group.dart @@ -110,34 +110,12 @@ class ImageGroup extends StatelessWidget { Navigator.push( context, MaterialPageRoute( - builder: (context) { - return Scaffold( - appBar: AppBar( - backgroundColor: Colors.transparent, - iconTheme: IconThemeData( - color: Colors.white, - ), + builder: (context) => + FullScreenImage(urls: images.map((e) => e.imageUrl).toList(), + startIndex: index, + userName: message.user.name, + sentAt: message.createdAt, ), - backgroundColor: Colors.black, - body: SizedBox.expand( - child: CarouselSlider( - items: images - .map((image) => FullScreenImage( - url: image.imageUrl ?? - image.thumbUrl ?? - image.assetUrl, - )) - .toList(), - options: CarouselOptions( - initialPage: index ?? 0, - enableInfiniteScroll: false, - viewportFraction: 0.95, - height: MediaQuery.of(context).size.height, - ), - ), - ), - ); - }, ), ); } diff --git a/lib/src/image_header.dart b/lib/src/image_header.dart new file mode 100644 index 00000000..39f2ccb9 --- /dev/null +++ b/lib/src/image_header.dart @@ -0,0 +1,101 @@ +import 'package:flutter/material.dart'; +import 'package:stream_chat/stream_chat.dart'; +import 'package:stream_chat_flutter/src/back_button.dart'; +import 'package:stream_chat_flutter/src/channel_info.dart'; +import 'package:stream_chat_flutter/src/channel_name.dart'; +import 'package:stream_chat_flutter/src/stream_chat_theme.dart'; +import 'package:stream_chat_flutter/src/stream_icons.dart'; + +import './channel_name.dart'; +import 'channel_image.dart'; +import 'stream_channel.dart'; + +class ImageHeader extends StatelessWidget implements PreferredSizeWidget { + /// True if this header shows the leading back button + final bool showBackButton; + + /// Callback to call when pressing the back button. + /// By default it calls [Navigator.pop] + final VoidCallback onBackPressed; + + /// Callback to call when the header is tapped. + final VoidCallback onTitleTap; + + /// Callback to call when the image is tapped. + final VoidCallback onImageTap; + + final String userName; + final String sentAt; + + /// Creates a channel header + ImageHeader({ + Key key, + this.showBackButton = true, + this.onBackPressed, + this.onTitleTap, + this.onImageTap, + this.userName = '', + this.sentAt = '', + }) : preferredSize = Size.fromHeight(kToolbarHeight), + super(key: key); + + @override + Widget build(BuildContext context) { + return AppBar( + brightness: Theme.of(context).brightness, + elevation: 1, + leading: showBackButton + ? IconButton( + icon: Icon( + StreamIcons.close, + color: Colors.black, + size: 24.0, + ), + onPressed: onBackPressed, + ) + : SizedBox(), + backgroundColor: + StreamChatTheme.of(context).channelTheme.channelHeaderTheme.color, + actions: [ + IconButton( + icon: Icon( + StreamIcons.menu_point_v, + color: Colors.black, + size: 24.0, + ), + onPressed: () {}, + ), + ], + centerTitle: true, + title: InkWell( + onTap: onTitleTap, + child: Container( + height: preferredSize.height, + width: preferredSize.width, + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.center, + mainAxisSize: MainAxisSize.min, + children: [ + Text( + userName, + style: TextStyle( + fontSize: 16.0, + fontWeight: FontWeight.w700, + color: Colors.black, + ), + ), + Text( + sentAt, + style: StreamChatTheme.of(context).channelPreviewTheme.subtitle, + ), + ], + ), + ), + ), + ); + } + + @override + final Size preferredSize; +} From b14819efc5029fbd0282788c119e3305e367a878 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Thu, 12 Nov 2020 12:53:37 +0100 Subject: [PATCH 0356/1140] fix dragging --- lib/src/media_list_view.dart | 17 ----------------- lib/src/message_input.dart | 24 ++++++++---------------- 2 files changed, 8 insertions(+), 33 deletions(-) diff --git a/lib/src/media_list_view.dart b/lib/src/media_list_view.dart index 5a2fc25f..627a480c 100644 --- a/lib/src/media_list_view.dart +++ b/lib/src/media_list_view.dart @@ -99,23 +99,9 @@ class _MediaListViewState extends State { @override void initState() { super.initState(); - - _scrollController.addListener(() { - if (_scrollController.offset > - _scrollController.position.maxScrollExtent - 100) { - _getMedia(); - } - }); - _getMedia(); } - @override - void dispose() { - _scrollController.dispose(); - super.dispose(); - } - void _getMedia() async { final List collections = await MediaGallery.listMediaCollections( @@ -154,8 +140,5 @@ class _MediaListViewState extends State { setState(() { _media.addAll(allItems); }); - - print( - '_media.where((element) => element.mediaType == MediaType.video).length: ${_media.where((element) => element.mediaType == MediaType.video).length}'); } } diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 8014ed89..e4693244 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -171,7 +171,7 @@ class MessageInputState extends State { final _imagePicker = ImagePicker(); bool _inputEnabled = true; bool _messageIsPresent = false; - bool _typingStarted = false; + bool _animateContainer = true; bool _commandEnabled = false; OverlayEntry _commandsOverlay, _mentionsOverlay, _emojiOverlay; Iterable _emojiNames; @@ -383,11 +383,6 @@ class MessageInputState extends State { _checkEmoji(s, context); }, - onTap: () { - setState(() { - _typingStarted = true; - }); - }, style: Theme.of(context).textTheme.bodyText2, autofocus: false, textAlignVertical: TextAlignVertical.center, @@ -613,7 +608,7 @@ class MessageInputState extends State { Widget _buildFilePickerSection() { return AnimatedContainer( - duration: Duration(milliseconds: 300), + duration: _animateContainer ? Duration(milliseconds: 300) : Duration.zero, height: _openFilePickerSection ? _filePickerSize : 0, child: Material( color: Color(0xFFF2F2F2), @@ -662,13 +657,11 @@ class MessageInputState extends State { GestureDetector( onVerticalDragUpdate: (update) { setState(() { - _filePickerSize -= update.delta.dy; - if (_filePickerSize < 100) { - _filePickerSize = 100.0; - } else if (_filePickerSize > - MediaQuery.of(context).size.height / 1.7) { - _filePickerSize = MediaQuery.of(context).size.height / 1.7; - } + _animateContainer = false; + _filePickerSize = (_filePickerSize - update.delta.dy).clamp( + 100, + MediaQuery.of(context).size.height / 1.7, + ); }); }, child: Container( @@ -1206,6 +1199,7 @@ class MessageInputState extends State { if (_openFilePickerSection) { setState(() { + _animateContainer = true; _openFilePickerSection = false; _filePickerSize = 250.0; }); @@ -1536,7 +1530,6 @@ class MessageInputState extends State { setState(() { _messageIsPresent = false; - _typingStarted = false; _commandEnabled = false; }); @@ -1632,7 +1625,6 @@ class MessageInputState extends State { void _parseExistingMessage(Message message) { textEditingController.text = message.text; - _typingStarted = true; _messageIsPresent = true; message.attachments?.forEach((attachment) { From 10e502f84a64072bafe8545f6f69672f27f24e68 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Thu, 12 Nov 2020 15:05:31 +0100 Subject: [PATCH 0357/1140] fix qa --- example/assets/icon_arrow_right.svg | 5 +++++ example/lib/choose_user_page.dart | 15 +++++++++------ example/lib/stream_version.dart | 1 - example/pubspec.yaml | 2 +- lib/src/stream_chat_theme.dart | 1 + lib/src/user_avatar.dart | 1 + 6 files changed, 17 insertions(+), 8 deletions(-) create mode 100644 example/assets/icon_arrow_right.svg diff --git a/example/assets/icon_arrow_right.svg b/example/assets/icon_arrow_right.svg new file mode 100644 index 00000000..7cfa0c56 --- /dev/null +++ b/example/assets/icon_arrow_right.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/example/lib/choose_user_page.dart b/example/lib/choose_user_page.dart index b5296f8a..3a035f34 100644 --- a/example/lib/choose_user_page.dart +++ b/example/lib/choose_user_page.dart @@ -178,9 +178,10 @@ class ChooseUserPage extends StatelessWidget { style: TextStyle(fontWeight: FontWeight.bold), ), subtitle: Text('Stream test account'), - trailing: Icon( - StreamIcons.arrow_right, - color: StreamChatTheme.of(context).accentColor, + trailing: SvgPicture.asset( + 'assets/icon_arrow_right.svg', + height: 24, + width: 24, ), ); }), @@ -206,9 +207,11 @@ class ChooseUserPage extends StatelessWidget { style: TextStyle(fontWeight: FontWeight.bold), ), subtitle: Text('Custom settings'), - trailing: Icon( - StreamIcons.arrow_right, - color: StreamChatTheme.of(context).accentColor, + trailing: SvgPicture.asset( + 'assets/icon_arrow_right.svg', + height: 24, + width: 24, + clipBehavior: Clip.none, ), ), ][i]; diff --git a/example/lib/stream_version.dart b/example/lib/stream_version.dart index ee340f89..113e36c0 100644 --- a/example/lib/stream_version.dart +++ b/example/lib/stream_version.dart @@ -24,7 +24,6 @@ class StreamVersion extends StatelessWidget { final streamChatDep = yaml['packages']['stream_chat_flutter']['version']; - print('streamChatDep: ${streamChatDep}'); return Text( 'Stream SDK v ${streamChatDep}', style: TextStyle( diff --git a/example/pubspec.yaml b/example/pubspec.yaml index c6743cd4..ce1ab622 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -1,6 +1,6 @@ name: example description: A new Flutter project. -version: 1.0.53+55 +version: 1.0.54+56 environment: sdk: ">=2.2.2 <3.0.0" diff --git a/lib/src/stream_chat_theme.dart b/lib/src/stream_chat_theme.dart index 3b3725ed..967cbbbf 100644 --- a/lib/src/stream_chat_theme.dart +++ b/lib/src/stream_chat_theme.dart @@ -229,6 +229,7 @@ class StreamChatThemeData { backgroundColor: isDark ? Colors.black : Colors.white, defaultUserImage: (context, user) => Center( child: CachedNetworkImage( + filterQuality: FilterQuality.high, imageUrl: getRandomPicUrl(user), fit: BoxFit.cover, ), diff --git a/lib/src/user_avatar.dart b/lib/src/user_avatar.dart index 86bf7abd..66edba39 100644 --- a/lib/src/user_avatar.dart +++ b/lib/src/user_avatar.dart @@ -49,6 +49,7 @@ class UserAvatar extends StatelessWidget { ), child: hasImage ? CachedNetworkImage( + filterQuality: FilterQuality.high, imageUrl: user.extraData['image'], errorWidget: (_, __, ___) { return streamChatTheme.defaultUserImage(context, user); From 39a6861e4ceb5942a302948f4a44ff41f62c0e75 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Thu, 12 Nov 2020 18:26:13 +0100 Subject: [PATCH 0358/1140] remove waiting for keystorage --- example/lib/choose_user_page.dart | 26 ++++++++++++-------------- example/pubspec.yaml | 2 +- 2 files changed, 13 insertions(+), 15 deletions(-) diff --git a/example/lib/choose_user_page.dart b/example/lib/choose_user_page.dart index 3a035f34..fd7d2b6c 100644 --- a/example/lib/choose_user_page.dart +++ b/example/lib/choose_user_page.dart @@ -135,20 +135,18 @@ class ChooseUserPage extends StatelessWidget { token, ); - await Future.wait([ - secureStorage.write( - key: kStreamApiKey, - value: kDefaultStreamApiKey, - ), - secureStorage.write( - key: kStreamUserId, - value: user.id, - ), - secureStorage.write( - key: kStreamToken, - value: token, - ), - ]); + secureStorage.write( + key: kStreamApiKey, + value: kDefaultStreamApiKey, + ); + secureStorage.write( + key: kStreamUserId, + value: user.id, + ); + secureStorage.write( + key: kStreamToken, + value: token, + ); if (!kIsWeb) { initNotifications(client); diff --git a/example/pubspec.yaml b/example/pubspec.yaml index ce1ab622..f85127f0 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -1,6 +1,6 @@ name: example description: A new Flutter project. -version: 1.0.54+56 +version: 1.0.55+57 environment: sdk: ">=2.2.2 <3.0.0" From 7eb9a9dfd9be8d10f9098a4bfa0f4d646d438493 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Thu, 12 Nov 2020 18:35:55 +0100 Subject: [PATCH 0359/1140] remoe editing from giphy messages --- lib/src/message_widget.dart | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/src/message_widget.dart b/lib/src/message_widget.dart index f9871d69..fd6286a2 100644 --- a/lib/src/message_widget.dart +++ b/lib/src/message_widget.dart @@ -493,7 +493,10 @@ class _MessageWidgetState extends State { message: widget.message, editMessageInputBuilder: widget.editMessageInputBuilder, onThreadTap: widget.onThreadTap, - showEditMessage: widget.showEditMessage, + showEditMessage: widget.showEditMessage && + widget.message.attachments + ?.any((element) => element.type == 'giphy') != + true, showReactions: widget.showReactions, showReply: widget.showReplyIndicator && widget.onThreadTap != null, From 0eb3aee4212984d5e249951d6b476eefeb40070f Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Thu, 12 Nov 2020 18:52:10 +0100 Subject: [PATCH 0360/1140] fix group images --- lib/src/group_image.dart | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/lib/src/group_image.dart b/lib/src/group_image.dart index 2385007d..96e25f74 100644 --- a/lib/src/group_image.dart +++ b/lib/src/group_image.dart @@ -46,9 +46,16 @@ class GroupImage extends StatelessWidget { .take(2) .map((url) => Flexible( fit: FlexFit.tight, - child: CachedNetworkImage( - imageUrl: url, + child: FittedBox( fit: BoxFit.cover, + clipBehavior: Clip.antiAlias, + child: Transform.scale( + scale: 1.2, + child: CachedNetworkImage( + imageUrl: url, + fit: BoxFit.cover, + ), + ), ), )) .toList(), @@ -64,9 +71,16 @@ class GroupImage extends StatelessWidget { .skip(2) .map((url) => Flexible( fit: FlexFit.tight, - child: CachedNetworkImage( - imageUrl: url, + child: FittedBox( fit: BoxFit.cover, + clipBehavior: Clip.antiAlias, + child: Transform.scale( + scale: 1.2, + child: CachedNetworkImage( + imageUrl: url, + fit: BoxFit.cover, + ), + ), ), )) .toList(), From 44dc5c24ae166a968c97ef91c48e30677c229c5d Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Fri, 13 Nov 2020 11:25:55 +0100 Subject: [PATCH 0361/1140] put error text inside textfield --- example/ios/Podfile.lock | 2 +- example/lib/advanced_options_page.dart | 85 +++++++++++++++++++++----- example/pubspec.yaml | 2 +- 3 files changed, 72 insertions(+), 17 deletions(-) diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock index f23764fa..5b00ea2d 100644 --- a/example/ios/Podfile.lock +++ b/example/ios/Podfile.lock @@ -268,7 +268,7 @@ SPEC CHECKSUMS: SwiftyGif: e466e86c660d343357ab944a819a101c4127cb40 url_launcher: 6fef411d543ceb26efce54b05a0a40bfd74cbbef video_player: 9cc823b1d9da7e8427ee591e8438bfbcde500e6e - wakelock: 0d4a70faf8950410735e3f61fb15d517c8a6efc4 + wakelock: bfc7955c418d0db797614075aabbc58a39ab5107 PODFILE CHECKSUM: eb001256612a59f8f9e4d083ad8b9671e69dd184 diff --git a/example/lib/advanced_options_page.dart b/example/lib/advanced_options_page.dart index 8a4c79c0..59c59c26 100644 --- a/example/lib/advanced_options_page.dart +++ b/example/lib/advanced_options_page.dart @@ -17,10 +17,13 @@ class _AdvancedOptionsPageState extends State { final _formKey = GlobalKey(); final TextEditingController _apiKeyController = TextEditingController(); + String _apiKeyError; final TextEditingController _userIdController = TextEditingController(); + String _userIdError; final TextEditingController _userTokenController = TextEditingController(); + String _userTokenError; final TextEditingController _usernameController = TextEditingController(); @@ -65,17 +68,34 @@ class _AdvancedOptionsPageState extends State { children: [ TextFormField( controller: _apiKeyController, + onChanged: (_) { + if (_apiKeyError != null) { + setState(() { + _apiKeyError = null; + }); + } + }, validator: (value) { if (value.isEmpty) { - return 'Please enter the Chat API Key'; + setState(() { + _apiKeyError = 'Please enter the Chat API Key'; + }); + return _apiKeyError; } return null; }, + style: TextStyle( + fontSize: 14, + color: Colors.black, + ), decoration: InputDecoration( + errorStyle: TextStyle(fontSize: 0), labelStyle: TextStyle( fontSize: 14, fontWeight: FontWeight.bold, - color: Colors.black.withOpacity(.5), + color: _apiKeyError != null + ? Color(0xffff3742) + : Colors.black.withOpacity(.5), ), border: UnderlineInputBorder( borderRadius: BorderRadius.circular(8), @@ -83,7 +103,8 @@ class _AdvancedOptionsPageState extends State { ), fillColor: Color(0xffF5F5F5), filled: true, - labelText: 'Chat API Key', + labelText: + 'Chat API Key ${_apiKeyError != null ? ': $_apiKeyError' : ''}', ), textInputAction: TextInputAction.next, ), @@ -91,18 +112,35 @@ class _AdvancedOptionsPageState extends State { padding: const EdgeInsets.only(top: 8.0), child: TextFormField( controller: _userIdController, + onChanged: (_) { + if (_userIdError != null) { + setState(() { + _userIdError = null; + }); + } + }, validator: (value) { if (value.isEmpty) { - return 'Please enter the User ID'; + setState(() { + _userIdError = 'Please enter the User ID'; + }); + return _userIdError; } return null; }, + style: TextStyle( + fontSize: 14, + color: Colors.black, + ), textInputAction: TextInputAction.next, decoration: InputDecoration( + errorStyle: TextStyle(fontSize: 0), labelStyle: TextStyle( fontWeight: FontWeight.bold, fontSize: 14, - color: Colors.black.withOpacity(.5), + color: _userIdError != null + ? Color(0xffff3742) + : Colors.black.withOpacity(.5), ), border: UnderlineInputBorder( borderRadius: BorderRadius.circular(8), @@ -110,26 +148,44 @@ class _AdvancedOptionsPageState extends State { ), fillColor: Color(0xffF5F5F5), filled: true, - labelText: 'User ID', + labelText: + 'User ID ${_userIdError != null ? ': $_userIdError' : ''}', ), ), ), Padding( padding: const EdgeInsets.only(top: 8.0), child: TextFormField( + onChanged: (_) { + if (_userTokenError != null) { + setState(() { + _userTokenError = null; + }); + } + }, controller: _userTokenController, validator: (value) { if (value.isEmpty) { - return 'Please enter the user token'; + setState(() { + _userTokenError = 'Please enter the user token'; + }); + return _userTokenError; } return null; }, + style: TextStyle( + fontSize: 14, + color: Colors.black, + ), textInputAction: TextInputAction.next, decoration: InputDecoration( + errorStyle: TextStyle(fontSize: 0), labelStyle: TextStyle( fontWeight: FontWeight.bold, fontSize: 14, - color: Colors.black.withOpacity(.5), + color: _userTokenError != null + ? Color(0xffff3742) + : Colors.black.withOpacity(.5), ), border: UnderlineInputBorder( borderRadius: BorderRadius.circular(8), @@ -137,7 +193,8 @@ class _AdvancedOptionsPageState extends State { ), fillColor: Color(0xffF5F5F5), filled: true, - labelText: 'User Token', + labelText: + 'User Token ${_userTokenError != null ? ': $_userTokenError' : ''}', ), ), ), @@ -183,13 +240,13 @@ class _AdvancedOptionsPageState extends State { if (loading) { return; } - loading = true; if (_formKey.currentState.validate()) { final apiKey = _apiKeyController.text; final userId = _userIdController.text; final userToken = _userTokenController.text; final username = _usernameController.text; + loading = true; showDialog( barrierDismissible: false, context: context, @@ -232,11 +289,9 @@ class _AdvancedOptionsPageState extends State { errorText = e['message'] ?? errorText; } Navigator.pop(context); - Scaffold.of(context).showSnackBar( - SnackBar( - content: Text(errorText), - ), - ); + setState(() { + _apiKeyError = errorText; + }); loading = false; await client.disconnect(); return; diff --git a/example/pubspec.yaml b/example/pubspec.yaml index f85127f0..d4da197e 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -1,6 +1,6 @@ name: example description: A new Flutter project. -version: 1.0.55+57 +version: 1.0.56+58 environment: sdk: ">=2.2.2 <3.0.0" From c113862005cf1f942edfae091d756d2ca504c938 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Fri, 13 Nov 2020 11:35:40 +0100 Subject: [PATCH 0362/1140] fix error label --- example/lib/advanced_options_page.dart | 7 +++---- example/pubspec.yaml | 2 +- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/example/lib/advanced_options_page.dart b/example/lib/advanced_options_page.dart index 59c59c26..56c9dbf0 100644 --- a/example/lib/advanced_options_page.dart +++ b/example/lib/advanced_options_page.dart @@ -104,7 +104,7 @@ class _AdvancedOptionsPageState extends State { fillColor: Color(0xffF5F5F5), filled: true, labelText: - 'Chat API Key ${_apiKeyError != null ? ': $_apiKeyError' : ''}', + 'Chat API Key ${_apiKeyError != null ? ':$_apiKeyError' : ''}', ), textInputAction: TextInputAction.next, ), @@ -149,7 +149,7 @@ class _AdvancedOptionsPageState extends State { fillColor: Color(0xffF5F5F5), filled: true, labelText: - 'User ID ${_userIdError != null ? ': $_userIdError' : ''}', + 'User ID ${_userIdError != null ? ':$_userIdError' : ''}', ), ), ), @@ -194,7 +194,7 @@ class _AdvancedOptionsPageState extends State { fillColor: Color(0xffF5F5F5), filled: true, labelText: - 'User Token ${_userTokenError != null ? ': $_userTokenError' : ''}', + 'User Token ${_userTokenError != null ? ':$_userTokenError' : ''}', ), ), ), @@ -265,7 +265,6 @@ class _AdvancedOptionsPageState extends State { ), ); - print('CREATE CLIENT'); final client = Client( apiKey, logLevel: Level.INFO, diff --git a/example/pubspec.yaml b/example/pubspec.yaml index d4da197e..85fd549e 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -1,6 +1,6 @@ name: example description: A new Flutter project. -version: 1.0.56+58 +version: 1.0.57+59 environment: sdk: ">=2.2.2 <3.0.0" From a649e2d5e7b083039735df6b707ab44a13896eb3 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Fri, 13 Nov 2020 12:26:47 +0100 Subject: [PATCH 0363/1140] fix thumbnails --- lib/src/message_input.dart | 49 ++++++++++++++++++++++++++++++++------ lib/src/user_avatar.dart | 34 +++++++++++++------------- 2 files changed, 58 insertions(+), 25 deletions(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index e4693244..72c754e0 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -730,12 +730,18 @@ class MessageInputState extends State { void _addAttachment(Media medium) async { final mediaFile = await medium.getFile(); + final thumbBytes = await medium.getThumbnail(); final file = PlatformFile( path: mediaFile.path, bytes: mediaFile.readAsBytesSync(), ); + final thumbFile = PlatformFile( + bytes: thumbBytes, + name: '${file.name ?? file.path?.split('/')?.last}_thumbnail.jpeg', + ); + setState(() { _inputEnabled = true; }); @@ -747,6 +753,7 @@ class MessageInputState extends State { final channel = StreamChannel.of(context).channel; final attachment = _SendingAttachment( file: file, + thumbFile: thumbFile, attachment: Attachment( localUri: file.path != null ? Uri.parse(file.path) : null, type: medium.mediaType == MediaType.image ? 'image' : 'video', @@ -758,6 +765,11 @@ class MessageInputState extends State { _attachments.add(attachment); }); + final thumbUrl = await _uploadImage( + thumbFile, + channel, + ); + final url = await _uploadAttachment( file, medium.mediaType == MediaType.image @@ -772,10 +784,12 @@ class MessageInputState extends State { if (fileType == DefaultAttachmentTypes.image) { attachment.attachment = attachment.attachment.copyWith( imageUrl: url, + thumbUrl: thumbUrl, ); } else { attachment.attachment = attachment.attachment.copyWith( assetUrl: url, + thumbUrl: thumbUrl, ); } @@ -1041,7 +1055,7 @@ class MessageInputState extends State { return _attachments.isEmpty ? Container() : LimitedBox( - maxHeight: 76.0, + maxHeight: 104.0, child: ListView( scrollDirection: Axis.horizontal, children: _attachments @@ -1055,8 +1069,8 @@ class MessageInputState extends State { AspectRatio( aspectRatio: 1.0, child: Container( - height: 50, - width: 50, + height: 104, + width: 104, child: _buildAttachment(attachment), ), ), @@ -1138,9 +1152,26 @@ class MessageInputState extends State { ); break; case 'video': - return Container( - child: Icon(Icons.videocam), - color: Colors.black26, + return Stack( + children: [ + Container( + child: attachment.thumbFile != null + ? Image.memory( + attachment.thumbFile.bytes, + fit: BoxFit.cover, + ) + : Icon(Icons.videocam), + color: Colors.black26, + ), + Positioned( + left: 8, + bottom: 10, + child: SvgPicture.asset( + 'svgs/video_call_icon.svg', + package: 'stream_chat_flutter', + ), + ), + ], ); break; default: @@ -1426,7 +1457,9 @@ class MessageInputState extends State { MultipartFile.fromBytes( bytes, filename: filename, - contentType: httpParser.MediaType.parse(lookupMimeType(filename)), + contentType: filename != null + ? httpParser.MediaType.parse(lookupMimeType(filename)) + : null, ), ); return res.file; @@ -1657,12 +1690,14 @@ class MessageInputState extends State { class _SendingAttachment { PlatformFile file; + PlatformFile thumbFile; Attachment attachment; bool uploaded; String id; _SendingAttachment({ this.file, + this.thumbFile, this.attachment, this.uploaded = false, this.id, diff --git a/lib/src/user_avatar.dart b/lib/src/user_avatar.dart index 86bf7abd..d1dd2e41 100644 --- a/lib/src/user_avatar.dart +++ b/lib/src/user_avatar.dart @@ -38,25 +38,23 @@ class UserAvatar extends StatelessWidget { : null, child: Stack( children: [ - ClipRRect( - borderRadius: borderRadius ?? - streamChatTheme.ownMessageTheme.avatarTheme.borderRadius, - child: Container( - constraints: constraints ?? - streamChatTheme.ownMessageTheme.avatarTheme.constraints, - decoration: BoxDecoration( - color: streamChatTheme.accentColor, - ), - child: hasImage - ? CachedNetworkImage( - imageUrl: user.extraData['image'], - errorWidget: (_, __, ___) { - return streamChatTheme.defaultUserImage(context, user); - }, - fit: BoxFit.cover, - ) - : streamChatTheme.defaultUserImage(context, user), + Container( + constraints: constraints ?? + streamChatTheme.ownMessageTheme.avatarTheme.constraints, + clipBehavior: Clip.antiAlias, + decoration: BoxDecoration( + borderRadius: borderRadius ?? + streamChatTheme.ownMessageTheme.avatarTheme.borderRadius, + color: streamChatTheme.accentColor, ), + child: hasImage + ? CachedNetworkImage( + imageUrl: user.extraData['image'], + errorWidget: (_, __, ___) { + return streamChatTheme.defaultUserImage(context, user); + }, + ) + : streamChatTheme.defaultUserImage(context, user), ), if (showOnlineStatus && user.online == true) Positioned( From 64ed2b2187d8eac5a6343bd779ed172c545b2c96 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Fri, 13 Nov 2020 19:41:45 +0530 Subject: [PATCH 0364/1140] feat: Added image actions modal --- lib/src/full_screen_image.dart | 100 +++++++++++---------- lib/src/image_actions_modal.dart | 145 +++++++++++++++++++++++++++++++ lib/src/image_header.dart | 16 +++- 3 files changed, 215 insertions(+), 46 deletions(-) create mode 100644 lib/src/image_actions_modal.dart diff --git a/lib/src/full_screen_image.dart b/lib/src/full_screen_image.dart index e0dd79a3..b616c17a 100644 --- a/lib/src/full_screen_image.dart +++ b/lib/src/full_screen_image.dart @@ -35,7 +35,7 @@ class _FullScreenImageState extends State AnimationController _controller; PageController _pageController; - + int _currentPage; @override @@ -53,56 +53,66 @@ class _FullScreenImageState extends State body: Stack( children: [ AnimatedBuilder( - animation: _controller, - builder: (context, snapshot) { - return PageView.builder( - controller: _pageController, - onPageChanged: (val) { - setState(() { - _currentPage = val; - }); - }, - itemBuilder: (context, position) { - return PhotoView( - imageProvider: CachedNetworkImageProvider(widget.urls[position]), - maxScale: PhotoViewComputedScale.covered, - minScale: PhotoViewComputedScale.contained, - heroAttributes: PhotoViewHeroAttributes( - tag: widget.urls, - ), - backgroundDecoration: BoxDecoration( - color: ColorTween( - begin: StreamChatTheme.of(context) - .channelTheme - .channelHeaderTheme - .color, - end: Colors.black).lerp(_controller.value), - ), - onTapUp: (a, b, c) { - setState(() { - _optionsShown = !_optionsShown; - }); - if(_controller.isCompleted) { - _controller.reverse(); - } else { - _controller.forward(); - } - }, - ); - }, - itemCount: widget.urls.length, - ); - } - ), + animation: _controller, + builder: (context, snapshot) { + return PageView.builder( + controller: _pageController, + onPageChanged: (val) { + setState(() { + _currentPage = val; + }); + }, + itemBuilder: (context, position) { + return PhotoView( + imageProvider: + CachedNetworkImageProvider(widget.urls[position]), + maxScale: PhotoViewComputedScale.covered, + minScale: PhotoViewComputedScale.contained, + heroAttributes: PhotoViewHeroAttributes( + tag: widget.urls, + ), + backgroundDecoration: BoxDecoration( + color: ColorTween( + begin: StreamChatTheme.of(context) + .channelTheme + .channelHeaderTheme + .color, + end: Colors.black) + .lerp(_controller.value), + ), + onTapUp: (a, b, c) { + setState(() { + _optionsShown = !_optionsShown; + }); + if (_controller.isCompleted) { + _controller.reverse(); + } else { + _controller.forward(); + } + }, + ); + }, + itemCount: widget.urls.length, + ); + }), AnimatedOpacity( opacity: _optionsShown ? 1.0 : 0.0, duration: Duration(milliseconds: 300), child: Column( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - ImageHeader(userName: widget.userName, sentAt: 'Sent at${Jiffy(widget.sentAt.toLocal()) - .format(' HH:mm')}',), - ImageFooter(currentPage: _currentPage, totalPages: widget.urls.length,), + ImageHeader( + userName: widget.userName, + sentAt: + 'Sent at${Jiffy(widget.sentAt.toLocal()).format(' HH:mm')}', + onBackPressed: () { + Navigator.of(context).pop(); + }, + ), + ImageFooter( + currentPage: _currentPage, + totalPages: widget.urls.length, + ), ], ), ), diff --git a/lib/src/image_actions_modal.dart b/lib/src/image_actions_modal.dart new file mode 100644 index 00000000..03603795 --- /dev/null +++ b/lib/src/image_actions_modal.dart @@ -0,0 +1,145 @@ +import 'dart:ui'; + +import 'package:flutter/material.dart'; + +import '../stream_chat_flutter.dart'; +import 'stream_icons.dart'; + +class ImageActionsModal extends StatelessWidget { + final String userName; + final String sentAt; + + ImageActionsModal({this.userName, this.sentAt}); + + @override + Widget build(BuildContext context) { + return GestureDetector( + behavior: HitTestBehavior.translucent, + onTap: () { + Navigator.pop(context); + }, + child: Stack( + children: [ + Positioned.fill( + child: Container( + decoration: BoxDecoration( + gradient: LinearGradient( + begin: Alignment.topCenter, + end: Alignment.bottomCenter, + colors: [ + Colors.black.withOpacity(0.8), + Colors.transparent, + ], + stops: [0.0, 0.4], + ) + ), + ) + ), + _buildPage(context), + ], + ), + ); + } + + Widget _buildPage(context) { + return Material( + color: Colors.transparent, + child: Column( + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Padding( + padding: const EdgeInsets.all(8.0), + child: Container( + width: 40.0, + ), + ), + Column( + children: [ + Padding( + padding: const EdgeInsets.only(top: 8.0), + child: Text( + userName, + style: TextStyle( + fontSize: 16.0, + fontWeight: FontWeight.w700, + color: Colors.white, + ), + ), + ), + Text( + sentAt, + style: + StreamChatTheme.of(context).channelPreviewTheme.subtitle.copyWith(color: Colors.white.withOpacity(0.5)), + ), + ], + ), + IconButton( + icon: Icon( + StreamIcons.close, + size: 24.0, + color: Colors.white, + ), + onPressed: () { + Navigator.pop(context); + }, + ), + ], + ), + Align( + alignment: Alignment.centerRight, + child: Container( + width: MediaQuery.of(context).size.width / 1.8, + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Material( + clipBehavior: Clip.hardEdge, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(16), + ), + color: Color(0xffe5e5e5), + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: ListTile.divideTiles( + context: context, + tiles: [ + _buildButton(context, 'Reply', StreamIcons.curve_line_down_left, () {}), + _buildButton(context, 'Show in Chat', StreamIcons.eye, () {}), + _buildButton(context, 'Save Image', StreamIcons.save_1, () {}), + _buildButton(context, 'Copy', StreamIcons.copy, () {}), + _buildButton(context, 'Delete', StreamIcons.delete, () {}, color: Colors.red), + ], + ).toList(), + ), + ), + ), + ), + ), + ], + ), + ); + } + + Widget _buildButton(context, String title, IconData iconData, VoidCallback onTap, {Color color}) { + var titleStyle = TextStyle( + fontSize: 14.5, + color: Colors.black, + fontWeight: FontWeight.w500, + ); + + return ListTile( + dense: true, + title: Text( + title, + style: color == null ? titleStyle : titleStyle.copyWith(color: color), + ), + leading: Icon( + iconData, + color: color ?? StreamChatTheme.of(context).primaryIconTheme.color, + size: 24.0, + ), + onTap: onTap, + ); + } +} diff --git a/lib/src/image_header.dart b/lib/src/image_header.dart index 39f2ccb9..b4dfb36d 100644 --- a/lib/src/image_header.dart +++ b/lib/src/image_header.dart @@ -8,6 +8,7 @@ import 'package:stream_chat_flutter/src/stream_icons.dart'; import './channel_name.dart'; import 'channel_image.dart'; +import 'image_actions_modal.dart'; import 'stream_channel.dart'; class ImageHeader extends StatelessWidget implements PreferredSizeWidget { @@ -63,7 +64,9 @@ class ImageHeader extends StatelessWidget implements PreferredSizeWidget { color: Colors.black, size: 24.0, ), - onPressed: () {}, + onPressed: () { + _showMessageActionModalBottomSheet(context); + }, ), ], centerTitle: true, @@ -98,4 +101,15 @@ class ImageHeader extends StatelessWidget implements PreferredSizeWidget { @override final Size preferredSize; + + void _showMessageActionModalBottomSheet(BuildContext context) { + showDialog( + context: context, + builder: (context) { + return ImageActionsModal( + userName: userName, + sentAt: sentAt, + ); + }); + } } From 8dd718b148f4981cb259a5fbc20d140f349d2bff Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Fri, 13 Nov 2020 16:26:24 +0100 Subject: [PATCH 0365/1140] ask permissions --- example/ios/Podfile.lock | 16 +- example/ios/Runner.xcodeproj/project.pbxproj | 4 +- example/lib/choose_user_page.dart | 268 ++++++++++--------- example/lib/main.dart | 130 ++++----- example/pubspec.yaml | 2 +- lib/src/message_input.dart | 102 +++++-- svgs/icon_picture_empty_state.svg | 4 + 7 files changed, 303 insertions(+), 223 deletions(-) create mode 100644 svgs/icon_picture_empty_state.svg diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock index af3a3d40..131e8aec 100644 --- a/example/ios/Podfile.lock +++ b/example/ios/Podfile.lock @@ -108,6 +108,8 @@ PODS: - GoogleUtilities/Logger - image_picker (0.0.1): - Flutter + - media_gallery (0.0.1): + - Flutter - nanopb (1.30906.0): - nanopb/decode (= 1.30906.0) - nanopb/encode (= 1.30906.0) @@ -115,7 +117,7 @@ PODS: - nanopb/encode (1.30906.0) - path_provider (0.0.1): - Flutter - - photo_gallery (0.0.1): + - "permission_handler (5.0.1+1)": - Flutter - PromisesObjC (1.2.11) - Protobuf (3.13.0) @@ -167,8 +169,9 @@ DEPENDENCIES: - flutter_local_notifications (from `.symlinks/plugins/flutter_local_notifications/ios`) - flutter_secure_storage (from `.symlinks/plugins/flutter_secure_storage/ios`) - image_picker (from `.symlinks/plugins/image_picker/ios`) + - media_gallery (from `.symlinks/plugins/media_gallery/ios`) - path_provider (from `.symlinks/plugins/path_provider/ios`) - - photo_gallery (from `.symlinks/plugins/photo_gallery/ios`) + - permission_handler (from `.symlinks/plugins/permission_handler/ios`) - shared_preferences (from `.symlinks/plugins/shared_preferences/ios`) - sqflite (from `.symlinks/plugins/sqflite/ios`) - sqlite3_flutter_libs (from `.symlinks/plugins/sqlite3_flutter_libs/ios`) @@ -220,10 +223,12 @@ EXTERNAL SOURCES: :path: ".symlinks/plugins/flutter_secure_storage/ios" image_picker: :path: ".symlinks/plugins/image_picker/ios" + media_gallery: + :path: ".symlinks/plugins/media_gallery/ios" path_provider: :path: ".symlinks/plugins/path_provider/ios" - photo_gallery: - :path: ".symlinks/plugins/photo_gallery/ios" + permission_handler: + :path: ".symlinks/plugins/permission_handler/ios" shared_preferences: :path: ".symlinks/plugins/shared_preferences/ios" sqflite: @@ -259,9 +264,10 @@ SPEC CHECKSUMS: GoogleDataTransport: f56af7caa4ed338dc8e138a5d7c5973e66440833 GoogleUtilities: 7f2f5a07f888cdb145101d6042bc4422f57e70b3 image_picker: 9c3312491f862b28d21ecd8fdf0ee14e601b3f09 + media_gallery: 834a04455a476b975c280aa1f24ed2853dfe36de nanopb: 59317e09cf1f1a0af72f12af412d54edf52603fc path_provider: abfe2b5c733d04e238b0d8691db0cfd63a27a93c - photo_gallery: 9f95e57747cd22c10676ece3660d1ffe6c603ee5 + permission_handler: eac8e15b4a1a3fba55b761d19f3f4e6b005d15b6 PromisesObjC: 8c196f5a328c2cba3e74624585467a557dcb482f Protobuf: 3dac39b34a08151c6d949560efe3f86134a3f748 SDWebImage: b69257f4ab14e9b6a2ef53e910fdf914d8f757c1 diff --git a/example/ios/Runner.xcodeproj/project.pbxproj b/example/ios/Runner.xcodeproj/project.pbxproj index ea52b6eb..709db931 100644 --- a/example/ios/Runner.xcodeproj/project.pbxproj +++ b/example/ios/Runner.xcodeproj/project.pbxproj @@ -327,9 +327,9 @@ "${BUILT_PRODUCTS_DIR}/flutter_local_notifications/flutter_local_notifications.framework", "${BUILT_PRODUCTS_DIR}/flutter_secure_storage/flutter_secure_storage.framework", "${BUILT_PRODUCTS_DIR}/image_picker/image_picker.framework", + "${BUILT_PRODUCTS_DIR}/media_gallery/media_gallery.framework", "${BUILT_PRODUCTS_DIR}/nanopb/nanopb.framework", "${BUILT_PRODUCTS_DIR}/path_provider/path_provider.framework", - "${BUILT_PRODUCTS_DIR}/photo_gallery/photo_gallery.framework", "${BUILT_PRODUCTS_DIR}/shared_preferences/shared_preferences.framework", "${BUILT_PRODUCTS_DIR}/sqflite/sqflite.framework", "${BUILT_PRODUCTS_DIR}/sqlite3/sqlite3.framework", @@ -358,9 +358,9 @@ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/flutter_local_notifications.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/flutter_secure_storage.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/image_picker.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/media_gallery.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/nanopb.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/path_provider.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/photo_gallery.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/shared_preferences.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/sqflite.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/sqlite3.framework", diff --git a/example/lib/choose_user_page.dart b/example/lib/choose_user_page.dart index fd7d2b6c..30205088 100644 --- a/example/lib/choose_user_page.dart +++ b/example/lib/choose_user_page.dart @@ -59,165 +59,167 @@ class ChooseUserPage extends StatelessWidget { (_, value) => value..extraData['image'] = getRandomPicUrl(value)); return Scaffold( - body: Column( - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Padding( - padding: const EdgeInsets.only( - top: 34, - bottom: 20, - ), - child: Center( - child: SvgPicture.asset( - 'assets/logo.svg', - height: 40, + body: SafeArea( + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Padding( + padding: const EdgeInsets.only( + top: 34, + bottom: 20, + ), + child: Center( + child: SvgPicture.asset( + 'assets/logo.svg', + height: 40, + ), ), ), - ), - Padding( - padding: const EdgeInsets.only(bottom: 13.0), - child: Text( - 'Welcome to Stream Chat', + Padding( + padding: const EdgeInsets.only(bottom: 13.0), + child: Text( + 'Welcome to Stream Chat', + style: TextStyle( + fontSize: 22, + color: Colors.black, + fontWeight: FontWeight.bold, + ), + ), + ), + Text( + 'Select a user to try the Flutter SDK:', style: TextStyle( - fontSize: 22, + fontSize: 14.5, color: Colors.black, - fontWeight: FontWeight.bold, ), ), - ), - Text( - 'Select a user to try the Flutter SDK:', - style: TextStyle( - fontSize: 14.5, - color: Colors.black, - ), - ), - Expanded( - child: ListView.separated( - separatorBuilder: (context, i) { - return Container( - width: double.infinity, - color: Colors.black12, - height: 1, - ); - }, - itemCount: users.length + 1, - itemBuilder: (context, i) { - return [ - ...users.entries.map((entry) { - final token = entry.key; - final user = entry.value; - return ListTile( - onTap: () async { - showDialog( - barrierDismissible: false, - context: context, - builder: (context) => Center( - child: Container( - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(16), - color: Colors.white, - ), - height: 100, - width: 100, - child: Center( - child: CircularProgressIndicator(), + Expanded( + child: ListView.separated( + separatorBuilder: (context, i) { + return Container( + width: double.infinity, + color: Colors.black12, + height: 1, + ); + }, + itemCount: users.length + 1, + itemBuilder: (context, i) { + return [ + ...users.entries.map((entry) { + final token = entry.key; + final user = entry.value; + return ListTile( + onTap: () async { + showDialog( + barrierDismissible: false, + context: context, + builder: (context) => Center( + child: Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(16), + color: Colors.white, + ), + height: 100, + width: 100, + child: Center( + child: CircularProgressIndicator(), + ), ), ), + ); + + final secureStorage = FlutterSecureStorage(); + final client = StreamChat.of(context).client; + + await client.setUser( + user, + token, + ); + + secureStorage.write( + key: kStreamApiKey, + value: kDefaultStreamApiKey, + ); + secureStorage.write( + key: kStreamUserId, + value: user.id, + ); + secureStorage.write( + key: kStreamToken, + value: token, + ); + + if (!kIsWeb) { + initNotifications(client); + } + + Navigator.pop(context); + await Navigator.pushReplacement( + context, + MaterialPageRoute( + builder: (context) { + return StreamChat( + client: client, + child: ChannelListPage(), + ); + }, + ), + ); + }, + leading: UserAvatar( + user: user, + constraints: BoxConstraints.tight( + Size.fromRadius(20), ), - ); - - final secureStorage = FlutterSecureStorage(); - final client = StreamChat.of(context).client; - - await client.setUser( - user, - token, - ); - - secureStorage.write( - key: kStreamApiKey, - value: kDefaultStreamApiKey, - ); - secureStorage.write( - key: kStreamUserId, - value: user.id, - ); - secureStorage.write( - key: kStreamToken, - value: token, - ); - - if (!kIsWeb) { - initNotifications(client); - } - - Navigator.pop(context); - await Navigator.pushReplacement( + ), + title: Text( + user.name, + style: TextStyle(fontWeight: FontWeight.bold), + ), + subtitle: Text('Stream test account'), + trailing: SvgPicture.asset( + 'assets/icon_arrow_right.svg', + height: 24, + width: 24, + ), + ); + }), + ListTile( + onTap: () { + Navigator.push( context, MaterialPageRoute( - builder: (context) { - return StreamChat( - client: client, - child: ChannelListPage(), - ); - }, + builder: (context) => AdvancedOptionsPage(), ), ); }, - leading: UserAvatar( - user: user, - constraints: BoxConstraints.tight( - Size.fromRadius(20), + leading: CircleAvatar( + child: Icon( + StreamIcons.settings, + color: Colors.black, ), + backgroundColor: + StreamChatTheme.of(context).secondaryColor, ), title: Text( - user.name, + 'Advanced Options', style: TextStyle(fontWeight: FontWeight.bold), ), - subtitle: Text('Stream test account'), + subtitle: Text('Custom settings'), trailing: SvgPicture.asset( 'assets/icon_arrow_right.svg', height: 24, width: 24, + clipBehavior: Clip.none, ), - ); - }), - ListTile( - onTap: () { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => AdvancedOptionsPage(), - ), - ); - }, - leading: CircleAvatar( - child: Icon( - StreamIcons.settings, - color: Colors.black, - ), - backgroundColor: - StreamChatTheme.of(context).secondaryColor, ), - title: Text( - 'Advanced Options', - style: TextStyle(fontWeight: FontWeight.bold), - ), - subtitle: Text('Custom settings'), - trailing: SvgPicture.asset( - 'assets/icon_arrow_right.svg', - height: 24, - width: 24, - clipBehavior: Clip.none, - ), - ), - ][i]; - }, + ][i]; + }, + ), ), - ), - StreamVersion(), - ], + StreamVersion(), + ], + ), ), ); } diff --git a/example/lib/main.dart b/example/lib/main.dart index 1da02072..2e3f43e2 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -64,83 +64,85 @@ class ChannelListPage extends StatelessWidget { final user = StreamChat.of(context).user; return Scaffold( drawer: Drawer( - 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, + ), + 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, + ), ), ), + ], + ), + ), + ListTile( + leading: Icon(StreamIcons.edit), + title: Text( + 'New direct message', + style: TextStyle( + fontSize: 14.5, ), - ], - ), - ), - ListTile( - leading: Icon(StreamIcons.edit), - title: Text( - 'New direct message', - style: TextStyle( - fontSize: 14.5, ), ), - ), - ListTile( - leading: Icon(StreamIcons.group), - title: Text( - 'New group', - style: TextStyle( - fontSize: 14.5, + ListTile( + leading: Icon(StreamIcons.group), + title: Text( + 'New group', + style: TextStyle( + fontSize: 14.5, + ), ), ), - ), - Expanded( - child: Container( - alignment: Alignment.bottomCenter, - child: ListTile( - onTap: () async { - await StreamChat.of(context).client.disconnect(); + Expanded( + child: Container( + alignment: Alignment.bottomCenter, + child: ListTile( + onTap: () async { + await StreamChat.of(context).client.disconnect(); - final secureStorage = FlutterSecureStorage(); - await secureStorage.deleteAll(); - Navigator.pop(context); - await Navigator.pushReplacement( - context, - MaterialPageRoute( - builder: (context) => ChooseUserPage(), + final secureStorage = FlutterSecureStorage(); + await secureStorage.deleteAll(); + Navigator.pop(context); + await Navigator.pushReplacement( + context, + MaterialPageRoute( + builder: (context) => ChooseUserPage(), + ), + ); + }, + leading: Icon(StreamIcons.user), + title: Text( + 'Sign out', + style: TextStyle( + fontSize: 14.5, ), - ); - }, - leading: Icon(StreamIcons.user), - title: Text( - 'Sign out', - style: TextStyle( - fontSize: 14.5, ), ), ), ), - ), - ], + ], + ), ), ), ), diff --git a/example/pubspec.yaml b/example/pubspec.yaml index e1442635..8fc2dadb 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -1,6 +1,6 @@ name: example description: A new Flutter project. -version: 1.0.58+60 +version: 1.0.59+61 environment: sdk: ">=2.2.2 <3.0.0" diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 72c754e0..1f157ed3 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -1,4 +1,5 @@ import 'dart:async'; +import 'dart:io'; import 'dart:math'; import 'package:emojis/emoji.dart'; @@ -659,7 +660,7 @@ class MessageInputState extends State { setState(() { _animateContainer = false; _filePickerSize = (_filePickerSize - update.delta.dy).clamp( - 100, + 240.0, MediaQuery.of(context).size.height / 1.7, ); }); @@ -709,17 +710,80 @@ class MessageInputState extends State { Widget _buildPickerSection() { switch (_filePickerIndex) { case 0: - return MediaListView( - selectedIds: _attachments.map((e) => e.id).toList(), - onSelect: (media) { - if (!_attachments.any((element) => element.id == media.id)) { - _addAttachment(media); - } else { - _attachments.removeWhere((element) => element.id == media.id); - setState(() {}); - } - }, - ); + return FutureBuilder( + future: Platform.isAndroid + ? Permission.storage.status + : Permission.photos.status, + builder: (context, snapshot) { + if (!snapshot.hasData) { + return Center( + child: CircularProgressIndicator(), + ); + } + + if (snapshot.data.isGranted) { + return MediaListView( + selectedIds: _attachments.map((e) => e.id).toList(), + onSelect: (media) { + if (!_attachments + .any((element) => element.id == media.id)) { + _addAttachment(media); + } else { + _attachments + .removeWhere((element) => element.id == media.id); + setState(() {}); + } + }, + ); + } + + return InkWell( + onTap: () async { + var status = await (Platform.isAndroid + ? Permission.storage.status + : Permission.photos.status); + print('status: ${status}'); + if (status.isPermanentlyDenied || status.isDenied) { + if (await openAppSettings()) { + setState(() {}); + } + } else { + status = await (Platform.isAndroid + ? Permission.storage + : Permission.photos) + .request(); + if (status.isGranted) { + setState(() {}); + } + } + }, + child: Container( + color: Color(0xFFF2F2F2), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + SvgPicture.asset( + 'svgs/icon_picture_empty_state.svg', + package: 'stream_chat_flutter', + height: 140, + color: StreamChatTheme.of(context).accentColor, + ), + Center( + child: Text( + 'Allow access to your gallery', + style: TextStyle( + fontSize: 14, + fontWeight: FontWeight.bold, + color: StreamChatTheme.of(context).accentColor, + ), + ), + ), + ], + ), + ), + ); + }); break; case 1: break; @@ -1235,12 +1299,14 @@ class MessageInputState extends State { _filePickerSize = 250.0; }); } else { - final status = await Permission.storage.request(); - if (status.isDenied || status.isPermanentlyDenied) { - final res = await openAppSettings(); - if (!res) { - return; - } + final status = await (Platform.isAndroid + ? Permission.storage.status + : Permission.photos.status); + if (status.isUndetermined) { + await (Platform.isAndroid + ? Permission.storage + : Permission.photos) + .request(); } showAttachmentModal(); } diff --git a/svgs/icon_picture_empty_state.svg b/svgs/icon_picture_empty_state.svg new file mode 100644 index 00000000..135772d0 --- /dev/null +++ b/svgs/icon_picture_empty_state.svg @@ -0,0 +1,4 @@ + + + + From 49dc157ea751150fc36518f6a537ca7f26c948f5 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Fri, 13 Nov 2020 17:12:36 +0100 Subject: [PATCH 0366/1140] fix attachment shape --- lib/src/message_input.dart | 57 +++++++++++++++++++++---------------- lib/src/message_widget.dart | 25 ++++++++++------ 2 files changed, 48 insertions(+), 34 deletions(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 1f157ed3..bac36ef7 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -218,7 +218,7 @@ class MessageInputState extends State { Flex _buildTextField(BuildContext context) { return Flex( direction: Axis.horizontal, - crossAxisAlignment: CrossAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.end, children: [ if (!_commandEnabled) _buildExpandActionsButton(), if (widget.actionsLocation == ActionsLocation.left) @@ -388,10 +388,7 @@ class MessageInputState extends State { autofocus: false, textAlignVertical: TextAlignVertical.center, decoration: InputDecoration( - hintText: - (_commandEnabled && _chosenCommand.name == 'giphy') - ? 'Search GIFs' - : 'Write a message', + hintText: _getHint(), prefixText: _commandEnabled ? null : ' ', border: OutlineInputBorder( borderSide: BorderSide(color: Colors.transparent)), @@ -443,6 +440,16 @@ class MessageInputState extends State { ); } + String _getHint() { + if (_commandEnabled && _chosenCommand.name == 'giphy') { + return 'Search GIFs'; + } + if (_attachments.isNotEmpty) { + return 'Add a command or send'; + } + return 'Write a message'; + } + void _checkEmoji(String s, BuildContext context) { if (textEditingController.selection.isCollapsed && (s.isNotEmpty && s[textEditingController.selection.start - 1] == ':' || @@ -551,8 +558,10 @@ class MessageInputState extends State { Padding( padding: const EdgeInsets.symmetric(horizontal: 8.0), - child: Icon(StreamIcons.lightning, - color: StreamChatTheme.of(context).accentColor), + child: Icon( + StreamIcons.lightning, + color: StreamChatTheme.of(context).accentColor, + ), ), Text( 'Instant Commands', @@ -1247,26 +1256,24 @@ class MessageInputState extends State { } Widget _buildCommandButton() { - return Center( - child: InkWell( - child: Padding( - padding: const EdgeInsets.only( - left: 4.0, right: 8.0, top: 8.0, bottom: 8.0), - child: Icon( - StreamIcons.lightning, - color: Color(0xFF000000).withAlpha(128), - ), + return InkWell( + child: Padding( + padding: + const EdgeInsets.only(left: 4.0, right: 8.0, top: 8.0, bottom: 8.0), + child: Icon( + StreamIcons.lightning, + color: Color(0xFF000000).withAlpha(128), ), - onTap: () { - if (_commandsOverlay == null) { - _commandsOverlay = _buildCommandsOverlayEntry(); - Overlay.of(context).insert(_commandsOverlay); - } else { - _commandsOverlay?.remove(); - _commandsOverlay = null; - } - }, ), + onTap: () { + if (_commandsOverlay == null) { + _commandsOverlay = _buildCommandsOverlayEntry(); + Overlay.of(context).insert(_commandsOverlay); + } else { + _commandsOverlay?.remove(); + _commandsOverlay = null; + } + }, ); } diff --git a/lib/src/message_widget.dart b/lib/src/message_widget.dart index fd6286a2..ffe52634 100644 --- a/lib/src/message_widget.dart +++ b/lib/src/message_widget.dart @@ -585,14 +585,22 @@ class _MessageWidgetState extends State { widget.message, attachment, ); - return wrapAttachmentWidget(context, attachmentWidget, - attachment: attachment); + return wrapAttachmentWidget( + context, + attachmentWidget, + attachment: attachment, + ); })?.toList() ?? []; } - Padding wrapAttachmentWidget(BuildContext context, Widget attachmentWidget, - {Attachment attachment}) { + Padding wrapAttachmentWidget( + BuildContext context, + Widget attachmentWidget, { + Attachment attachment, + }) { + final attachmentShape = + widget.attachmentShape ?? widget.shape ?? _getDefaultShape(context); return Padding( padding: EdgeInsets.only( bottom: 4, @@ -605,13 +613,12 @@ class _MessageWidgetState extends State { ? Colors.white : _getBackgroundColor(), clipBehavior: Clip.hardEdge, - shape: widget.attachmentShape ?? - widget.shape ?? - _getDefaultShape(context), + shape: attachmentShape, child: Padding( padding: widget.attachmentPadding, - child: ClipRRect( - borderRadius: BorderRadius.circular(6), + child: Material( + clipBehavior: Clip.hardEdge, + shape: attachmentShape, child: Transform( transform: Matrix4.rotationY(widget.reverse ? pi : 0), alignment: Alignment.center, From 2a7fdc750dc01e29c36930410514748d2cbfb67a Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Fri, 13 Nov 2020 17:20:12 +0100 Subject: [PATCH 0367/1140] fix modal with attachment and text --- lib/src/message_actions_modal.dart | 13 +++++++------ lib/src/message_reactions_modal.dart | 13 +++++++------ 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/lib/src/message_actions_modal.dart b/lib/src/message_actions_modal.dart index 00354a49..16c48e25 100644 --- a/lib/src/message_actions_modal.dart +++ b/lib/src/message_actions_modal.dart @@ -45,14 +45,15 @@ class MessageActionsModal extends StatelessWidget { @override Widget build(BuildContext context) { - var size = MediaQuery.of(context).size; - var user = StreamChat.of(context).user; + final size = MediaQuery.of(context).size; + final user = StreamChat.of(context).user; - var roughMaxSize = 2 * size.width / 3; - var roughSentenceSize = + final roughMaxSize = 2 * size.width / 3; + final roughSentenceSize = message.text.length * messageTheme.messageText.fontSize * 1.2; - var divFactor = - roughSentenceSize == 0 ? 1 : (roughSentenceSize / roughMaxSize); + final divFactor = message.attachments?.isNotEmpty == true + ? 1 + : (roughSentenceSize == 0 ? 1 : (roughSentenceSize / roughMaxSize)); return GestureDetector( behavior: HitTestBehavior.translucent, diff --git a/lib/src/message_reactions_modal.dart b/lib/src/message_reactions_modal.dart index fc3f68a4..d68bd769 100644 --- a/lib/src/message_reactions_modal.dart +++ b/lib/src/message_reactions_modal.dart @@ -36,14 +36,15 @@ class MessageReactionsModal extends StatelessWidget { @override Widget build(BuildContext context) { - var size = MediaQuery.of(context).size; - var user = StreamChat.of(context).user; + final size = MediaQuery.of(context).size; + final user = StreamChat.of(context).user; - var roughMaxSize = 2 * size.width / 3; - var roughSentenceSize = + final roughMaxSize = 2 * size.width / 3; + final roughSentenceSize = message.text.length * messageTheme.messageText.fontSize * 1.2; - var divFactor = - roughSentenceSize == 0 ? 1 : (roughSentenceSize / roughMaxSize); + final divFactor = message.attachments?.isNotEmpty == true + ? 1 + : (roughSentenceSize == 0 ? 1 : (roughSentenceSize / roughMaxSize)); return GestureDetector( behavior: HitTestBehavior.translucent, From ef8e9788e36a209af5a663f6c0b78025016bc09c Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Mon, 16 Nov 2020 12:37:50 +0100 Subject: [PATCH 0368/1140] upgrade llc --- pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pubspec.yaml b/pubspec.yaml index 241025d0..04d07d55 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -27,7 +27,7 @@ dependencies: file_picker: ^2.0.12 image_picker: ^0.6.7+2 flutter_keyboard_visibility: ^3.3.0 - stream_chat: ^0.2.11 + stream_chat: ^0.2.11+1 mime: ^0.9.6+3 visibility_detector: ^0.1.5 http_parser: ^3.1.4 From d7e6978ccf001b041943bf072d7ccbb623b7575f Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Mon, 16 Nov 2020 19:33:11 +0530 Subject: [PATCH 0369/1140] feat: Added images modal, fixed image group errors --- lib/src/full_screen_image.dart | 1 + lib/src/image_footer.dart | 78 +++++++++++++++++++++++++++++++++- lib/src/image_group.dart | 2 +- 3 files changed, 78 insertions(+), 3 deletions(-) diff --git a/lib/src/full_screen_image.dart b/lib/src/full_screen_image.dart index b616c17a..c88053f9 100644 --- a/lib/src/full_screen_image.dart +++ b/lib/src/full_screen_image.dart @@ -112,6 +112,7 @@ class _FullScreenImageState extends State ImageFooter( currentPage: _currentPage, totalPages: widget.urls.length, + urls: widget.urls, ), ], ), diff --git a/lib/src/image_footer.dart b/lib/src/image_footer.dart index fade96bf..668f556f 100644 --- a/lib/src/image_footer.dart +++ b/lib/src/image_footer.dart @@ -1,3 +1,4 @@ +import 'package:cached_network_image/cached_network_image.dart'; import 'package:flutter/material.dart'; import 'package:stream_chat/stream_chat.dart'; import 'package:stream_chat_flutter/src/back_button.dart'; @@ -24,6 +25,8 @@ class ImageFooter extends StatelessWidget { final int currentPage; final int totalPages; + final List urls; + /// Creates a channel header ImageFooter({ Key key, @@ -32,6 +35,7 @@ class ImageFooter extends StatelessWidget { this.onImageTap, this.currentPage = 0, this.totalPages = 0, + this.urls, }) : preferredSize = Size.fromHeight(kToolbarHeight), super(key: key); @@ -39,7 +43,8 @@ class ImageFooter extends StatelessWidget { Widget build(BuildContext context) { return SafeArea( child: Container( - color: StreamChatTheme.of(context).channelTheme.channelHeaderTheme.color, + color: + StreamChatTheme.of(context).channelTheme.channelHeaderTheme.color, padding: EdgeInsets.symmetric(vertical: 8.0), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, @@ -77,7 +82,9 @@ class ImageFooter extends StatelessWidget { StreamIcons.grid, color: Colors.black, ), - onPressed: () {}, + onPressed: () { + _buildPhotosModal(context); + }, ), ], ), @@ -128,6 +135,73 @@ class ImageFooter extends StatelessWidget { ); } + Widget _buildPhotosModal(context) { + showModalBottomSheet( + context: context, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(16.0), + ), + builder: (context) { + return Column( + mainAxisSize: MainAxisSize.min, + children: [ + Container( + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.only( + topRight: Radius.circular(8.0), + topLeft: Radius.circular(8.0), + ) + ), + child: Stack( + children: [ + Center( + child: Padding( + padding: const EdgeInsets.all(16.0), + child: Text( + 'Photos', + style: TextStyle( + fontSize: 16.0, + fontWeight: FontWeight.w700, + color: Colors.black, + ), + ), + ), + ), + Align( + alignment: Alignment.centerRight, + child: IconButton( + icon: Icon(StreamIcons.close, color: Colors.black,), + onPressed: () { + Navigator.pop(context); + }, + ), + ), + ], + ), + ), + Container( + color: Colors.white, + child: GridView.builder( + shrinkWrap: true, + physics: NeverScrollableScrollPhysics(), + itemBuilder: (context, position) { + return Padding( + padding: const EdgeInsets.all(1.0), + child: AspectRatio(child: CachedNetworkImage(imageUrl: urls[position]), aspectRatio: 1.0,), + ); + }, + itemCount: urls.length, + gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: 3), + ), + ), + ], + ); + }, + ); + } + @override final Size preferredSize; } diff --git a/lib/src/image_group.dart b/lib/src/image_group.dart index 4592d94d..a97bde81 100644 --- a/lib/src/image_group.dart +++ b/lib/src/image_group.dart @@ -111,7 +111,7 @@ class ImageGroup extends StatelessWidget { context, MaterialPageRoute( builder: (context) => - FullScreenImage(urls: images.map((e) => e.imageUrl).toList(), + FullScreenImage(urls: images.map((e) => e.imageUrl ?? e.thumbUrl ?? e.assetUrl).toList(), startIndex: index, userName: message.user.name, sentAt: message.createdAt, From f9415636895cf96ff9bb89e5dd806ac558ac86c2 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Mon, 16 Nov 2020 15:04:49 +0100 Subject: [PATCH 0370/1140] update llc dependency --- pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pubspec.yaml b/pubspec.yaml index 04d07d55..a3a1f55a 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -27,7 +27,7 @@ dependencies: file_picker: ^2.0.12 image_picker: ^0.6.7+2 flutter_keyboard_visibility: ^3.3.0 - stream_chat: ^0.2.11+1 + stream_chat: ^0.2.11+2 mime: ^0.9.6+3 visibility_detector: ^0.1.5 http_parser: ^3.1.4 From 0efce1bf3a2b27c4a48dbad73672c0e19f6512b5 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Mon, 16 Nov 2020 16:33:44 +0100 Subject: [PATCH 0371/1140] fix tests --- lib/src/message_widget.dart | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/src/message_widget.dart b/lib/src/message_widget.dart index ffe52634..4f551655 100644 --- a/lib/src/message_widget.dart +++ b/lib/src/message_widget.dart @@ -816,7 +816,8 @@ class _MessageWidgetState extends State { ), ), if (widget.message.attachments - .any((element) => element.ogScrapeUrl != null)) + ?.any((element) => element.ogScrapeUrl != null) == + true) _buildUrlAttachment(), ], ), @@ -843,7 +844,8 @@ class _MessageWidgetState extends State { } if (widget.message.attachments - .any((element) => element.ogScrapeUrl != null)) { + ?.any((element) => element.ogScrapeUrl != null) == + true) { return Color(0xFFE9F2FF); } From 2c6c2f5bc168583ebe2ac4cf1d336ade9ce270e9 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Mon, 16 Nov 2020 16:41:58 +0100 Subject: [PATCH 0372/1140] update message input radius --- lib/src/message_input.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index bac36ef7..139d6ab7 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -341,7 +341,7 @@ class MessageInputState extends State { child: Container( clipBehavior: Clip.antiAlias, decoration: BoxDecoration( - borderRadius: BorderRadius.circular(32.0), + borderRadius: BorderRadius.circular(20.0), border: Border.all( color: Colors.grey, ), From c04d72d46f3af897cdcdcd1779a05e84402766de Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Mon, 16 Nov 2020 16:44:00 +0100 Subject: [PATCH 0373/1140] update message input radius --- lib/src/media_list_view.dart | 3 ++- lib/src/message_input.dart | 6 +++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/lib/src/media_list_view.dart b/lib/src/media_list_view.dart index 627a480c..225d327b 100644 --- a/lib/src/media_list_view.dart +++ b/lib/src/media_list_view.dart @@ -63,10 +63,11 @@ class _MediaListViewState extends State { right: 8, ), child: CircleAvatar( - maxRadius: 12.0, + radius: 12, backgroundColor: Colors.white, child: Icon( StreamIcons.check, + size: 24, color: Colors.black, ), ), diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 139d6ab7..e393cd3c 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -1170,8 +1170,8 @@ class MessageInputState extends State { Positioned _buildRemoveButton(_SendingAttachment attachment) { return Positioned( - height: 16, - width: 16, + height: 24, + width: 24, top: 4, right: 4, child: RawMaterialButton( @@ -1192,7 +1192,7 @@ class MessageInputState extends State { child: Center( child: Icon( StreamIcons.close, - size: 15, + size: 24, color: Colors.white, ), ), From 4ff3a225b2e68c468ce43c6dbb90c1e9801c3f17 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Mon, 16 Nov 2020 16:49:00 +0100 Subject: [PATCH 0374/1140] add record icon --- lib/src/message_input.dart | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index e393cd3c..872864bd 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -630,6 +630,7 @@ class MessageInputState extends State { IconButton( icon: Icon( StreamIcons.picture, + size: 24, color: _filePickerIndex == 0 ? StreamChatTheme.of(context).accentColor : Colors.black.withOpacity(0.5), @@ -643,6 +644,7 @@ class MessageInputState extends State { IconButton( icon: Icon( StreamIcons.folder, + size: 24, color: _filePickerIndex == 1 ? StreamChatTheme.of(context).accentColor : Colors.black.withOpacity(0.5), @@ -654,6 +656,7 @@ class MessageInputState extends State { IconButton( icon: Icon( StreamIcons.camera, + size: 24, color: _filePickerIndex == 2 ? StreamChatTheme.of(context).accentColor : Colors.black.withOpacity(0.5), @@ -662,6 +665,18 @@ class MessageInputState extends State { pickFile(DefaultAttachmentTypes.image, true); }, ), + IconButton( + icon: Icon( + StreamIcons.record, + size: 24, + color: _filePickerIndex == 2 + ? StreamChatTheme.of(context).accentColor + : Colors.black.withOpacity(0.5), + ), + onPressed: () { + pickFile(DefaultAttachmentTypes.video, true); + }, + ), ], ), GestureDetector( @@ -794,10 +809,6 @@ class MessageInputState extends State { ); }); break; - case 1: - break; - case 2: - break; } } From b0cbcbc6c846a83ac8fa2f02e47c7e7a8ca464a4 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Mon, 16 Nov 2020 16:59:58 +0100 Subject: [PATCH 0375/1140] update giphy label --- lib/src/giphy_attachment.dart | 134 ++++++++++++++++------------------ 1 file changed, 64 insertions(+), 70 deletions(-) diff --git a/lib/src/giphy_attachment.dart b/lib/src/giphy_attachment.dart index bfa21239..8cec9ce5 100644 --- a/lib/src/giphy_attachment.dart +++ b/lib/src/giphy_attachment.dart @@ -283,80 +283,74 @@ class GiphyAttachment extends StatelessWidget { Widget _buildSentAttachment(context) { return Container( - child: Column( - children: [ - Container( - decoration: BoxDecoration( - borderRadius: BorderRadius.only( - topRight: Radius.circular(16.0), - bottomRight: Radius.circular(0.0), - topLeft: Radius.circular(16.0), - bottomLeft: Radius.circular(16.0), - ), - ), - clipBehavior: Clip.antiAlias, - child: GestureDetector( - onTap: () { - Navigator.push(context, MaterialPageRoute(builder: (_) { - return FullScreenImage( - url: attachment.imageUrl ?? - attachment.assetUrl ?? - attachment.thumbUrl, - ); - })); + child: GestureDetector( + onTap: () { + Navigator.push(context, MaterialPageRoute(builder: (_) { + return FullScreenImage( + url: attachment.imageUrl ?? + attachment.assetUrl ?? + attachment.thumbUrl, + ); + })); + }, + child: Stack( + children: [ + CachedNetworkImage( + height: size?.height, + width: size?.width, + placeholder: (_, __) { + return Container( + width: size?.width, + height: size?.height, + child: Center( + child: CircularProgressIndicator(), + ), + ); }, - child: CachedNetworkImage( - height: size?.height, - width: size?.width, - placeholder: (_, __) { - return Container( - width: size?.width, - height: size?.height, - child: Center( - child: CircularProgressIndicator(), - ), - ); - }, - imageUrl: attachment.thumbUrl ?? - attachment.imageUrl ?? - attachment.assetUrl, - errorWidget: (context, url, error) => AttachmentError( - attachment: attachment, - size: size, + imageUrl: attachment.thumbUrl ?? + attachment.imageUrl ?? + attachment.assetUrl, + errorWidget: (context, url, error) => AttachmentError( + attachment: attachment, + size: size, + ), + fit: BoxFit.cover, + ), + Positioned( + bottom: 8, + left: 8, + child: Material( + color: Colors.black.withOpacity(.5), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12), + ), + child: Padding( + padding: const EdgeInsets.symmetric( + horizontal: 8.0, + vertical: 4.0, + ), + child: Row( + children: [ + Icon( + StreamIcons.lightning, + color: Colors.white, + size: 16, + ), + Text( + 'GIPHY', + style: TextStyle( + color: Colors.white, + fontWeight: FontWeight.bold, + fontSize: 11, + ), + ), + ], + ), ), - fit: BoxFit.cover, ), ), - ), - Padding( - padding: const EdgeInsets.only( - top: 8.0, - bottom: 8, - ), - child: Row( - children: [ - Row( - children: [ - Icon( - StreamIcons.lightning, - color: StreamChatTheme.of(context).accentColor, - size: 15.0, - ), - Text( - 'GIPHY', - style: TextStyle( - color: StreamChatTheme.of(context).accentColor, - fontWeight: FontWeight.bold, - fontSize: 11.0, - ), - ), - ], - ), - ], - mainAxisAlignment: MainAxisAlignment.start, - ), - ) - ], + ], + ), ), ); } From 989ea91554e0062aa3bf79164b88dbfa9b5f2f81 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Tue, 17 Nov 2020 14:47:32 +0530 Subject: [PATCH 0376/1140] feat: Added user share section ui --- lib/src/image_footer.dart | 208 ++++++++++++++++++++++++++++++++++---- 1 file changed, 189 insertions(+), 19 deletions(-) diff --git a/lib/src/image_footer.dart b/lib/src/image_footer.dart index 668f556f..5898208c 100644 --- a/lib/src/image_footer.dart +++ b/lib/src/image_footer.dart @@ -4,14 +4,16 @@ import 'package:stream_chat/stream_chat.dart'; import 'package:stream_chat_flutter/src/back_button.dart'; import 'package:stream_chat_flutter/src/channel_info.dart'; import 'package:stream_chat_flutter/src/channel_name.dart'; +import 'package:stream_chat_flutter/src/stream_chat.dart'; import 'package:stream_chat_flutter/src/stream_chat_theme.dart'; import 'package:stream_chat_flutter/src/stream_icons.dart'; +import 'package:stream_chat_flutter/src/user_avatar.dart'; import './channel_name.dart'; import 'channel_image.dart'; import 'stream_channel.dart'; -class ImageFooter extends StatelessWidget { +class ImageFooter extends StatefulWidget { /// Callback to call when pressing the back button. /// By default it calls [Navigator.pop] final VoidCallback onBackPressed; @@ -39,6 +41,22 @@ class ImageFooter extends StatelessWidget { }) : preferredSize = Size.fromHeight(kToolbarHeight), super(key: key); + @override + _ImageFooterState createState() => _ImageFooterState(); + + @override + final Size preferredSize; +} + +class _ImageFooterState extends State { + Future _userQuery; + + @override + void initState() { + super.initState(); + _userQuery = _queryUsers(context); + } + @override Widget build(BuildContext context) { return SafeArea( @@ -55,10 +73,12 @@ class ImageFooter extends StatelessWidget { size: 24.0, color: Colors.black, ), - onPressed: onBackPressed, + onPressed: () { + _buildShareModal(context); + }, ), InkWell( - onTap: onTitleTap, + onTap: widget.onTitleTap, child: Container( child: Column( crossAxisAlignment: CrossAxisAlignment.center, @@ -66,7 +86,7 @@ class ImageFooter extends StatelessWidget { mainAxisSize: MainAxisSize.min, children: [ Text( - '${currentPage + 1} of $totalPages', + '${widget.currentPage + 1} of ${widget.totalPages}', style: TextStyle( fontSize: 16.0, fontWeight: FontWeight.w700, @@ -96,7 +116,7 @@ class ImageFooter extends StatelessWidget { elevation: 1, leading: IconButton( icon: Icon(StreamIcons.share), - onPressed: onBackPressed, + onPressed: widget.onBackPressed, ), backgroundColor: StreamChatTheme.of(context).channelTheme.channelHeaderTheme.color, @@ -108,10 +128,10 @@ class ImageFooter extends StatelessWidget { ], centerTitle: true, title: InkWell( - onTap: onTitleTap, + onTap: widget.onTitleTap, child: Container( - height: preferredSize.height, - width: preferredSize.width, + height: widget.preferredSize.height, + width: widget.preferredSize.width, child: Column( crossAxisAlignment: CrossAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center, @@ -147,12 +167,11 @@ class ImageFooter extends StatelessWidget { children: [ Container( decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.only( - topRight: Radius.circular(8.0), - topLeft: Radius.circular(8.0), - ) - ), + color: Colors.white, + borderRadius: BorderRadius.only( + topRight: Radius.circular(8.0), + topLeft: Radius.circular(8.0), + )), child: Stack( children: [ Center( @@ -171,7 +190,10 @@ class ImageFooter extends StatelessWidget { Align( alignment: Alignment.centerRight, child: IconButton( - icon: Icon(StreamIcons.close, color: Colors.black,), + icon: Icon( + StreamIcons.close, + color: Colors.black, + ), onPressed: () { Navigator.pop(context); }, @@ -188,10 +210,16 @@ class ImageFooter extends StatelessWidget { itemBuilder: (context, position) { return Padding( padding: const EdgeInsets.all(1.0), - child: AspectRatio(child: CachedNetworkImage(imageUrl: urls[position]), aspectRatio: 1.0,), + child: AspectRatio( + child: CachedNetworkImage( + imageUrl: widget.urls[position], + fit: BoxFit.cover, + ), + aspectRatio: 1.0, + ), ); }, - itemCount: urls.length, + itemCount: widget.urls.length, gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: 3), ), @@ -202,6 +230,148 @@ class ImageFooter extends StatelessWidget { ); } - @override - final Size preferredSize; + Widget _buildShareModal(context) { + showModalBottomSheet( + context: context, + backgroundColor: Colors.transparent, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(16.0), + ), + builder: (context) { + return Column( + mainAxisSize: MainAxisSize.min, + children: [ + Container( + margin: EdgeInsets.symmetric( + horizontal: 8.0, + ), + padding: EdgeInsets.symmetric( + vertical: 4.0, + ), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.only( + topRight: Radius.circular(16.0), + topLeft: Radius.circular(16.0), + )), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Padding( + padding: const EdgeInsets.symmetric(horizontal: 6.0), + child: IconButton( + icon: Icon( + StreamIcons.search, + color: Colors.black, + ), + iconSize: 24.0, + onPressed: () {}, + ), + ), + Padding( + padding: const EdgeInsets.all(16.0), + child: Text( + 'Select a Chat to Share', + style: TextStyle( + fontSize: 16.0, + fontWeight: FontWeight.w700, + color: Colors.black, + ), + ), + ), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 6.0), + child: IconButton( + icon: Icon( + StreamIcons.share, + color: Colors.black, + ), + iconSize: 24.0, + onPressed: () {}, + ), + ), + ], + ), + ), + Expanded( + child: Container( + color: Colors.white, + margin: EdgeInsets.symmetric( + horizontal: 8.0, + ), + child: FutureBuilder( + future: _userQuery, + builder: (context, snapshot) { + if (!snapshot.hasData) { + return Center( + child: CircularProgressIndicator(), + ); + } + + return GridView.builder( + shrinkWrap: true, + itemBuilder: (context, position) { + var user = snapshot.data.users[position]; + + return Padding( + padding: const EdgeInsets.all(8.0), + child: Column( + mainAxisSize: MainAxisSize.min, + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Stack( + children: [ + UserAvatar( + onTap: (user) {}, + user: user, + constraints: BoxConstraints.tightFor( + height: 64, + width: 64, + ), + borderRadius: BorderRadius.circular(32), + ), + ], + ), + Padding( + padding: const EdgeInsets.all(8.0), + child: Text( + user.name, + style: Theme.of(context).textTheme.subtitle2, + textAlign: TextAlign.center, + maxLines: 2, + ), + ), + ], + ), + ); + }, + itemCount: snapshot.data.users.length, + gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: 4, + childAspectRatio: 0.75, + ), + ); + }), + ), + ), + ], + ); + }, + ); + } + + Future _queryUsers(context) { + return StreamChat.of(context).client.queryUsers( + pagination: PaginationParams( + limit: 25, + ), + sort: [ + SortOption( + 'name', + direction: SortOption.ASC, + ), + ], + ); + } } From 413dec0336d66b5bbddefa2b385149e58770fb62 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Tue, 17 Nov 2020 16:00:52 +0530 Subject: [PATCH 0377/1140] feat: Navigate to new chat screen on drawer item click Signed-off-by: xsahil03x --- example/lib/main.dart | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/example/lib/main.dart b/example/lib/main.dart index 2e3f43e2..7c288eae 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -63,6 +63,13 @@ class ChannelListPage extends StatelessWidget { Widget build(BuildContext context) { final user = StreamChat.of(context).user; return Scaffold( + appBar: AppBar( + backgroundColor: Colors.white, + title: Text( + 'Stream Chat', + style: TextStyle(color: Colors.black), + ), + ), drawer: Drawer( child: SafeArea( child: Padding( @@ -97,6 +104,12 @@ class ChannelListPage extends StatelessWidget { ), ), ListTile( + onTap: () { + Navigator.push( + context, + MaterialPageRoute(builder: (_) => NewChatScreen()), + ); + }, leading: Icon(StreamIcons.edit), title: Text( 'New direct message', @@ -434,3 +447,24 @@ class _CreateChannelPageState extends State { }).whenComplete(() => loading = false); } } + +class NewChatScreen extends StatefulWidget { + @override + _NewChatScreenState createState() => _NewChatScreenState(); +} + +class _NewChatScreenState extends State { + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + backgroundColor: Colors.white, + title: Text( + 'New Chat', + style: TextStyle(color: Colors.black), + ), + ), + body: Container(), + ); + } +} From 0d7bf98a5b2797c4771543dfb2f2a4357dda292d Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Tue, 17 Nov 2020 11:38:34 +0100 Subject: [PATCH 0378/1140] add shimmer effect --- example/lib/main.dart | 2 +- example/pubspec.yaml | 2 +- lib/src/channel_list_view.dart | 317 +++++++++++++++++++++------------ pubspec.yaml | 1 + 4 files changed, 203 insertions(+), 119 deletions(-) diff --git a/example/lib/main.dart b/example/lib/main.dart index 2e3f43e2..c09030f3 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -21,7 +21,7 @@ void main() async { logLevel: Level.INFO, showLocalNotification: (!kIsWeb && Platform.isAndroid) ? showLocalNotification : null, - persistenceEnabled: true, + persistenceEnabled: false, ); if (userId != null) { diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 8fc2dadb..fca549d2 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -1,6 +1,6 @@ name: example description: A new Flutter project. -version: 1.0.59+61 +version: 1.0.60+62 environment: sdk: ">=2.2.2 <3.0.0" diff --git a/lib/src/channel_list_view.dart b/lib/src/channel_list_view.dart index a10ad4bc..8b66db34 100644 --- a/lib/src/channel_list_view.dart +++ b/lib/src/channel_list_view.dart @@ -4,6 +4,7 @@ import 'dart:convert'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_slidable/flutter_slidable.dart'; +import 'package:shimmer/shimmer.dart'; import 'package:stream_chat/stream_chat.dart'; import 'package:stream_chat_flutter/src/channels_bloc.dart'; import 'package:stream_chat_flutter/src/utils.dart'; @@ -163,127 +164,209 @@ class _ChannelListViewState extends State return StreamBuilder>( stream: channelsBlocState.channelsStream, builder: (context, snapshot) { + var child; if (snapshot.hasError) { - if (snapshot.error is Error) { - print((snapshot.error as Error).stackTrace); + child = _buildErrorWidget( + snapshot, + context, + channelsBlocState, + ); + } else if (!snapshot.hasData) { + child = _buildLoadingWidget(); + } else { + final channels = snapshot.data; + + if (channels.isEmpty && widget.emptyBuilder != null) { + child = widget.emptyBuilder(context); } - if (widget.errorBuilder != null) { - return widget.errorBuilder(snapshot.error); + if (channels.isEmpty && widget.emptyBuilder == null) { + child = LayoutBuilder( + builder: (context, viewportConstraints) { + return SingleChildScrollView( + physics: AlwaysScrollableScrollPhysics(), + child: ConstrainedBox( + constraints: BoxConstraints( + minHeight: viewportConstraints.maxHeight, + ), + child: Center( + child: Text('You have no channels currently'), + ), + ), + ); + }, + ); } - var message = snapshot.error.toString(); - if (snapshot.error is DioError) { - final dioError = snapshot.error as DioError; - if (dioError.type == DioErrorType.RESPONSE) { - message = dioError.message; - } else { - message = 'Check your connection and retry'; - } + if (channels.isNotEmpty) { + child = ListView.custom( + physics: AlwaysScrollableScrollPhysics(), + controller: _scrollController, + childrenDelegate: SliverChildBuilderDelegate( + (context, i) { + return _itemBuilder(context, i, channels); + }, + childCount: (channels.length * 2) + 1, + findChildIndexCallback: (key) { + final ValueKey valueKey = key; + final index = channels.indexWhere( + (channel) => 'CHANNEL-${channel.id}' == valueKey.value); + return index != -1 ? (index * 2) : null; + }, + ), + ); } - return Center( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text.rich( - TextSpan( - children: [ - WidgetSpan( - child: Padding( - padding: const EdgeInsets.only( - right: 2.0, - ), - child: Icon(Icons.error_outline), - ), - ), - TextSpan(text: 'Error loading channels'), - ], - ), - style: Theme.of(context).textTheme.headline6, - ), - Padding( - padding: const EdgeInsets.only( - top: 16.0, - ), - child: Text(message), - ), - FlatButton( - onPressed: () { - channelsBlocState.queryChannels( - filter: widget.filter, - sortOptions: widget.sort, - paginationParams: widget.pagination, - options: widget.options, - ); - }, - child: Text('Retry'), - ), - ], - ), - ); } - if (!snapshot.hasData) { - return LayoutBuilder( - builder: (context, viewportConstraints) { - return SingleChildScrollView( - physics: AlwaysScrollableScrollPhysics(), - child: ConstrainedBox( - constraints: BoxConstraints( - minHeight: viewportConstraints.maxHeight, - ), - child: Center( - child: CircularProgressIndicator(), - ), - ), - ); - }, - ); - } - - final channels = snapshot.data; - - if (channels.isEmpty && widget.emptyBuilder != null) { - return widget.emptyBuilder(context); - } - - if (channels.isEmpty && widget.emptyBuilder == null) { - return LayoutBuilder( - builder: (context, viewportConstraints) { - return SingleChildScrollView( - physics: AlwaysScrollableScrollPhysics(), - child: ConstrainedBox( - constraints: BoxConstraints( - minHeight: viewportConstraints.maxHeight, - ), - child: Center( - child: Text('You have no channels currently'), - ), - ), - ); - }, - ); - } - - return ListView.custom( - physics: AlwaysScrollableScrollPhysics(), - controller: _scrollController, - childrenDelegate: SliverChildBuilderDelegate( - (context, i) { - return _itemBuilder(context, i, channels); - }, - childCount: (channels.length * 2) + 1, - findChildIndexCallback: (key) { - final ValueKey valueKey = key; - final index = channels.indexWhere( - (channel) => 'CHANNEL-${channel.id}' == valueKey.value); - return index != -1 ? (index * 2) : null; - }, - ), + return AnimatedSwitcher( + child: child, + duration: Duration(milliseconds: 500), ); }); } + Widget _buildLoadingWidget() { + return ListView( + physics: AlwaysScrollableScrollPhysics(), + children: List.generate( + 25, + (i) { + if (i % 2 != 0) { + if (widget.separatorBuilder != null) { + return widget.separatorBuilder(context, i); + } + return _separatorBuilder(context, i); + } + return _buildLoadingItem(); + }, + ), + ); + } + + Shimmer _buildLoadingItem() { + return Shimmer.fromColors( + baseColor: Color(0xffE5E5E5), + highlightColor: Color(0xffffffff), + child: ListTile( + leading: Container( + decoration: BoxDecoration( + color: Colors.white, + shape: BoxShape.circle, + ), + constraints: BoxConstraints.tightFor( + height: 40, + width: 40, + ), + ), + title: Align( + alignment: Alignment.centerLeft, + child: Container( + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(11), + ), + constraints: BoxConstraints.tightFor( + height: 16, + width: 82, + ), + ), + ), + subtitle: Row( + children: [ + Align( + alignment: Alignment.centerLeft, + child: Container( + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(11), + ), + constraints: BoxConstraints.tightFor( + height: 16, + width: 238, + ), + ), + ), + Container( + margin: const EdgeInsets.only(left: 16), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(11), + ), + constraints: BoxConstraints.tightFor( + height: 16, + width: 42, + ), + ), + ], + ), + ), + ); + } + + Widget _buildErrorWidget( + AsyncSnapshot> snapshot, + BuildContext context, + ChannelsBlocState channelsBlocState, + ) { + if (snapshot.error is Error) { + print((snapshot.error as Error).stackTrace); + } + + if (widget.errorBuilder != null) { + return widget.errorBuilder(snapshot.error); + } + + var message = snapshot.error.toString(); + if (snapshot.error is DioError) { + final dioError = snapshot.error as DioError; + if (dioError.type == DioErrorType.RESPONSE) { + message = dioError.message; + } else { + message = 'Check your connection and retry'; + } + } + return Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text.rich( + TextSpan( + children: [ + WidgetSpan( + child: Padding( + padding: const EdgeInsets.only( + right: 2.0, + ), + child: Icon(Icons.error_outline), + ), + ), + TextSpan(text: 'Error loading channels'), + ], + ), + style: Theme.of(context).textTheme.headline6, + ), + Padding( + padding: const EdgeInsets.only( + top: 16.0, + ), + child: Text(message), + ), + FlatButton( + onPressed: () { + channelsBlocState.queryChannels( + filter: widget.filter, + sortOptions: widget.sort, + paginationParams: widget.pagination, + options: widget.options, + ); + }, + child: Text('Retry'), + ), + ], + ), + ); + } + Widget _itemBuilder(context, int i, List channels) { if (i % 2 != 0) { if (widget.separatorBuilder != null) { @@ -441,7 +524,9 @@ class _ChannelListViewState extends State } Widget _buildQueryProgressIndicator( - context, ChannelsBlocState channelsProvider) { + context, + ChannelsBlocState channelsProvider, + ) { return StreamBuilder( stream: channelsProvider.queryChannelsLoading, initialData: false, @@ -457,13 +542,11 @@ class _ChannelListViewState extends State ), ); } - return Container( - height: 100, - padding: EdgeInsets.all(32), - child: Center( - child: snapshot.data ? CircularProgressIndicator() : Container(), - ), - ); + return snapshot.data + ? _buildLoadingItem() + : Container( + height: 70, + ); }); } diff --git a/pubspec.yaml b/pubspec.yaml index 9c1b0a29..804c9728 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -19,6 +19,7 @@ dependencies: flutter_svg: ^0.19.1 flutter_portal: ^0.3.0 cached_network_image: ^2.2.0+1 + shimmer: ^1.1.2 flutter_markdown: ^0.5.0 url_launcher: ^5.4.11 emojis: ^0.9.3 From e6b930fe2b429b336e98ad7a9ccc8290a8cf065e Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Tue, 17 Nov 2020 18:15:40 +0530 Subject: [PATCH 0379/1140] feat: Added ui for search functionality --- lib/src/full_screen_image.dart | 1 + lib/src/image_footer.dart | 413 ++++++++++++++++++++------------- 2 files changed, 256 insertions(+), 158 deletions(-) diff --git a/lib/src/full_screen_image.dart b/lib/src/full_screen_image.dart index c88053f9..0001585f 100644 --- a/lib/src/full_screen_image.dart +++ b/lib/src/full_screen_image.dart @@ -50,6 +50,7 @@ class _FullScreenImageState extends State @override Widget build(BuildContext context) { return Scaffold( + resizeToAvoidBottomInset: false, body: Stack( children: [ AnimatedBuilder( diff --git a/lib/src/image_footer.dart b/lib/src/image_footer.dart index 5898208c..37ddf58f 100644 --- a/lib/src/image_footer.dart +++ b/lib/src/image_footer.dart @@ -50,6 +50,8 @@ class ImageFooter extends StatefulWidget { class _ImageFooterState extends State { Future _userQuery; + bool _userSearchMode = false; + TextEditingController _searchController = TextEditingController(); @override void initState() { @@ -110,49 +112,6 @@ class _ImageFooterState extends State { ), ), ); - - return AppBar( - brightness: Theme.of(context).brightness, - elevation: 1, - leading: IconButton( - icon: Icon(StreamIcons.share), - onPressed: widget.onBackPressed, - ), - backgroundColor: - StreamChatTheme.of(context).channelTheme.channelHeaderTheme.color, - actions: [ - IconButton( - icon: Icon(StreamIcons.grid), - onPressed: () {}, - ), - ], - centerTitle: true, - title: InkWell( - onTap: widget.onTitleTap, - child: Container( - height: widget.preferredSize.height, - width: widget.preferredSize.width, - child: Column( - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisAlignment: MainAxisAlignment.center, - mainAxisSize: MainAxisSize.min, - children: [ - Text( - 'Demo name', - style: StreamChatTheme.of(context) - .channelTheme - .channelHeaderTheme - .title, - ), - Text( - '1 of 1', - style: StreamChatTheme.of(context).channelPreviewTheme.subtitle, - ), - ], - ), - ), - ), - ); } Widget _buildPhotosModal(context) { @@ -231,136 +190,274 @@ class _ImageFooterState extends State { } Widget _buildShareModal(context) { - showModalBottomSheet( + showDialog( context: context, - backgroundColor: Colors.transparent, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(16.0), - ), builder: (context) { - return Column( - mainAxisSize: MainAxisSize.min, - children: [ - Container( - margin: EdgeInsets.symmetric( - horizontal: 8.0, + return StatefulBuilder(builder: (context, modalSetState) { + return Align( + alignment: + _userSearchMode ? Alignment.topCenter : Alignment.bottomCenter, + child: Material( + color: Colors.transparent, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(16.0), ), - padding: EdgeInsets.symmetric( - vertical: 4.0, - ), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.only( - topRight: Radius.circular(16.0), - topLeft: Radius.circular(16.0), - )), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, + child: Stack( children: [ - Padding( - padding: const EdgeInsets.symmetric(horizontal: 6.0), - child: IconButton( - icon: Icon( - StreamIcons.search, - color: Colors.black, + ListView( + children: [ + if (!_userSearchMode) + GestureDetector( + child: Container( + height: MediaQuery.of(context).size.height / 2, + color: Colors.transparent, + ), + onTapUp: (val) { + Navigator.pop(context); + }, + ), + Container( + margin: EdgeInsets.symmetric( + horizontal: 8.0, + ), + padding: EdgeInsets.symmetric( + vertical: 4.0, + ), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.only( + topRight: Radius.circular(16.0), + topLeft: Radius.circular(16.0), + )), + child: _buildTextInputSection(modalSetState), ), - iconSize: 24.0, - onPressed: () {}, - ), + Container( + margin: EdgeInsets.symmetric( + horizontal: 8.0, + ), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.only( + bottomRight: + Radius.circular(_userSearchMode ? 16.0 : 0.0), + bottomLeft: + Radius.circular(_userSearchMode ? 16.0 : 0.0), + ), + ), + child: FutureBuilder( + future: _userQuery, + builder: (context, snapshot) { + if (!snapshot.hasData) { + return Center( + child: CircularProgressIndicator(), + ); + } + + var filteredData = snapshot.data.users.toList(); + + if (_userSearchMode && + _searchController.text.length > 0) { + filteredData = snapshot.data.users + .where((element) => element.name + .toLowerCase() + .contains(_searchController.text + .toLowerCase())) + .toList(); + } + + return GridView.builder( + shrinkWrap: true, + physics: NeverScrollableScrollPhysics(), + itemBuilder: (context, position) { + var user = filteredData[position]; + + return Padding( + padding: const EdgeInsets.all(8.0), + child: Column( + mainAxisSize: MainAxisSize.min, + mainAxisAlignment: + MainAxisAlignment.start, + crossAxisAlignment: + CrossAxisAlignment.center, + children: [ + Stack( + children: [ + UserAvatar( + onTap: (user) {}, + user: user, + constraints: + BoxConstraints.tightFor( + height: 64, + width: 64, + ), + borderRadius: + BorderRadius.circular(32), + ), + ], + ), + Padding( + padding: const EdgeInsets.all(8.0), + child: Text( + user.name, + style: Theme.of(context) + .textTheme + .subtitle2, + textAlign: TextAlign.center, + maxLines: 2, + ), + ), + ], + ), + ); + }, + itemCount: filteredData.length, + gridDelegate: + SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: 4, + childAspectRatio: 0.75, + ), + ); + }), + ), + ], ), - Padding( - padding: const EdgeInsets.all(16.0), - child: Text( - 'Select a Chat to Share', - style: TextStyle( - fontSize: 16.0, - fontWeight: FontWeight.w700, - color: Colors.black, + if (!_userSearchMode) + Align( + alignment: Alignment.bottomCenter, + child: Container( + color: Colors.white, + height: 48.0, + margin: EdgeInsets.symmetric( + horizontal: 8.0, + ), + child: SizedBox.expand( + child: Center( + child: Text( + 'Save to Photos', + style: TextStyle( + color: StreamChatTheme.of(context).accentColor, + fontWeight: FontWeight.bold, + ), + ), + ), + ), ), ), - ), - Padding( - padding: const EdgeInsets.symmetric(horizontal: 6.0), - child: IconButton( - icon: Icon( - StreamIcons.share, - color: Colors.black, - ), - iconSize: 24.0, - onPressed: () {}, - ), - ), ], ), ), - Expanded( - child: Container( - color: Colors.white, - margin: EdgeInsets.symmetric( - horizontal: 8.0, - ), - child: FutureBuilder( - future: _userQuery, - builder: (context, snapshot) { - if (!snapshot.hasData) { - return Center( - child: CircularProgressIndicator(), - ); - } - - return GridView.builder( - shrinkWrap: true, - itemBuilder: (context, position) { - var user = snapshot.data.users[position]; - - return Padding( - padding: const EdgeInsets.all(8.0), - child: Column( - mainAxisSize: MainAxisSize.min, - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Stack( - children: [ - UserAvatar( - onTap: (user) {}, - user: user, - constraints: BoxConstraints.tightFor( - height: 64, - width: 64, - ), - borderRadius: BorderRadius.circular(32), - ), - ], - ), - Padding( - padding: const EdgeInsets.all(8.0), - child: Text( - user.name, - style: Theme.of(context).textTheme.subtitle2, - textAlign: TextAlign.center, - maxLines: 2, - ), - ), - ], - ), - ); - }, - itemCount: snapshot.data.users.length, - gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( - crossAxisCount: 4, - childAspectRatio: 0.75, - ), - ); - }), - ), - ), - ], - ); + ); + }); }, ); } + Widget _buildTextInputSection(modalSetState) { + if (_userSearchMode) { + return Column( + children: [ + SizedBox( + height: 16.0, + ), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + SizedBox( + width: 16.0, + ), + Expanded( + child: TextField( + controller: _searchController, + onChanged: (val) { + modalSetState(() {}); + }, + cursorColor: Colors.black, + autofocus: true, + decoration: InputDecoration( + isDense: true, + prefixIcon: Icon( + StreamIcons.search, + color: Colors.black, + ), + hintText: 'Search', + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(32.0), + borderSide: + BorderSide(color: Colors.black.withOpacity(0.08)), + gapPadding: 0.0, + ), + focusedBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(32.0), + borderSide: + BorderSide(color: Colors.black.withOpacity(0.08)), + gapPadding: 0.0, + ), + contentPadding: EdgeInsets.zero, + ), + ), + ), + SizedBox( + width: 8.0, + ), + IconButton( + icon: Icon(StreamIcons.close_circle), + onPressed: () { + modalSetState(() { + _userSearchMode = false; + }); + setState(() {}); + }, + ) + ], + ), + ], + ); + } else { + return Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Padding( + padding: const EdgeInsets.symmetric(horizontal: 6.0), + child: IconButton( + icon: Icon( + StreamIcons.search, + color: Colors.black, + ), + iconSize: 24.0, + onPressed: () { + modalSetState(() { + _userSearchMode = true; + }); + }, + ), + ), + Padding( + padding: const EdgeInsets.all(16.0), + child: Text( + 'Select a Chat to Share', + style: TextStyle( + fontSize: 16.0, + fontWeight: FontWeight.w700, + color: Colors.black, + ), + ), + ), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 6.0), + child: IconButton( + icon: Icon( + StreamIcons.share, + color: Colors.black, + ), + iconSize: 24.0, + onPressed: () {}, + ), + ), + ], + ); + } + } + Future _queryUsers(context) { return StreamChat.of(context).client.queryUsers( pagination: PaginationParams( From a8a5e5dfdf67d2ad3c3d422ed138f72ece0047b9 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Tue, 17 Nov 2020 18:19:33 +0530 Subject: [PATCH 0380/1140] [Channels Bloc] Fix typo Signed-off-by: Sahil Kumar --- lib/src/channels_bloc.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/channels_bloc.dart b/lib/src/channels_bloc.dart index 3af2300d..474d9599 100644 --- a/lib/src/channels_bloc.dart +++ b/lib/src/channels_bloc.dart @@ -31,7 +31,7 @@ class ChannelsBloc extends StatefulWidget { streamChatState = context.findAncestorStateOfType(); if (streamChatState == null) { - throw Exception('You must have a ChannelsBloc widget as anchestor'); + throw Exception('You must have a ChannelsBloc widget as ancestor'); } return streamChatState; From cd8ca90052836203a8a47bbc4049793d93fe5b38 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Tue, 17 Nov 2020 21:30:05 +0530 Subject: [PATCH 0381/1140] feat: user list Signed-off-by: Sahil Kumar --- lib/src/user_list_view.dart | 468 +++++++++++++++++++++++++++++++++++ lib/src/users_bloc.dart | 114 +++++++++ lib/stream_chat_flutter.dart | 1 + 3 files changed, 583 insertions(+) create mode 100644 lib/src/user_list_view.dart create mode 100644 lib/src/users_bloc.dart diff --git a/lib/src/user_list_view.dart b/lib/src/user_list_view.dart new file mode 100644 index 00000000..5b661ee8 --- /dev/null +++ b/lib/src/user_list_view.dart @@ -0,0 +1,468 @@ +import 'package:flutter/material.dart'; +import 'package:stream_chat/stream_chat.dart'; +import 'package:stream_chat_flutter/src/users_bloc.dart'; + +import 'stream_chat.dart'; + +typedef UserTapCallback = void Function(User, Widget); + +/// +/// It shows the list of current users. +/// +/// ```dart +/// class UsersListPage extends StatelessWidget { +/// @override +/// Widget build(BuildContext context) { +/// return Scaffold( +/// body: UsersListView( +/// filter: { +/// 'members': { +/// '\$in': [StreamChat.of(context).user.id], +/// } +/// }, +/// sort: [SortOption('last_message_at')], +/// pagination: PaginationParams( +/// limit: 20, +/// ), +/// channelWidget: ChannelPage(), +/// ), +/// ); +/// } +/// } +/// ``` +/// +/// +/// Make sure to have a [StreamChat] ancestor in order to provide the information about the channels. +/// The widget uses a [ListView.custom] to render the list of channels. +/// +/// The widget components render the ui based on the first ancestor of type [StreamChatTheme]. +/// Modify it to change the widget appearance. +class UserListView extends StatefulWidget { + /// Instantiate a new UserListView + const UserListView({ + Key key, + this.errorBuilder, + this.emptyBuilder, + this.filter, + this.options, + this.sort, + this.pagination, + this.onUserTap, + this.onUserLongPress, + this.userWidget, + this.separatorBuilder, + this.onImageTap, + this.swipeToAction = false, + this.pullToRefresh = true, + }) : super(key: key); + + /// The builder that will be used in case of error + final Widget Function(Error error) errorBuilder; + + /// If true a default swipe to action behaviour will be added to this widget + final bool swipeToAction; + + /// The builder used when the channel list is empty. + final WidgetBuilder emptyBuilder; + + /// The query filters to use. + /// You can query on any of the custom fields you've defined on the [Channel]. + /// You can also filter other built-in channel fields. + final Map filter; + + /// Query channels options. + /// + /// state: if true returns the Channel state + /// watch: if true listen to changes to this Channel in real time. + final Map options; + + /// The sorting used for the channels matching the filters. + /// Sorting is based on field and direction, multiple sorting options can be provided. + /// You can sort based on last_updated, last_message_at, updated_at, created_at or member_count. + /// Direction can be ascending or descending. + final List sort; + + /// Pagination parameters + /// limit: the number of users to return (max is 30) + /// offset: the offset (max is 1000) + /// message_limit: how many messages should be included to each channel + final PaginationParams pagination; + + /// Function called when tapping on a channel + /// By default it calls [Navigator.push] building a [MaterialPageRoute] + /// with the widget [userWidget] as child. + final UserTapCallback onUserTap; + + /// Function called when long pressing on a channel + final Function(User) onUserLongPress; + + /// Widget used when opening a channel + final Widget userWidget; + + // /// Builder used to create a custom channel preview + // final ChannelPreviewBuilder channelPreviewBuilder; + + /// Builder used to create a custom item separator + final Function(BuildContext, int) separatorBuilder; + + /// The function called when the image is tapped + final Function(User) onImageTap; + + /// Set it to false to disable the pull-to-refresh widget + final bool pullToRefresh; + + @override + _UserListViewState createState() => _UserListViewState(); +} + +class _UserListViewState extends State + with WidgetsBindingObserver { + final ScrollController _scrollController = ScrollController(); + + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + final usersBloc = UsersBloc.of(context); + + if (!widget.pullToRefresh) { + return _buildListView(usersBloc); + } + + return RefreshIndicator( + onRefresh: () async { + return usersBloc.queryUsers( + filter: widget.filter, + sort: widget.sort, + options: widget.options, + pagination: widget.pagination, + ); + }, + child: _buildListView(usersBloc), + ); + } + + StreamBuilder> _buildListView( + UsersBlocState usersBlocState, + ) { + return StreamBuilder( + stream: usersBlocState.usersStream, + builder: (context, snapshot) { + if (snapshot.hasError) { + if (snapshot.error is Error) { + print((snapshot.error as Error).stackTrace); + } + + if (widget.errorBuilder != null) { + return widget.errorBuilder(snapshot.error); + } + + var message = snapshot.error.toString(); + if (snapshot.error is DioError) { + final dioError = snapshot.error as DioError; + if (dioError.type == DioErrorType.RESPONSE) { + message = dioError.message; + } else { + message = 'Check your connection and retry'; + } + } + return Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text.rich( + TextSpan( + children: [ + WidgetSpan( + child: Padding( + padding: const EdgeInsets.only( + right: 2.0, + ), + child: Icon(Icons.error_outline), + ), + ), + TextSpan(text: 'Error loading channels'), + ], + ), + style: Theme.of(context).textTheme.headline6, + ), + Padding( + padding: const EdgeInsets.only( + top: 16.0, + ), + child: Text(message), + ), + FlatButton( + onPressed: () { + usersBlocState.queryUsers( + filter: widget.filter, + sort: widget.sort, + pagination: widget.pagination, + options: widget.options, + ); + }, + child: Text('Retry'), + ), + ], + ), + ); + } + + if (!snapshot.hasData) { + return LayoutBuilder( + builder: (context, viewportConstraints) { + return SingleChildScrollView( + physics: AlwaysScrollableScrollPhysics(), + child: ConstrainedBox( + constraints: BoxConstraints( + minHeight: viewportConstraints.maxHeight, + ), + child: Center( + child: CircularProgressIndicator(), + ), + ), + ); + }, + ); + } + + final users = snapshot.data; + + if (users.isEmpty && widget.emptyBuilder != null) { + return widget.emptyBuilder(context); + } + + if (users.isEmpty && widget.emptyBuilder == null) { + return LayoutBuilder( + builder: (context, viewportConstraints) { + return SingleChildScrollView( + physics: AlwaysScrollableScrollPhysics(), + child: ConstrainedBox( + constraints: BoxConstraints( + minHeight: viewportConstraints.maxHeight, + ), + child: Center( + child: Text('There are no users currently'), + ), + ), + ); + }, + ); + } + + return ListView.custom( + physics: AlwaysScrollableScrollPhysics(), + controller: _scrollController, + childrenDelegate: SliverChildBuilderDelegate( + (context, i) { + return _itemBuilder(context, i, users); + }, + childCount: (users.length * 2) + 1, + findChildIndexCallback: (key) { + final ValueKey valueKey = key; + final index = users.indexWhere( + (channel) => 'CHANNEL-${channel.id}' == valueKey.value); + return index != -1 ? (index * 2) : null; + }, + ), + ); + }, + ); + } + + Widget _itemBuilder(context, int i, List users) { + if (i % 2 != 0) { + if (widget.separatorBuilder != null) { + return widget.separatorBuilder(context, i); + } + return _separatorBuilder(context, i); + } + + i = i ~/ 2; + + final usersProvider = UsersBloc.of(context); + if (i < users.length) { + final user = users[i]; + + UserTapCallback onTap; + if (widget.onUserTap != null) { + onTap = widget.onUserTap; + } else { + onTap = (client, _) { + // Navigator.push( + // context, + // MaterialPageRoute( + // builder: (context) { + // return StreamChannel( + // child: widget.userWidget, + // channel: client, + // ); + // }, + // ), + // ); + }; + } + + return Container( + key: ValueKey('USER-${user.id}'), + child: Builder( + builder: (context) { + Widget child; + child = ListTile( + title: Text(user.name), + ); + // if (widget.channelPreviewBuilder != null) { + // child = Stack( + // children: [ + // widget.channelPreviewBuilder( + // context, + // channel, + // ), + // Positioned.fill( + // child: Material( + // color: Colors.transparent, + // child: InkWell( + // onTap: () { + // onTap(channel, widget.channelWidget); + // }, + // ), + // ), + // ), + // ], + // ); + // } else { + // final backgroundColor = + // Theme.of(context).brightness == Brightness.light + // ? Color(0xffEBEBEB) + // : Color(0xff141414); + // child = Slidable( + // enabled: widget.swipeToAction, + // actionPane: SlidableBehindActionPane(), + // actionExtentRatio: 0.12, + // closeOnScroll: true, + // secondaryActions: [ + // IconSlideAction( + // color: backgroundColor, + // icon: Icons.more_horiz, + // onTap: () { + // showModalBottomSheet( + // clipBehavior: Clip.hardEdge, + // shape: RoundedRectangleBorder( + // borderRadius: BorderRadius.only( + // topLeft: Radius.circular(32), + // topRight: Radius.circular(32), + // ), + // ), + // context: context, + // builder: (context) { + // return ChannelBottomSheet(channel: channel); + // }, + // ); + // }, + // ), + // IconSlideAction( + // color: backgroundColor, + // icon: StreamIcons.mute, + // onTap: () async { + // if (!channel.isMuted) { + // await channel.mute(); + // } else { + // await channel.unmute(); + // } + // }, + // ), + // if (channel.isGroup && !channel.isDistinct) + // IconSlideAction( + // color: backgroundColor, + // icon: StreamIcons.user_minus, + // onTap: () async { + // final confirm = await showConfirmationDialog( + // context, + // 'Do you want to leave the group?', + // ); + // if (confirm == true) { + // await channel + // .removeMembers([StreamChat.of(context).user.id]); + // } + // }, + // ), + // if (!channel.isGroup && !channel.isDistinct) + // IconSlideAction( + // color: backgroundColor, + // icon: Icons.delete_outline, + // onTap: () async { + // final confirm = await showConfirmationDialog( + // context, + // 'Do you want to delete the chat?', + // ); + // if (confirm == true) { + // await channel + // .removeMembers([StreamChat.of(context).user.id]); + // } + // }, + // ), + // ], + // child: Container( + // color: StreamChatTheme.of(context).backgroundColor, + // child: ChannelPreview( + // onLongPress: widget.onChannelLongPress, + // channel: channel, + // onImageTap: widget.onImageTap != null + // ? () { + // widget.onImageTap(channel); + // } + // : null, + // onTap: (channel) { + // onTap(channel, widget.userWidget); + // }, + // ), + // ), + // ); + // } + return child; + }, + ), + ); + } else { + return _buildQueryProgressIndicator(context, usersProvider); + } + } + + Widget _buildQueryProgressIndicator(context, UsersBlocState usersProvider) { + return StreamBuilder( + stream: usersProvider.queryUsersLoading, + initialData: false, + builder: (context, snapshot) { + if (snapshot.hasError) { + return Container( + color: Color(0xffd0021B).withAlpha(26), + child: Padding( + padding: const EdgeInsets.symmetric(vertical: 16.0), + child: Center( + child: Text('Error loading users'), + ), + ), + ); + } + return Container( + height: 100, + padding: EdgeInsets.all(32), + child: Center( + child: snapshot.data ? CircularProgressIndicator() : Container(), + ), + ); + }); + } + + Widget _separatorBuilder(context, i) { + return Container( + height: 1, + color: Theme.of(context).brightness == Brightness.dark + ? Colors.white.withOpacity(0.1) + : Colors.black.withOpacity(0.1), + ); + } +} diff --git a/lib/src/users_bloc.dart b/lib/src/users_bloc.dart new file mode 100644 index 00000000..da2221e0 --- /dev/null +++ b/lib/src/users_bloc.dart @@ -0,0 +1,114 @@ +import 'package:flutter/material.dart'; +import 'package:rxdart/rxdart.dart'; +import 'package:stream_chat/stream_chat.dart'; + +import 'stream_chat.dart'; + +/// Widget dedicated to the management of a users list with pagination +class UsersBloc extends StatefulWidget { + /// The widget child + final Widget child; + + /// Instantiate a new UsersBloc + const UsersBloc({ + Key key, + @required this.child, + }) : super(key: key); + + @override + UsersBlocState createState() => UsersBlocState(); + + /// Use this method to get the current [UsersBlocState] instance + static UsersBlocState of(BuildContext context) { + UsersBlocState state; + + state = context.findAncestorStateOfType(); + + if (state == null) { + throw Exception('You must have a UsersBloc widget as ancestor'); + } + + return state; + } +} + +/// The current state of the [UsersBloc] +class UsersBlocState extends State + with AutomaticKeepAliveClientMixin { + /// The current users list + List get users => _usersController.value; + + /// The current users list as a stream + Stream> get usersStream => _usersController.stream; + + final BehaviorSubject> _usersController = BehaviorSubject(); + + final BehaviorSubject _queryUsersLoadingController = + BehaviorSubject.seeded(false); + + /// The stream notifying the state of queryUsers call + Stream get queryUsersLoading => _queryUsersLoadingController.stream; + + /// Calls [Client.queryUsers] updating [queryUsersLoading] stream + Future queryUsers({ + Map filter, + List sort, + Map options, + PaginationParams pagination, + }) async { + final client = StreamChat.of(context).client; + + if (client.state?.user == null || + _queryUsersLoadingController.value == true) { + return; + } + _queryUsersLoadingController.add(true); + try { + final clear = pagination == null || + pagination.offset == null || + pagination.offset == 0; + + final oldUsers = List.from(users ?? []); + + final usersResponse = await client.queryUsers( + filter: filter, + sort: sort, + options: options, + pagination: pagination, + ); + + if (clear) { + _usersController.add(usersResponse.users); + } else { + final temp = oldUsers + usersResponse.users; + _usersController.add(temp); + } + + _queryUsersLoadingController.add(false); + } catch (err, stackTrace) { + _queryUsersLoadingController.addError(err, stackTrace); + } + } + + @override + void initState() { + super.initState(); + final client = StreamChat.of(context).client; + } + + @override + Widget build(BuildContext context) { + super.build(context); + return widget.child; + } + + @override + void dispose() { + _usersController.close(); + _queryUsersLoadingController.close(); + super.dispose(); + } + + @override + bool get wantKeepAlive => true; +} diff --git a/lib/stream_chat_flutter.dart b/lib/stream_chat_flutter.dart index e433e58e..3c9554fc 100644 --- a/lib/stream_chat_flutter.dart +++ b/lib/stream_chat_flutter.dart @@ -30,3 +30,4 @@ export 'src/typing_indicator.dart'; export 'src/user_avatar.dart'; export 'src/utils.dart'; export 'src/video_attachment.dart'; +export 'src/user_list_view.dart'; From e5b25d8d06d57896dfbbe9fc08ceb470b727f78e Mon Sep 17 00:00:00 2001 From: xsahil03x Date: Tue, 17 Nov 2020 23:32:16 +0530 Subject: [PATCH 0382/1140] feat: user list --- example/lib/main.dart | 14 ++- lib/src/user_item.dart | 69 +++++++++++++ lib/src/user_list_view.dart | 187 ++++++++++++----------------------- lib/src/users_bloc.dart | 6 -- lib/stream_chat_flutter.dart | 1 + 5 files changed, 148 insertions(+), 129 deletions(-) create mode 100644 lib/src/user_item.dart diff --git a/example/lib/main.dart b/example/lib/main.dart index 7c288eae..5fba1c06 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -464,7 +464,19 @@ class _NewChatScreenState extends State { style: TextStyle(color: Colors.black), ), ), - body: Container(), + body: UsersBloc( + child: UserListView( + pagination: PaginationParams( + limit: 25, + ), + sort: [ + SortOption( + 'name', + direction: SortOption.ASC, + ), + ], + ), + ), ); } } diff --git a/lib/src/user_item.dart b/lib/src/user_item.dart new file mode 100644 index 00000000..14b488c7 --- /dev/null +++ b/lib/src/user_item.dart @@ -0,0 +1,69 @@ +import 'package:flutter/material.dart'; +import 'package:jiffy/jiffy.dart'; +import 'package:stream_chat/stream_chat.dart'; +import 'package:stream_chat_flutter/src/user_list_view.dart'; +import 'package:stream_chat_flutter/stream_chat_flutter.dart'; + +import 'stream_chat_theme.dart'; + +/// +/// It shows the current [User] preview. +/// +/// The widget uses a [StreamBuilder] to render the user information image as soon as it updates. +/// +/// Usually you don't use this widget as it's the default user preview used by [UserListView]. +/// +/// The widget renders the ui based on the first ancestor of type [StreamChatTheme]. +/// Modify it to change the widget appearance. +class UserItem extends StatelessWidget { + /// Instantiate a new UserItem + const UserItem( + {Key key, + @required this.user, + this.onTap, + this.onLongPress, + this.onImageTap}) + : super(key: key); + + /// Function called when tapping this widget + final void Function(User) onTap; + + /// Function called when long pressing this widget + final void Function(User) onLongPress; + + /// User displayed + final User user; + + /// The function called when the image is tapped + final void Function(User) onImageTap; + + @override + Widget build(BuildContext context) { + return ListTile( + onTap: () { + if (onTap != null) { + onTap(user); + } + }, + onLongPress: () { + if (onLongPress != null) { + onLongPress(user); + } + }, + leading: UserAvatar( + user: user, + showOnlineStatus: true, + onTap: (user) { + if (onImageTap != null) { + onImageTap(user); + } + }), + title: Text(user.name), + subtitle: _buildLastActive(context), + ); + } + + Widget _buildLastActive(context) { + return Text('Last seen ${Jiffy(user.lastActive).fromNow()}'); + } +} diff --git a/lib/src/user_list_view.dart b/lib/src/user_list_view.dart index 5b661ee8..93c21849 100644 --- a/lib/src/user_list_view.dart +++ b/lib/src/user_list_view.dart @@ -1,11 +1,18 @@ +import 'dart:convert'; + import 'package:flutter/material.dart'; import 'package:stream_chat/stream_chat.dart'; import 'package:stream_chat_flutter/src/users_bloc.dart'; import 'stream_chat.dart'; +import 'user_item.dart'; +/// Callback called when tapping on a user typedef UserTapCallback = void Function(User, Widget); +/// Builder used to create a custom [UserItem] from a [User] +typedef UserItemBuilder = Widget Function(BuildContext, User); + /// /// It shows the list of current users. /// @@ -50,6 +57,7 @@ class UserListView extends StatefulWidget { this.onUserTap, this.onUserLongPress, this.userWidget, + this.userItemBuilder, this.separatorBuilder, this.onImageTap, this.swipeToAction = false, @@ -99,8 +107,8 @@ class UserListView extends StatefulWidget { /// Widget used when opening a channel final Widget userWidget; - // /// Builder used to create a custom channel preview - // final ChannelPreviewBuilder channelPreviewBuilder; + /// Builder used to create a custom user preview + final UserItemBuilder userItemBuilder; /// Builder used to create a custom item separator final Function(BuildContext, int) separatorBuilder; @@ -122,6 +130,21 @@ class _UserListViewState extends State @override void initState() { super.initState(); + final channelsBloc = UsersBloc.of(context); + channelsBloc.queryUsers( + filter: widget.filter, + sort: widget.sort, + pagination: widget.pagination, + options: widget.options, + ); + + _scrollController.addListener(() { + channelsBloc.queryUsersLoading.first.then((loading) { + if (!loading) { + _listenUserPagination(channelsBloc); + } + }); + }); } @override @@ -263,8 +286,8 @@ class _UserListViewState extends State childCount: (users.length * 2) + 1, findChildIndexCallback: (key) { final ValueKey valueKey = key; - final index = users.indexWhere( - (channel) => 'CHANNEL-${channel.id}' == valueKey.value); + final index = users + .indexWhere((user) => 'USER-${user.id}' == valueKey.value); return index != -1 ? (index * 2) : null; }, ), @@ -306,125 +329,12 @@ class _UserListViewState extends State }; } - return Container( + return UserItem( key: ValueKey('USER-${user.id}'), - child: Builder( - builder: (context) { - Widget child; - child = ListTile( - title: Text(user.name), - ); - // if (widget.channelPreviewBuilder != null) { - // child = Stack( - // children: [ - // widget.channelPreviewBuilder( - // context, - // channel, - // ), - // Positioned.fill( - // child: Material( - // color: Colors.transparent, - // child: InkWell( - // onTap: () { - // onTap(channel, widget.channelWidget); - // }, - // ), - // ), - // ), - // ], - // ); - // } else { - // final backgroundColor = - // Theme.of(context).brightness == Brightness.light - // ? Color(0xffEBEBEB) - // : Color(0xff141414); - // child = Slidable( - // enabled: widget.swipeToAction, - // actionPane: SlidableBehindActionPane(), - // actionExtentRatio: 0.12, - // closeOnScroll: true, - // secondaryActions: [ - // IconSlideAction( - // color: backgroundColor, - // icon: Icons.more_horiz, - // onTap: () { - // showModalBottomSheet( - // clipBehavior: Clip.hardEdge, - // shape: RoundedRectangleBorder( - // borderRadius: BorderRadius.only( - // topLeft: Radius.circular(32), - // topRight: Radius.circular(32), - // ), - // ), - // context: context, - // builder: (context) { - // return ChannelBottomSheet(channel: channel); - // }, - // ); - // }, - // ), - // IconSlideAction( - // color: backgroundColor, - // icon: StreamIcons.mute, - // onTap: () async { - // if (!channel.isMuted) { - // await channel.mute(); - // } else { - // await channel.unmute(); - // } - // }, - // ), - // if (channel.isGroup && !channel.isDistinct) - // IconSlideAction( - // color: backgroundColor, - // icon: StreamIcons.user_minus, - // onTap: () async { - // final confirm = await showConfirmationDialog( - // context, - // 'Do you want to leave the group?', - // ); - // if (confirm == true) { - // await channel - // .removeMembers([StreamChat.of(context).user.id]); - // } - // }, - // ), - // if (!channel.isGroup && !channel.isDistinct) - // IconSlideAction( - // color: backgroundColor, - // icon: Icons.delete_outline, - // onTap: () async { - // final confirm = await showConfirmationDialog( - // context, - // 'Do you want to delete the chat?', - // ); - // if (confirm == true) { - // await channel - // .removeMembers([StreamChat.of(context).user.id]); - // } - // }, - // ), - // ], - // child: Container( - // color: StreamChatTheme.of(context).backgroundColor, - // child: ChannelPreview( - // onLongPress: widget.onChannelLongPress, - // channel: channel, - // onImageTap: widget.onImageTap != null - // ? () { - // widget.onImageTap(channel); - // } - // : null, - // onTap: (channel) { - // onTap(channel, widget.userWidget); - // }, - // ), - // ), - // ); - // } - return child; - }, - ), + user: user, + onTap: (user) => onTap(user, widget.userWidget), + onLongPress: widget.onUserLongPress, + onImageTap: widget.onImageTap, ); } else { return _buildQueryProgressIndicator(context, usersProvider); @@ -465,4 +375,37 @@ class _UserListViewState extends State : Colors.black.withOpacity(0.1), ); } + + void _listenUserPagination(UsersBlocState usersProvider) { + if (_scrollController.position.maxScrollExtent == + _scrollController.offset && + _scrollController.offset != 0) { + usersProvider.queryUsers( + filter: widget.filter, + sort: widget.sort, + pagination: widget.pagination.copyWith( + offset: usersProvider.users?.length ?? 0, + ), + options: widget.options, + ); + } + } + + @override + void didUpdateWidget(UserListView oldWidget) { + super.didUpdateWidget(oldWidget); + if (widget.filter?.toString() != oldWidget.filter?.toString() || + jsonEncode(widget.sort) != jsonEncode(oldWidget.sort) || + widget.pagination?.toJson()?.toString() != + oldWidget.pagination?.toJson()?.toString() || + widget.options?.toString() != oldWidget.options?.toString()) { + final channelsBloc = UsersBloc.of(context); + channelsBloc.queryUsers( + filter: widget.filter, + sort: widget.sort, + pagination: widget.pagination, + options: widget.options, + ); + } + } } diff --git a/lib/src/users_bloc.dart b/lib/src/users_bloc.dart index da2221e0..91cbaf80 100644 --- a/lib/src/users_bloc.dart +++ b/lib/src/users_bloc.dart @@ -90,12 +90,6 @@ class UsersBlocState extends State } } - @override - void initState() { - super.initState(); - final client = StreamChat.of(context).client; - } - @override Widget build(BuildContext context) { super.build(context); diff --git a/lib/stream_chat_flutter.dart b/lib/stream_chat_flutter.dart index 3c9554fc..663e72a9 100644 --- a/lib/stream_chat_flutter.dart +++ b/lib/stream_chat_flutter.dart @@ -30,4 +30,5 @@ export 'src/typing_indicator.dart'; export 'src/user_avatar.dart'; export 'src/utils.dart'; export 'src/video_attachment.dart'; +export 'src/users_bloc.dart'; export 'src/user_list_view.dart'; From 9b36c2348ebbd65374c4a49d561609a7045ef70b Mon Sep 17 00:00:00 2001 From: xsahil03x Date: Wed, 18 Nov 2020 00:09:07 +0530 Subject: [PATCH 0383/1140] feat: add selection property to user list item --- lib/src/user_item.dart | 27 ++++++++++++++++++++------- lib/src/user_list_view.dart | 6 ++++++ 2 files changed, 26 insertions(+), 7 deletions(-) diff --git a/lib/src/user_item.dart b/lib/src/user_item.dart index 14b488c7..ef442440 100644 --- a/lib/src/user_item.dart +++ b/lib/src/user_item.dart @@ -17,13 +17,14 @@ import 'stream_chat_theme.dart'; /// Modify it to change the widget appearance. class UserItem extends StatelessWidget { /// Instantiate a new UserItem - const UserItem( - {Key key, - @required this.user, - this.onTap, - this.onLongPress, - this.onImageTap}) - : super(key: key); + const UserItem({ + Key key, + @required this.user, + this.onTap, + this.onLongPress, + this.onImageTap, + this.selected = false, + }) : super(key: key); /// Function called when tapping this widget final void Function(User) onTap; @@ -37,6 +38,9 @@ class UserItem extends StatelessWidget { /// The function called when the image is tapped final void Function(User) onImageTap; + /// If true the [UserItem] will show a trailing checkmark + final bool selected; + @override Widget build(BuildContext context) { return ListTile( @@ -58,6 +62,15 @@ class UserItem extends StatelessWidget { onImageTap(user); } }), + trailing: selected + ? CircleAvatar( + child: Icon( + StreamIcons.check, + size: 20, + ), + radius: 10, + ) + : null, title: Text(user.name), subtitle: _buildLastActive(context), ); diff --git a/lib/src/user_list_view.dart b/lib/src/user_list_view.dart index 93c21849..f4487dc0 100644 --- a/lib/src/user_list_view.dart +++ b/lib/src/user_list_view.dart @@ -60,6 +60,7 @@ class UserListView extends StatefulWidget { this.userItemBuilder, this.separatorBuilder, this.onImageTap, + this.selectedUsers, this.swipeToAction = false, this.pullToRefresh = true, }) : super(key: key); @@ -119,6 +120,9 @@ class UserListView extends StatefulWidget { /// Set it to false to disable the pull-to-refresh widget final bool pullToRefresh; + /// Sets a blue trailing checkMark in [UserItem] for all the [selectedUsers] + final List selectedUsers; + @override _UserListViewState createState() => _UserListViewState(); } @@ -309,6 +313,7 @@ class _UserListViewState extends State final usersProvider = UsersBloc.of(context); if (i < users.length) { final user = users[i]; + final selected = widget.selectedUsers?.contains(user) ?? false; UserTapCallback onTap; if (widget.onUserTap != null) { @@ -335,6 +340,7 @@ class _UserListViewState extends State onTap: (user) => onTap(user, widget.userWidget), onLongPress: widget.onUserLongPress, onImageTap: widget.onImageTap, + selected: selected, ); } else { return _buildQueryProgressIndicator(context, usersProvider); From c8001de7ad0c13ac6883ac34628a115fb63e457d Mon Sep 17 00:00:00 2001 From: xsahil03x Date: Wed, 18 Nov 2020 00:09:57 +0530 Subject: [PATCH 0384/1140] [CreateChannelPage] Refactor to use newly build UserListView --- example/lib/main.dart | 93 +++++++++++-------------------------------- 1 file changed, 23 insertions(+), 70 deletions(-) diff --git a/example/lib/main.dart b/example/lib/main.dart index 5fba1c06..0f84c3a8 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -268,12 +268,7 @@ class CreateChannelPage extends StatefulWidget { } class _CreateChannelPageState extends State { - final ScrollController _scrollController = ScrollController(); - Client client; - List users = []; List selectedUsers = []; - int offset = 0; - bool loading = false; @override Widget build(BuildContext context) { @@ -292,31 +287,29 @@ class _CreateChannelPageState extends State { ); } - ListView _buildListView() { - return ListView.builder( - controller: _scrollController, - itemBuilder: _itemBuilder, - itemCount: users.length, - ); - } - - Widget _itemBuilder(context, i) { - final user = users[i]; - return ListTile( - onLongPress: () { - _selectUser(user); - }, - selected: selectedUsers.contains(user), - onTap: () { - if (selectedUsers.isNotEmpty) { - return _selectUser(user); - } - _createChannel(context, [user]); - }, - leading: UserAvatar( - user: user, + Widget _buildListView() { + return UsersBloc( + child: UserListView( + pagination: PaginationParams( + limit: 25, + ), + sort: [ + SortOption( + 'name', + direction: SortOption.ASC, + ), + ], + onUserLongPress: (user) { + _selectUser(user); + }, + selectedUsers: selectedUsers, + onUserTap: (user, _) { + if (selectedUsers.isNotEmpty) { + return _selectUser(user); + } + _createChannel(context, [user]); + }, ), - title: Text(user.name), ); } @@ -373,6 +366,7 @@ class _CreateChannelPageState extends State { List users, [ String name, ]) async { + final client = StreamChat.of(context).client; final channel = client.channel('messaging', extraData: { 'members': [ client.state.user.id, @@ -405,47 +399,6 @@ class _CreateChannelPageState extends State { }); } } - - @override - void initState() { - super.initState(); - - client = StreamChat.of(context).client; - - _scrollController.addListener(() async { - if (!loading && - _scrollController.offset >= - _scrollController.position.maxScrollExtent - 100) { - offset += 25; - await _queryUsers(); - } - }); - - _queryUsers(); - } - - Future _queryUsers() { - loading = true; - return client.queryUsers( - pagination: PaginationParams( - limit: 25, - offset: offset, - ), - sort: [ - SortOption( - 'name', - direction: SortOption.ASC, - ), - ], - ).then((value) { - setState(() { - users = [ - ...users, - ...value.users, - ]; - }); - }).whenComplete(() => loading = false); - } } class NewChatScreen extends StatefulWidget { From b115cd254c377981aff56737374b5b8991838493 Mon Sep 17 00:00:00 2001 From: xsahil03x Date: Wed, 18 Nov 2020 12:56:46 +0530 Subject: [PATCH 0385/1140] feat : Add alphabetically grouping flag to User list --- lib/src/user_list_view.dart | 166 +++++++++++++++++++++++++++--------- 1 file changed, 125 insertions(+), 41 deletions(-) diff --git a/lib/src/user_list_view.dart b/lib/src/user_list_view.dart index f4487dc0..56cb762d 100644 --- a/lib/src/user_list_view.dart +++ b/lib/src/user_list_view.dart @@ -3,6 +3,7 @@ import 'dart:convert'; import 'package:flutter/material.dart'; import 'package:stream_chat/stream_chat.dart'; import 'package:stream_chat_flutter/src/users_bloc.dart'; +import 'package:stream_chat_flutter/stream_chat_flutter.dart'; import 'stream_chat.dart'; import 'user_item.dart'; @@ -10,8 +11,8 @@ import 'user_item.dart'; /// Callback called when tapping on a user typedef UserTapCallback = void Function(User, Widget); -/// Builder used to create a custom [UserItem] from a [User] -typedef UserItemBuilder = Widget Function(BuildContext, User); +/// Builder used to create a custom [ListUserItem] from a [User] +typedef UserItemBuilder = Widget Function(BuildContext, User, bool); /// /// It shows the list of current users. @@ -63,6 +64,7 @@ class UserListView extends StatefulWidget { this.selectedUsers, this.swipeToAction = false, this.pullToRefresh = true, + this.groupAlphabetically = false, }) : super(key: key); /// The builder that will be used in case of error @@ -120,9 +122,14 @@ class UserListView extends StatefulWidget { /// Set it to false to disable the pull-to-refresh widget final bool pullToRefresh; - /// Sets a blue trailing checkMark in [UserItem] for all the [selectedUsers] + /// Sets a blue trailing checkMark in [ListUserItem] for all the [selectedUsers] final List selectedUsers; + /// Set it to true to group users by their first character + /// + /// defaults to false + final bool groupAlphabetically; + @override _UserListViewState createState() => _UserListViewState(); } @@ -172,11 +179,30 @@ class _UserListViewState extends State ); } - StreamBuilder> _buildListView( + StreamBuilder> _buildListView( UsersBlocState usersBlocState, ) { return StreamBuilder( - stream: usersBlocState.usersStream, + stream: usersBlocState.usersStream.map( + (users) { + if (widget.groupAlphabetically) { + final temp = users + ..sort((curr, next) => curr.name.compareTo(next.name)); + final groupedUsers = >{}; + for (var e in temp) { + final alphabet = e.name[0]; + groupedUsers[alphabet] = [...groupedUsers[alphabet] ?? [], e]; + } + final items = []; + for (var key in groupedUsers.keys) { + items.add(ListHeaderItem(key)); + items.addAll(groupedUsers[key].map((e) => ListUserItem(e))); + } + return items; + } + return users.map((e) => ListUserItem(e)).toList(); + }, + ), builder: (context, snapshot) { if (snapshot.hasError) { if (snapshot.error is Error) { @@ -256,13 +282,13 @@ class _UserListViewState extends State ); } - final users = snapshot.data; + final items = snapshot.data; - if (users.isEmpty && widget.emptyBuilder != null) { + if (items.isEmpty && widget.emptyBuilder != null) { return widget.emptyBuilder(context); } - if (users.isEmpty && widget.emptyBuilder == null) { + if (items.isEmpty && widget.emptyBuilder == null) { return LayoutBuilder( builder: (context, viewportConstraints) { return SingleChildScrollView( @@ -285,13 +311,13 @@ class _UserListViewState extends State controller: _scrollController, childrenDelegate: SliverChildBuilderDelegate( (context, i) { - return _itemBuilder(context, i, users); + return _itemBuilder(context, i, items); }, - childCount: (users.length * 2) + 1, + childCount: (items.length * 2) + 1, findChildIndexCallback: (key) { final ValueKey valueKey = key; - final index = users - .indexWhere((user) => 'USER-${user.id}' == valueKey.value); + final index = + items.indexWhere((item) => item.key == valueKey.value); return index != -1 ? (index * 2) : null; }, ), @@ -300,7 +326,7 @@ class _UserListViewState extends State ); } - Widget _itemBuilder(context, int i, List users) { + Widget _itemBuilder(BuildContext context, int i, List items) { if (i % 2 != 0) { if (widget.separatorBuilder != null) { return widget.separatorBuilder(context, i); @@ -311,36 +337,57 @@ class _UserListViewState extends State i = i ~/ 2; final usersProvider = UsersBloc.of(context); - if (i < users.length) { - final user = users[i]; - final selected = widget.selectedUsers?.contains(user) ?? false; + if (i < items.length) { + final item = items[i]; + return item.when( + headerItem: (header) { + return Container( + key: ValueKey('HEADER-$header'), + color: Colors.grey.shade100, + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Text( + header, + style: TextStyle(fontWeight: FontWeight.w500), + ), + ), + ); + }, + userItem: (user) { + final selected = widget.selectedUsers?.contains(user) ?? false; - UserTapCallback onTap; - if (widget.onUserTap != null) { - onTap = widget.onUserTap; - } else { - onTap = (client, _) { - // Navigator.push( - // context, - // MaterialPageRoute( - // builder: (context) { - // return StreamChannel( - // child: widget.userWidget, - // channel: client, - // ); - // }, - // ), - // ); - }; - } + UserTapCallback onTap; + if (widget.onUserTap != null) { + onTap = widget.onUserTap; + } else { + onTap = (client, _) { + // Navigator.push( + // context, + // MaterialPageRoute( + // builder: (context) { + // return StreamChannel( + // child: widget.userWidget, + // channel: client, + // ); + // }, + // ), + // ); + }; + } - return UserItem( - key: ValueKey('USER-${user.id}'), - user: user, - onTap: (user) => onTap(user, widget.userWidget), - onLongPress: widget.onUserLongPress, - onImageTap: widget.onImageTap, - selected: selected, + return Container( + key: ValueKey('USER-${user.id}'), + child: widget.userItemBuilder != null + ? widget.userItemBuilder(context, user, selected) + : UserItem( + user: user, + onTap: (user) => onTap(user, widget.userWidget), + onLongPress: widget.onUserLongPress, + onImageTap: widget.onImageTap, + selected: selected, + ), + ); + }, ); } else { return _buildQueryProgressIndicator(context, usersProvider); @@ -415,3 +462,40 @@ class _UserListViewState extends State } } } + +abstract class ListItem { + String get key { + if (this is ListHeaderItem) { + final header = (this as ListHeaderItem).heading; + return 'HEADER-$header'; + } + if (this is ListUserItem) { + final user = (this as ListUserItem).user; + return 'USER-${user.id}'; + } + } + + Widget when({ + @required Widget Function(String heading) headerItem, + @required Widget Function(User user) userItem, + }) { + if (this is ListHeaderItem) { + return headerItem((this as ListHeaderItem).heading); + } + if (this is ListUserItem) { + return userItem((this as ListUserItem).user); + } + } +} + +class ListHeaderItem extends ListItem { + final String heading; + + ListHeaderItem(this.heading); +} + +class ListUserItem extends ListItem { + final User user; + + ListUserItem(this.user); +} From 4561057452f76fb8ced3af7c68d78ab6d6302b9a Mon Sep 17 00:00:00 2001 From: xsahil03x Date: Wed, 18 Nov 2020 13:30:03 +0530 Subject: [PATCH 0386/1140] feat : Add support for userName filtering in user list --- lib/src/user_list_view.dart | 74 ++++++++++++++++++++++++++----------- 1 file changed, 53 insertions(+), 21 deletions(-) diff --git a/lib/src/user_list_view.dart b/lib/src/user_list_view.dart index 56cb762d..57abcc99 100644 --- a/lib/src/user_list_view.dart +++ b/lib/src/user_list_view.dart @@ -1,6 +1,7 @@ import 'dart:convert'; import 'package:flutter/material.dart'; +import 'package:rxdart/rxdart.dart'; import 'package:stream_chat/stream_chat.dart'; import 'package:stream_chat_flutter/src/users_bloc.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; @@ -65,7 +66,13 @@ class UserListView extends StatefulWidget { this.swipeToAction = false, this.pullToRefresh = true, this.groupAlphabetically = false, - }) : super(key: key); + this.filterByUserName = '', + this.filterByUserNameStream, + }) : assert( + filterByUserName == null || filterByUserNameStream == null, + 'Cannot provide both filterByUserName and filterByUserNameStream.', + ), + super(key: key); /// The builder that will be used in case of error final Widget Function(Error error) errorBuilder; @@ -130,6 +137,12 @@ class UserListView extends StatefulWidget { /// defaults to false final bool groupAlphabetically; + /// + final String filterByUserName; + + /// + final Stream filterByUserNameStream; + @override _UserListViewState createState() => _UserListViewState(); } @@ -179,30 +192,49 @@ class _UserListViewState extends State ); } + List _getFilteredItems(List users, String query) { + if (widget.groupAlphabetically) { + var temp = users..sort((curr, next) => curr.name.compareTo(next.name)); + temp = temp + .where((it) => it.name.toLowerCase().contains(query.toLowerCase())); + final groupedUsers = >{}; + for (var e in temp) { + final alphabet = e.name[0]; + groupedUsers[alphabet] = [...groupedUsers[alphabet] ?? [], e]; + } + final items = []; + for (var key in groupedUsers.keys) { + items.add(ListHeaderItem(key)); + items.addAll(groupedUsers[key].map((e) => ListUserItem(e))); + } + return items; + } + return users + .where((it) => it.name.toLowerCase().contains(query.toLowerCase())) + .map((e) => ListUserItem(e)) + .toList(); + } + + Stream> _buildUserStream( + UsersBlocState usersBlocState, + ) { + if (widget.filterByUserNameStream == null) { + return usersBlocState.usersStream.map( + (users) => _getFilteredItems(users, widget.filterByUserName), + ); + } + return Rx.combineLatest2( + usersBlocState.usersStream, + widget.filterByUserNameStream, + _getFilteredItems, + ); + } + StreamBuilder> _buildListView( UsersBlocState usersBlocState, ) { return StreamBuilder( - stream: usersBlocState.usersStream.map( - (users) { - if (widget.groupAlphabetically) { - final temp = users - ..sort((curr, next) => curr.name.compareTo(next.name)); - final groupedUsers = >{}; - for (var e in temp) { - final alphabet = e.name[0]; - groupedUsers[alphabet] = [...groupedUsers[alphabet] ?? [], e]; - } - final items = []; - for (var key in groupedUsers.keys) { - items.add(ListHeaderItem(key)); - items.addAll(groupedUsers[key].map((e) => ListUserItem(e))); - } - return items; - } - return users.map((e) => ListUserItem(e)).toList(); - }, - ), + stream: _buildUserStream(usersBlocState), builder: (context, snapshot) { if (snapshot.hasError) { if (snapshot.error is Error) { From eda42df7da5c786dbe9c1f162922d96cb2c2cb8c Mon Sep 17 00:00:00 2001 From: xsahil03x Date: Wed, 18 Nov 2020 13:38:08 +0530 Subject: [PATCH 0387/1140] fix : whereIterable to List --- lib/src/user_list_view.dart | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/src/user_list_view.dart b/lib/src/user_list_view.dart index 57abcc99..1c3652ff 100644 --- a/lib/src/user_list_view.dart +++ b/lib/src/user_list_view.dart @@ -196,7 +196,8 @@ class _UserListViewState extends State if (widget.groupAlphabetically) { var temp = users..sort((curr, next) => curr.name.compareTo(next.name)); temp = temp - .where((it) => it.name.toLowerCase().contains(query.toLowerCase())); + .where((it) => it.name.toLowerCase().contains(query.toLowerCase())) + .toList(); final groupedUsers = >{}; for (var e in temp) { final alphabet = e.name[0]; From d379de9f9672cba83f34e0a365da2994951d1c61 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Wed, 18 Nov 2020 10:49:35 +0100 Subject: [PATCH 0388/1140] minor fixes --- example/ios/Flutter/.last_build_id | 2 +- example/lib/choose_user_page.dart | 207 ++++++++-------- example/lib/main.dart | 185 +++++++------- example/pubspec.yaml | 2 +- lib/src/channel_list_view.dart | 86 ++++++- lib/src/giphy_attachment.dart | 381 ++++++++++++++--------------- lib/src/message_widget.dart | 1 + 7 files changed, 471 insertions(+), 393 deletions(-) diff --git a/example/ios/Flutter/.last_build_id b/example/ios/Flutter/.last_build_id index 8aba7787..20c7c514 100644 --- a/example/ios/Flutter/.last_build_id +++ b/example/ios/Flutter/.last_build_id @@ -1 +1 @@ -bb5f9103d9045cd6244bcae1f5f343e5 \ No newline at end of file +c3e639ccf9b069e37a7d1345194e6b99 \ No newline at end of file diff --git a/example/lib/choose_user_page.dart b/example/lib/choose_user_page.dart index 30205088..4583a2a6 100644 --- a/example/lib/choose_user_page.dart +++ b/example/lib/choose_user_page.dart @@ -94,127 +94,130 @@ class ChooseUserPage extends StatelessWidget { ), ), Expanded( - child: ListView.separated( - separatorBuilder: (context, i) { - return Container( - width: double.infinity, - color: Colors.black12, - height: 1, - ); - }, - itemCount: users.length + 1, - itemBuilder: (context, i) { - return [ - ...users.entries.map((entry) { - final token = entry.key; - final user = entry.value; - return ListTile( - onTap: () async { - showDialog( - barrierDismissible: false, - context: context, - builder: (context) => Center( - child: Container( - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(16), - color: Colors.white, - ), - height: 100, - width: 100, - child: Center( - child: CircularProgressIndicator(), + child: Padding( + padding: const EdgeInsets.only(top: 32), + child: ListView.separated( + separatorBuilder: (context, i) { + return Container( + width: double.infinity, + color: Colors.black12, + height: 1, + ); + }, + itemCount: users.length + 1, + itemBuilder: (context, i) { + return [ + ...users.entries.map((entry) { + final token = entry.key; + final user = entry.value; + return ListTile( + onTap: () async { + showDialog( + barrierDismissible: false, + context: context, + builder: (context) => Center( + child: Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(16), + color: Colors.white, + ), + height: 100, + width: 100, + child: Center( + child: CircularProgressIndicator(), + ), ), ), + ); + + final secureStorage = FlutterSecureStorage(); + final client = StreamChat.of(context).client; + + await client.setUser( + user, + token, + ); + + secureStorage.write( + key: kStreamApiKey, + value: kDefaultStreamApiKey, + ); + secureStorage.write( + key: kStreamUserId, + value: user.id, + ); + secureStorage.write( + key: kStreamToken, + value: token, + ); + + if (!kIsWeb) { + initNotifications(client); + } + + Navigator.pop(context); + await Navigator.pushReplacement( + context, + MaterialPageRoute( + builder: (context) { + return StreamChat( + client: client, + child: ChannelListPage(), + ); + }, + ), + ); + }, + leading: UserAvatar( + user: user, + constraints: BoxConstraints.tight( + Size.fromRadius(20), ), - ); - - final secureStorage = FlutterSecureStorage(); - final client = StreamChat.of(context).client; - - await client.setUser( - user, - token, - ); - - secureStorage.write( - key: kStreamApiKey, - value: kDefaultStreamApiKey, - ); - secureStorage.write( - key: kStreamUserId, - value: user.id, - ); - secureStorage.write( - key: kStreamToken, - value: token, - ); - - if (!kIsWeb) { - initNotifications(client); - } - - Navigator.pop(context); - await Navigator.pushReplacement( + ), + title: Text( + user.name, + style: TextStyle(fontWeight: FontWeight.bold), + ), + subtitle: Text('Stream test account'), + trailing: SvgPicture.asset( + 'assets/icon_arrow_right.svg', + height: 24, + width: 24, + ), + ); + }), + ListTile( + onTap: () { + Navigator.push( context, MaterialPageRoute( - builder: (context) { - return StreamChat( - client: client, - child: ChannelListPage(), - ); - }, + builder: (context) => AdvancedOptionsPage(), ), ); }, - leading: UserAvatar( - user: user, - constraints: BoxConstraints.tight( - Size.fromRadius(20), + leading: CircleAvatar( + child: Icon( + StreamIcons.settings, + color: Colors.black, ), + backgroundColor: + StreamChatTheme.of(context).secondaryColor, ), title: Text( - user.name, + 'Advanced Options', style: TextStyle(fontWeight: FontWeight.bold), ), - subtitle: Text('Stream test account'), + subtitle: Text('Custom settings'), trailing: SvgPicture.asset( 'assets/icon_arrow_right.svg', height: 24, width: 24, + clipBehavior: Clip.none, ), - ); - }), - ListTile( - onTap: () { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => AdvancedOptionsPage(), - ), - ); - }, - leading: CircleAvatar( - child: Icon( - StreamIcons.settings, - color: Colors.black, - ), - backgroundColor: - StreamChatTheme.of(context).secondaryColor, ), - title: Text( - 'Advanced Options', - style: TextStyle(fontWeight: FontWeight.bold), - ), - subtitle: Text('Custom settings'), - trailing: SvgPicture.asset( - 'assets/icon_arrow_right.svg', - height: 24, - width: 24, - clipBehavior: Clip.none, - ), - ), - ][i]; - }, + ][i]; + }, + ), ), ), StreamVersion(), diff --git a/example/lib/main.dart b/example/lib/main.dart index c09030f3..d0b39d98 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -21,7 +21,7 @@ void main() async { logLevel: Level.INFO, showLocalNotification: (!kIsWeb && Platform.isAndroid) ? showLocalNotification : null, - persistenceEnabled: false, + persistenceEnabled: true, ); if (userId != null) { @@ -43,6 +43,7 @@ class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( + debugShowCheckedModeBanner: false, theme: ThemeData.light(), darkTheme: ThemeData.dark(), //TODO change to system once dark theme is implemented @@ -63,89 +64,9 @@ class ChannelListPage extends StatelessWidget { Widget build(BuildContext context) { final user = StreamChat.of(context).user; return Scaffold( - drawer: Drawer( - 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, - ), - ), - ), - ], - ), - ), - ListTile( - leading: Icon(StreamIcons.edit), - title: Text( - 'New direct message', - style: TextStyle( - fontSize: 14.5, - ), - ), - ), - ListTile( - leading: Icon(StreamIcons.group), - title: Text( - 'New group', - style: TextStyle( - fontSize: 14.5, - ), - ), - ), - Expanded( - child: Container( - alignment: Alignment.bottomCenter, - child: ListTile( - onTap: () async { - await StreamChat.of(context).client.disconnect(); - - final secureStorage = FlutterSecureStorage(); - await secureStorage.deleteAll(); - Navigator.pop(context); - await Navigator.pushReplacement( - context, - MaterialPageRoute( - builder: (context) => ChooseUserPage(), - ), - ); - }, - leading: Icon(StreamIcons.user), - title: Text( - 'Sign out', - style: TextStyle( - fontSize: 14.5, - ), - ), - ), - ), - ), - ], - ), - ), - ), - ), + drawerEnableOpenDragGesture: true, + drawerEdgeDragWidth: 50, + drawer: _buildDrawer(context, user), floatingActionButton: FloatingActionButton( child: Icon(Icons.add), onPressed: () { @@ -156,6 +77,11 @@ class ChannelListPage extends StatelessWidget { ), body: ChannelsBloc( child: ChannelListView( + onStartChatPressed: () { + Navigator.of(context).push(MaterialPageRoute(builder: (context) { + return CreateChannelPage(); + })); + }, swipeToAction: true, filter: { 'members': { @@ -174,6 +100,92 @@ class ChannelListPage extends StatelessWidget { ), ); } + + Drawer _buildDrawer(BuildContext context, User user) { + return Drawer( + 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, + ), + ), + ), + ], + ), + ), + ListTile( + leading: Icon(StreamIcons.edit), + title: Text( + 'New direct message', + style: TextStyle( + fontSize: 14.5, + ), + ), + ), + ListTile( + leading: Icon(StreamIcons.group), + title: Text( + 'New group', + style: TextStyle( + fontSize: 14.5, + ), + ), + ), + Expanded( + child: Container( + alignment: Alignment.bottomCenter, + child: ListTile( + onTap: () async { + await StreamChat.of(context).client.disconnect(); + + final secureStorage = FlutterSecureStorage(); + await secureStorage.deleteAll(); + Navigator.pop(context); + await Navigator.pushReplacement( + context, + MaterialPageRoute( + builder: (context) => ChooseUserPage(), + ), + ); + }, + leading: Icon(StreamIcons.user), + title: Text( + 'Sign out', + style: TextStyle( + fontSize: 14.5, + ), + ), + ), + ), + ), + ], + ), + ), + ), + ); + } } class ChannelPage extends StatelessWidget { @@ -418,6 +430,11 @@ class _CreateChannelPageState extends State { limit: 25, offset: offset, ), + filter: { + 'id': { + r'$ne': client.state.user.id, + } + }, sort: [ SortOption( 'name', diff --git a/example/pubspec.yaml b/example/pubspec.yaml index fca549d2..0fe6a0ad 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -1,6 +1,6 @@ name: example description: A new Flutter project. -version: 1.0.60+62 +version: 1.0.62+64 environment: sdk: ">=2.2.2 <3.0.0" diff --git a/lib/src/channel_list_view.dart b/lib/src/channel_list_view.dart index 8b66db34..9dae4213 100644 --- a/lib/src/channel_list_view.dart +++ b/lib/src/channel_list_view.dart @@ -70,6 +70,7 @@ class ChannelListView extends StatefulWidget { this.errorBuilder, this.emptyBuilder, this.onImageTap, + this.onStartChatPressed, this.swipeToAction = false, this.pullToRefresh = true, }) : super(key: key); @@ -129,6 +130,9 @@ class ChannelListView extends StatefulWidget { /// Set it to false to disable the pull-to-refresh widget final bool pullToRefresh; + /// Callback used in the default empty list widget + final VoidCallback onStartChatPressed; + @override _ChannelListViewState createState() => _ChannelListViewState(); } @@ -185,13 +189,69 @@ class _ChannelListViewState extends State builder: (context, viewportConstraints) { return SingleChildScrollView( physics: AlwaysScrollableScrollPhysics(), - child: ConstrainedBox( - constraints: BoxConstraints( - minHeight: viewportConstraints.maxHeight, - ), - child: Center( - child: Text('You have no channels currently'), - ), + child: Stack( + children: [ + ConstrainedBox( + constraints: BoxConstraints( + minHeight: viewportConstraints.maxHeight, + ), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Padding( + padding: const EdgeInsets.all(8.0), + child: Icon( + StreamIcons.message, + size: 136, + color: Color(0xffDBDBDB), + ), + ), + Padding( + padding: const EdgeInsets.all(8.0), + child: Text( + 'Let’s start chatting!', + style: TextStyle( + fontSize: 16, + ), + ), + ), + Padding( + padding: const EdgeInsets.symmetric( + vertical: 8.0, + horizontal: 52, + ), + child: Text( + 'How about sending your first message to a friend?', + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 14, + color: Color(0xff7A7A7A), + ), + ), + ), + ], + ), + ), + if (widget.onStartChatPressed != null) + Positioned( + right: 0, + left: 0, + bottom: 32, + child: Center( + child: FlatButton( + onPressed: widget.onStartChatPressed, + child: Text( + 'Start a chat', + style: TextStyle( + color: + StreamChatTheme.of(context).accentColor, + fontWeight: FontWeight.bold, + ), + ), + ), + ), + ), + ], ), ); }, @@ -542,11 +602,13 @@ class _ChannelListViewState extends State ), ); } - return snapshot.data - ? _buildLoadingItem() - : Container( - height: 70, - ); + return Container( + height: 100, + padding: EdgeInsets.all(32), + child: Center( + child: snapshot.data ? CircularProgressIndicator() : Container(), + ), + ); }); } diff --git a/lib/src/giphy_attachment.dart b/lib/src/giphy_attachment.dart index 8cec9ce5..df4708c5 100644 --- a/lib/src/giphy_attachment.dart +++ b/lib/src/giphy_attachment.dart @@ -41,211 +41,206 @@ class GiphyAttachment extends StatelessWidget { return Column( mainAxisSize: MainAxisSize.min, children: [ - DecoratedBox( - decoration: BoxDecoration(), - child: Card( - elevation: 2, - clipBehavior: Clip.antiAlias, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.only( - topRight: Radius.circular(16.0), - bottomRight: Radius.circular(0.0), - topLeft: Radius.circular(16.0), - bottomLeft: Radius.circular(16.0), - ), + Card( + elevation: 2, + clipBehavior: Clip.antiAlias, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.only( + topRight: Radius.circular(16.0), + bottomRight: Radius.circular(0.0), + topLeft: Radius.circular(16.0), + bottomLeft: Radius.circular(16.0), ), - child: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - Stack( - children: [ - Padding( - padding: const EdgeInsets.all(8.0), - child: GestureDetector( - onTap: () { - Navigator.push(context, - MaterialPageRoute(builder: (_) { - return FullScreenImage( - url: attachment.imageUrl ?? - attachment.assetUrl ?? - attachment.thumbUrl, - ); - })); - }, - child: CachedNetworkImage( - height: size?.height, - width: size?.width, - placeholder: (_, __) { - return Container( - width: size?.width, - height: size?.height, - child: Center( - child: CircularProgressIndicator(), - ), - ); - }, - imageUrl: attachment.thumbUrl ?? - attachment.imageUrl ?? - attachment.assetUrl, - errorWidget: (context, url, error) => AttachmentError( - attachment: attachment, - size: size, - ), - fit: BoxFit.cover, - ), - ), - ), - Positioned( - left: 0, - top: 0, - child: Container( - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.only( - bottomRight: Radius.circular(16.0), - )), - child: Padding( - padding: const EdgeInsets.only( - left: 8.0, - right: 8.0, - top: 8.0, - bottom: 4.0, - ), - child: Row( - children: [ - Icon( - StreamIcons.lightning, - color: StreamChatTheme.of(context).accentColor, - size: 16.0, - ), - Text( - 'GIPHY', - style: TextStyle( - color: - StreamChatTheme.of(context).accentColor, - fontWeight: FontWeight.bold, - fontSize: 11.0, - ), - ), - ], - ), - ), - ), - ), - ], - ), - if (attachment.title != null) - Container( - alignment: Alignment.bottomCenter, - child: Padding( - padding: const EdgeInsets.symmetric(horizontal: 8.0), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Card( - elevation: 2, - child: IconButton( - padding: const EdgeInsets.all(0), - constraints: BoxConstraints.tight(Size(32, 32)), - icon: Icon( - StreamIcons.left, - size: 24.0, - ), - splashRadius: 16, - onPressed: () { - streamChannel.channel.sendAction(message, { - 'image_action': 'shuffle', - }); - }, - ), - shape: CircleBorder(), - ), - Expanded( + ), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Stack( + children: [ + Padding( + padding: const EdgeInsets.all(8.0), + child: GestureDetector( + onTap: () { + Navigator.push(context, MaterialPageRoute(builder: (_) { + return FullScreenImage( + url: attachment.imageUrl ?? + attachment.assetUrl ?? + attachment.thumbUrl, + ); + })); + }, + child: CachedNetworkImage( + height: size?.height, + width: size?.width, + placeholder: (_, __) { + return Container( + width: size?.width, + height: size?.height, child: Center( - child: Text( - '"${attachment.title}"', - style: TextStyle( - fontStyle: FontStyle.italic, - ), - ), + child: CircularProgressIndicator(), ), - ), - Card( - elevation: 2, - child: IconButton( - padding: const EdgeInsets.all(0), - constraints: BoxConstraints.tight(Size(32, 32)), - icon: Icon( - StreamIcons.right, - size: 24.0, - ), - splashRadius: 16, - onPressed: () { - streamChannel.channel.sendAction(message, { - 'image_action': 'shuffle', - }); - }, - ), - shape: CircleBorder(), - ), - ], + ); + }, + imageUrl: attachment.thumbUrl ?? + attachment.imageUrl ?? + attachment.assetUrl, + errorWidget: (context, url, error) => AttachmentError( + attachment: attachment, + size: size, + ), + fit: BoxFit.cover, ), ), ), - SizedBox( - height: 4.0, - ), - Container( - color: Colors.black.withOpacity(0.2), - width: double.infinity, - height: 0.5, - ), - Row( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Expanded( - child: FlatButton( - height: 50, - onPressed: () { - streamChannel.channel.sendAction(message, { - 'image_action': 'cancel', - }); - }, - child: Text( - 'Cancel', - style: TextStyle( - fontWeight: FontWeight.bold, - color: Colors.black.withOpacity(0.5)), + Positioned( + left: 0, + top: 0, + child: Container( + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.only( + bottomRight: Radius.circular(16.0), + )), + child: Padding( + padding: const EdgeInsets.only( + left: 8.0, + right: 8.0, + top: 8.0, + bottom: 4.0, ), - ), - ), - Container( - width: 0.5, - color: Colors.black.withOpacity(0.2), - height: 50.0, - ), - Expanded( - child: FlatButton( - height: 50, - onPressed: () { - streamChannel.channel.sendAction(message, { - 'image_action': 'send', - }); - }, - child: Text( - 'Send', - style: TextStyle( + child: Row( + children: [ + Icon( + StreamIcons.lightning, color: StreamChatTheme.of(context).accentColor, - fontWeight: FontWeight.bold), + size: 16.0, + ), + Text( + 'GIPHY', + style: TextStyle( + color: StreamChatTheme.of(context).accentColor, + fontWeight: FontWeight.bold, + fontSize: 11.0, + ), + ), + ], ), ), ), - ], + ), + ], + ), + if (attachment.title != null) + Container( + alignment: Alignment.bottomCenter, + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 8.0), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Card( + elevation: 2, + child: IconButton( + padding: const EdgeInsets.all(0), + constraints: BoxConstraints.tight(Size(32, 32)), + icon: Icon( + StreamIcons.left, + size: 24.0, + ), + splashRadius: 16, + onPressed: () { + streamChannel.channel.sendAction(message, { + 'image_action': 'shuffle', + }); + }, + ), + shape: CircleBorder(), + ), + Expanded( + child: Center( + child: Text( + '"${attachment.title}"', + style: TextStyle( + fontStyle: FontStyle.italic, + ), + ), + ), + ), + Card( + elevation: 2, + child: IconButton( + padding: const EdgeInsets.all(0), + constraints: BoxConstraints.tight(Size(32, 32)), + icon: Icon( + StreamIcons.right, + size: 24.0, + ), + splashRadius: 16, + onPressed: () { + streamChannel.channel.sendAction(message, { + 'image_action': 'shuffle', + }); + }, + ), + shape: CircleBorder(), + ), + ], + ), + ), ), - ], - ), + SizedBox( + height: 4.0, + ), + Container( + color: Colors.black.withOpacity(0.2), + width: double.infinity, + height: 0.5, + ), + Row( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Expanded( + child: FlatButton( + height: 50, + onPressed: () { + streamChannel.channel.sendAction(message, { + 'image_action': 'cancel', + }); + }, + child: Text( + 'Cancel', + style: TextStyle( + fontWeight: FontWeight.bold, + color: Colors.black.withOpacity(0.5)), + ), + ), + ), + Container( + width: 0.5, + color: Colors.black.withOpacity(0.2), + height: 50.0, + ), + Expanded( + child: FlatButton( + height: 50, + onPressed: () { + streamChannel.channel.sendAction(message, { + 'image_action': 'send', + }); + }, + child: Text( + 'Send', + style: TextStyle( + color: StreamChatTheme.of(context).accentColor, + fontWeight: FontWeight.bold), + ), + ), + ), + ], + ), + ], ), ), SizedBox( diff --git a/lib/src/message_widget.dart b/lib/src/message_widget.dart index 4f551655..86479ebe 100644 --- a/lib/src/message_widget.dart +++ b/lib/src/message_widget.dart @@ -619,6 +619,7 @@ class _MessageWidgetState extends State { child: Material( clipBehavior: Clip.hardEdge, shape: attachmentShape, + type: MaterialType.transparency, child: Transform( transform: Matrix4.rotationY(widget.reverse ? pi : 0), alignment: Alignment.center, From e021ea5cd675dc263072eabb675d178457973d9f Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Wed, 18 Nov 2020 12:06:26 +0100 Subject: [PATCH 0389/1140] update flutter action --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index a8e87c58..4b3e086a 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -8,7 +8,7 @@ jobs: steps: - uses: actions/checkout@v2 - name: Flutter action - uses: subosito/flutter-action@v1.3.2 + uses: subosito/flutter-action@v1.4.0 with: channel: 'stable' - name: Get dependencies From 1742fe6f5fa6b39af7caf24226f3e6a4cbe1f3ea Mon Sep 17 00:00:00 2001 From: xsahil03x Date: Wed, 18 Nov 2020 17:16:18 +0530 Subject: [PATCH 0390/1140] feat: Replace List with Set for easier computation. --- lib/src/user_list_view.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/user_list_view.dart b/lib/src/user_list_view.dart index 1c3652ff..c4e3f2ce 100644 --- a/lib/src/user_list_view.dart +++ b/lib/src/user_list_view.dart @@ -130,7 +130,7 @@ class UserListView extends StatefulWidget { final bool pullToRefresh; /// Sets a blue trailing checkMark in [ListUserItem] for all the [selectedUsers] - final List selectedUsers; + final Set selectedUsers; /// Set it to true to group users by their first character /// From 7cf30b501f123914a531ab3d55a8f5d52de8d332 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Wed, 18 Nov 2020 13:32:18 +0100 Subject: [PATCH 0391/1140] fix qa --- example/ios/Flutter/.last_build_id | 2 +- example/pubspec.yaml | 2 +- lib/src/message_input.dart | 99 ++++++++++++++---------------- lib/src/video_thumbnail.dart | 37 +++++++++++ svgs/icon_camera.svg | 3 + 5 files changed, 87 insertions(+), 56 deletions(-) create mode 100644 lib/src/video_thumbnail.dart create mode 100644 svgs/icon_camera.svg diff --git a/example/ios/Flutter/.last_build_id b/example/ios/Flutter/.last_build_id index 8aba7787..20c7c514 100644 --- a/example/ios/Flutter/.last_build_id +++ b/example/ios/Flutter/.last_build_id @@ -1 +1 @@ -bb5f9103d9045cd6244bcae1f5f343e5 \ No newline at end of file +c3e639ccf9b069e37a7d1345194e6b99 \ No newline at end of file diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 8fc2dadb..fca549d2 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -1,6 +1,6 @@ name: example description: A new Flutter project. -version: 1.0.59+61 +version: 1.0.60+62 environment: sdk: ">=2.2.2 <3.0.0" diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 6024169b..dc5bf2f6 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -19,6 +19,7 @@ import 'package:stream_chat_flutter/src/media_list_view.dart'; import 'package:stream_chat_flutter/src/message_list_view.dart'; import 'package:stream_chat_flutter/src/stream_chat_theme.dart'; import 'package:stream_chat_flutter/src/user_avatar.dart'; +import 'package:stream_chat_flutter/src/video_thumbnail.dart'; import 'package:substring_highlight/substring_highlight.dart'; import '../stream_chat_flutter.dart'; @@ -41,6 +42,8 @@ enum DefaultAttachmentTypes { file, } +const _kMinMediaPickerSize = 360.0; + /// Inactive state /// ![screenshot](https://raw.githubusercontent.com/GetStream/stream-chat-flutter/master/screenshots/message_input.png) /// ![screenshot](https://raw.githubusercontent.com/GetStream/stream-chat-flutter/master/screenshots/message_input_paint.png) @@ -182,7 +185,7 @@ class MessageInputState extends State { bool _sendAsDm = false; bool _openFilePickerSection = false; int _filePickerIndex = 0; - double _filePickerSize = 250.0; + double _filePickerSize = _kMinMediaPickerSize; /// The editing controller passed to the input TextField TextEditingController textEditingController; @@ -654,9 +657,11 @@ class MessageInputState extends State { }, ), IconButton( - icon: Icon( - StreamIcons.camera, - size: 24, + icon: SvgPicture.asset( + 'svgs/icon_camera.svg', + package: 'stream_chat_flutter', + height: 24, + width: 24, color: _filePickerIndex == 2 ? StreamChatTheme.of(context).accentColor : Colors.black.withOpacity(0.5), @@ -684,7 +689,7 @@ class MessageInputState extends State { setState(() { _animateContainer = false; _filePickerSize = (_filePickerSize - update.delta.dy).clamp( - 240.0, + _kMinMediaPickerSize, MediaQuery.of(context).size.height / 1.7, ); }); @@ -753,9 +758,10 @@ class MessageInputState extends State { .any((element) => element.id == media.id)) { _addAttachment(media); } else { - _attachments - .removeWhere((element) => element.id == media.id); - setState(() {}); + setState(() { + _attachments + .removeWhere((element) => element.id == media.id); + }); } }, ); @@ -813,35 +819,7 @@ class MessageInputState extends State { } void _addAttachment(Media medium) async { - final mediaFile = await medium.getFile(); - final thumbBytes = await medium.getThumbnail(); - - final file = PlatformFile( - path: mediaFile.path, - bytes: mediaFile.readAsBytesSync(), - ); - - final thumbFile = PlatformFile( - bytes: thumbBytes, - name: '${file.name ?? file.path?.split('/')?.last}_thumbnail.jpeg', - ); - - setState(() { - _inputEnabled = true; - }); - - if (file == null) { - return; - } - - final channel = StreamChannel.of(context).channel; final attachment = _SendingAttachment( - file: file, - thumbFile: thumbFile, - attachment: Attachment( - localUri: file.path != null ? Uri.parse(file.path) : null, - type: medium.mediaType == MediaType.image ? 'image' : 'video', - ), id: medium.id, ); @@ -849,11 +827,23 @@ class MessageInputState extends State { _attachments.add(attachment); }); - final thumbUrl = await _uploadImage( - thumbFile, - channel, + final mediaFile = await medium.getFile(); + + final file = PlatformFile( + path: mediaFile.path, + bytes: mediaFile.readAsBytesSync(), ); + final channel = StreamChannel.of(context).channel; + setState(() { + attachment + ..file = file + ..attachment = Attachment( + localUri: file.path != null ? Uri.parse(file.path) : null, + type: medium.mediaType == MediaType.image ? 'image' : 'video', + ); + }); + final url = await _uploadAttachment( file, medium.mediaType == MediaType.image @@ -868,12 +858,10 @@ class MessageInputState extends State { if (fileType == DefaultAttachmentTypes.image) { attachment.attachment = attachment.attachment.copyWith( imageUrl: url, - thumbUrl: thumbUrl, ); } else { attachment.attachment = attachment.attachment.copyWith( assetUrl: url, - thumbUrl: thumbUrl, ); } @@ -1221,6 +1209,10 @@ class MessageInputState extends State { ); } + if (attachment.attachment == null) { + return SizedBox(); + } + switch (attachment.attachment.type) { case 'image': case 'giphy': @@ -1230,22 +1222,20 @@ class MessageInputState extends State { fit: BoxFit.cover, ) : Image.network( - attachment.attachment.imageUrl ?? - attachment.attachment.thumbUrl, + attachment.attachment.imageUrl, fit: BoxFit.cover, ); break; case 'video': return Stack( children: [ - Container( - child: attachment.thumbFile != null - ? Image.memory( - attachment.thumbFile.bytes, - fit: BoxFit.cover, - ) - : Icon(Icons.videocam), - color: Colors.black26, + Positioned.fill( + child: Container( + child: VideoThumbnail( + file: File( + attachment.file.path, + )), + ), ), Positioned( left: 8, @@ -1314,7 +1304,7 @@ class MessageInputState extends State { setState(() { _animateContainer = true; _openFilePickerSection = false; - _filePickerSize = 250.0; + _filePickerSize = _kMinMediaPickerSize; }); } else { final status = await (Platform.isAndroid @@ -1450,6 +1440,9 @@ class MessageInputState extends State { } else if (fileType == DefaultAttachmentTypes.video) { pickedFile = await _imagePicker.getVideo(source: ImageSource.camera); } + if (pickedFile == null) { + return; + } final bytes = await pickedFile.readAsBytes(); file = PlatformFile( path: pickedFile.path, @@ -1774,14 +1767,12 @@ class MessageInputState extends State { class _SendingAttachment { PlatformFile file; - PlatformFile thumbFile; Attachment attachment; bool uploaded; String id; _SendingAttachment({ this.file, - this.thumbFile, this.attachment, this.uploaded = false, this.id, diff --git a/lib/src/video_thumbnail.dart b/lib/src/video_thumbnail.dart new file mode 100644 index 00000000..c36ab327 --- /dev/null +++ b/lib/src/video_thumbnail.dart @@ -0,0 +1,37 @@ +import 'dart:io'; + +import 'package:flutter/material.dart'; +import 'package:video_player/video_player.dart'; + +class VideoThumbnail extends StatefulWidget { + final File file; + + const VideoThumbnail({ + Key key, + @required this.file, + }) : super(key: key); + + @override + _VideoThumbnailState createState() => _VideoThumbnailState(); +} + +class _VideoThumbnailState extends State { + VideoPlayerController _videoPlayerController; + @override + Widget build(BuildContext context) { + return VideoPlayer(_videoPlayerController); + } + + @override + void initState() { + _videoPlayerController = VideoPlayerController.file(widget.file) + ..initialize(); + super.initState(); + } + + @override + void dispose() { + _videoPlayerController.dispose(); + super.dispose(); + } +} diff --git a/svgs/icon_camera.svg b/svgs/icon_camera.svg new file mode 100644 index 00000000..0bf3122d --- /dev/null +++ b/svgs/icon_camera.svg @@ -0,0 +1,3 @@ + + + From dd829e18bccbf7c0649a360ac5823f21b706684c Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Wed, 18 Nov 2020 19:32:54 +0530 Subject: [PATCH 0392/1140] feat: Added share user selection and text input --- lib/src/image_footer.dart | 400 ++++++++++++++++++++++++-------------- 1 file changed, 258 insertions(+), 142 deletions(-) diff --git a/lib/src/image_footer.dart b/lib/src/image_footer.dart index 37ddf58f..1d74d017 100644 --- a/lib/src/image_footer.dart +++ b/lib/src/image_footer.dart @@ -1,9 +1,12 @@ +import 'dart:math'; + import 'package:cached_network_image/cached_network_image.dart'; import 'package:flutter/material.dart'; import 'package:stream_chat/stream_chat.dart'; import 'package:stream_chat_flutter/src/back_button.dart'; import 'package:stream_chat_flutter/src/channel_info.dart'; import 'package:stream_chat_flutter/src/channel_name.dart'; +import 'package:stream_chat_flutter/src/message_input.dart'; import 'package:stream_chat_flutter/src/stream_chat.dart'; import 'package:stream_chat_flutter/src/stream_chat_theme.dart'; import 'package:stream_chat_flutter/src/stream_icons.dart'; @@ -52,6 +55,9 @@ class _ImageFooterState extends State { Future _userQuery; bool _userSearchMode = false; TextEditingController _searchController = TextEditingController(); + TextEditingController _messageController = TextEditingController(); + + List selectedUsers = []; @override void initState() { @@ -193,161 +199,182 @@ class _ImageFooterState extends State { showDialog( context: context, builder: (context) { - return StatefulBuilder(builder: (context, modalSetState) { - return Align( - alignment: - _userSearchMode ? Alignment.topCenter : Alignment.bottomCenter, - child: Material( - color: Colors.transparent, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(16.0), - ), - child: Stack( - children: [ - ListView( - children: [ - if (!_userSearchMode) - GestureDetector( - child: Container( - height: MediaQuery.of(context).size.height / 2, - color: Colors.transparent, + print('KEY ${MediaQuery.of(context).viewInsets.bottom}'); + print(MediaQuery.of(context).viewInsets.bottom == 0.0); + return Scaffold( + backgroundColor: Colors.transparent, + body: StatefulBuilder(builder: (modalContext, modalSetState) { + return Align( + alignment: + _userSearchMode ? Alignment.topCenter : Alignment.bottomCenter, + child: Material( + color: Colors.transparent, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(16.0), + ), + child: Stack( + children: [ + ListView( + children: [ + if (!_userSearchMode && MediaQuery.of(context).viewInsets.bottom == 0.0) + GestureDetector( + child: Container( + height: MediaQuery.of(modalContext).size.height / 2, + color: Colors.transparent, + ), + onTapUp: (val) { + Navigator.pop(modalContext); + }, ), - onTapUp: (val) { - Navigator.pop(context); - }, + Container( + margin: EdgeInsets.symmetric( + horizontal: 8.0, + ), + padding: EdgeInsets.symmetric( + vertical: 4.0, + ), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.only( + topRight: Radius.circular(16.0), + topLeft: Radius.circular(16.0), + )), + child: _buildTextInputSection(modalSetState), ), - Container( - margin: EdgeInsets.symmetric( - horizontal: 8.0, - ), - padding: EdgeInsets.symmetric( - vertical: 4.0, - ), - decoration: BoxDecoration( + Container( + margin: EdgeInsets.symmetric( + horizontal: 8.0, + ), + decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.only( - topRight: Radius.circular(16.0), - topLeft: Radius.circular(16.0), - )), - child: _buildTextInputSection(modalSetState), - ), - Container( - margin: EdgeInsets.symmetric( - horizontal: 8.0, - ), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.only( - bottomRight: - Radius.circular(_userSearchMode ? 16.0 : 0.0), - bottomLeft: - Radius.circular(_userSearchMode ? 16.0 : 0.0), + bottomRight: + Radius.circular(_userSearchMode ? 16.0 : 0.0), + bottomLeft: + Radius.circular(_userSearchMode ? 16.0 : 0.0), + ), ), - ), - child: FutureBuilder( - future: _userQuery, - builder: (context, snapshot) { - if (!snapshot.hasData) { - return Center( - child: CircularProgressIndicator(), - ); - } - - var filteredData = snapshot.data.users.toList(); - - if (_userSearchMode && - _searchController.text.length > 0) { - filteredData = snapshot.data.users - .where((element) => element.name - .toLowerCase() - .contains(_searchController.text - .toLowerCase())) - .toList(); - } - - return GridView.builder( - shrinkWrap: true, - physics: NeverScrollableScrollPhysics(), - itemBuilder: (context, position) { - var user = filteredData[position]; - - return Padding( - padding: const EdgeInsets.all(8.0), - child: Column( - mainAxisSize: MainAxisSize.min, - mainAxisAlignment: - MainAxisAlignment.start, - crossAxisAlignment: - CrossAxisAlignment.center, - children: [ - Stack( - children: [ - UserAvatar( - onTap: (user) {}, - user: user, - constraints: - BoxConstraints.tightFor( - height: 64, - width: 64, - ), - borderRadius: - BorderRadius.circular(32), - ), - ], - ), - Padding( - padding: const EdgeInsets.all(8.0), - child: Text( - user.name, - style: Theme.of(context) - .textTheme - .subtitle2, - textAlign: TextAlign.center, - maxLines: 2, - ), - ), - ], - ), + child: FutureBuilder( + future: _userQuery, + builder: (context, snapshot) { + if (!snapshot.hasData) { + return Center( + child: CircularProgressIndicator(), ); - }, - itemCount: filteredData.length, - gridDelegate: - SliverGridDelegateWithFixedCrossAxisCount( - crossAxisCount: 4, - childAspectRatio: 0.75, - ), - ); - }), - ), - ], - ), - if (!_userSearchMode) - Align( - alignment: Alignment.bottomCenter, - child: Container( - color: Colors.white, - height: 48.0, - margin: EdgeInsets.symmetric( - horizontal: 8.0, + } + + var filteredData = snapshot.data.users.toList(); + + if (_userSearchMode && + _searchController.text.length > 0) { + filteredData = snapshot.data.users + .where((element) => element.name + .toLowerCase() + .contains(_searchController.text + .toLowerCase())) + .toList(); + } + + return GridView.builder( + shrinkWrap: true, + physics: NeverScrollableScrollPhysics(), + itemBuilder: (context, position) { + var user = filteredData[position]; + var isUserSelected = + selectedUsers.contains(user); + + return Padding( + padding: const EdgeInsets.all(8.0), + child: Column( + mainAxisSize: MainAxisSize.min, + mainAxisAlignment: + MainAxisAlignment.start, + crossAxisAlignment: + CrossAxisAlignment.center, + children: [ + Stack( + children: [ + CircleAvatar( + maxRadius: 32.0, + child: UserAvatar( + onTap: (user) { + if (isUserSelected) { + selectedUsers.remove(user); + } else { + selectedUsers.add(user); + } + modalSetState(() {}); + }, + user: user, + constraints: + BoxConstraints.tightFor( + height: + isUserSelected ? 56 : 64, + width: + isUserSelected ? 56 : 64, + ), + borderRadius: + BorderRadius.circular(32), + ), + ), + ], + ), + Padding( + padding: const EdgeInsets.all(8.0), + child: Text( + user.name, + style: Theme.of(context) + .textTheme + .subtitle2, + textAlign: TextAlign.center, + maxLines: 2, + ), + ), + ], + ), + ); + }, + itemCount: filteredData.length, + gridDelegate: + SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: 4, + childAspectRatio: 0.75, + ), + ); + }), ), - child: SizedBox.expand( - child: Center( - child: Text( - 'Save to Photos', - style: TextStyle( - color: StreamChatTheme.of(context).accentColor, - fontWeight: FontWeight.bold, + ], + ), + if (!_userSearchMode && selectedUsers.isEmpty) + Align( + alignment: Alignment.bottomCenter, + child: Container( + color: Colors.white, + height: 48.0, + margin: EdgeInsets.symmetric( + horizontal: 8.0, + ), + child: SizedBox.expand( + child: Center( + child: Text( + 'Save to Photos', + style: TextStyle( + color: StreamChatTheme.of(modalContext).accentColor, + fontWeight: FontWeight.bold, + ), ), ), ), ), ), - ), - ], + if (!_userSearchMode && selectedUsers.isNotEmpty) + _buildShareTextInputSection(modalSetState), + ], + ), ), - ), - ); - }); + ); + }), + ); }, ); } @@ -458,6 +485,95 @@ class _ImageFooterState extends State { } } + Widget _buildShareTextInputSection(modalSetState) { + return Align( + alignment: Alignment.bottomCenter, + child: Container( + color: Colors.white, + height: 56.0, + child: Row( + children: [ + Expanded( + child: Padding( + padding: const EdgeInsets.only(left: 8.0), + child: TextField( + controller: _messageController, + onChanged: (val) { + modalSetState(() {}); + }, + onTap: () { + modalSetState(() {}); + setState(() {}); + }, + decoration: InputDecoration( + isDense: true, + prefixText: ' ', + hintText: 'Add a comment', + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(32.0), + borderSide: BorderSide( + color: Colors.black.withOpacity(0.16), + ), + ), + focusedBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(32.0), + borderSide: BorderSide( + color: Colors.black.withOpacity(0.16), + ) + ), + contentPadding: EdgeInsets.symmetric(vertical: 12.0), + ), + ), + ), + ), + AnimatedCrossFade( + crossFadeState: _messageController.text.isNotEmpty + ? CrossFadeState.showFirst + : CrossFadeState.showSecond, + firstChild: IconTheme( + data: + StreamChatTheme.of(context).channelTheme.messageInputButtonIconTheme, + child: Center( + child: Padding( + padding: const EdgeInsets.all(8.0), + child: InkWell( + onTap: () { + // sendMessage(); + }, + child: Transform.rotate( + angle: -pi / 2, + child: Icon( + StreamIcons.send_message, + color: StreamChatTheme.of(context).accentColor, + ),), + ), + ), + ), + ), + secondChild: IconTheme( + data: + StreamChatTheme.of(context).channelTheme.messageInputButtonIconTheme, + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Center( + child: InkWell( + onTap: () {}, + child: Icon( + StreamIcons.send_message, + color: Colors.grey, + ), + )), + ), + ), + duration: Duration(milliseconds: 300), + alignment: Alignment.center, + ), + ], + ), + ), + ); + } + Future _queryUsers(context) { return StreamChat.of(context).client.queryUsers( pagination: PaginationParams( From 6411afdee00728dd01042cded5fa2ab418de89ad Mon Sep 17 00:00:00 2001 From: xsahil03x Date: Wed, 18 Nov 2020 20:15:34 +0530 Subject: [PATCH 0393/1140] temp push --- example/lib/chips_input_text_field.dart | 142 ++++++++++++++++++++++++ example/lib/main.dart | 114 +++++++++++++++++-- 2 files changed, 245 insertions(+), 11 deletions(-) create mode 100644 example/lib/chips_input_text_field.dart diff --git a/example/lib/chips_input_text_field.dart b/example/lib/chips_input_text_field.dart new file mode 100644 index 00000000..e62773f7 --- /dev/null +++ b/example/lib/chips_input_text_field.dart @@ -0,0 +1,142 @@ +import 'package:flutter/material.dart'; +import 'package:stream_chat_flutter/src/stream_icons.dart'; + +typedef ChipBuilder = Widget Function(BuildContext context, T chip); +typedef OnChipAdded = void Function(T chip); +typedef OnChipRemoved = void Function(T chip); + +class ChipsInputTextField extends StatefulWidget { + final TextEditingController controller; + final FocusNode focusNode; + final ValueChanged onInputChanged; + final ChipBuilder chipBuilder; + final OnChipAdded onChipAdded; + final OnChipRemoved onChipRemoved; + final String hint; + + const ChipsInputTextField({ + Key key, + @required this.chipBuilder, + @required this.controller, + this.onInputChanged, + this.focusNode, + this.onChipAdded, + this.onChipRemoved, + this.hint = 'Type a name or group', + }) : super(key: key); + + @override + ChipInputTextFieldState createState() => ChipInputTextFieldState(); +} + +class ChipInputTextFieldState extends State> { + final _chips = {}; + bool _pauseItemAddition = false; + + void addItem(T item) { + if (!_pauseItemAddition) { + setState(() => _chips.add(item)); + if (widget.onChipAdded != null) widget.onChipAdded(item); + } + } + + void removeItem(T item) { + setState(() { + _chips.remove(item); + if (_chips.isEmpty) resumeItemAddition(); + }); + if (widget.focusNode != null) widget.focusNode.requestFocus(); + if (widget.onChipRemoved != null) widget.onChipRemoved(item); + } + + void pauseItemAddition() { + if (!_pauseItemAddition) { + setState(() => _pauseItemAddition = true); + } + } + + void resumeItemAddition() { + if (_pauseItemAddition) { + setState(() => _pauseItemAddition = false); + } + } + + @override + Widget build(BuildContext context) { + return Material( + elevation: 4, + color: Colors.white, + child: Container( + child: Padding( + padding: const EdgeInsets.symmetric( + vertical: 16.0, + horizontal: 16.0, + ), + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: const EdgeInsets.symmetric(vertical: 10.0), + child: Text( + 'TO:', + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.w500, + ), + ), + ), + SizedBox(width: 12), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + Wrap( + spacing: 4.0, + runSpacing: 4.0, + children: _chips.map((item) { + return widget.chipBuilder(context, item); + }).toList(), + ), + if (!_pauseItemAddition) ...[ + if (_chips.isNotEmpty) SizedBox(height: 4), + TextField( + controller: widget.controller, + onChanged: widget.onInputChanged, + focusNode: widget.focusNode, + style: TextStyle(fontSize: 18), + decoration: InputDecoration( + isDense: true, + border: InputBorder.none, + focusedBorder: InputBorder.none, + enabledBorder: InputBorder.none, + errorBorder: InputBorder.none, + disabledBorder: InputBorder.none, + contentPadding: const EdgeInsets.symmetric( + vertical: 8, + ), + hintText: widget.hint, + hintStyle: TextStyle(fontSize: 18)), + ), + ] + ], + ), + ), + SizedBox(width: 12), + IconButton( + icon: Icon( + _chips.isEmpty ? StreamIcons.user : StreamIcons.user_add, + ), + onPressed: () { + resumeItemAddition(); + }, + visualDensity: VisualDensity.compact, + padding: const EdgeInsets.all(0), + ), + ], + ), + ), + ), + ); + } +} diff --git a/example/lib/main.dart b/example/lib/main.dart index 0f84c3a8..fa1c14a6 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -6,6 +6,7 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_secure_storage/flutter_secure_storage.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; +import 'chips_input_text_field.dart'; import 'notifications_service.dart'; @@ -268,7 +269,7 @@ class CreateChannelPage extends StatefulWidget { } class _CreateChannelPageState extends State { - List selectedUsers = []; + final selectedUsers = {}; @override Widget build(BuildContext context) { @@ -282,7 +283,7 @@ class _CreateChannelPageState extends State { ), ), floatingActionButton: - selectedUsers.isNotEmpty ? _buildFAB(context) : SizedBox(), + selectedUsers.isNotEmpty ? _buildFAB(context) : null, body: _buildListView(), ); } @@ -325,7 +326,7 @@ class _CreateChannelPageState extends State { } } - _createChannel(context, selectedUsers, name); + _createChannel(context, selectedUsers.toList(), name); }, ); } @@ -407,10 +408,44 @@ class NewChatScreen extends StatefulWidget { } class _NewChatScreenState extends State { + final _chipInputTextFieldStateKey = + GlobalKey>(); + + TextEditingController _controller; + + ChipInputTextFieldState get _chipInputTextFieldState => + _chipInputTextFieldStateKey.currentState; + + String _userNameQuery = ''; + + final _selectedUsers = {}; + + bool _isSearchActive = false; + + @override + void initState() { + super.initState(); + _controller = TextEditingController() + ..addListener(() { + setState(() { + _userNameQuery = _controller.text; + _isSearchActive = _userNameQuery.isNotEmpty; + }); + }); + } + + @override + void dispose() { + _controller?.clear(); + _controller?.dispose(); + super.dispose(); + } + @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( + elevation: 0, backgroundColor: Colors.white, title: Text( 'New Chat', @@ -418,14 +453,71 @@ class _NewChatScreenState extends State { ), ), body: UsersBloc( - child: UserListView( - pagination: PaginationParams( - limit: 25, - ), - sort: [ - SortOption( - 'name', - direction: SortOption.ASC, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + ChipsInputTextField( + key: _chipInputTextFieldStateKey, + controller: _controller, + focusNode: FocusNode(), + chipBuilder: (context, user) { + return InputChip( + key: ObjectKey(user), + label: Text( + user.name, + style: TextStyle(color: Colors.black), + ), + avatar: UserAvatar( + user: user, + ), + onDeleted: () => _chipInputTextFieldState.removeItem(user), + materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, + ); + }, + onChipAdded: (user) { + setState(() => _selectedUsers.add(user)); + }, + onChipRemoved: (user) { + setState(() => _selectedUsers.remove(user)); + }, + ), + Container( + width: double.maxFinite, + color: Colors.white54, + child: Padding( + padding: const EdgeInsets.symmetric( + vertical: 8, + horizontal: 8, + ), + child: Text( + _isSearchActive + ? "Matches for \"$_userNameQuery\"" + : 'On the platform', + style: TextStyle( + fontWeight: FontWeight.w500, + ), + ), + ), + ), + Expanded( + child: UserListView( + filterByUserName: _userNameQuery, + selectedUsers: _selectedUsers, + groupAlphabetically: _isSearchActive ? false : true, + onUserTap: (user, _) { + if (!_selectedUsers.contains(user)) { + _controller.clear(); + _chipInputTextFieldState + ..addItem(user) + ..pauseItemAddition(); + } + }, + pagination: PaginationParams( + limit: 25, + ), + ), + ), + MessageInput( ), ], ), From 6c4bcd2073a5f52473d26a3304aa29ac6b3e1fa4 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Wed, 18 Nov 2020 18:06:27 +0100 Subject: [PATCH 0394/1140] fix messageinput --- example/lib/main.dart | 149 ++++++++++++++++++++---------------- example/pubspec.yaml | 2 +- lib/src/message_input.dart | 20 ++--- lib/src/stream_channel.dart | 4 +- pubspec.yaml | 2 +- 5 files changed, 98 insertions(+), 79 deletions(-) diff --git a/example/lib/main.dart b/example/lib/main.dart index fa1c14a6..c4917e51 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -6,8 +6,8 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_secure_storage/flutter_secure_storage.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; -import 'chips_input_text_field.dart'; +import 'chips_input_text_field.dart'; import 'notifications_service.dart'; void main() async { @@ -422,9 +422,12 @@ class _NewChatScreenState extends State { bool _isSearchActive = false; + Channel channel; + @override void initState() { super.initState(); + channel = StreamChat.of(context).client.channel('messaging'); _controller = TextEditingController() ..addListener(() { setState(() { @@ -452,74 +455,88 @@ class _NewChatScreenState extends State { style: TextStyle(color: Colors.black), ), ), - body: UsersBloc( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - ChipsInputTextField( - key: _chipInputTextFieldStateKey, - controller: _controller, - focusNode: FocusNode(), - chipBuilder: (context, user) { - return InputChip( - key: ObjectKey(user), - label: Text( - user.name, - style: TextStyle(color: Colors.black), - ), - avatar: UserAvatar( - user: user, - ), - onDeleted: () => _chipInputTextFieldState.removeItem(user), - materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, - ); - }, - onChipAdded: (user) { - setState(() => _selectedUsers.add(user)); - }, - onChipRemoved: (user) { - setState(() => _selectedUsers.remove(user)); - }, - ), - Container( - width: double.maxFinite, - color: Colors.white54, - child: Padding( - padding: const EdgeInsets.symmetric( - vertical: 8, - horizontal: 8, - ), - child: Text( - _isSearchActive - ? "Matches for \"$_userNameQuery\"" - : 'On the platform', - style: TextStyle( - fontWeight: FontWeight.w500, - ), - ), - ), - ), - Expanded( - child: UserListView( - filterByUserName: _userNameQuery, - selectedUsers: _selectedUsers, - groupAlphabetically: _isSearchActive ? false : true, - onUserTap: (user, _) { - if (!_selectedUsers.contains(user)) { - _controller.clear(); - _chipInputTextFieldState - ..addItem(user) - ..pauseItemAddition(); - } + body: StreamChannel( + showLoading: false, + channel: channel, + child: UsersBloc( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + ChipsInputTextField( + key: _chipInputTextFieldStateKey, + controller: _controller, + focusNode: FocusNode(), + chipBuilder: (context, user) { + return InputChip( + key: ObjectKey(user), + label: Text( + user.name, + style: TextStyle(color: Colors.black), + ), + avatar: UserAvatar( + user: user, + ), + onDeleted: () => _chipInputTextFieldState.removeItem(user), + materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, + ); }, - pagination: PaginationParams( - limit: 25, + onChipAdded: (user) { + setState(() => _selectedUsers.add(user)); + }, + onChipRemoved: (user) { + setState(() => _selectedUsers.remove(user)); + }, + ), + Container( + width: double.maxFinite, + color: Colors.white54, + child: Padding( + padding: const EdgeInsets.symmetric( + vertical: 8, + horizontal: 8, + ), + child: Text( + _isSearchActive + ? "Matches for \"$_userNameQuery\"" + : 'On the platform', + style: TextStyle( + fontWeight: FontWeight.w500, + ), + ), ), ), - ), - MessageInput( - ), - ], + Expanded( + child: UserListView( + filterByUserName: _userNameQuery, + selectedUsers: _selectedUsers, + groupAlphabetically: _isSearchActive ? false : true, + onUserTap: (user, _) { + if (!_selectedUsers.contains(user)) { + _controller.clear(); + _chipInputTextFieldState + ..addItem(user) + ..pauseItemAddition(); + } + }, + pagination: PaginationParams( + limit: 25, + ), + ), + ), + MessageInput( + preMessageSending: (message) async { + channel.extraData = { + 'members': [ + ..._selectedUsers.map((e) => e.id), + channel.client.state.user.id, + ], + }; + await channel.watch(); + return message; + }, + ), + ], + ), ), ), ); diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 8fc2dadb..fca549d2 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -1,6 +1,6 @@ name: example description: A new Flutter project. -version: 1.0.59+61 +version: 1.0.60+62 environment: sdk: ">=2.2.2 <3.0.0" diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 6024169b..6f89db84 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -364,7 +364,10 @@ class MessageInputState extends State { controller: textEditingController, focusNode: _focusNode, onChanged: (s) { - StreamChannel.of(context).channel.keyStroke(); + StreamChannel.of(context) + .channel + .keyStroke() + .catchError((e) {}); setState(() { _messageIsPresent = s.trim().isNotEmpty; @@ -479,7 +482,9 @@ class MessageInputState extends State { void _checkMentions(String s, BuildContext context) { if (textEditingController.selection.isCollapsed && - (s.isNotEmpty && s[textEditingController.selection.start - 1] == '@' || + (s.isNotEmpty && + textEditingController.selection.start > 0 && + s[textEditingController.selection.start - 1] == '@' || textEditingController.text .substring(0, textEditingController.selection.start) .split(' ') @@ -1569,14 +1574,9 @@ class MessageInputState extends State { child: Padding( padding: const EdgeInsets.all(8.0), child: Center( - child: InkWell( - onTap: () { - sendMessage(); - }, - child: Icon( - _getIdleSendIcon(), - color: Colors.grey, - ), + child: Icon( + _getIdleSendIcon(), + color: Colors.grey, )), ), ); diff --git a/lib/src/stream_channel.dart b/lib/src/stream_channel.dart index ce19b261..6fafa070 100644 --- a/lib/src/stream_channel.dart +++ b/lib/src/stream_channel.dart @@ -12,12 +12,14 @@ class StreamChannel extends StatefulWidget { Key key, @required this.child, @required this.channel, + this.showLoading = true, }) : super( key: key, ); final Widget child; final Channel channel; + final bool showLoading; /// Use this method to get the current [StreamChannelState] instance static StreamChannelState of(BuildContext context) { @@ -155,7 +157,7 @@ class StreamChannelState extends State { future: widget.channel.initialized, initialData: widget.channel.state != null, builder: (context, snapshot) { - if (!snapshot.hasData || !snapshot.data) { + if (widget.showLoading && (!snapshot.hasData || !snapshot.data)) { return Container( height: 30, child: Center( diff --git a/pubspec.yaml b/pubspec.yaml index 9c1b0a29..7e7fe36b 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -27,7 +27,7 @@ dependencies: file_picker: ^2.0.12 image_picker: ^0.6.7+2 flutter_keyboard_visibility: ^3.3.0 - stream_chat: ^0.2.13 + stream_chat: ^0.2.13+1 mime: ^0.9.6+3 visibility_detector: ^0.1.5 http_parser: ^3.1.4 From 7733cc74591904968e92968338ada29e580c0d0d Mon Sep 17 00:00:00 2001 From: xsahil03x Date: Thu, 19 Nov 2020 12:11:57 +0530 Subject: [PATCH 0395/1140] [NewChatScreen] Navigate to ChannelPage on successful messageSent --- example/lib/main.dart | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/example/lib/main.dart b/example/lib/main.dart index c4917e51..0be01886 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -534,6 +534,19 @@ class _NewChatScreenState extends State { await channel.watch(); return message; }, + onMessageSent: (_) { + Navigator.pushReplacement( + context, + MaterialPageRoute( + builder: (context) { + return StreamChannel( + child: ChannelPage(), + channel: channel, + ); + }, + ), + ); + }, ), ], ), From 83d68c4baf8c60ebf5c52ce85de9cb0ee1424257 Mon Sep 17 00:00:00 2001 From: xsahil03x Date: Thu, 19 Nov 2020 13:14:08 +0530 Subject: [PATCH 0396/1140] [NewChatScreen] Add create group button, Finishing touches --- example/lib/chips_input_text_field.dart | 2 +- example/lib/main.dart | 28 ++++++++++++- example/lib/neumorphic_button.dart | 52 +++++++++++++++++++++++++ 3 files changed, 80 insertions(+), 2 deletions(-) create mode 100644 example/lib/neumorphic_button.dart diff --git a/example/lib/chips_input_text_field.dart b/example/lib/chips_input_text_field.dart index e62773f7..ef8229c8 100644 --- a/example/lib/chips_input_text_field.dart +++ b/example/lib/chips_input_text_field.dart @@ -64,7 +64,7 @@ class ChipInputTextFieldState extends State> { @override Widget build(BuildContext context) { return Material( - elevation: 4, + elevation: 2, color: Colors.white, child: Container( child: Padding( diff --git a/example/lib/main.dart b/example/lib/main.dart index 0be01886..f681129d 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -9,6 +9,7 @@ import 'package:stream_chat_flutter/stream_chat_flutter.dart'; import 'chips_input_text_field.dart'; import 'notifications_service.dart'; +import 'neumorphic_button.dart'; void main() async { WidgetsFlutterBinding.ensureInitialized(); @@ -487,9 +488,34 @@ class _NewChatScreenState extends State { setState(() => _selectedUsers.remove(user)); }, ), + if (!_isSearchActive) + Container( + color: Colors.white54, + child: InkWell( + onTap: () {}, + child: Row( + children: [ + NeumorphicButton( + child: Icon( + StreamIcons.group, + color: Colors.blue.shade700, + ), + ), + SizedBox(width: 8), + Text( + 'Create a Group', + style: TextStyle( + fontWeight: FontWeight.w500, + fontSize: 18, + ), + ), + ], + ), + ), + ), Container( width: double.maxFinite, - color: Colors.white54, + color: Colors.grey.shade50, child: Padding( padding: const EdgeInsets.symmetric( vertical: 8, diff --git a/example/lib/neumorphic_button.dart b/example/lib/neumorphic_button.dart new file mode 100644 index 00000000..c738cecd --- /dev/null +++ b/example/lib/neumorphic_button.dart @@ -0,0 +1,52 @@ +import 'package:flutter/material.dart'; + +extension ColorUtils on Color { + Color mix(Color another, double amount) { + return Color.lerp(this, another, amount); + } +} + +class NeumorphicButton extends StatelessWidget { + final Widget child; + final Color backgroundColor; + final EdgeInsets margin; + final EdgeInsets padding; + + const NeumorphicButton({ + Key key, + @required this.child, + this.backgroundColor = Colors.white, + this.margin = const EdgeInsets.all(8), + this.padding = const EdgeInsets.all(14), + }) : super(key: key); + + @override + Widget build(BuildContext context) { + return Container( + child: child, + margin: margin, + padding: padding, + decoration: BoxDecoration( + shape: BoxShape.circle, + color: backgroundColor, + gradient: LinearGradient( + begin: Alignment.topLeft, + end: Alignment.bottomRight, + colors: [ + backgroundColor.mix(Colors.white, 0.2), + backgroundColor.mix(Colors.black, 0.1), + ]), + boxShadow: [ + BoxShadow( + blurRadius: 1, + color: backgroundColor.mix(Colors.white, 0.6), + ), + BoxShadow( + blurRadius: 1, + color: backgroundColor.mix(Colors.black, 0.3), + ) + ], + ), + ); + } +} From 1a21dc27a2f080404857aef69699dbf6233fc32f Mon Sep 17 00:00:00 2001 From: xsahil03x Date: Thu, 19 Nov 2020 13:20:55 +0530 Subject: [PATCH 0397/1140] [Drawer,NewChatScreen] Navigate to NewGroupChatScreen on "New Group" button press. --- example/lib/chips_input_text_field.dart | 2 +- example/lib/main.dart | 33 ++++++++++++++++++++++++- 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/example/lib/chips_input_text_field.dart b/example/lib/chips_input_text_field.dart index ef8229c8..e62773f7 100644 --- a/example/lib/chips_input_text_field.dart +++ b/example/lib/chips_input_text_field.dart @@ -64,7 +64,7 @@ class ChipInputTextFieldState extends State> { @override Widget build(BuildContext context) { return Material( - elevation: 2, + elevation: 4, color: Colors.white, child: Container( child: Padding( diff --git a/example/lib/main.dart b/example/lib/main.dart index f681129d..82fee6b2 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -121,6 +121,12 @@ class ChannelListPage extends StatelessWidget { ), ), ListTile( + onTap: () { + Navigator.push( + context, + MaterialPageRoute(builder: (_) => NewGroupChatScreen()), + ); + }, leading: Icon(StreamIcons.group), title: Text( 'New group', @@ -492,7 +498,12 @@ class _NewChatScreenState extends State { Container( color: Colors.white54, child: InkWell( - onTap: () {}, + onTap: () { + Navigator.push( + context, + MaterialPageRoute(builder: (_) => NewGroupChatScreen()), + ); + }, child: Row( children: [ NeumorphicButton( @@ -581,3 +592,23 @@ class _NewChatScreenState extends State { ); } } + +class NewGroupChatScreen extends StatefulWidget { + @override + _NewGroupChatScreenState createState() => _NewGroupChatScreenState(); +} + +class _NewGroupChatScreenState extends State { + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + backgroundColor: Colors.white, + title: Text( + 'Add Group Members', + style: TextStyle(color: Colors.black), + ), + ), + ); + } +} From 33e91ff18801dbe4205fc523b2f9c8eb0bd05531 Mon Sep 17 00:00:00 2001 From: xsahil03x Date: Thu, 19 Nov 2020 15:11:40 +0530 Subject: [PATCH 0398/1140] [New Group Chat] Complete add group members screen --- example/lib/main.dart | 168 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 168 insertions(+) diff --git a/example/lib/main.dart b/example/lib/main.dart index 82fee6b2..907d4ec3 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -599,15 +599,183 @@ class NewGroupChatScreen extends StatefulWidget { } class _NewGroupChatScreenState extends State { + TextEditingController _controller; + + String _userNameQuery = ''; + + final _selectedUsers = {}; + + bool _isSearchActive = false; + + @override + void initState() { + super.initState(); + _controller = TextEditingController() + ..addListener(() { + setState(() { + _userNameQuery = _controller.text; + _isSearchActive = _userNameQuery.isNotEmpty; + }); + }); + } + + @override + void dispose() { + _controller?.clear(); + _controller?.dispose(); + super.dispose(); + } + @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( + elevation: 2, backgroundColor: Colors.white, title: Text( 'Add Group Members', style: TextStyle(color: Colors.black), ), + actions: [ + if (_selectedUsers.isNotEmpty) + IconButton( + icon: Icon( + StreamIcons.arrow_right, + color: Colors.blue.shade700, + ), + onPressed: () {}, + ) + ], + ), + body: UsersBloc( + child: Column( + children: [ + Container( + decoration: BoxDecoration( + border: Border.all( + color: Colors.grey.shade300, + ), + borderRadius: BorderRadius.circular(24), + ), + margin: const EdgeInsets.symmetric( + vertical: 8, + horizontal: 8, + ), + child: TextField( + onTap: () {}, + controller: _controller, + decoration: InputDecoration( + prefixIcon: Icon(StreamIcons.search), + hintText: 'Search', + contentPadding: const EdgeInsets.all(8), + border: OutlineInputBorder( + borderSide: BorderSide.none, + borderRadius: BorderRadius.circular(24), + ), + ), + ), + ), + if (_selectedUsers.isNotEmpty) + Container( + height: 120, + child: ListView.separated( + scrollDirection: Axis.horizontal, + itemCount: _selectedUsers.length, + padding: const EdgeInsets.all(8), + separatorBuilder: (_, __) => SizedBox(width: 16), + itemBuilder: (_, index) { + final user = _selectedUsers.elementAt(index); + return Column( + children: [ + Stack( + children: [ + UserAvatar( + user: user, + showOnlineStatus: true, + borderRadius: BorderRadius.circular(40), + constraints: BoxConstraints.tightFor( + height: 80, + width: 80, + ), + ), + Positioned( + top: 0, + right: 0, + child: InkWell( + onTap: () { + if (_selectedUsers.contains(user)) { + setState(() => _selectedUsers.remove(user)); + } + }, + child: Container( + decoration: BoxDecoration( + color: Colors.white, + shape: BoxShape.circle, + border: + Border.all(color: Colors.grey.shade100), + ), + child: Padding( + padding: const EdgeInsets.all(4.0), + child: Icon( + Icons.clear_rounded, + size: 16, + ), + ), + ), + ), + ) + ], + ), + SizedBox(height: 4), + Text( + user.name.split(' ')[0], + style: TextStyle( + fontWeight: FontWeight.w500, + fontSize: 16, + ), + ), + ], + ); + }, + ), + ), + Container( + width: double.maxFinite, + color: Colors.grey.shade50, + child: Padding( + padding: const EdgeInsets.symmetric( + vertical: 8, + horizontal: 8, + ), + child: Text( + _isSearchActive + ? 'Matches for \"$_userNameQuery\"' + : 'On the platform', + style: TextStyle( + fontWeight: FontWeight.w500, + ), + ), + ), + ), + Expanded( + child: UserListView( + filterByUserName: _userNameQuery, + selectedUsers: _selectedUsers, + groupAlphabetically: _isSearchActive ? false : true, + onUserTap: (user, _) { + if (!_selectedUsers.contains(user)) { + setState(() { + _selectedUsers.add(user); + }); + } + }, + pagination: PaginationParams( + limit: 25, + ), + ), + ), + ], + ), ), ); } From 7bb769e0a6f0ad49026f0d4a09fcd557402f6fec Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Thu, 19 Nov 2020 12:32:28 +0100 Subject: [PATCH 0399/1140] update github action --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index a8e87c58..4b3e086a 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -8,7 +8,7 @@ jobs: steps: - uses: actions/checkout@v2 - name: Flutter action - uses: subosito/flutter-action@v1.3.2 + uses: subosito/flutter-action@v1.4.0 with: channel: 'stable' - name: Get dependencies From d3ae3a5e4d6d58d6c669c4661938d7165d7fd82e Mon Sep 17 00:00:00 2001 From: xsahil03x Date: Thu, 19 Nov 2020 17:06:44 +0530 Subject: [PATCH 0400/1140] [UserItem] Add "showLastSeen" property --- lib/src/user_item.dart | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/src/user_item.dart b/lib/src/user_item.dart index ef442440..d4331cf8 100644 --- a/lib/src/user_item.dart +++ b/lib/src/user_item.dart @@ -24,6 +24,7 @@ class UserItem extends StatelessWidget { this.onLongPress, this.onImageTap, this.selected = false, + this.showLastSeen = true, }) : super(key: key); /// Function called when tapping this widget @@ -41,6 +42,9 @@ class UserItem extends StatelessWidget { /// If true the [UserItem] will show a trailing checkmark final bool selected; + /// If true the [UserItem] will show the last seen + final bool showLastSeen; + @override Widget build(BuildContext context) { return ListTile( @@ -72,7 +76,7 @@ class UserItem extends StatelessWidget { ) : null, title: Text(user.name), - subtitle: _buildLastActive(context), + subtitle: showLastSeen ? _buildLastActive(context) : null, ); } From 382e77e4a419ef893b4115e74ef1e21e6568d8f2 Mon Sep 17 00:00:00 2001 From: xsahil03x Date: Thu, 19 Nov 2020 17:07:54 +0530 Subject: [PATCH 0401/1140] Expose UserItem from the package. --- lib/stream_chat_flutter.dart | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/stream_chat_flutter.dart b/lib/stream_chat_flutter.dart index 663e72a9..91ac68c8 100644 --- a/lib/stream_chat_flutter.dart +++ b/lib/stream_chat_flutter.dart @@ -32,3 +32,4 @@ export 'src/utils.dart'; export 'src/video_attachment.dart'; export 'src/users_bloc.dart'; export 'src/user_list_view.dart'; +export 'src/user_item.dart'; From 08bc56799dc5c7c4d50829ba2c03c718a9d99829 Mon Sep 17 00:00:00 2001 From: xsahil03x Date: Thu, 19 Nov 2020 17:38:36 +0530 Subject: [PATCH 0402/1140] [New Group Chat] Complete name of group chat screen. --- example/lib/main.dart | 174 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 173 insertions(+), 1 deletion(-) diff --git a/example/lib/main.dart b/example/lib/main.dart index 907d4ec3..9158b6b0 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -643,7 +643,16 @@ class _NewGroupChatScreenState extends State { StreamIcons.arrow_right, color: Colors.blue.shade700, ), - onPressed: () {}, + onPressed: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (_) => GroupChatDetailsScreen( + selectedUsers: _selectedUsers.toList(growable: false), + ), + ), + ); + }, ) ], ), @@ -780,3 +789,166 @@ class _NewGroupChatScreenState extends State { ); } } + +class GroupChatDetailsScreen extends StatefulWidget { + final List selectedUsers; + + const GroupChatDetailsScreen({ + Key key, + @required this.selectedUsers, + }) : super(key: key); + + @override + _GroupChatDetailsScreenState createState() => _GroupChatDetailsScreenState(); +} + +class _GroupChatDetailsScreenState extends State { + final _selectedUsers = []; + + TextEditingController _groupNameController; + + Channel _channel; + + bool _isGroupNameEmpty = true; + + @override + void initState() { + super.initState(); + _channel = StreamChat.of(context).client.channel('messaging'); + _selectedUsers.addAll(widget.selectedUsers); + _groupNameController = TextEditingController() + ..addListener(() { + final name = _groupNameController.text; + setState(() { + _isGroupNameEmpty = name.isEmpty; + }); + }); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + elevation: 2, + backgroundColor: Colors.white, + title: Text( + 'Name of Group Chat', + style: TextStyle(color: Colors.black), + ), + bottom: PreferredSize( + preferredSize: Size.fromHeight(kToolbarHeight), + child: Padding( + padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 16), + child: Row( + children: [ + Text( + 'NAME', + style: TextStyle( + fontWeight: FontWeight.w500, + fontSize: 16, + ), + ), + SizedBox(width: 16), + Expanded( + child: TextField( + controller: _groupNameController, + style: TextStyle(fontSize: 18), + decoration: InputDecoration( + isDense: true, + border: InputBorder.none, + focusedBorder: InputBorder.none, + enabledBorder: InputBorder.none, + errorBorder: InputBorder.none, + disabledBorder: InputBorder.none, + contentPadding: const EdgeInsets.symmetric( + vertical: 8, + ), + hintText: 'Choose a group chat name', + hintStyle: TextStyle(fontSize: 18)), + ), + ), + ], + ), + ), + ), + actions: [ + NeumorphicButton( + padding: const EdgeInsets.all(8), + margin: const EdgeInsets.symmetric(vertical: 8), + child: IconButton( + padding: const EdgeInsets.all(0), + icon: Icon(StreamIcons.check), + color: Colors.blue.shade700, + onPressed: _isGroupNameEmpty + ? null + : () async { + final groupName = _groupNameController.text; + final client = _channel.client; + _channel.extraData = { + 'members': [ + client.state.user.id, + ..._selectedUsers.map((e) => e.id), + ], + 'name': groupName, + }; + await _channel.watch(); + Navigator.of(context) + ..pop() + ..pushReplacement( + MaterialPageRoute( + builder: (context) { + return StreamChannel( + child: ChannelPage(), + channel: _channel, + ); + }, + ), + ); + }, + ), + ), + ], + ), + body: Column( + children: [ + Container( + width: double.maxFinite, + color: Colors.grey.shade50, + child: Padding( + padding: const EdgeInsets.symmetric( + vertical: 8, + horizontal: 8, + ), + child: Text( + '5 Members', + style: TextStyle( + fontWeight: FontWeight.w500, + ), + ), + ), + ), + Expanded( + child: ListView.separated( + itemCount: _selectedUsers.length, + separatorBuilder: (_, __) => Container( + height: 1, + color: Theme.of(context).brightness == Brightness.dark + ? Colors.white.withOpacity(0.1) + : Colors.black.withOpacity(0.1), + ), + itemBuilder: (_, index) { + final user = _selectedUsers[index]; + return UserItem( + key: ObjectKey(user), + user: user, + selected: true, + showLastSeen: false, + ); + }, + ), + ), + ], + ), + ); + } +} From 97b03910f1eeeee3670e1b3894e1b1933f9d75ab Mon Sep 17 00:00:00 2001 From: xsahil03x Date: Thu, 19 Nov 2020 17:47:50 +0530 Subject: [PATCH 0403/1140] Minor ui fixes --- example/lib/main.dart | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/example/lib/main.dart b/example/lib/main.dart index 9158b6b0..382c938d 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -671,7 +671,6 @@ class _NewGroupChatScreenState extends State { horizontal: 8, ), child: TextField( - onTap: () {}, controller: _controller, decoration: InputDecoration( prefixIcon: Icon(StreamIcons.search), @@ -811,6 +810,8 @@ class _GroupChatDetailsScreenState extends State { bool _isGroupNameEmpty = true; + int get _totalUsers => _selectedUsers.length; + @override void initState() { super.initState(); @@ -920,7 +921,7 @@ class _GroupChatDetailsScreenState extends State { horizontal: 8, ), child: Text( - '5 Members', + '$_totalUsers ${_totalUsers > 1 ? 'Members' : 'Member'}', style: TextStyle( fontWeight: FontWeight.w500, ), From 26e8ffeae3ebd1f779661f72641148e36a984440 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Thu, 19 Nov 2020 13:24:48 +0100 Subject: [PATCH 0404/1140] remove onchanged --- lib/src/message_input.dart | 3 --- 1 file changed, 3 deletions(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 5fef41f7..cd96119a 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -366,9 +366,6 @@ class MessageInputState extends State { keyboardType: widget.keyboardType, controller: textEditingController, focusNode: _focusNode, - onChanged: (s) { - _onChanged(context, s); - }, style: Theme.of(context).textTheme.bodyText2, autofocus: false, textAlignVertical: TextAlignVertical.center, From 0138f87c75f9dce2eddd6cca6664a1a483d7f422 Mon Sep 17 00:00:00 2001 From: xsahil03x Date: Thu, 19 Nov 2020 18:18:01 +0530 Subject: [PATCH 0405/1140] [NewChat, NewGroup] Add emptyState widget --- example/lib/main.dart | 58 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/example/lib/main.dart b/example/lib/main.dart index 382c938d..43a92d1b 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -558,6 +558,35 @@ class _NewChatScreenState extends State { pagination: PaginationParams( limit: 25, ), + emptyBuilder: (_) { + return LayoutBuilder( + builder: (context, viewportConstraints) { + return SingleChildScrollView( + physics: AlwaysScrollableScrollPhysics(), + child: ConstrainedBox( + constraints: BoxConstraints( + minHeight: viewportConstraints.maxHeight, + ), + child: Center( + child: Column( + children: [ + Padding( + padding: const EdgeInsets.all(24), + child: Icon( + StreamIcons.search, + size: 96, + color: Colors.grey, + ), + ), + Text('No user matches these keywords...'), + ], + ), + ), + ), + ); + }, + ); + }, ), ), MessageInput( @@ -780,6 +809,35 @@ class _NewGroupChatScreenState extends State { pagination: PaginationParams( limit: 25, ), + emptyBuilder: (_) { + return LayoutBuilder( + builder: (context, viewportConstraints) { + return SingleChildScrollView( + physics: AlwaysScrollableScrollPhysics(), + child: ConstrainedBox( + constraints: BoxConstraints( + minHeight: viewportConstraints.maxHeight, + ), + child: Center( + child: Column( + children: [ + Padding( + padding: const EdgeInsets.all(24), + child: Icon( + StreamIcons.search, + size: 96, + color: Colors.grey, + ), + ), + Text('No user matches these keywords...'), + ], + ), + ), + ), + ); + }, + ); + }, ), ), ], From f3c32148029f0ef5c04e976c6c598a471ca0f342 Mon Sep 17 00:00:00 2001 From: xsahil03x Date: Thu, 19 Nov 2020 18:18:55 +0530 Subject: [PATCH 0406/1140] [UserListView] Cleanup --- lib/src/user_list_view.dart | 22 +--------------------- 1 file changed, 1 insertion(+), 21 deletions(-) diff --git a/lib/src/user_list_view.dart b/lib/src/user_list_view.dart index c4e3f2ce..4a3ae96c 100644 --- a/lib/src/user_list_view.dart +++ b/lib/src/user_list_view.dart @@ -388,33 +388,13 @@ class _UserListViewState extends State }, userItem: (user) { final selected = widget.selectedUsers?.contains(user) ?? false; - - UserTapCallback onTap; - if (widget.onUserTap != null) { - onTap = widget.onUserTap; - } else { - onTap = (client, _) { - // Navigator.push( - // context, - // MaterialPageRoute( - // builder: (context) { - // return StreamChannel( - // child: widget.userWidget, - // channel: client, - // ); - // }, - // ), - // ); - }; - } - return Container( key: ValueKey('USER-${user.id}'), child: widget.userItemBuilder != null ? widget.userItemBuilder(context, user, selected) : UserItem( user: user, - onTap: (user) => onTap(user, widget.userWidget), + onTap: (user) => widget.onUserTap(user, widget.userWidget), onLongPress: widget.onUserLongPress, onImageTap: widget.onImageTap, selected: selected, From 1cbb10942f20f35a8ef62a235317ffd4d0f0db2b Mon Sep 17 00:00:00 2001 From: xsahil03x Date: Thu, 19 Nov 2020 18:32:49 +0530 Subject: [PATCH 0407/1140] Remove old create channel screen --- example/lib/main.dart | 147 ------------------------------------------ 1 file changed, 147 deletions(-) diff --git a/example/lib/main.dart b/example/lib/main.dart index 43a92d1b..f9250efe 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -167,14 +167,6 @@ class ChannelListPage extends StatelessWidget { ), ), ), - floatingActionButton: FloatingActionButton( - child: Icon(Icons.add), - onPressed: () { - Navigator.of(context).push(MaterialPageRoute(builder: (context) { - return CreateChannelPage(); - })); - }, - ), body: ChannelsBloc( child: ChannelListView( swipeToAction: true, @@ -270,145 +262,6 @@ class ThreadPage extends StatelessWidget { } } -class CreateChannelPage extends StatefulWidget { - @override - _CreateChannelPageState createState() => _CreateChannelPageState(); -} - -class _CreateChannelPageState extends State { - final selectedUsers = {}; - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - elevation: 0, - backgroundColor: Colors.transparent, - title: Text( - 'Create a channel', - style: Theme.of(context).textTheme.headline6, - ), - ), - floatingActionButton: - selectedUsers.isNotEmpty ? _buildFAB(context) : null, - body: _buildListView(), - ); - } - - Widget _buildListView() { - return UsersBloc( - child: UserListView( - pagination: PaginationParams( - limit: 25, - ), - sort: [ - SortOption( - 'name', - direction: SortOption.ASC, - ), - ], - onUserLongPress: (user) { - _selectUser(user); - }, - selectedUsers: selectedUsers, - onUserTap: (user, _) { - if (selectedUsers.isNotEmpty) { - return _selectUser(user); - } - _createChannel(context, [user]); - }, - ), - ); - } - - Widget _buildFAB(BuildContext context) { - return FloatingActionButton( - child: Icon(Icons.done), - onPressed: () async { - String name; - if (selectedUsers.length > 1) { - name = await _showEnterNameDialog(context); - if (name?.isNotEmpty != true) { - return; - } - } - - _createChannel(context, selectedUsers.toList(), name); - }, - ); - } - - Future _showEnterNameDialog(BuildContext context) { - final controller = TextEditingController(); - return showDialog( - context: context, - builder: (context) => SimpleDialog( - contentPadding: const EdgeInsets.all(16), - title: Text('Enter a name for the channel'), - children: [ - TextField( - controller: controller, - decoration: InputDecoration( - border: OutlineInputBorder(), - ), - ), - ButtonBar( - children: [ - FlatButton( - onPressed: () => Navigator.pop(context), - child: Text('Cancel'), - ), - FlatButton( - onPressed: () => Navigator.pop(context, controller.text), - child: Text('Ok'), - ), - ], - ), - ], - ), - ); - } - - Future _createChannel( - BuildContext context, - List users, [ - String name, - ]) async { - final client = StreamChat.of(context).client; - final channel = client.channel('messaging', extraData: { - 'members': [ - client.state.user.id, - ...users.map((e) => e.id), - ], - if (name != null) 'name': name, - }); - await channel.watch(); - Navigator.pushReplacement( - context, - MaterialPageRoute( - builder: (context) { - return StreamChannel( - child: ChannelPage(), - channel: channel, - ); - }, - ), - ); - } - - void _selectUser(User user) { - if (!selectedUsers.contains(user)) { - setState(() { - selectedUsers.add(user); - }); - } else { - setState(() { - selectedUsers.remove(user); - }); - } - } -} - class NewChatScreen extends StatefulWidget { @override _NewChatScreenState createState() => _NewChatScreenState(); From 822547b6442d749b4402384b8f31323db756cb79 Mon Sep 17 00:00:00 2001 From: xsahil03x Date: Thu, 19 Nov 2020 18:40:45 +0530 Subject: [PATCH 0408/1140] Release textEditingController listeners in dispose. --- example/lib/main.dart | 54 +++++++++++++++++++++++++++---------------- 1 file changed, 34 insertions(+), 20 deletions(-) diff --git a/example/lib/main.dart b/example/lib/main.dart index f9250efe..baddd1ee 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -284,22 +284,24 @@ class _NewChatScreenState extends State { Channel channel; + void _userNameListener() { + setState(() { + _userNameQuery = _controller.text; + _isSearchActive = _userNameQuery.isNotEmpty; + }); + } + @override void initState() { super.initState(); channel = StreamChat.of(context).client.channel('messaging'); - _controller = TextEditingController() - ..addListener(() { - setState(() { - _userNameQuery = _controller.text; - _isSearchActive = _userNameQuery.isNotEmpty; - }); - }); + _controller = TextEditingController()..addListener(_userNameListener); } @override void dispose() { _controller?.clear(); + _controller?.removeListener(_userNameListener); _controller?.dispose(); super.dispose(); } @@ -489,21 +491,23 @@ class _NewGroupChatScreenState extends State { bool _isSearchActive = false; + void _userNameListener() { + setState(() { + _userNameQuery = _controller.text; + _isSearchActive = _userNameQuery.isNotEmpty; + }); + } + @override void initState() { super.initState(); - _controller = TextEditingController() - ..addListener(() { - setState(() { - _userNameQuery = _controller.text; - _isSearchActive = _userNameQuery.isNotEmpty; - }); - }); + _controller = TextEditingController()..addListener(_userNameListener); } @override void dispose() { _controller?.clear(); + _controller?.removeListener(_userNameListener); _controller?.dispose(); super.dispose(); } @@ -723,18 +727,28 @@ class _GroupChatDetailsScreenState extends State { int get _totalUsers => _selectedUsers.length; + void _groupNameListener() { + final name = _groupNameController.text; + setState(() { + _isGroupNameEmpty = name.isEmpty; + }); + } + @override void initState() { super.initState(); _channel = StreamChat.of(context).client.channel('messaging'); _selectedUsers.addAll(widget.selectedUsers); _groupNameController = TextEditingController() - ..addListener(() { - final name = _groupNameController.text; - setState(() { - _isGroupNameEmpty = name.isEmpty; - }); - }); + ..addListener(_groupNameListener); + } + + @override + void dispose() { + _groupNameController?.clear(); + _groupNameController?.removeListener(_groupNameListener); + _groupNameController?.dispose(); + super.dispose(); } @override From 5421a447ba7870fbc5bcc3dbbdf14efebef30311 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Thu, 19 Nov 2020 16:22:16 +0100 Subject: [PATCH 0409/1140] init notifications --- example/lib/advanced_options_page.dart | 4 ++++ example/lib/main.dart | 3 +++ example/pubspec.yaml | 2 +- 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/example/lib/advanced_options_page.dart b/example/lib/advanced_options_page.dart index 56c9dbf0..c84ef58e 100644 --- a/example/lib/advanced_options_page.dart +++ b/example/lib/advanced_options_page.dart @@ -282,6 +282,10 @@ class _AdvancedOptionsPageState extends State { }), userToken, ); + + if (!kIsWeb) { + initNotifications(client); + } } catch (e) { var errorText = 'Error connecting, retry'; if (e is Map) { diff --git a/example/lib/main.dart b/example/lib/main.dart index 2e3f43e2..d42bb7af 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -30,6 +30,9 @@ void main() async { User(id: userId), token, ); + if (!kIsWeb) { + initNotifications(client); + } } runApp(MyApp(client)); diff --git a/example/pubspec.yaml b/example/pubspec.yaml index fca549d2..e5c11897 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -1,6 +1,6 @@ name: example description: A new Flutter project. -version: 1.0.60+62 +version: 1.0.61+63 environment: sdk: ">=2.2.2 <3.0.0" From 412c721ab8abe5274ccd901902f4294053da5c56 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Thu, 19 Nov 2020 21:01:17 +0530 Subject: [PATCH 0410/1140] feat: Added sharing and added actions for buttons --- lib/src/full_screen_image.dart | 4 + lib/src/giphy_attachment.dart | 36 ++- lib/src/image_actions_modal.dart | 60 ++-- lib/src/image_attachment.dart | 18 +- lib/src/image_footer.dart | 533 +++++++++++++++++-------------- lib/src/image_group.dart | 15 +- lib/src/image_header.dart | 15 +- 7 files changed, 397 insertions(+), 284 deletions(-) diff --git a/lib/src/full_screen_image.dart b/lib/src/full_screen_image.dart index 0001585f..ca302790 100644 --- a/lib/src/full_screen_image.dart +++ b/lib/src/full_screen_image.dart @@ -11,6 +11,7 @@ import '../stream_chat_flutter.dart'; class FullScreenImage extends StatefulWidget { /// The url of the image final List urls; + final Message message; final int startIndex; final String userName; @@ -20,6 +21,7 @@ class FullScreenImage extends StatefulWidget { const FullScreenImage({ Key key, @required this.urls, + this.message, this.startIndex = 0, this.userName = '', this.sentAt, @@ -109,11 +111,13 @@ class _FullScreenImageState extends State onBackPressed: () { Navigator.of(context).pop(); }, + message: widget.message, ), ImageFooter( currentPage: _currentPage, totalPages: widget.urls.length, urls: widget.urls, + message: widget.message, ), ], ), diff --git a/lib/src/giphy_attachment.dart b/lib/src/giphy_attachment.dart index f99ccb27..e5464987 100644 --- a/lib/src/giphy_attachment.dart +++ b/lib/src/giphy_attachment.dart @@ -64,14 +64,20 @@ class GiphyAttachment extends StatelessWidget { padding: const EdgeInsets.all(8.0), child: GestureDetector( onTap: () { + final channel = StreamChannel.of(context).channel; + Navigator.push(context, MaterialPageRoute(builder: (_) { - return FullScreenImage( - urls: [attachment.imageUrl ?? - attachment.assetUrl ?? - attachment.thumbUrl], - userName: message.user.name, - sentAt: message.createdAt, + return StreamChannel( + channel: channel, + child: FullScreenImage( + urls: [attachment.imageUrl ?? + attachment.assetUrl ?? + attachment.thumbUrl], + userName: message.user.name, + sentAt: message.createdAt, + message: message, + ), ); })); }, @@ -299,13 +305,19 @@ class GiphyAttachment extends StatelessWidget { clipBehavior: Clip.antiAlias, child: GestureDetector( onTap: () { + final channel = StreamChannel.of(context).channel; + Navigator.push(context, MaterialPageRoute(builder: (_) { - return FullScreenImage( - urls: [attachment.imageUrl ?? - attachment.assetUrl ?? - attachment.thumbUrl], - userName: message.user.name, - sentAt: message.createdAt, + return StreamChannel( + channel: channel, + child: FullScreenImage( + urls: [attachment.imageUrl ?? + attachment.assetUrl ?? + attachment.thumbUrl], + userName: message.user.name, + sentAt: message.createdAt, + message: message, + ), ); })); }, diff --git a/lib/src/image_actions_modal.dart b/lib/src/image_actions_modal.dart index 03603795..8b39737d 100644 --- a/lib/src/image_actions_modal.dart +++ b/lib/src/image_actions_modal.dart @@ -6,10 +6,11 @@ import '../stream_chat_flutter.dart'; import 'stream_icons.dart'; class ImageActionsModal extends StatelessWidget { + final Message message; final String userName; final String sentAt; - ImageActionsModal({this.userName, this.sentAt}); + ImageActionsModal({this.message, this.userName, this.sentAt}); @override Widget build(BuildContext context) { @@ -21,20 +22,18 @@ class ImageActionsModal extends StatelessWidget { child: Stack( children: [ Positioned.fill( - child: Container( - decoration: BoxDecoration( + child: Container( + decoration: BoxDecoration( gradient: LinearGradient( - begin: Alignment.topCenter, - end: Alignment.bottomCenter, - colors: [ - Colors.black.withOpacity(0.8), - Colors.transparent, - ], - stops: [0.0, 0.4], - ) - ), - ) - ), + begin: Alignment.topCenter, + end: Alignment.bottomCenter, + colors: [ + Colors.black.withOpacity(0.8), + Colors.transparent, + ], + stops: [0.0, 0.4], + )), + )), _buildPage(context), ], ), @@ -70,8 +69,10 @@ class ImageActionsModal extends StatelessWidget { ), Text( sentAt, - style: - StreamChatTheme.of(context).channelPreviewTheme.subtitle.copyWith(color: Colors.white.withOpacity(0.5)), + style: StreamChatTheme.of(context) + .channelPreviewTheme + .subtitle + .copyWith(color: Colors.white.withOpacity(0.5)), ), ], ), @@ -104,11 +105,26 @@ class ImageActionsModal extends StatelessWidget { children: ListTile.divideTiles( context: context, tiles: [ - _buildButton(context, 'Reply', StreamIcons.curve_line_down_left, () {}), - _buildButton(context, 'Show in Chat', StreamIcons.eye, () {}), - _buildButton(context, 'Save Image', StreamIcons.save_1, () {}), + _buildButton(context, 'Reply', + StreamIcons.curve_line_down_left, () {}), + _buildButton(context, 'Show in Chat', StreamIcons.eye, + () { + Navigator.pop(context); + Navigator.pop(context); + }), + _buildButton( + context, 'Save Image', StreamIcons.save_1, () {}), _buildButton(context, 'Copy', StreamIcons.copy, () {}), - _buildButton(context, 'Delete', StreamIcons.delete, () {}, color: Colors.red), + if (StreamChat.of(context).user.id == message.user.id) + _buildButton(context, 'Delete', StreamIcons.delete, + () { + Navigator.pop(context); + Navigator.pop(context); + StreamChat.of(context).client.deleteMessage( + message, + StreamChannel.of(context).channel.cid, + ); + }, color: Colors.red), ], ).toList(), ), @@ -121,7 +137,9 @@ class ImageActionsModal extends StatelessWidget { ); } - Widget _buildButton(context, String title, IconData iconData, VoidCallback onTap, {Color color}) { + Widget _buildButton( + context, String title, IconData iconData, VoidCallback onTap, + {Color color}) { var titleStyle = TextStyle( fontSize: 14.5, color: Colors.black, diff --git a/lib/src/image_attachment.dart b/lib/src/image_attachment.dart index d493fa66..b429e064 100644 --- a/lib/src/image_attachment.dart +++ b/lib/src/image_attachment.dart @@ -43,12 +43,18 @@ class ImageAttachment extends StatelessWidget { context, MaterialPageRoute( builder: (_) { - return FullScreenImage( - urls: [attachment.imageUrl ?? - attachment.assetUrl ?? - attachment.thumbUrl], - userName: message.user.name, - sentAt: message.createdAt, + final channel = StreamChannel.of(context).channel; + + return StreamChannel( + channel: channel, + child: FullScreenImage( + urls: [attachment.imageUrl ?? + attachment.assetUrl ?? + attachment.thumbUrl], + userName: message.user.name, + sentAt: message.createdAt, + message: message, + ), ); }, ), diff --git a/lib/src/image_footer.dart b/lib/src/image_footer.dart index 1d74d017..02a8a6ef 100644 --- a/lib/src/image_footer.dart +++ b/lib/src/image_footer.dart @@ -11,6 +11,7 @@ import 'package:stream_chat_flutter/src/stream_chat.dart'; import 'package:stream_chat_flutter/src/stream_chat_theme.dart'; import 'package:stream_chat_flutter/src/stream_icons.dart'; import 'package:stream_chat_flutter/src/user_avatar.dart'; +import 'package:stream_chat_flutter/stream_chat_flutter.dart'; import './channel_name.dart'; import 'channel_image.dart'; @@ -31,6 +32,7 @@ class ImageFooter extends StatefulWidget { final int totalPages; final List urls; + final Message message; /// Creates a channel header ImageFooter({ @@ -41,6 +43,7 @@ class ImageFooter extends StatefulWidget { this.currentPage = 0, this.totalPages = 0, this.urls, + this.message, }) : preferredSize = Size.fromHeight(kToolbarHeight), super(key: key); @@ -57,7 +60,7 @@ class _ImageFooterState extends State { TextEditingController _searchController = TextEditingController(); TextEditingController _messageController = TextEditingController(); - List selectedUsers = []; + List _selectedUsers = []; @override void initState() { @@ -134,8 +137,8 @@ class _ImageFooterState extends State { decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.only( - topRight: Radius.circular(8.0), - topLeft: Radius.circular(8.0), + topRight: Radius.circular(16.0), + topLeft: Radius.circular(16.0), )), child: Stack( children: [ @@ -196,184 +199,197 @@ class _ImageFooterState extends State { } Widget _buildShareModal(context) { + final channel = StreamChannel.of(context).channel; + showDialog( context: context, builder: (context) { - print('KEY ${MediaQuery.of(context).viewInsets.bottom}'); - print(MediaQuery.of(context).viewInsets.bottom == 0.0); - return Scaffold( - backgroundColor: Colors.transparent, - body: StatefulBuilder(builder: (modalContext, modalSetState) { - return Align( - alignment: - _userSearchMode ? Alignment.topCenter : Alignment.bottomCenter, - child: Material( - color: Colors.transparent, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(16.0), - ), - child: Stack( - children: [ - ListView( - children: [ - if (!_userSearchMode && MediaQuery.of(context).viewInsets.bottom == 0.0) - GestureDetector( - child: Container( - height: MediaQuery.of(modalContext).size.height / 2, - color: Colors.transparent, + return StreamChannel( + channel: channel, + child: Scaffold( + backgroundColor: Colors.transparent, + body: StatefulBuilder(builder: (modalContext, modalSetState) { + return Align( + alignment: _userSearchMode + ? Alignment.topCenter + : Alignment.bottomCenter, + child: Material( + color: Colors.transparent, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(16.0), + ), + child: Stack( + children: [ + ListView( + children: [ + if (!_userSearchMode && + MediaQuery.of(context).viewInsets.bottom == 0.0) + GestureDetector( + child: Container( + height: + MediaQuery.of(modalContext).size.height / 2, + color: Colors.transparent, + ), + onTapUp: (val) { + Navigator.pop(modalContext); + }, ), - onTapUp: (val) { - Navigator.pop(modalContext); - }, + Container( + margin: EdgeInsets.symmetric( + horizontal: 8.0, + ), + padding: EdgeInsets.symmetric( + vertical: 4.0, + ), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.only( + topRight: Radius.circular(16.0), + topLeft: Radius.circular(16.0), + )), + child: _buildTextInputSection(modalSetState), ), - Container( - margin: EdgeInsets.symmetric( - horizontal: 8.0, - ), - padding: EdgeInsets.symmetric( - vertical: 4.0, - ), - decoration: BoxDecoration( + Container( + margin: EdgeInsets.symmetric( + horizontal: 8.0, + ), + decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.only( - topRight: Radius.circular(16.0), - topLeft: Radius.circular(16.0), - )), - child: _buildTextInputSection(modalSetState), - ), - Container( - margin: EdgeInsets.symmetric( - horizontal: 8.0, - ), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.only( - bottomRight: - Radius.circular(_userSearchMode ? 16.0 : 0.0), - bottomLeft: - Radius.circular(_userSearchMode ? 16.0 : 0.0), + bottomRight: Radius.circular( + _userSearchMode ? 16.0 : 0.0), + bottomLeft: Radius.circular( + _userSearchMode ? 16.0 : 0.0), + ), ), - ), - child: FutureBuilder( - future: _userQuery, - builder: (context, snapshot) { - if (!snapshot.hasData) { - return Center( - child: CircularProgressIndicator(), - ); - } - - var filteredData = snapshot.data.users.toList(); - - if (_userSearchMode && - _searchController.text.length > 0) { - filteredData = snapshot.data.users - .where((element) => element.name - .toLowerCase() - .contains(_searchController.text - .toLowerCase())) - .toList(); - } - - return GridView.builder( - shrinkWrap: true, - physics: NeverScrollableScrollPhysics(), - itemBuilder: (context, position) { - var user = filteredData[position]; - var isUserSelected = - selectedUsers.contains(user); - - return Padding( - padding: const EdgeInsets.all(8.0), - child: Column( - mainAxisSize: MainAxisSize.min, - mainAxisAlignment: - MainAxisAlignment.start, - crossAxisAlignment: - CrossAxisAlignment.center, - children: [ - Stack( - children: [ - CircleAvatar( - maxRadius: 32.0, - child: UserAvatar( - onTap: (user) { - if (isUserSelected) { - selectedUsers.remove(user); - } else { - selectedUsers.add(user); - } - modalSetState(() {}); - }, - user: user, - constraints: - BoxConstraints.tightFor( - height: - isUserSelected ? 56 : 64, - width: - isUserSelected ? 56 : 64, - ), - borderRadius: - BorderRadius.circular(32), - ), - ), - ], - ), - Padding( - padding: const EdgeInsets.all(8.0), - child: Text( - user.name, - style: Theme.of(context) - .textTheme - .subtitle2, - textAlign: TextAlign.center, - maxLines: 2, - ), - ), - ], - ), + child: FutureBuilder( + future: _userQuery, + builder: (context, snapshot) { + if (!snapshot.hasData) { + return Center( + child: CircularProgressIndicator(), ); - }, - itemCount: filteredData.length, - gridDelegate: - SliverGridDelegateWithFixedCrossAxisCount( - crossAxisCount: 4, - childAspectRatio: 0.75, - ), - ); - }), - ), - ], - ), - if (!_userSearchMode && selectedUsers.isEmpty) - Align( - alignment: Alignment.bottomCenter, - child: Container( - color: Colors.white, - height: 48.0, - margin: EdgeInsets.symmetric( - horizontal: 8.0, + } + + var filteredData = + snapshot.data.users.toList(); + + if (_userSearchMode && + _searchController.text.length > 0) { + filteredData = snapshot.data.users + .where((element) => element.name + .toLowerCase() + .contains(_searchController.text + .toLowerCase())) + .toList(); + } + + return GridView.builder( + shrinkWrap: true, + physics: NeverScrollableScrollPhysics(), + itemBuilder: (context, position) { + var user = filteredData[position]; + var isUserSelected = + _selectedUsers.contains(user); + + return Padding( + padding: const EdgeInsets.all(8.0), + child: Column( + mainAxisSize: MainAxisSize.min, + mainAxisAlignment: + MainAxisAlignment.start, + crossAxisAlignment: + CrossAxisAlignment.center, + children: [ + Stack( + children: [ + CircleAvatar( + maxRadius: 32.0, + child: UserAvatar( + onTap: (user) { + if (isUserSelected) { + _selectedUsers + .remove(user); + } else { + _selectedUsers.add(user); + } + modalSetState(() {}); + }, + user: user, + constraints: + BoxConstraints.tightFor( + height: isUserSelected + ? 56 + : 64, + width: isUserSelected + ? 56 + : 64, + ), + borderRadius: + BorderRadius.circular( + 32), + ), + ), + ], + ), + Padding( + padding: + const EdgeInsets.all(8.0), + child: Text( + user.name, + style: Theme.of(context) + .textTheme + .subtitle2, + textAlign: TextAlign.center, + maxLines: 2, + ), + ), + ], + ), + ); + }, + itemCount: filteredData.length, + gridDelegate: + SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: 4, + childAspectRatio: 0.75, + ), + ); + }), ), - child: SizedBox.expand( - child: Center( - child: Text( - 'Save to Photos', - style: TextStyle( - color: StreamChatTheme.of(modalContext).accentColor, - fontWeight: FontWeight.bold, + ], + ), + if (!_userSearchMode && _selectedUsers.isEmpty) + Align( + alignment: Alignment.bottomCenter, + child: Container( + color: Colors.white, + height: 48.0, + margin: EdgeInsets.symmetric( + horizontal: 8.0, + ), + child: SizedBox.expand( + child: Center( + child: Text( + 'Save to Photos', + style: TextStyle( + color: StreamChatTheme.of(modalContext) + .accentColor, + fontWeight: FontWeight.bold, + ), ), ), ), ), ), - ), - if (!_userSearchMode && selectedUsers.isNotEmpty) - _buildShareTextInputSection(modalSetState), - ], + if (!_userSearchMode && _selectedUsers.isNotEmpty) + _buildShareTextInputSection(modalSetState), + ], + ), ), - ), - ); - }), + ); + }), + ), ); }, ); @@ -487,91 +503,93 @@ class _ImageFooterState extends State { Widget _buildShareTextInputSection(modalSetState) { return Align( - alignment: Alignment.bottomCenter, - child: Container( - color: Colors.white, - height: 56.0, - child: Row( - children: [ - Expanded( - child: Padding( - padding: const EdgeInsets.only(left: 8.0), - child: TextField( - controller: _messageController, - onChanged: (val) { - modalSetState(() {}); - }, - onTap: () { - modalSetState(() {}); - setState(() {}); - }, - decoration: InputDecoration( - isDense: true, - prefixText: ' ', - hintText: 'Add a comment', - border: OutlineInputBorder( + alignment: Alignment.bottomCenter, + child: Container( + color: Colors.white, + height: 56.0, + child: Row( + children: [ + Expanded( + child: Padding( + padding: const EdgeInsets.only(left: 8.0), + child: TextField( + controller: _messageController, + onChanged: (val) { + modalSetState(() {}); + }, + onTap: () { + modalSetState(() {}); + setState(() {}); + }, + decoration: InputDecoration( + isDense: true, + prefixText: ' ', + hintText: 'Add a comment', + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(32.0), + borderSide: BorderSide( + color: Colors.black.withOpacity(0.16), + ), + ), + focusedBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(32.0), borderSide: BorderSide( color: Colors.black.withOpacity(0.16), - ), - ), - focusedBorder: OutlineInputBorder( - borderRadius: BorderRadius.circular(32.0), - borderSide: BorderSide( - color: Colors.black.withOpacity(0.16), - ) - ), - contentPadding: EdgeInsets.symmetric(vertical: 12.0), - ), + )), + contentPadding: EdgeInsets.symmetric(vertical: 12.0), ), ), ), - AnimatedCrossFade( - crossFadeState: _messageController.text.isNotEmpty - ? CrossFadeState.showFirst - : CrossFadeState.showSecond, - firstChild: IconTheme( - data: - StreamChatTheme.of(context).channelTheme.messageInputButtonIconTheme, - child: Center( - child: Padding( - padding: const EdgeInsets.all(8.0), - child: InkWell( - onTap: () { - // sendMessage(); - }, - child: Transform.rotate( - angle: -pi / 2, - child: Icon( - StreamIcons.send_message, - color: StreamChatTheme.of(context).accentColor, - ),), - ), - ), - ), - ), - secondChild: IconTheme( - data: - StreamChatTheme.of(context).channelTheme.messageInputButtonIconTheme, + ), + AnimatedCrossFade( + crossFadeState: _messageController.text.isNotEmpty + ? CrossFadeState.showFirst + : CrossFadeState.showSecond, + firstChild: IconTheme( + data: StreamChatTheme.of(context) + .channelTheme + .messageInputButtonIconTheme, + child: Center( child: Padding( padding: const EdgeInsets.all(8.0), - child: Center( - child: InkWell( - onTap: () {}, - child: Icon( - StreamIcons.send_message, - color: Colors.grey, - ), - )), + child: InkWell( + onTap: () { + sendMessage(); + }, + child: Transform.rotate( + angle: -pi / 2, + child: Icon( + StreamIcons.send_message, + color: StreamChatTheme.of(context).accentColor, + ), + ), + ), ), ), - duration: Duration(milliseconds: 300), - alignment: Alignment.center, ), - ], - ), + secondChild: IconTheme( + data: StreamChatTheme.of(context) + .channelTheme + .messageInputButtonIconTheme, + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Center( + child: InkWell( + onTap: () {}, + child: Icon( + StreamIcons.send_message, + color: Colors.grey, + ), + )), + ), + ), + duration: Duration(milliseconds: 300), + alignment: Alignment.center, + ), + ], ), - ); + ), + ); } Future _queryUsers(context) { @@ -587,4 +605,43 @@ class _ImageFooterState extends State { ], ); } + + /// Sends the current message + void sendMessage() async { + var text = _messageController.text.trim(); + + final attachments = widget.message.attachments; + + _messageController.clear(); + + final client = StreamChat.of(context).client; + + for(var user in _selectedUsers) { + var c = client.channel('messaging', extraData: { + 'members': [ + user.id, + StreamChat.of(context).user.id, + ], + }); + + await c.create(); + + Future sendingFuture; + Message message; + + message = (Message()).copyWith( + text: text, + attachments: attachments, + mentionedUsers: [], + showInChannel: false, + ); + + sendingFuture = c.sendMessage(message); + + await sendingFuture; + } + + Navigator.pop(context); + Navigator.pop(context); + } } diff --git a/lib/src/image_group.dart b/lib/src/image_group.dart index a97bde81..afccaf7a 100644 --- a/lib/src/image_group.dart +++ b/lib/src/image_group.dart @@ -4,6 +4,7 @@ import 'package:carousel_slider/carousel_slider.dart'; import 'package:flutter/material.dart'; import 'package:stream_chat/stream_chat.dart'; import 'package:stream_chat_flutter/src/full_screen_image.dart'; +import 'package:stream_chat_flutter/stream_chat_flutter.dart'; class ImageGroup extends StatelessWidget { const ImageGroup({ @@ -107,14 +108,20 @@ class ImageGroup extends StatelessWidget { BuildContext context, [ int index, ]) { + final channel = StreamChannel.of(context).channel; + Navigator.push( context, MaterialPageRoute( builder: (context) => - FullScreenImage(urls: images.map((e) => e.imageUrl ?? e.thumbUrl ?? e.assetUrl).toList(), - startIndex: index, - userName: message.user.name, - sentAt: message.createdAt, + StreamChannel( + channel: channel, + child: FullScreenImage(urls: images.map((e) => e.imageUrl ?? e.thumbUrl ?? e.assetUrl).toList(), + startIndex: index, + userName: message.user.name, + sentAt: message.createdAt, + message: message, + ), ), ), ); diff --git a/lib/src/image_header.dart b/lib/src/image_header.dart index b4dfb36d..29c36ad9 100644 --- a/lib/src/image_header.dart +++ b/lib/src/image_header.dart @@ -25,12 +25,15 @@ class ImageHeader extends StatelessWidget implements PreferredSizeWidget { /// Callback to call when the image is tapped. final VoidCallback onImageTap; + final Message message; + final String userName; final String sentAt; /// Creates a channel header ImageHeader({ Key key, + this.message, this.showBackButton = true, this.onBackPressed, this.onTitleTap, @@ -103,12 +106,18 @@ class ImageHeader extends StatelessWidget implements PreferredSizeWidget { final Size preferredSize; void _showMessageActionModalBottomSheet(BuildContext context) { + final channel = StreamChannel.of(context).channel; + showDialog( context: context, builder: (context) { - return ImageActionsModal( - userName: userName, - sentAt: sentAt, + return StreamChannel( + channel: channel, + child: ImageActionsModal( + userName: userName, + sentAt: sentAt, + message: message, + ), ); }); } From fbb1d52db9c343eb5900810d2d4d4cf01dfe47ea Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Thu, 19 Nov 2020 21:05:23 +0530 Subject: [PATCH 0411/1140] fix: Fixed behavior after sharing --- lib/src/image_footer.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/image_footer.dart b/lib/src/image_footer.dart index 02a8a6ef..83960091 100644 --- a/lib/src/image_footer.dart +++ b/lib/src/image_footer.dart @@ -641,7 +641,7 @@ class _ImageFooterState extends State { await sendingFuture; } - Navigator.pop(context); + _selectedUsers.clear(); Navigator.pop(context); } } From 389656a4777d34923bc82ac4172781a4ee4c63c8 Mon Sep 17 00:00:00 2001 From: xsahil03x Date: Fri, 20 Nov 2020 12:06:00 +0530 Subject: [PATCH 0412/1140] UI nit picks --- example/lib/chips_input_text_field.dart | 44 ++++----- example/lib/main.dart | 125 ++++++++++++++++-------- lib/src/user_item.dart | 21 ++-- lib/src/user_list_view.dart | 10 +- 4 files changed, 124 insertions(+), 76 deletions(-) diff --git a/example/lib/chips_input_text_field.dart b/example/lib/chips_input_text_field.dart index e62773f7..e3b0eae7 100644 --- a/example/lib/chips_input_text_field.dart +++ b/example/lib/chips_input_text_field.dart @@ -64,24 +64,20 @@ class ChipInputTextFieldState extends State> { @override Widget build(BuildContext context) { return Material( - elevation: 4, + elevation: 1, color: Colors.white, child: Container( child: Padding( - padding: const EdgeInsets.symmetric( - vertical: 16.0, - horizontal: 16.0, - ), + padding: const EdgeInsets.fromLTRB(16, 16, 16, 16), child: Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ Padding( - padding: const EdgeInsets.symmetric(vertical: 10.0), + padding: const EdgeInsets.symmetric(vertical: 4.0), child: Text( 'TO:', style: TextStyle( - fontSize: 16, - fontWeight: FontWeight.w500, + color: Colors.black.withOpacity(0.5), ), ), ), @@ -92,46 +88,48 @@ class ChipInputTextFieldState extends State> { mainAxisSize: MainAxisSize.min, children: [ Wrap( - spacing: 4.0, + spacing: 8.0, runSpacing: 4.0, children: _chips.map((item) { return widget.chipBuilder(context, item); }).toList(), ), if (!_pauseItemAddition) ...[ - if (_chips.isNotEmpty) SizedBox(height: 4), TextField( controller: widget.controller, onChanged: widget.onInputChanged, focusNode: widget.focusNode, - style: TextStyle(fontSize: 18), decoration: InputDecoration( - isDense: true, - border: InputBorder.none, - focusedBorder: InputBorder.none, - enabledBorder: InputBorder.none, - errorBorder: InputBorder.none, - disabledBorder: InputBorder.none, - contentPadding: const EdgeInsets.symmetric( - vertical: 8, - ), - hintText: widget.hint, - hintStyle: TextStyle(fontSize: 18)), + isDense: true, + border: InputBorder.none, + focusedBorder: InputBorder.none, + enabledBorder: InputBorder.none, + errorBorder: InputBorder.none, + disabledBorder: InputBorder.none, + contentPadding: const EdgeInsets.only(top: 4.0), + hintText: widget.hint, + ), ), ] ], ), ), - SizedBox(width: 12), IconButton( icon: Icon( _chips.isEmpty ? StreamIcons.user : StreamIcons.user_add, + color: Colors.black.withOpacity(0.5), ), onPressed: () { resumeItemAddition(); }, + alignment: Alignment.topRight, visualDensity: VisualDensity.compact, padding: const EdgeInsets.all(0), + splashRadius: 24, + constraints: BoxConstraints.tightFor( + height: 24, + width: 24, + ), ), ], ), diff --git a/example/lib/main.dart b/example/lib/main.dart index baddd1ee..f187ac05 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -312,10 +312,12 @@ class _NewChatScreenState extends State { appBar: AppBar( elevation: 0, backgroundColor: Colors.white, + leading: const StreamBackButton(), title: Text( 'New Chat', style: TextStyle(color: Colors.black), ), + centerTitle: true, ), body: StreamChannel( showLoading: false, @@ -329,17 +331,31 @@ class _NewChatScreenState extends State { controller: _controller, focusNode: FocusNode(), chipBuilder: (context, user) { - return InputChip( - key: ObjectKey(user), - label: Text( - user.name, - style: TextStyle(color: Colors.black), - ), - avatar: UserAvatar( - user: user, - ), - onDeleted: () => _chipInputTextFieldState.removeItem(user), - materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, + return Stack( + alignment: AlignmentDirectional.centerStart, + children: [ + Container( + decoration: BoxDecoration( + color: Colors.black.withOpacity(0.05), + borderRadius: BorderRadius.circular(12), + ), + padding: const EdgeInsets.only(left: 24), + child: Padding( + padding: const EdgeInsets.fromLTRB(8, 4, 12, 4), + child: Text( + user.name, + style: TextStyle(color: Colors.black), + ), + ), + ), + UserAvatar( + user: user, + constraints: BoxConstraints.tightFor( + height: 24, + width: 24, + ), + ), + ], ); }, onChipAdded: (user) { @@ -381,7 +397,17 @@ class _NewChatScreenState extends State { ), Container( width: double.maxFinite, - color: Colors.grey.shade50, + decoration: BoxDecoration( + gradient: LinearGradient( + begin: Alignment.centerLeft, + end: Alignment.centerRight, + colors: [ + Colors.black.withOpacity(0.02), + Colors.white.withOpacity(0.05), + ], + stops: [0, 1], + ), + ), child: Padding( padding: const EdgeInsets.symmetric( vertical: 8, @@ -392,7 +418,7 @@ class _NewChatScreenState extends State { ? "Matches for \"$_userNameQuery\"" : 'On the platform', style: TextStyle( - fontWeight: FontWeight.w500, + color: Colors.black.withOpacity(0.5), ), ), ), @@ -516,12 +542,14 @@ class _NewGroupChatScreenState extends State { Widget build(BuildContext context) { return Scaffold( appBar: AppBar( - elevation: 2, + elevation: 1, backgroundColor: Colors.white, + leading: const StreamBackButton(), title: Text( 'Add Group Members', style: TextStyle(color: Colors.black), ), + centerTitle: true, actions: [ if (_selectedUsers.isNotEmpty) IconButton( @@ -546,6 +574,7 @@ class _NewGroupChatScreenState extends State { child: Column( children: [ Container( + height: 36, decoration: BoxDecoration( border: Border.all( color: Colors.grey.shade300, @@ -559,9 +588,13 @@ class _NewGroupChatScreenState extends State { child: TextField( controller: _controller, decoration: InputDecoration( - prefixIcon: Icon(StreamIcons.search), + prefixIcon: Icon( + StreamIcons.search, + color: Colors.black, + ), hintText: 'Search', - contentPadding: const EdgeInsets.all(8), + contentPadding: const EdgeInsets.all(0), + // isDense: true, border: OutlineInputBorder( borderSide: BorderSide.none, borderRadius: BorderRadius.circular(24), @@ -571,7 +604,7 @@ class _NewGroupChatScreenState extends State { ), if (_selectedUsers.isNotEmpty) Container( - height: 120, + height: 104, child: ListView.separated( scrollDirection: Axis.horizontal, itemCount: _selectedUsers.length, @@ -586,10 +619,10 @@ class _NewGroupChatScreenState extends State { UserAvatar( user: user, showOnlineStatus: true, - borderRadius: BorderRadius.circular(40), + borderRadius: BorderRadius.circular(32), constraints: BoxConstraints.tightFor( - height: 80, - width: 80, + height: 64, + width: 64, ), ), Positioned( @@ -609,10 +642,10 @@ class _NewGroupChatScreenState extends State { Border.all(color: Colors.grey.shade100), ), child: Padding( - padding: const EdgeInsets.all(4.0), + padding: const EdgeInsets.all(2.0), child: Icon( Icons.clear_rounded, - size: 16, + size: 14, ), ), ), @@ -624,8 +657,8 @@ class _NewGroupChatScreenState extends State { Text( user.name.split(' ')[0], style: TextStyle( - fontWeight: FontWeight.w500, - fontSize: 16, + fontWeight: FontWeight.bold, + fontSize: 12, ), ), ], @@ -635,7 +668,17 @@ class _NewGroupChatScreenState extends State { ), Container( width: double.maxFinite, - color: Colors.grey.shade50, + decoration: BoxDecoration( + gradient: LinearGradient( + begin: Alignment.centerLeft, + end: Alignment.centerRight, + colors: [ + Colors.black.withOpacity(0.02), + Colors.white.withOpacity(0.05), + ], + stops: [0, 1], + ), + ), child: Padding( padding: const EdgeInsets.symmetric( vertical: 8, @@ -646,7 +689,7 @@ class _NewGroupChatScreenState extends State { ? 'Matches for \"$_userNameQuery\"' : 'On the platform', style: TextStyle( - fontWeight: FontWeight.w500, + color: Colors.black.withOpacity(0.5), ), ), ), @@ -755,42 +798,40 @@ class _GroupChatDetailsScreenState extends State { Widget build(BuildContext context) { return Scaffold( appBar: AppBar( - elevation: 2, + elevation: 1, backgroundColor: Colors.white, + leading: const StreamBackButton(), title: Text( 'Name of Group Chat', style: TextStyle(color: Colors.black), ), + centerTitle: true, bottom: PreferredSize( preferredSize: Size.fromHeight(kToolbarHeight), child: Padding( - padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 16), + padding: const EdgeInsets.symmetric(vertical: 18, horizontal: 16), child: Row( children: [ Text( 'NAME', style: TextStyle( - fontWeight: FontWeight.w500, - fontSize: 16, + color: Colors.black.withOpacity(0.5), ), ), SizedBox(width: 16), Expanded( child: TextField( controller: _groupNameController, - style: TextStyle(fontSize: 18), decoration: InputDecoration( - isDense: true, - border: InputBorder.none, - focusedBorder: InputBorder.none, - enabledBorder: InputBorder.none, - errorBorder: InputBorder.none, - disabledBorder: InputBorder.none, - contentPadding: const EdgeInsets.symmetric( - vertical: 8, - ), - hintText: 'Choose a group chat name', - hintStyle: TextStyle(fontSize: 18)), + isDense: true, + border: InputBorder.none, + focusedBorder: InputBorder.none, + enabledBorder: InputBorder.none, + errorBorder: InputBorder.none, + disabledBorder: InputBorder.none, + contentPadding: const EdgeInsets.all(0), + hintText: 'Choose a group chat name', + ), ), ), ], diff --git a/lib/src/user_item.dart b/lib/src/user_item.dart index d4331cf8..0c320b7c 100644 --- a/lib/src/user_item.dart +++ b/lib/src/user_item.dart @@ -59,13 +59,18 @@ class UserItem extends StatelessWidget { } }, leading: UserAvatar( - user: user, - showOnlineStatus: true, - onTap: (user) { - if (onImageTap != null) { - onImageTap(user); - } - }), + user: user, + showOnlineStatus: true, + onTap: (user) { + if (onImageTap != null) { + onImageTap(user); + } + }, + constraints: BoxConstraints.tightFor( + height: 40, + width: 40, + ), + ), trailing: selected ? CircleAvatar( child: Icon( @@ -75,7 +80,7 @@ class UserItem extends StatelessWidget { radius: 10, ) : null, - title: Text(user.name), + title: Text(user.name,style: TextStyle(fontWeight: FontWeight.bold),), subtitle: showLastSeen ? _buildLastActive(context) : null, ); } diff --git a/lib/src/user_list_view.dart b/lib/src/user_list_view.dart index 4a3ae96c..b35c1c68 100644 --- a/lib/src/user_list_view.dart +++ b/lib/src/user_list_view.dart @@ -376,12 +376,16 @@ class _UserListViewState extends State headerItem: (header) { return Container( key: ValueKey('HEADER-$header'), - color: Colors.grey.shade100, + color: Colors.black.withOpacity(0.05), child: Padding( - padding: const EdgeInsets.all(8.0), + padding: const EdgeInsets.symmetric(horizontal:8.0,vertical: 6), child: Text( header, - style: TextStyle(fontWeight: FontWeight.w500), + style: TextStyle( + fontWeight: FontWeight.bold, + fontSize: 12, + color:Colors.black.withOpacity(0.3) + ), ), ), ); From 404ec4c89d43bb9b39505be13931e7c0d39aae87 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Fri, 20 Nov 2020 13:26:26 +0530 Subject: [PATCH 0413/1140] feat: Added reaction modal animations --- lib/src/message_actions_modal.dart | 116 ++++++++++++++---------- lib/src/reaction_picker.dart | 139 ++++++++++++++++++++--------- pubspec.yaml | 1 + 3 files changed, 168 insertions(+), 88 deletions(-) diff --git a/lib/src/message_actions_modal.dart b/lib/src/message_actions_modal.dart index 16c48e25..049f1be7 100644 --- a/lib/src/message_actions_modal.dart +++ b/lib/src/message_actions_modal.dart @@ -95,58 +95,78 @@ class MessageActionsModal extends StatelessWidget { 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, - showUserAvatar: showUserAvatar, - showTimestamp: false, - translateUserAvatar: false, - showReactionPickerIndicator: true, - showSendingIndicator: DisplayWidget.gone, - shape: messageShape, - ), + TweenAnimationBuilder( + tween: Tween(begin: 0.0, end: 1.0), + duration: Duration(milliseconds: 300), + builder: (context, val, snapshot) { + return Transform.scale( + scale: val, + child: 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, + showUserAvatar: showUserAvatar, + showTimestamp: false, + translateUserAvatar: false, + showReactionPickerIndicator: true, + 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( - 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(), - ), - ), + TweenAnimationBuilder( + tween: Tween(begin: 0.0, end: 1.0), + duration: Duration(milliseconds: 300), + curve: Curves.easeInOut, + builder: (context, val, wid) { + return Transform( + transform: Matrix4.identity()..scale(val)..rotateZ(-1.0 + val), + alignment: Alignment.topRight, + child: 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( + 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/reaction_picker.dart b/lib/src/reaction_picker.dart index e7d302e6..1946e9ff 100644 --- a/lib/src/reaction_picker.dart +++ b/lib/src/reaction_picker.dart @@ -1,4 +1,6 @@ +import 'package:ezanimation/ezanimation.dart'; import 'package:flutter/material.dart'; +import 'package:flutter/physics.dart'; import '../stream_chat_flutter.dart'; @@ -8,7 +10,8 @@ import '../stream_chat_flutter.dart'; /// It shows a reaction picker /// /// Usually you don't use this widget as it's one of the default widgets used by [MessageWidget.onMessageActions]. -class ReactionPicker extends StatelessWidget { + +class ReactionPicker extends StatefulWidget { const ReactionPicker({ Key key, @required this.message, @@ -18,59 +21,115 @@ class ReactionPicker extends StatelessWidget { final Message message; final MessageTheme messageTheme; + @override + _ReactionPickerState createState() => _ReactionPickerState(); +} + +class _ReactionPickerState extends State { + List animations = []; + @override Widget build(BuildContext context) { final reactionIcons = StreamChatTheme.of(context).reactionIcons; - return Material( - color: messageTheme.reactionsBackgroundColor, - 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 = message.ownReactions?.indexWhere( - (reaction) => reaction.type == reactionIcon.type) ?? - -1; - return IconButton( - iconSize: 24, - icon: Icon( - reactionIcon.iconData, - color: ownReactionIndex != -1 - ? StreamChatTheme.of(context).accentColor - : Theme.of(context).iconTheme.color.withOpacity(.5), + + if (animations.isEmpty && reactionIcons.isNotEmpty) { + reactionIcons.forEach((element) { + animations.add( + EzAnimation.sequence([ + SequenceItem(0.0, 1.4), + SequenceItem(1.4, 1.0), + ], Duration(milliseconds: 500)), + ); + }); + + triggerAnimations(); + } + + return TweenAnimationBuilder( + tween: Tween(begin: 0.0, end: 1.0), + curve: Curves.easeInOutExpo, + duration: Duration(milliseconds: 500), + builder: (context, val, wid) { + return Transform.scale( + scale: val, + child: Material( + color: widget.messageTheme.reactionsBackgroundColor, + 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); + + 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: Icon( + reactionIcon.iconData, + size: animations[index].value * 24.0, + color: ownReactionIndex != -1 + ? StreamChatTheme.of(context).accentColor + : Theme.of(context) + .iconTheme + .color + .withOpacity(.5), + ), + ); + }), + onPressed: () { + if (ownReactionIndex != -1) { + removeReaction( + context, + widget.message.ownReactions[ownReactionIndex], + ); + } else { + sendReaction( + context, + reactionIcon.type, + ); + } + }, + ); + }).toList(), + ), ), - onPressed: () { - if (ownReactionIndex != -1) { - removeReaction( - context, - message.ownReactions[ownReactionIndex], - ); - } else { - sendReaction( - context, - reactionIcon.type, - ); - } - }, ); - }).toList(), - ), - ); + }); + } + + void triggerAnimations() async { + for (var a in animations) { + a.start(); + await Future.delayed(Duration(milliseconds: 100)); + } } /// Add a reaction to the message void sendReaction(BuildContext context, String reactionType) { - StreamChannel.of(context).channel.sendReaction(message, reactionType); + StreamChannel.of(context) + .channel + .sendReaction(widget.message, reactionType); Navigator.of(context).pop(); } /// Remove a reaction from the message void removeReaction(BuildContext context, Reaction reaction) { - StreamChannel.of(context).channel.deleteReaction(message, reaction); + StreamChannel.of(context).channel.deleteReaction(widget.message, reaction); Navigator.of(context).pop(); } } diff --git a/pubspec.yaml b/pubspec.yaml index 1716bab1..689a54b8 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -38,6 +38,7 @@ dependencies: media_gallery: ^0.1.5 permission_handler: ^5.0.1+1 transparent_image: ^1.0.0 + ezanimation: ^0.4.0 flutter: assets: From f9231e93b3059be68cece526288555d5e63e7cba Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Fri, 20 Nov 2020 13:38:15 +0530 Subject: [PATCH 0414/1140] feat: Added reaction list modal animations --- lib/src/message_reactions_modal.dart | 146 +++++++++++++++------------ 1 file changed, 82 insertions(+), 64 deletions(-) diff --git a/lib/src/message_reactions_modal.dart b/lib/src/message_reactions_modal.dart index d68bd769..db5d8710 100644 --- a/lib/src/message_reactions_modal.dart +++ b/lib/src/message_reactions_modal.dart @@ -86,27 +86,35 @@ class MessageReactionsModal extends StatelessWidget { 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, - showUserAvatar: showUserAvatar, - showReplyIndicator: false, - showTimestamp: false, - translateUserAvatar: false, - showSendingIndicator: DisplayWidget.gone, - shape: messageShape, - showReactionPickerIndicator: true, - ), - ), + TweenAnimationBuilder( + tween: Tween(begin: 0.0, end: 1.0), + duration: Duration(milliseconds: 300), + builder: (context, val, snapshot) { + return Transform.scale( + scale: val, + child: 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, + showUserAvatar: showUserAvatar, + showReplyIndicator: false, + showTimestamp: false, + translateUserAvatar: false, + showSendingIndicator: DisplayWidget.gone, + shape: messageShape, + showReactionPickerIndicator: true, + ), + ), + ); + }), SizedBox( height: 16, ), @@ -178,50 +186,60 @@ class MessageReactionsModal extends StatelessWidget { BuildContext context, ) { final isCurrentUser = reaction.user.id == currentUser.id; - 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), - ), - Positioned( - child: Align( - alignment: Alignment.centerLeft, - child: ReactionBubble( - reactions: [reaction], - borderColor: messageTheme.reactionsBorderColor, - backgroundColor: messageTheme.reactionsBackgroundColor, - highlightOwnReactions: false, + return TweenAnimationBuilder( + tween: Tween(begin: 0.0, end: 1.0), + duration: Duration(milliseconds: 300), + curve: Curves.easeInOut, + builder: (context, val, snapshot) { + return Transform.scale( + scale: val, + child: 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), + ), + Positioned( + child: Align( + alignment: Alignment.centerLeft, + child: ReactionBubble( + reactions: [reaction], + borderColor: messageTheme.reactionsBorderColor, + backgroundColor: + messageTheme.reactionsBackgroundColor, + highlightOwnReactions: false, + ), + ), + bottom: 4, + left: isCurrentUser ? 0 : null, + right: isCurrentUser ? 0 : null, + ), + ], ), - ), - bottom: 4, - 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 c70c49d54d33c6f40404579ba1c382ca3d333dce Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Fri, 20 Nov 2020 15:07:42 +0530 Subject: [PATCH 0415/1140] feat: Added animations for giphy and mentions --- lib/src/message_input.dart | 302 ++++++++++++++++++++----------------- 1 file changed, 165 insertions(+), 137 deletions(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index cd96119a..01c531de 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -536,86 +536,101 @@ class MessageInputState extends State { bottom: size.height + MediaQuery.of(context).viewInsets.bottom, left: 0, right: 0, - child: Padding( - padding: const EdgeInsets.all(8.0), - child: Card( - elevation: 2.0, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(8.0), - ), - color: StreamChatTheme.of(context).primaryColor, - clipBehavior: Clip.antiAlias, - child: Container( - constraints: BoxConstraints.loose(Size.fromHeight(400)), - decoration: BoxDecoration( - color: StreamChatTheme.of(context).primaryColor, - borderRadius: BorderRadius.circular(8.0)), - child: ListView( - padding: const EdgeInsets.all(0), - shrinkWrap: true, - children: [ - if (commands.isNotEmpty) - Padding( - padding: const EdgeInsets.only(left: 8.0, top: 8.0), - child: Row( + child: TweenAnimationBuilder( + tween: Tween(begin: 0.0, end: 1.0), + duration: Duration(milliseconds: 300), + curve: Curves.easeInOutExpo, + builder: (context, val, wid) { + return Transform.scale( + alignment: Alignment.center, + scale: val, + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Card( + elevation: 2.0, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8.0), + ), + color: StreamChatTheme.of(context).primaryColor, + clipBehavior: Clip.antiAlias, + child: Container( + constraints: BoxConstraints.loose(Size.fromHeight(400)), + decoration: BoxDecoration( + color: StreamChatTheme.of(context).primaryColor, + borderRadius: BorderRadius.circular(8.0)), + child: ListView( + padding: const EdgeInsets.all(0), + shrinkWrap: true, children: [ - Padding( - padding: - const EdgeInsets.symmetric(horizontal: 8.0), - child: Icon( - StreamIcons.lightning, - color: StreamChatTheme.of(context).accentColor, + if (commands.isNotEmpty) + Padding( + padding: + const EdgeInsets.only(left: 8.0, top: 8.0), + child: Row( + children: [ + Padding( + padding: const EdgeInsets.symmetric( + horizontal: 8.0), + child: Icon( + StreamIcons.lightning, + color: StreamChatTheme.of(context) + .accentColor, + ), + ), + Text( + 'Instant Commands', + style: TextStyle( + color: Colors.black.withOpacity(.5), + ), + ) + ], + ), ), - ), - Text( - 'Instant Commands', - style: TextStyle( - color: Colors.black.withOpacity(.5), - ), - ) + ...commands + .map( + (c) => ListTile( + leading: c.name == 'giphy' + ? _buildGiphyIcon() + : null, + title: Text.rich( + TextSpan( + text: '${c.name.capitalize()}', + style: TextStyle( + fontWeight: FontWeight.bold), + children: [ + TextSpan( + text: ' /${c.name} ${c.args}', + style: TextStyle( + fontWeight: FontWeight.w300, + ), + ), + ], + ), + ), + trailing: CircleAvatar( + backgroundColor: + StreamChatTheme.of(context).accentColor, + child: Icon( + StreamIcons.lightning, + color: Colors.white, + size: 12.5, + ), + maxRadius: 12, + ), + //subtitle: Text(c.description), + onTap: () { + _setCommand(c); + }, + ), + ) + .toList(), ], ), ), - ...commands - .map( - (c) => ListTile( - leading: c.name == 'giphy' ? _buildGiphyIcon() : null, - title: Text.rich( - TextSpan( - text: '${c.name.capitalize()}', - style: TextStyle(fontWeight: FontWeight.bold), - children: [ - TextSpan( - text: ' /${c.name} ${c.args}', - style: TextStyle( - fontWeight: FontWeight.w300, - ), - ), - ], - ), - ), - trailing: CircleAvatar( - backgroundColor: - StreamChatTheme.of(context).accentColor, - child: Icon( - StreamIcons.lightning, - color: Colors.white, - size: 12.5, - ), - maxRadius: 12, - ), - //subtitle: Text(c.description), - onTap: () { - _setCommand(c); - }, - ), - ) - .toList(), - ], - ), - ), - ), - ), + ), + ), + ); + }), ); }); } @@ -925,71 +940,84 @@ class MessageInputState extends State { bottom: size.height + MediaQuery.of(context).viewInsets.bottom, left: 0, right: 0, - child: Card( - margin: EdgeInsets.all(8.0), - elevation: 2.0, - color: StreamChatTheme.of(context).primaryColor, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(8.0), - ), - clipBehavior: Clip.antiAlias, - child: Container( - constraints: BoxConstraints.loose(Size.fromHeight(400)), - decoration: BoxDecoration( - color: StreamChatTheme.of(context).primaryColor, - ), - child: FutureBuilder>( - future: queryMembers ?? Future.value(members), - initialData: members, - builder: (context, snapshot) { - return ListView( - padding: const EdgeInsets.all(0), - shrinkWrap: true, - children: snapshot.data - .map((m) => ListTile( - leading: UserAvatar( - constraints: BoxConstraints.tight( - Size( - 40, - 40, - ), - ), - user: m.user, - ), - title: Text( - '${m.user.name}', - style: TextStyle(fontWeight: FontWeight.bold), - ), - subtitle: Text('@${m.userId}'), - trailing: Icon( - StreamIcons.at_mention, - color: StreamChatTheme.of(context).accentColor, - ), - onTap: () { - _mentionedUsers.add(m.user); + child: TweenAnimationBuilder( + tween: Tween(begin: 0.0, end: 1.0), + duration: Duration(milliseconds: 300), + curve: Curves.easeInOutExpo, + builder: (context, val, wid) { + return Transform.scale( + scale: val, + child: Card( + margin: EdgeInsets.all(8.0), + elevation: 2.0, + color: StreamChatTheme.of(context).primaryColor, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8.0), + ), + clipBehavior: Clip.antiAlias, + child: Container( + constraints: BoxConstraints.loose(Size.fromHeight(400)), + decoration: BoxDecoration( + color: StreamChatTheme.of(context).primaryColor, + ), + child: FutureBuilder>( + future: queryMembers ?? Future.value(members), + initialData: members, + builder: (context, snapshot) { + return ListView( + padding: const EdgeInsets.all(0), + shrinkWrap: true, + children: snapshot.data + .map((m) => ListTile( + leading: UserAvatar( + constraints: BoxConstraints.tight( + Size( + 40, + 40, + ), + ), + user: m.user, + ), + title: Text( + '${m.user.name}', + style: TextStyle( + fontWeight: FontWeight.bold), + ), + subtitle: Text('@${m.userId}'), + trailing: Icon( + StreamIcons.at_mention, + color: StreamChatTheme.of(context) + .accentColor, + ), + onTap: () { + _mentionedUsers.add(m.user); - splits[splits.length - 1] = m.user.name; - final rejoin = splits.join('@'); + splits[splits.length - 1] = m.user.name; + final rejoin = splits.join('@'); - textEditingController.value = TextEditingValue( - text: rejoin + - textEditingController.text.substring( - textEditingController - .selection.start), - selection: TextSelection.collapsed( - offset: rejoin.length, - ), - ); + textEditingController.value = + TextEditingValue( + text: rejoin + + textEditingController.text + .substring( + textEditingController + .selection.start), + selection: TextSelection.collapsed( + offset: rejoin.length, + ), + ); - _mentionsOverlay?.remove(); - _mentionsOverlay = null; - }, - )) - .toList(), - ); - }), - ), - ), + _mentionsOverlay?.remove(); + _mentionsOverlay = null; + }, + )) + .toList(), + ); + }), + ), + ), + ); + }), ); }); } From c7e27577b2dc9d28534522c1ce27cf0b129becce Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Fri, 20 Nov 2020 11:22:41 +0100 Subject: [PATCH 0416/1140] use fork of media gallery waiting for the pr to be merged --- lib/src/media_list_view.dart | 1 + pubspec.yaml | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/src/media_list_view.dart b/lib/src/media_list_view.dart index 225d327b..da21111b 100644 --- a/lib/src/media_list_view.dart +++ b/lib/src/media_list_view.dart @@ -44,6 +44,7 @@ class _MediaListViewState extends State { placeholder: MemoryImage(kTransparentImage), image: MediaThumbnailProvider( media: media, + highQuality: true, ), fit: BoxFit.cover, ), diff --git a/pubspec.yaml b/pubspec.yaml index 9c1b0a29..97804c53 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -35,7 +35,8 @@ dependencies: flutter_slidable: ^0.5.4 carousel_slider: ^2.2.1 clipboard: ^0.1.2+8 - media_gallery: ^0.1.5 + media_gallery: + git: https://github.com/imtoori/media_gallery.git permission_handler: ^5.0.1+1 transparent_image: ^1.0.0 From 09fd54a605898ac309ea12ceb828bc88298b8158 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Fri, 20 Nov 2020 11:58:11 +0100 Subject: [PATCH 0417/1140] update fadeinduration --- lib/src/media_list_view.dart | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/src/media_list_view.dart b/lib/src/media_list_view.dart index da21111b..cd414fa9 100644 --- a/lib/src/media_list_view.dart +++ b/lib/src/media_list_view.dart @@ -41,6 +41,7 @@ class _MediaListViewState extends State { AspectRatio( aspectRatio: 1.0, child: FadeInImage( + fadeInDuration: Duration(milliseconds: 300), placeholder: MemoryImage(kTransparentImage), image: MediaThumbnailProvider( media: media, From 68e9f98b7fdadd8211b151041a350de3908d2162 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Fri, 20 Nov 2020 16:36:29 +0530 Subject: [PATCH 0418/1140] feat: Added download and sharing of images --- .../android/app/src/main/AndroidManifest.xml | 1 + lib/src/full_screen_image.dart | 2 + lib/src/image_actions_modal.dart | 14 +++- lib/src/image_footer.dart | 66 ++++++++++++++----- lib/src/image_header.dart | 7 ++ pubspec.yaml | 2 + 6 files changed, 73 insertions(+), 19 deletions(-) diff --git a/example/android/app/src/main/AndroidManifest.xml b/example/android/app/src/main/AndroidManifest.xml index a90d828e..ca0d2720 100644 --- a/example/android/app/src/main/AndroidManifest.xml +++ b/example/android/app/src/main/AndroidManifest.xml @@ -6,6 +6,7 @@ additional functionality it is fine to subclass or reimplement FlutterApplication and put your custom class here. --> + Navigator.of(context).pop(); }, message: widget.message, + urls: widget.urls, + currentIndex: _currentPage, ), ImageFooter( currentPage: _currentPage, diff --git a/lib/src/image_actions_modal.dart b/lib/src/image_actions_modal.dart index 8b39737d..f07efcb6 100644 --- a/lib/src/image_actions_modal.dart +++ b/lib/src/image_actions_modal.dart @@ -1,6 +1,7 @@ import 'dart:ui'; import 'package:flutter/material.dart'; +import 'package:gallery_saver/gallery_saver.dart'; import '../stream_chat_flutter.dart'; import 'stream_icons.dart'; @@ -9,8 +10,11 @@ class ImageActionsModal extends StatelessWidget { final Message message; final String userName; final String sentAt; + final List urls; + final currentIndex; - ImageActionsModal({this.message, this.userName, this.sentAt}); + ImageActionsModal( + {this.message, this.userName, this.sentAt, this.urls, this.currentIndex}); @override Widget build(BuildContext context) { @@ -112,8 +116,12 @@ class ImageActionsModal extends StatelessWidget { Navigator.pop(context); Navigator.pop(context); }), - _buildButton( - context, 'Save Image', StreamIcons.save_1, () {}), + _buildButton(context, 'Save Image', StreamIcons.save_1, + () async { + await GallerySaver.saveImage( + urls[currentIndex].split('?')[0]); + Navigator.pop(context); + }), _buildButton(context, 'Copy', StreamIcons.copy, () {}), if (StreamChat.of(context).user.id == message.user.id) _buildButton(context, 'Delete', StreamIcons.delete, diff --git a/lib/src/image_footer.dart b/lib/src/image_footer.dart index 83960091..57119f8e 100644 --- a/lib/src/image_footer.dart +++ b/lib/src/image_footer.dart @@ -1,7 +1,12 @@ +import 'dart:io'; import 'dart:math'; +import 'dart:typed_data'; import 'package:cached_network_image/cached_network_image.dart'; +import 'package:esys_flutter_share/esys_flutter_share.dart'; +import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; +import 'package:gallery_saver/gallery_saver.dart'; import 'package:stream_chat/stream_chat.dart'; import 'package:stream_chat_flutter/src/back_button.dart'; import 'package:stream_chat_flutter/src/channel_info.dart'; @@ -61,6 +66,7 @@ class _ImageFooterState extends State { TextEditingController _messageController = TextEditingController(); List _selectedUsers = []; + bool _loading = false; @override void initState() { @@ -311,7 +317,8 @@ class _ImageFooterState extends State { _selectedUsers .remove(user); } else { - _selectedUsers.add(user); + _selectedUsers + .add(user); } modalSetState(() {}); }, @@ -368,14 +375,23 @@ class _ImageFooterState extends State { margin: EdgeInsets.symmetric( horizontal: 8.0, ), - child: SizedBox.expand( - child: Center( - child: Text( - 'Save to Photos', - style: TextStyle( - color: StreamChatTheme.of(modalContext) - .accentColor, - fontWeight: FontWeight.bold, + child: Material( + child: InkWell( + onTap: () async { + await GallerySaver.saveImage( + widget.urls[widget.currentPage].split('?')[0]); + Navigator.pop(context); + }, + child: SizedBox.expand( + child: Center( + child: Text( + 'Save to Photos', + style: TextStyle( + color: StreamChatTheme.of(modalContext) + .accentColor, + fontWeight: FontWeight.bold, + ), + ), ), ), ), @@ -493,7 +509,14 @@ class _ImageFooterState extends State { color: Colors.black, ), iconSize: 24.0, - onPressed: () {}, + onPressed: () async { + var url = widget.urls[widget.currentPage]; + var type = url?.split('?')?.first?.split('.')?.last ?? 'jpg'; + var request = await HttpClient().getUrl(Uri.parse(url)); + var response = await request.close(); + var bytes = await consolidateHttpClientResponseBytes(response); + await Share.file('File', 'image.$type', bytes, 'image/$type'); + }, ), ), ], @@ -507,7 +530,12 @@ class _ImageFooterState extends State { child: Container( color: Colors.white, height: 56.0, - child: Row( + child: _loading ? Center( + child: Padding( + padding: const EdgeInsets.all(8.0), + child: CircularProgressIndicator(), + ), + ) : Row( children: [ Expanded( child: Padding( @@ -553,8 +581,14 @@ class _ImageFooterState extends State { child: Padding( padding: const EdgeInsets.all(8.0), child: InkWell( - onTap: () { - sendMessage(); + onTap: () async { + modalSetState(() { + _loading = true; + }); + await sendMessage(); + modalSetState(() { + _loading = false; + }); }, child: Transform.rotate( angle: -pi / 2, @@ -607,7 +641,7 @@ class _ImageFooterState extends State { } /// Sends the current message - void sendMessage() async { + Future sendMessage() async { var text = _messageController.text.trim(); final attachments = widget.message.attachments; @@ -615,8 +649,8 @@ class _ImageFooterState extends State { _messageController.clear(); final client = StreamChat.of(context).client; - - for(var user in _selectedUsers) { + + for (var user in _selectedUsers) { var c = client.channel('messaging', extraData: { 'members': [ user.id, diff --git a/lib/src/image_header.dart b/lib/src/image_header.dart index 29c36ad9..707750c5 100644 --- a/lib/src/image_header.dart +++ b/lib/src/image_header.dart @@ -30,10 +30,15 @@ class ImageHeader extends StatelessWidget implements PreferredSizeWidget { final String userName; final String sentAt; + final List urls; + final currentIndex; + /// Creates a channel header ImageHeader({ Key key, this.message, + this.urls, + this.currentIndex, this.showBackButton = true, this.onBackPressed, this.onTitleTap, @@ -117,6 +122,8 @@ class ImageHeader extends StatelessWidget implements PreferredSizeWidget { userName: userName, sentAt: sentAt, message: message, + urls: urls, + currentIndex: currentIndex, ), ); }); diff --git a/pubspec.yaml b/pubspec.yaml index 241025d0..78add1a5 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -35,6 +35,8 @@ dependencies: flutter_slidable: ^0.5.4 carousel_slider: ^2.2.1 clipboard: ^0.1.2+8 + gallery_saver: ^2.0.1 + esys_flutter_share: ^1.0.2 flutter: assets: From 3c7b10173d80342dcba29535e973bfc79c649c94 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Fri, 20 Nov 2020 17:17:52 +0530 Subject: [PATCH 0419/1140] fix: Fixed icons, timing, copy button --- lib/src/full_screen_image.dart | 14 +++++++++++++- lib/src/image_actions_modal.dart | 1 - lib/src/image_footer.dart | 2 +- 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/lib/src/full_screen_image.dart b/lib/src/full_screen_image.dart index a55cb187..52e75871 100644 --- a/lib/src/full_screen_image.dart +++ b/lib/src/full_screen_image.dart @@ -107,7 +107,7 @@ class _FullScreenImageState extends State ImageHeader( userName: widget.userName, sentAt: - 'Sent at${Jiffy(widget.sentAt.toLocal()).format(' HH:mm')}', + 'Sent ${getDay(widget.message.createdAt)} at ${Jiffy(widget.sentAt.toLocal()).format('HH:mm')}', onBackPressed: () { Navigator.of(context).pop(); }, @@ -128,4 +128,16 @@ class _FullScreenImageState extends State ), ); } + + String getDay(DateTime dateTime) { + var now = DateTime.now(); + + if(DateTime(dateTime.year, dateTime.month, dateTime.day) == DateTime(now.year, now.month, now.day)) { + return 'today'; + } else if(DateTime(now.year, now.month, now.day).difference(dateTime).inHours < 24) { + return 'yesterday'; + } else { + return 'on ${Jiffy(dateTime).format("MMM do")}'; + } + } } diff --git a/lib/src/image_actions_modal.dart b/lib/src/image_actions_modal.dart index f07efcb6..f46cb008 100644 --- a/lib/src/image_actions_modal.dart +++ b/lib/src/image_actions_modal.dart @@ -122,7 +122,6 @@ class ImageActionsModal extends StatelessWidget { urls[currentIndex].split('?')[0]); Navigator.pop(context); }), - _buildButton(context, 'Copy', StreamIcons.copy, () {}), if (StreamChat.of(context).user.id == message.user.id) _buildButton(context, 'Delete', StreamIcons.delete, () { diff --git a/lib/src/image_footer.dart b/lib/src/image_footer.dart index 57119f8e..b1cf65d3 100644 --- a/lib/src/image_footer.dart +++ b/lib/src/image_footer.dart @@ -86,7 +86,7 @@ class _ImageFooterState extends State { children: [ IconButton( icon: Icon( - StreamIcons.share, + StreamIcons.share_1, size: 24.0, color: Colors.black, ), From c384588d5b1533e41412a27e0831d326a4c5e06e Mon Sep 17 00:00:00 2001 From: xsahil03x Date: Fri, 20 Nov 2020 17:55:55 +0530 Subject: [PATCH 0420/1140] UI nit picks --- example/lib/chips_input_text_field.dart | 9 +-- example/lib/main.dart | 78 +++++++++++++++------- example/lib/neumorphic_button.dart | 38 ++++------- lib/src/user_list_view.dart | 88 +++++++++---------------- 4 files changed, 102 insertions(+), 111 deletions(-) diff --git a/example/lib/chips_input_text_field.dart b/example/lib/chips_input_text_field.dart index e3b0eae7..695783d9 100644 --- a/example/lib/chips_input_text_field.dart +++ b/example/lib/chips_input_text_field.dart @@ -34,10 +34,8 @@ class ChipInputTextFieldState extends State> { bool _pauseItemAddition = false; void addItem(T item) { - if (!_pauseItemAddition) { - setState(() => _chips.add(item)); - if (widget.onChipAdded != null) widget.onChipAdded(item); - } + setState(() => _chips.add(item)); + if (widget.onChipAdded != null) widget.onChipAdded(item); } void removeItem(T item) { @@ -108,6 +106,9 @@ class ChipInputTextFieldState extends State> { disabledBorder: InputBorder.none, contentPadding: const EdgeInsets.only(top: 4.0), hintText: widget.hint, + hintStyle: TextStyle( + color: Colors.black.withOpacity(0.5), + ), ), ), ] diff --git a/example/lib/main.dart b/example/lib/main.dart index f187ac05..9cce3cf3 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -309,6 +309,7 @@ class _NewChatScreenState extends State { @override Widget build(BuildContext context) { return Scaffold( + backgroundColor: Color.fromRGBO(252, 252, 252, 1), appBar: AppBar( elevation: 0, backgroundColor: Colors.white, @@ -367,7 +368,6 @@ class _NewChatScreenState extends State { ), if (!_isSearchActive) Container( - color: Colors.white54, child: InkWell( onTap: () { Navigator.push( @@ -375,23 +375,26 @@ class _NewChatScreenState extends State { MaterialPageRoute(builder: (_) => NewGroupChatScreen()), ); }, - child: Row( - children: [ - NeumorphicButton( - child: Icon( - StreamIcons.group, - color: Colors.blue.shade700, + child: Padding( + padding: const EdgeInsets.symmetric(vertical: 8), + child: Row( + children: [ + NeumorphicButton( + child: Icon( + StreamIcons.group, + color: Color(0xFF006CFF), + ), ), - ), - SizedBox(width: 8), - Text( - 'Create a Group', - style: TextStyle( - fontWeight: FontWeight.w500, - fontSize: 18, + SizedBox(width: 8), + Text( + 'Create a Group', + style: TextStyle( + fontWeight: FontWeight.bold, + fontSize: 16, + ), ), - ), - ], + ], + ), ), ), ), @@ -425,20 +428,33 @@ class _NewChatScreenState extends State { ), Expanded( child: UserListView( - filterByUserName: _userNameQuery, selectedUsers: _selectedUsers, groupAlphabetically: _isSearchActive ? false : true, onUserTap: (user, _) { + _controller.clear(); if (!_selectedUsers.contains(user)) { - _controller.clear(); _chipInputTextFieldState ..addItem(user) ..pauseItemAddition(); + } else { + _chipInputTextFieldState.removeItem(user); } }, pagination: PaginationParams( limit: 25, ), + filter: { + if (_userNameQuery.isNotEmpty) + 'name': { + r'$autocomplete': _userNameQuery, + } + }, + sort: [ + SortOption( + 'name', + direction: 1, + ), + ], emptyBuilder: (_) { return LayoutBuilder( builder: (context, viewportConstraints) { @@ -541,6 +557,7 @@ class _NewGroupChatScreenState extends State { @override Widget build(BuildContext context) { return Scaffold( + backgroundColor: Color.fromRGBO(252, 252, 252, 1), appBar: AppBar( elevation: 1, backgroundColor: Colors.white, @@ -555,7 +572,7 @@ class _NewGroupChatScreenState extends State { IconButton( icon: Icon( StreamIcons.arrow_right, - color: Colors.blue.shade700, + color: Color(0xFF006CFF), ), onPressed: () { Navigator.push( @@ -576,6 +593,7 @@ class _NewGroupChatScreenState extends State { Container( height: 36, decoration: BoxDecoration( + color: Colors.white, border: Border.all( color: Colors.grey.shade300, ), @@ -593,8 +611,10 @@ class _NewGroupChatScreenState extends State { color: Colors.black, ), hintText: 'Search', + hintStyle: TextStyle( + color: Colors.black.withOpacity(0.5), + ), contentPadding: const EdgeInsets.all(0), - // isDense: true, border: OutlineInputBorder( borderSide: BorderSide.none, borderRadius: BorderRadius.circular(24), @@ -696,7 +716,6 @@ class _NewGroupChatScreenState extends State { ), Expanded( child: UserListView( - filterByUserName: _userNameQuery, selectedUsers: _selectedUsers, groupAlphabetically: _isSearchActive ? false : true, onUserTap: (user, _) { @@ -709,6 +728,18 @@ class _NewGroupChatScreenState extends State { pagination: PaginationParams( limit: 25, ), + filter: { + if (_userNameQuery.isNotEmpty) + 'name': { + r'$autocomplete': _userNameQuery, + } + }, + sort: [ + SortOption( + 'name', + direction: 1, + ), + ], emptyBuilder: (_) { return LayoutBuilder( builder: (context, viewportConstraints) { @@ -797,6 +828,7 @@ class _GroupChatDetailsScreenState extends State { @override Widget build(BuildContext context) { return Scaffold( + backgroundColor: Color.fromRGBO(252, 252, 252, 1), appBar: AppBar( elevation: 1, backgroundColor: Colors.white, @@ -840,12 +872,10 @@ class _GroupChatDetailsScreenState extends State { ), actions: [ NeumorphicButton( - padding: const EdgeInsets.all(8), - margin: const EdgeInsets.symmetric(vertical: 8), child: IconButton( padding: const EdgeInsets.all(0), icon: Icon(StreamIcons.check), - color: Colors.blue.shade700, + color: Color(0xFF006CFF), onPressed: _isGroupNameEmpty ? null : () async { diff --git a/example/lib/neumorphic_button.dart b/example/lib/neumorphic_button.dart index c738cecd..69454fb2 100644 --- a/example/lib/neumorphic_button.dart +++ b/example/lib/neumorphic_button.dart @@ -1,50 +1,38 @@ import 'package:flutter/material.dart'; -extension ColorUtils on Color { - Color mix(Color another, double amount) { - return Color.lerp(this, another, amount); - } -} - class NeumorphicButton extends StatelessWidget { final Widget child; final Color backgroundColor; - final EdgeInsets margin; - final EdgeInsets padding; const NeumorphicButton({ Key key, @required this.child, this.backgroundColor = Colors.white, - this.margin = const EdgeInsets.all(8), - this.padding = const EdgeInsets.all(14), }) : super(key: key); @override Widget build(BuildContext context) { return Container( child: child, - margin: margin, - padding: padding, + margin: EdgeInsets.all(8.0), + height: 40, + width: 40, decoration: BoxDecoration( - shape: BoxShape.circle, color: backgroundColor, - gradient: LinearGradient( - begin: Alignment.topLeft, - end: Alignment.bottomRight, - colors: [ - backgroundColor.mix(Colors.white, 0.2), - backgroundColor.mix(Colors.black, 0.1), - ]), + shape: BoxShape.circle, boxShadow: [ BoxShadow( - blurRadius: 1, - color: backgroundColor.mix(Colors.white, 0.6), + color: Colors.grey[700], + offset: Offset(0, 1.0), + blurRadius: 0.5, + spreadRadius: 0, ), BoxShadow( - blurRadius: 1, - color: backgroundColor.mix(Colors.black, 0.3), - ) + color: Colors.white, + offset: Offset.zero, + blurRadius: 0.5, + spreadRadius: 0, + ), ], ), ); diff --git a/lib/src/user_list_view.dart b/lib/src/user_list_view.dart index b35c1c68..b21e8c7d 100644 --- a/lib/src/user_list_view.dart +++ b/lib/src/user_list_view.dart @@ -1,7 +1,6 @@ import 'dart:convert'; import 'package:flutter/material.dart'; -import 'package:rxdart/rxdart.dart'; import 'package:stream_chat/stream_chat.dart'; import 'package:stream_chat_flutter/src/users_bloc.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; @@ -66,13 +65,7 @@ class UserListView extends StatefulWidget { this.swipeToAction = false, this.pullToRefresh = true, this.groupAlphabetically = false, - this.filterByUserName = '', - this.filterByUserNameStream, - }) : assert( - filterByUserName == null || filterByUserNameStream == null, - 'Cannot provide both filterByUserName and filterByUserNameStream.', - ), - super(key: key); + }) : super(key: key); /// The builder that will be used in case of error final Widget Function(Error error) errorBuilder; @@ -137,12 +130,6 @@ class UserListView extends StatefulWidget { /// defaults to false final bool groupAlphabetically; - /// - final String filterByUserName; - - /// - final Stream filterByUserNameStream; - @override _UserListViewState createState() => _UserListViewState(); } @@ -154,8 +141,8 @@ class _UserListViewState extends State @override void initState() { super.initState(); - final channelsBloc = UsersBloc.of(context); - channelsBloc.queryUsers( + final usersBloc = UsersBloc.of(context); + usersBloc.queryUsers( filter: widget.filter, sort: widget.sort, pagination: widget.pagination, @@ -163,9 +150,9 @@ class _UserListViewState extends State ); _scrollController.addListener(() { - channelsBloc.queryUsersLoading.first.then((loading) { + usersBloc.queryUsersLoading.first.then((loading) { if (!loading) { - _listenUserPagination(channelsBloc); + _listenUserPagination(usersBloc); } }); }); @@ -192,42 +179,28 @@ class _UserListViewState extends State ); } - List _getFilteredItems(List users, String query) { - if (widget.groupAlphabetically) { - var temp = users..sort((curr, next) => curr.name.compareTo(next.name)); - temp = temp - .where((it) => it.name.toLowerCase().contains(query.toLowerCase())) - .toList(); - final groupedUsers = >{}; - for (var e in temp) { - final alphabet = e.name[0]; - groupedUsers[alphabet] = [...groupedUsers[alphabet] ?? [], e]; - } - final items = []; - for (var key in groupedUsers.keys) { - items.add(ListHeaderItem(key)); - items.addAll(groupedUsers[key].map((e) => ListUserItem(e))); - } - return items; - } - return users - .where((it) => it.name.toLowerCase().contains(query.toLowerCase())) - .map((e) => ListUserItem(e)) - .toList(); - } - Stream> _buildUserStream( UsersBlocState usersBlocState, ) { - if (widget.filterByUserNameStream == null) { - return usersBlocState.usersStream.map( - (users) => _getFilteredItems(users, widget.filterByUserName), - ); - } - return Rx.combineLatest2( - usersBlocState.usersStream, - widget.filterByUserNameStream, - _getFilteredItems, + return usersBlocState.usersStream.map( + (users) { + if (widget.groupAlphabetically) { + var temp = users + ..sort((curr, next) => curr.name.compareTo(next.name)); + final groupedUsers = >{}; + for (var e in temp) { + final alphabet = e.name[0]; + groupedUsers[alphabet] = [...groupedUsers[alphabet] ?? [], e]; + } + final items = []; + for (var key in groupedUsers.keys) { + items.add(ListHeaderItem(key)); + items.addAll(groupedUsers[key].map((e) => ListUserItem(e))); + } + return items; + } + return users.map((e) => ListUserItem(e)).toList(); + }, ); } @@ -378,14 +351,13 @@ class _UserListViewState extends State key: ValueKey('HEADER-$header'), color: Colors.black.withOpacity(0.05), child: Padding( - padding: const EdgeInsets.symmetric(horizontal:8.0,vertical: 6), + padding: const EdgeInsets.symmetric(horizontal: 8.0, vertical: 6), child: Text( header, style: TextStyle( - fontWeight: FontWeight.bold, - fontSize: 12, - color:Colors.black.withOpacity(0.3) - ), + fontWeight: FontWeight.bold, + fontSize: 12, + color: Colors.black.withOpacity(0.3)), ), ), ); @@ -469,8 +441,8 @@ class _UserListViewState extends State widget.pagination?.toJson()?.toString() != oldWidget.pagination?.toJson()?.toString() || widget.options?.toString() != oldWidget.options?.toString()) { - final channelsBloc = UsersBloc.of(context); - channelsBloc.queryUsers( + final usersBloc = UsersBloc.of(context); + usersBloc.queryUsers( filter: widget.filter, sort: widget.sort, pagination: widget.pagination, From 98f3853a0828d04f641a7c3a6863d544ddabba72 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Fri, 20 Nov 2020 17:58:06 +0530 Subject: [PATCH 0421/1140] fix: Fixed textfield and actions color and font weight --- lib/src/image_actions_modal.dart | 2 +- lib/src/image_footer.dart | 41 +++++++++++++++++++++++++++----- 2 files changed, 36 insertions(+), 7 deletions(-) diff --git a/lib/src/image_actions_modal.dart b/lib/src/image_actions_modal.dart index f46cb008..0328209e 100644 --- a/lib/src/image_actions_modal.dart +++ b/lib/src/image_actions_modal.dart @@ -150,7 +150,6 @@ class ImageActionsModal extends StatelessWidget { var titleStyle = TextStyle( fontSize: 14.5, color: Colors.black, - fontWeight: FontWeight.w500, ); return ListTile( @@ -165,6 +164,7 @@ class ImageActionsModal extends StatelessWidget { size: 24.0, ), onTap: onTap, + tileColor: Colors.white, ); } } diff --git a/lib/src/image_footer.dart b/lib/src/image_footer.dart index b1cf65d3..5f4710d1 100644 --- a/lib/src/image_footer.dart +++ b/lib/src/image_footer.dart @@ -434,22 +434,25 @@ class _ImageFooterState extends State { autofocus: true, decoration: InputDecoration( isDense: true, - prefixIcon: Icon( - StreamIcons.search, - color: Colors.black, + prefixIconConstraints: BoxConstraints.tight(Size(38.0, 38.0)), + prefixIcon: Transform.scale( + scale: 1.2, + alignment: Alignment.center, + child: Icon( + StreamIcons.search, + color: Colors.black, + ), ), hintText: 'Search', border: OutlineInputBorder( borderRadius: BorderRadius.circular(32.0), borderSide: BorderSide(color: Colors.black.withOpacity(0.08)), - gapPadding: 0.0, ), focusedBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(32.0), borderSide: BorderSide(color: Colors.black.withOpacity(0.08)), - gapPadding: 0.0, ), contentPadding: EdgeInsets.zero, ), @@ -459,7 +462,7 @@ class _ImageFooterState extends State { width: 8.0, ), IconButton( - icon: Icon(StreamIcons.close_circle), + icon: Icon(StreamIcons.close_circle, color: Colors.black.withOpacity(0.5),), onPressed: () { modalSetState(() { _userSearchMode = false; @@ -679,3 +682,29 @@ class _ImageFooterState extends State { Navigator.pop(context); } } + +/// Used for clipping textfield prefix icon +class IconClipper extends CustomClipper { + @override + Path getClip(Size size) { + var leftX = size.width / 5; + var rightX = 4 * size.width / 5; + var topY = size.height / 5; + var bottomY = 4 * size.height / 5; + + final path = Path(); + path.moveTo(leftX, topY); + path.lineTo(leftX, bottomY); + path.lineTo(rightX, bottomY); + path.lineTo(rightX, topY); + path.lineTo(leftX, topY); + path.lineTo(0.0, 0.0); + path.close(); + return path; + } + + @override + bool shouldReclip(CustomClipper oldClipper) { + return false; + } +} From 409d95d86a6d3310e9bfe0b5ba60e004894b1523 Mon Sep 17 00:00:00 2001 From: xsahil03x Date: Fri, 20 Nov 2020 18:06:47 +0530 Subject: [PATCH 0422/1140] [UserListView] Add a "isListAlreadySorted" check before sorting list. --- lib/src/user_list_view.dart | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/lib/src/user_list_view.dart b/lib/src/user_list_view.dart index b21e8c7d..0f7b969e 100644 --- a/lib/src/user_list_view.dart +++ b/lib/src/user_list_view.dart @@ -179,14 +179,19 @@ class _UserListViewState extends State ); } + bool get isListAlreadySorted => + widget.sort?.any((e) => e.field == 'name' && e.direction == 1) ?? false; + Stream> _buildUserStream( UsersBlocState usersBlocState, ) { return usersBlocState.usersStream.map( (users) { if (widget.groupAlphabetically) { - var temp = users - ..sort((curr, next) => curr.name.compareTo(next.name)); + var temp = users; + if (!isListAlreadySorted) { + temp = users..sort((curr, next) => curr.name.compareTo(next.name)); + } final groupedUsers = >{}; for (var e in temp) { final alphabet = e.name[0]; From e952d350c54ebc9951cd3bc5b85adfdc8228455e Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Fri, 20 Nov 2020 18:10:23 +0530 Subject: [PATCH 0423/1140] fix: Stop animation before pop --- lib/src/reaction_picker.dart | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/lib/src/reaction_picker.dart b/lib/src/reaction_picker.dart index 1946e9ff..d661621e 100644 --- a/lib/src/reaction_picker.dart +++ b/lib/src/reaction_picker.dart @@ -119,17 +119,24 @@ class _ReactionPickerState extends State { } } + void pop() async { + for (var a in animations) { + a.stop(); + } + Navigator.of(context).pop(); + } + /// Add a reaction to the message void sendReaction(BuildContext context, String reactionType) { StreamChannel.of(context) .channel .sendReaction(widget.message, reactionType); - Navigator.of(context).pop(); + pop(); } /// Remove a reaction from the message void removeReaction(BuildContext context, Reaction reaction) { StreamChannel.of(context).channel.deleteReaction(widget.message, reaction); - Navigator.of(context).pop(); + pop(); } } From 2908cd66c5019cebcf49b54ffb4c4266dbe746b0 Mon Sep 17 00:00:00 2001 From: xsahil03x Date: Fri, 20 Nov 2020 18:11:57 +0530 Subject: [PATCH 0424/1140] Change last seen text to last online --- example/lib/main.dart | 2 +- lib/src/user_item.dart | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/example/lib/main.dart b/example/lib/main.dart index 9cce3cf3..ea665cb6 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -939,7 +939,7 @@ class _GroupChatDetailsScreenState extends State { key: ObjectKey(user), user: user, selected: true, - showLastSeen: false, + showLastOnline: false, ); }, ), diff --git a/lib/src/user_item.dart b/lib/src/user_item.dart index 0c320b7c..be8037b6 100644 --- a/lib/src/user_item.dart +++ b/lib/src/user_item.dart @@ -24,7 +24,7 @@ class UserItem extends StatelessWidget { this.onLongPress, this.onImageTap, this.selected = false, - this.showLastSeen = true, + this.showLastOnline = true, }) : super(key: key); /// Function called when tapping this widget @@ -43,7 +43,7 @@ class UserItem extends StatelessWidget { final bool selected; /// If true the [UserItem] will show the last seen - final bool showLastSeen; + final bool showLastOnline; @override Widget build(BuildContext context) { @@ -81,11 +81,11 @@ class UserItem extends StatelessWidget { ) : null, title: Text(user.name,style: TextStyle(fontWeight: FontWeight.bold),), - subtitle: showLastSeen ? _buildLastActive(context) : null, + subtitle: showLastOnline ? _buildLastActive(context) : null, ); } Widget _buildLastActive(context) { - return Text('Last seen ${Jiffy(user.lastActive).fromNow()}'); + return Text('Last online ${Jiffy(user.lastActive).fromNow()}'); } } From aa62d9a01de261261f85265aa1503eaaf364b486 Mon Sep 17 00:00:00 2001 From: xsahil03x Date: Fri, 20 Nov 2020 18:15:59 +0530 Subject: [PATCH 0425/1140] add debounce in searchQuery --- example/lib/main.dart | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/example/lib/main.dart b/example/lib/main.dart index ea665cb6..6f86ce23 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -10,6 +10,7 @@ import 'package:stream_chat_flutter/stream_chat_flutter.dart'; import 'chips_input_text_field.dart'; import 'notifications_service.dart'; import 'neumorphic_button.dart'; +import 'dart:async'; void main() async { WidgetsFlutterBinding.ensureInitialized(); @@ -284,10 +285,16 @@ class _NewChatScreenState extends State { Channel channel; + Timer _debounce; + void _userNameListener() { - setState(() { - _userNameQuery = _controller.text; - _isSearchActive = _userNameQuery.isNotEmpty; + if (_debounce?.isActive ?? false) _debounce.cancel(); + _debounce = Timer(const Duration(milliseconds: 500), () { + if (mounted) + setState(() { + _userNameQuery = _controller.text; + _isSearchActive = _userNameQuery.isNotEmpty; + }); }); } @@ -533,10 +540,16 @@ class _NewGroupChatScreenState extends State { bool _isSearchActive = false; + Timer _debounce; + void _userNameListener() { - setState(() { - _userNameQuery = _controller.text; - _isSearchActive = _userNameQuery.isNotEmpty; + if (_debounce?.isActive ?? false) _debounce.cancel(); + _debounce = Timer(const Duration(milliseconds: 500), () { + if (mounted) + setState(() { + _userNameQuery = _controller.text; + _isSearchActive = _userNameQuery.isNotEmpty; + }); }); } From 5b06e9c257ce5875fe40382b4343ef520346c4d9 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Fri, 20 Nov 2020 18:16:03 +0530 Subject: [PATCH 0426/1140] fix: Stop animation before pop --- lib/src/reaction_picker.dart | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/src/reaction_picker.dart b/lib/src/reaction_picker.dart index d661621e..802e8eb3 100644 --- a/lib/src/reaction_picker.dart +++ b/lib/src/reaction_picker.dart @@ -122,6 +122,7 @@ class _ReactionPickerState extends State { void pop() async { for (var a in animations) { a.stop(); + a.dispose(); } Navigator.of(context).pop(); } From ee5cec3c4566cdde3c46125fd6bafc0dc1bbb4e5 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Fri, 20 Nov 2020 18:27:12 +0530 Subject: [PATCH 0427/1140] fix: Stop animation before pop --- lib/src/reaction_picker.dart | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/lib/src/reaction_picker.dart b/lib/src/reaction_picker.dart index 802e8eb3..71ddcbb5 100644 --- a/lib/src/reaction_picker.dart +++ b/lib/src/reaction_picker.dart @@ -25,7 +25,8 @@ class ReactionPicker extends StatefulWidget { _ReactionPickerState createState() => _ReactionPickerState(); } -class _ReactionPickerState extends State { +class _ReactionPickerState extends State + with TickerProviderStateMixin { List animations = []; @override @@ -35,10 +36,14 @@ class _ReactionPickerState extends State { if (animations.isEmpty && reactionIcons.isNotEmpty) { reactionIcons.forEach((element) { animations.add( - EzAnimation.sequence([ - SequenceItem(0.0, 1.4), - SequenceItem(1.4, 1.0), - ], Duration(milliseconds: 500)), + EzAnimation.sequence( + [ + SequenceItem(0.0, 1.4), + SequenceItem(1.4, 1.0), + ], + Duration(milliseconds: 500), + vsync: this, + ), ); }); From b0b05e165cfa18591673ad57cabfb0730f38d308 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Fri, 20 Nov 2020 18:30:50 +0530 Subject: [PATCH 0428/1140] fix: Stop animation before pop --- lib/src/reaction_picker.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/reaction_picker.dart b/lib/src/reaction_picker.dart index 71ddcbb5..8d337498 100644 --- a/lib/src/reaction_picker.dart +++ b/lib/src/reaction_picker.dart @@ -127,7 +127,7 @@ class _ReactionPickerState extends State void pop() async { for (var a in animations) { a.stop(); - a.dispose(); + //a.dispose(); } Navigator.of(context).pop(); } From 4ded4d577d56e5c9711add180c8d12977e254bdf Mon Sep 17 00:00:00 2001 From: xsahil03x Date: Fri, 20 Nov 2020 18:38:07 +0530 Subject: [PATCH 0429/1140] Hide Create group button once a user is selected --- 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 6f86ce23..b0f5d73f 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -373,7 +373,7 @@ class _NewChatScreenState extends State { setState(() => _selectedUsers.remove(user)); }, ), - if (!_isSearchActive) + if (!_isSearchActive && !_selectedUsers.isNotEmpty) Container( child: InkWell( onTap: () { From daf8758f61aebf701ce6924d586f25307464e7d5 Mon Sep 17 00:00:00 2001 From: xsahil03x Date: Fri, 20 Nov 2020 18:58:53 +0530 Subject: [PATCH 0430/1140] Fix UserAdd IconButton alignment --- example/lib/chips_input_text_field.dart | 123 ++++++++++++------------ 1 file changed, 63 insertions(+), 60 deletions(-) diff --git a/example/lib/chips_input_text_field.dart b/example/lib/chips_input_text_field.dart index 695783d9..1eb3159d 100644 --- a/example/lib/chips_input_text_field.dart +++ b/example/lib/chips_input_text_field.dart @@ -67,72 +67,75 @@ class ChipInputTextFieldState extends State> { child: Container( child: Padding( padding: const EdgeInsets.fromLTRB(16, 16, 16, 16), - child: Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Padding( - padding: const EdgeInsets.symmetric(vertical: 4.0), - child: Text( - 'TO:', - style: TextStyle( - color: Colors.black.withOpacity(0.5), + child: IntrinsicHeight( + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: const EdgeInsets.symmetric(vertical: 4.0), + child: Text( + 'TO:', + style: TextStyle( + color: Colors.black.withOpacity(0.5), + ), ), ), - ), - SizedBox(width: 12), - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisSize: MainAxisSize.min, - children: [ - Wrap( - spacing: 8.0, - runSpacing: 4.0, - children: _chips.map((item) { - return widget.chipBuilder(context, item); - }).toList(), - ), - if (!_pauseItemAddition) ...[ - TextField( - controller: widget.controller, - onChanged: widget.onInputChanged, - focusNode: widget.focusNode, - decoration: InputDecoration( - isDense: true, - border: InputBorder.none, - focusedBorder: InputBorder.none, - enabledBorder: InputBorder.none, - errorBorder: InputBorder.none, - disabledBorder: InputBorder.none, - contentPadding: const EdgeInsets.only(top: 4.0), - hintText: widget.hint, - hintStyle: TextStyle( - color: Colors.black.withOpacity(0.5), + SizedBox(width: 12), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + Wrap( + spacing: 8.0, + runSpacing: 4.0, + children: _chips.map((item) { + return widget.chipBuilder(context, item); + }).toList(), + ), + if (!_pauseItemAddition) + TextField( + controller: widget.controller, + onChanged: widget.onInputChanged, + focusNode: widget.focusNode, + decoration: InputDecoration( + isDense: true, + border: InputBorder.none, + focusedBorder: InputBorder.none, + enabledBorder: InputBorder.none, + errorBorder: InputBorder.none, + disabledBorder: InputBorder.none, + contentPadding: const EdgeInsets.only(top: 4.0), + hintText: widget.hint, + hintStyle: TextStyle( + color: Colors.black.withOpacity(0.5), + ), ), ), - ), - ] - ], + ], + ), ), - ), - IconButton( - icon: Icon( - _chips.isEmpty ? StreamIcons.user : StreamIcons.user_add, - color: Colors.black.withOpacity(0.5), + SizedBox(width: 12), + Align( + alignment: Alignment.bottomCenter, + child: IconButton( + icon: Icon( + _chips.isEmpty ? StreamIcons.user : StreamIcons.user_add, + color: Colors.black.withOpacity(0.5), + ), + onPressed: !_pauseItemAddition ? null : resumeItemAddition, + alignment: Alignment.topRight, + visualDensity: VisualDensity.compact, + padding: const EdgeInsets.all(0), + splashRadius: 24, + constraints: BoxConstraints.tightFor( + height: 24, + width: 24, + ), + ), ), - onPressed: () { - resumeItemAddition(); - }, - alignment: Alignment.topRight, - visualDensity: VisualDensity.compact, - padding: const EdgeInsets.all(0), - splashRadius: 24, - constraints: BoxConstraints.tightFor( - height: 24, - width: 24, - ), - ), - ], + ], + ), ), ), ), From 8bc9e62917d85a66ef7a22703ed615c754603ae7 Mon Sep 17 00:00:00 2001 From: xsahil03x Date: Fri, 20 Nov 2020 18:59:36 +0530 Subject: [PATCH 0431/1140] Reduce debounce duration to 350ms from 500ms --- example/lib/main.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/example/lib/main.dart b/example/lib/main.dart index b0f5d73f..2a30af4f 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -289,7 +289,7 @@ class _NewChatScreenState extends State { void _userNameListener() { if (_debounce?.isActive ?? false) _debounce.cancel(); - _debounce = Timer(const Duration(milliseconds: 500), () { + _debounce = Timer(const Duration(milliseconds: 350), () { if (mounted) setState(() { _userNameQuery = _controller.text; @@ -544,7 +544,7 @@ class _NewGroupChatScreenState extends State { void _userNameListener() { if (_debounce?.isActive ?? false) _debounce.cancel(); - _debounce = Timer(const Duration(milliseconds: 500), () { + _debounce = Timer(const Duration(milliseconds: 350), () { if (mounted) setState(() { _userNameQuery = _controller.text; From cc22b1b4ae8c9b7ffd5600fa3054480d62452e6b Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Fri, 20 Nov 2020 14:55:38 +0100 Subject: [PATCH 0432/1140] fix ui issues --- example/lib/chips_input_text_field.dart | 5 ++- example/lib/main.dart | 43 +++++++++++++++++-------- example/pubspec.yaml | 2 +- lib/src/message_input.dart | 6 ++-- lib/src/user_avatar.dart | 15 +++++---- lib/src/user_item.dart | 5 ++- 6 files changed, 50 insertions(+), 26 deletions(-) diff --git a/example/lib/chips_input_text_field.dart b/example/lib/chips_input_text_field.dart index 1eb3159d..30183926 100644 --- a/example/lib/chips_input_text_field.dart +++ b/example/lib/chips_input_text_field.dart @@ -69,13 +69,14 @@ class ChipInputTextFieldState extends State> { padding: const EdgeInsets.fromLTRB(16, 16, 16, 16), child: IntrinsicHeight( child: Row( - crossAxisAlignment: CrossAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.baseline, children: [ Padding( padding: const EdgeInsets.symmetric(vertical: 4.0), child: Text( 'TO:', style: TextStyle( + fontSize: 12, color: Colors.black.withOpacity(0.5), ), ), @@ -109,6 +110,7 @@ class ChipInputTextFieldState extends State> { hintText: widget.hint, hintStyle: TextStyle( color: Colors.black.withOpacity(0.5), + fontSize: 14, ), ), ), @@ -122,6 +124,7 @@ class ChipInputTextFieldState extends State> { icon: Icon( _chips.isEmpty ? StreamIcons.user : StreamIcons.user_add, color: Colors.black.withOpacity(0.5), + size: 24, ), onPressed: !_pauseItemAddition ? null : resumeItemAddition, alignment: Alignment.topRight, diff --git a/example/lib/main.dart b/example/lib/main.dart index 2a30af4f..758e7784 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -1,3 +1,4 @@ +import 'dart:async'; import 'dart:io'; import 'package:example/choose_user_page.dart'; @@ -8,9 +9,8 @@ import 'package:flutter_secure_storage/flutter_secure_storage.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; import 'chips_input_text_field.dart'; -import 'notifications_service.dart'; import 'neumorphic_button.dart'; -import 'dart:async'; +import 'notifications_service.dart'; void main() async { WidgetsFlutterBinding.ensureInitialized(); @@ -179,7 +179,6 @@ class ChannelListPage extends StatelessWidget { options: { 'presence': true, }, - sort: [SortOption('last_message_at')], pagination: PaginationParams( limit: 20, ), @@ -323,7 +322,10 @@ class _NewChatScreenState extends State { leading: const StreamBackButton(), title: Text( 'New Chat', - style: TextStyle(color: Colors.black), + style: TextStyle( + color: Colors.black, + fontSize: 16, + ), ), centerTitle: true, ), @@ -577,7 +579,10 @@ class _NewGroupChatScreenState extends State { leading: const StreamBackButton(), title: Text( 'Add Group Members', - style: TextStyle(color: Colors.black), + style: TextStyle( + color: Colors.black, + fontSize: 16, + ), ), centerTitle: true, actions: [ @@ -622,10 +627,12 @@ class _NewGroupChatScreenState extends State { prefixIcon: Icon( StreamIcons.search, color: Colors.black, + size: 24, ), hintText: 'Search', hintStyle: TextStyle( color: Colors.black.withOpacity(0.5), + fontSize: 14, ), contentPadding: const EdgeInsets.all(0), border: OutlineInputBorder( @@ -650,6 +657,7 @@ class _NewGroupChatScreenState extends State { Stack( children: [ UserAvatar( + onlineIndicatorAlignment: Alignment(0.9, 0.9), user: user, showOnlineStatus: true, borderRadius: BorderRadius.circular(32), @@ -659,9 +667,9 @@ class _NewGroupChatScreenState extends State { ), ), Positioned( - top: 0, - right: 0, - child: InkWell( + top: -4, + right: -4, + child: GestureDetector( onTap: () { if (_selectedUsers.contains(user)) { setState(() => _selectedUsers.remove(user)); @@ -671,14 +679,15 @@ class _NewGroupChatScreenState extends State { decoration: BoxDecoration( color: Colors.white, shape: BoxShape.circle, - border: - Border.all(color: Colors.grey.shade100), + border: Border.all( + color: Colors.grey.shade100, + ), ), child: Padding( - padding: const EdgeInsets.all(2.0), + padding: const EdgeInsets.all(0.0), child: Icon( - Icons.clear_rounded, - size: 14, + StreamIcons.close, + size: 24, ), ), ), @@ -848,7 +857,10 @@ class _GroupChatDetailsScreenState extends State { leading: const StreamBackButton(), title: Text( 'Name of Group Chat', - style: TextStyle(color: Colors.black), + style: TextStyle( + color: Colors.black, + fontSize: 16, + ), ), centerTitle: true, bottom: PreferredSize( @@ -860,6 +872,7 @@ class _GroupChatDetailsScreenState extends State { Text( 'NAME', style: TextStyle( + fontSize: 12, color: Colors.black.withOpacity(0.5), ), ), @@ -876,6 +889,8 @@ class _GroupChatDetailsScreenState extends State { disabledBorder: InputBorder.none, contentPadding: const EdgeInsets.all(0), hintText: 'Choose a group chat name', + hintStyle: TextStyle( + fontSize: 14, color: Colors.black.withOpacity(.5)), ), ), ), diff --git a/example/pubspec.yaml b/example/pubspec.yaml index fca549d2..0fe6a0ad 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -1,6 +1,6 @@ name: example description: A new Flutter project. -version: 1.0.60+62 +version: 1.0.62+64 environment: sdk: ">=2.2.2 <3.0.0" diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index cd96119a..423d4c8f 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -423,7 +423,7 @@ class MessageInputState extends State { } void _onChanged(BuildContext context, String s) { - StreamChannel.of(context).channel.keyStroke(); + StreamChannel.of(context).channel.keyStroke().catchError((e) {}); setState(() { _messageIsPresent = s.trim().isNotEmpty; @@ -1712,7 +1712,9 @@ class MessageInputState extends State { if (!kIsWeb) { _keyboardListener = KeyboardVisibility.onChange.listen((visible) { - _onChanged(context, textEditingController.text); + if (_focusNode.hasFocus) { + _onChanged(context, textEditingController.text); + } }); } diff --git a/lib/src/user_avatar.dart b/lib/src/user_avatar.dart index 66edba39..566ef603 100644 --- a/lib/src/user_avatar.dart +++ b/lib/src/user_avatar.dart @@ -13,9 +13,11 @@ class UserAvatar extends StatelessWidget { this.onTap, this.showOnlineStatus = true, this.borderRadius, + this.onlineIndicatorAlignment = Alignment.topRight, }) : super(key: key); final User user; + final Alignment onlineIndicatorAlignment; final BoxConstraints constraints; final BorderRadius borderRadius; final BoxConstraints onlineIndicatorConstraints; @@ -60,11 +62,11 @@ class UserAvatar extends StatelessWidget { ), ), if (showOnlineStatus && user.online == true) - Positioned( - top: 0, - right: 0, - child: Material( - child: Center( + Positioned.fill( + child: Align( + alignment: onlineIndicatorAlignment, + child: Material( + type: MaterialType.circle, child: Container( padding: const EdgeInsets.all(2.0), constraints: onlineIndicatorConstraints ?? @@ -77,9 +79,8 @@ class UserAvatar extends StatelessWidget { color: Color(0xff20E070), ), ), + color: Colors.white, ), - shape: CircleBorder(), - color: Colors.white, ), ), ], diff --git a/lib/src/user_item.dart b/lib/src/user_item.dart index be8037b6..06ab0848 100644 --- a/lib/src/user_item.dart +++ b/lib/src/user_item.dart @@ -80,7 +80,10 @@ class UserItem extends StatelessWidget { radius: 10, ) : null, - title: Text(user.name,style: TextStyle(fontWeight: FontWeight.bold),), + title: Text( + user.name, + style: TextStyle(fontWeight: FontWeight.bold), + ), subtitle: showLastOnline ? _buildLastActive(context) : null, ); } From 879f5d31bc3c0e7e5ee5c9bcc6a99da85729090e Mon Sep 17 00:00:00 2001 From: xsahil03x Date: Fri, 20 Nov 2020 19:31:13 +0530 Subject: [PATCH 0433/1140] UI fixes --- example/lib/main.dart | 50 ++++++++++++++++++++++++++++++++++++++----- 1 file changed, 45 insertions(+), 5 deletions(-) diff --git a/example/lib/main.dart b/example/lib/main.dart index 2a30af4f..cc64cbd7 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -736,6 +736,10 @@ class _NewGroupChatScreenState extends State { setState(() { _selectedUsers.add(user); }); + } else { + setState(() { + _selectedUsers.remove(user); + }); } }, pagination: PaginationParams( @@ -939,7 +943,7 @@ class _GroupChatDetailsScreenState extends State { ), Expanded( child: ListView.separated( - itemCount: _selectedUsers.length, + itemCount: _selectedUsers.length + 1, separatorBuilder: (_, __) => Container( height: 1, color: Theme.of(context).brightness == Brightness.dark @@ -947,12 +951,48 @@ class _GroupChatDetailsScreenState extends State { : Colors.black.withOpacity(0.1), ), itemBuilder: (_, index) { + if (index == _selectedUsers.length) { + return Container( + height: 1, + color: Theme.of(context).brightness == Brightness.dark + ? Colors.white.withOpacity(0.1) + : Colors.black.withOpacity(0.1), + ); + } final user = _selectedUsers[index]; - return UserItem( + return ListTile( key: ObjectKey(user), - user: user, - selected: true, - showLastOnline: false, + leading: UserAvatar( + user: user, + constraints: BoxConstraints.tightFor( + width: 40, + height: 40, + ), + ), + title: Text( + user.name, + style: TextStyle(fontWeight: FontWeight.bold), + ), + contentPadding: const EdgeInsets.symmetric( + horizontal: 12, + vertical: 8, + ), + trailing: IconButton( + icon: Icon( + Icons.clear_rounded, + color: Colors.black, + ), + padding: const EdgeInsets.all(0), + splashRadius: 24, + onPressed: () { + setState(() { + _selectedUsers.remove(user); + }); + if (_selectedUsers.isEmpty) { + Navigator.pop(context); + } + }, + ), ); }, ), From 1d5717ce9a03cc5e5080b83db338e845fbe7e56b Mon Sep 17 00:00:00 2001 From: xsahil03x Date: Fri, 20 Nov 2020 20:04:51 +0530 Subject: [PATCH 0434/1140] Add flutter format check in test.yml --- .github/workflows/test.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 4b3e086a..a76cc4c8 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -13,6 +13,8 @@ jobs: channel: 'stable' - name: Get dependencies run: flutter pub get + - name: Run formatter + run: flutter format -n --set-exit-if-changed . - name: Coverage fix run: | file=test/coverage_helper_test.dart From 265e8622f3cc543de8070a076692fe6b3bdec832 Mon Sep 17 00:00:00 2001 From: xsahil03x Date: Fri, 20 Nov 2020 20:05:14 +0530 Subject: [PATCH 0435/1140] Add formatting mistake for testing action. --- 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 d42bb7af..9c1977e3 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -434,6 +434,6 @@ class _CreateChannelPageState extends State { ...value.users, ]; }); - }).whenComplete(() => loading = false); + }).whenComplete(() => loading = false ); } } From 593dcabc6e8510e00fcf53e6de7c6bf8fa355bd3 Mon Sep 17 00:00:00 2001 From: xsahil03x Date: Fri, 20 Nov 2020 20:08:50 +0530 Subject: [PATCH 0436/1140] Fix formatting mistake --- 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 9c1977e3..d42bb7af 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -434,6 +434,6 @@ class _CreateChannelPageState extends State { ...value.users, ]; }); - }).whenComplete(() => loading = false ); + }).whenComplete(() => loading = false); } } From 682c0b3e10736746b8d7f73cc38b93e03fb87946 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Fri, 20 Nov 2020 18:03:33 +0100 Subject: [PATCH 0437/1140] swap user list with message list and create channel with draft: true --- example/lib/chips_input_text_field.dart | 157 +++++----- example/lib/main.dart | 382 ++++++++++++++---------- example/pubspec.yaml | 2 +- lib/src/message_input.dart | 8 +- lib/src/message_list_view.dart | 19 ++ lib/src/url_attachment.dart | 6 +- 6 files changed, 339 insertions(+), 235 deletions(-) diff --git a/example/lib/chips_input_text_field.dart b/example/lib/chips_input_text_field.dart index 30183926..317a68f7 100644 --- a/example/lib/chips_input_text_field.dart +++ b/example/lib/chips_input_text_field.dart @@ -22,7 +22,7 @@ class ChipsInputTextField extends StatefulWidget { this.focusNode, this.onChipAdded, this.onChipRemoved, - this.hint = 'Type a name or group', + this.hint = 'Type a name', }) : super(key: key); @override @@ -61,83 +61,96 @@ class ChipInputTextFieldState extends State> { @override Widget build(BuildContext context) { - return Material( - elevation: 1, - color: Colors.white, - child: Container( - child: Padding( - padding: const EdgeInsets.fromLTRB(16, 16, 16, 16), - child: IntrinsicHeight( - child: Row( - crossAxisAlignment: CrossAxisAlignment.baseline, - children: [ - Padding( - padding: const EdgeInsets.symmetric(vertical: 4.0), - child: Text( - 'TO:', - style: TextStyle( - fontSize: 12, - color: Colors.black.withOpacity(0.5), + return GestureDetector( + onTap: _pauseItemAddition + ? () { + setState(() { + _pauseItemAddition = false; + widget.focusNode?.requestFocus(); + }); + } + : null, + child: Material( + elevation: 1, + color: Colors.white, + child: Container( + child: Padding( + padding: const EdgeInsets.fromLTRB(16, 16, 16, 16), + child: IntrinsicHeight( + child: Row( + crossAxisAlignment: CrossAxisAlignment.baseline, + children: [ + Padding( + padding: const EdgeInsets.symmetric(vertical: 4.0), + child: Text( + 'TO:', + style: TextStyle( + fontSize: 12, + color: Colors.black.withOpacity(0.5), + ), ), ), - ), - SizedBox(width: 12), - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisSize: MainAxisSize.min, - children: [ - Wrap( - spacing: 8.0, - runSpacing: 4.0, - children: _chips.map((item) { - return widget.chipBuilder(context, item); - }).toList(), - ), - if (!_pauseItemAddition) - TextField( - controller: widget.controller, - onChanged: widget.onInputChanged, - focusNode: widget.focusNode, - decoration: InputDecoration( - isDense: true, - border: InputBorder.none, - focusedBorder: InputBorder.none, - enabledBorder: InputBorder.none, - errorBorder: InputBorder.none, - disabledBorder: InputBorder.none, - contentPadding: const EdgeInsets.only(top: 4.0), - hintText: widget.hint, - hintStyle: TextStyle( - color: Colors.black.withOpacity(0.5), - fontSize: 14, + SizedBox(width: 12), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + Wrap( + spacing: 8.0, + runSpacing: 4.0, + children: _chips.map((item) { + return widget.chipBuilder(context, item); + }).toList(), + ), + if (!_pauseItemAddition) + TextField( + controller: widget.controller, + onChanged: widget.onInputChanged, + focusNode: widget.focusNode, + decoration: InputDecoration( + isDense: true, + border: InputBorder.none, + focusedBorder: InputBorder.none, + enabledBorder: InputBorder.none, + errorBorder: InputBorder.none, + disabledBorder: InputBorder.none, + contentPadding: const EdgeInsets.only(top: 4.0), + hintText: widget.hint, + hintStyle: TextStyle( + color: Colors.black.withOpacity(0.5), + fontSize: 14, + ), ), ), - ), - ], - ), - ), - SizedBox(width: 12), - Align( - alignment: Alignment.bottomCenter, - child: IconButton( - icon: Icon( - _chips.isEmpty ? StreamIcons.user : StreamIcons.user_add, - color: Colors.black.withOpacity(0.5), - size: 24, - ), - onPressed: !_pauseItemAddition ? null : resumeItemAddition, - alignment: Alignment.topRight, - visualDensity: VisualDensity.compact, - padding: const EdgeInsets.all(0), - splashRadius: 24, - constraints: BoxConstraints.tightFor( - height: 24, - width: 24, + ], ), ), - ), - ], + SizedBox(width: 12), + Align( + alignment: Alignment.bottomCenter, + child: IconButton( + icon: Icon( + _chips.isEmpty + ? StreamIcons.user + : StreamIcons.user_add, + color: Colors.black.withOpacity(0.5), + size: 24, + ), + onPressed: + !_pauseItemAddition ? null : resumeItemAddition, + alignment: Alignment.topRight, + visualDensity: VisualDensity.compact, + padding: const EdgeInsets.all(0), + splashRadius: 24, + constraints: BoxConstraints.tightFor( + height: 24, + width: 24, + ), + ), + ), + ], + ), ), ), ), diff --git a/example/lib/main.dart b/example/lib/main.dart index 70c11940..e2a8a5f7 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -111,6 +111,7 @@ class ChannelListPage extends StatelessWidget { ), ListTile( onTap: () { + Navigator.pop(context); Navigator.push( context, MaterialPageRoute(builder: (_) => NewChatScreen()), @@ -126,6 +127,7 @@ class ChannelListPage extends StatelessWidget { ), ListTile( onTap: () { + Navigator.pop(context); Navigator.push( context, MaterialPageRoute(builder: (_) => NewGroupChatScreen()), @@ -177,7 +179,10 @@ class ChannelListPage extends StatelessWidget { filter: { 'members': { '\$in': [user.id], - } + }, + 'draft': { + r'$ne': true, + }, }, options: { 'presence': true, @@ -283,12 +288,17 @@ class _NewChatScreenState extends State { final _selectedUsers = {}; + final _searchFocusNode = FocusNode(); + final _messageInputFocusNode = FocusNode(); + bool _isSearchActive = false; Channel channel; Timer _debounce; + bool _showUserList = true; + void _userNameListener() { if (_debounce?.isActive ?? false) _debounce.cancel(); _debounce = Timer(const Duration(milliseconds: 350), () { @@ -305,10 +315,50 @@ class _NewChatScreenState extends State { super.initState(); channel = StreamChat.of(context).client.channel('messaging'); _controller = TextEditingController()..addListener(_userNameListener); + + _searchFocusNode.addListener(() async { + if (_searchFocusNode.hasFocus && !_showUserList) { + if (channel.extraData['draft'] == true) { + await channel.stopWatching(); + channel.dispose(); + channel.client.state.channels.remove(channel.cid); + } + setState(() { + _showUserList = true; + }); + } + }); + + _messageInputFocusNode.addListener(() async { + if (_messageInputFocusNode.hasFocus && _selectedUsers.isNotEmpty) { + final chatState = StreamChat.of(context); + + channel = chatState.client.channel( + 'messaging', + extraData: { + 'members': [ + ..._selectedUsers.map((e) => e.id), + chatState.user.id, + ], + 'draft': true, + }, + ); + + if (!chatState.client.state.channels.containsKey(channel.cid)) { + await channel.watch(); + } + + setState(() { + _showUserList = false; + }); + } + }); } @override void dispose() { + _searchFocusNode.dispose(); + _messageInputFocusNode.dispose(); _controller?.clear(); _controller?.removeListener(_userNameListener); _controller?.dispose(); @@ -335,81 +385,81 @@ class _NewChatScreenState extends State { body: StreamChannel( showLoading: false, channel: channel, - child: UsersBloc( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - ChipsInputTextField( - key: _chipInputTextFieldStateKey, - controller: _controller, - focusNode: FocusNode(), - chipBuilder: (context, user) { - return Stack( - alignment: AlignmentDirectional.centerStart, - children: [ - Container( - decoration: BoxDecoration( - color: Colors.black.withOpacity(0.05), - borderRadius: BorderRadius.circular(12), - ), - padding: const EdgeInsets.only(left: 24), - child: Padding( - padding: const EdgeInsets.fromLTRB(8, 4, 12, 4), - child: Text( - user.name, - style: TextStyle(color: Colors.black), - ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + ChipsInputTextField( + key: _chipInputTextFieldStateKey, + controller: _controller, + focusNode: _searchFocusNode, + chipBuilder: (context, user) { + return Stack( + alignment: AlignmentDirectional.centerStart, + children: [ + Container( + decoration: BoxDecoration( + color: Colors.black.withOpacity(0.05), + borderRadius: BorderRadius.circular(12), + ), + padding: const EdgeInsets.only(left: 24), + child: Padding( + padding: const EdgeInsets.fromLTRB(8, 4, 12, 4), + child: Text( + user.name, + style: TextStyle(color: Colors.black), ), ), - UserAvatar( - user: user, - constraints: BoxConstraints.tightFor( - height: 24, - width: 24, + ), + UserAvatar( + user: user, + constraints: BoxConstraints.tightFor( + height: 24, + width: 24, + ), + ), + ], + ); + }, + onChipAdded: (user) { + setState(() => _selectedUsers.add(user)); + }, + onChipRemoved: (user) { + setState(() => _selectedUsers.remove(user)); + }, + ), + if (!_isSearchActive && !_selectedUsers.isNotEmpty) + Container( + child: InkWell( + onTap: () { + Navigator.push( + context, + MaterialPageRoute(builder: (_) => NewGroupChatScreen()), + ); + }, + child: Padding( + padding: const EdgeInsets.symmetric(vertical: 8), + child: Row( + children: [ + NeumorphicButton( + child: Icon( + StreamIcons.group, + color: Color(0xFF006CFF), + ), ), - ), - ], - ); - }, - onChipAdded: (user) { - setState(() => _selectedUsers.add(user)); - }, - onChipRemoved: (user) { - setState(() => _selectedUsers.remove(user)); - }, - ), - if (!_isSearchActive && !_selectedUsers.isNotEmpty) - Container( - child: InkWell( - onTap: () { - Navigator.push( - context, - MaterialPageRoute(builder: (_) => NewGroupChatScreen()), - ); - }, - child: Padding( - padding: const EdgeInsets.symmetric(vertical: 8), - child: Row( - children: [ - NeumorphicButton( - child: Icon( - StreamIcons.group, - color: Color(0xFF006CFF), - ), + SizedBox(width: 8), + Text( + 'Create a Group', + style: TextStyle( + fontWeight: FontWeight.bold, + fontSize: 16, ), - SizedBox(width: 8), - Text( - 'Create a Group', - style: TextStyle( - fontWeight: FontWeight.bold, - fontSize: 16, - ), - ), - ], - ), + ), + ], ), ), ), + ), + if (_showUserList) Container( width: double.maxFinite, decoration: BoxDecoration( @@ -438,97 +488,108 @@ class _NewChatScreenState extends State { ), ), ), - Expanded( - child: UserListView( - selectedUsers: _selectedUsers, - groupAlphabetically: _isSearchActive ? false : true, - onUserTap: (user, _) { - _controller.clear(); - if (!_selectedUsers.contains(user)) { - _chipInputTextFieldState - ..addItem(user) - ..pauseItemAddition(); - } else { - _chipInputTextFieldState.removeItem(user); - } - }, - pagination: PaginationParams( - limit: 25, - ), - filter: { - if (_userNameQuery.isNotEmpty) - 'name': { - r'$autocomplete': _userNameQuery, - } - }, - sort: [ - SortOption( - 'name', - direction: 1, - ), - ], - emptyBuilder: (_) { - return LayoutBuilder( - builder: (context, viewportConstraints) { - return SingleChildScrollView( - physics: AlwaysScrollableScrollPhysics(), - child: ConstrainedBox( - constraints: BoxConstraints( - minHeight: viewportConstraints.maxHeight, - ), - child: Center( - child: Column( - children: [ - Padding( - padding: const EdgeInsets.all(24), - child: Icon( - StreamIcons.search, - size: 96, - color: Colors.grey, + Expanded( + child: _showUserList + ? UsersBloc( + child: UserListView( + selectedUsers: _selectedUsers, + groupAlphabetically: _isSearchActive ? false : true, + onUserTap: (user, _) { + _controller.clear(); + if (!_selectedUsers.contains(user)) { + _chipInputTextFieldState + ..addItem(user) + ..pauseItemAddition(); + } else { + _chipInputTextFieldState.removeItem(user); + } + }, + pagination: PaginationParams( + limit: 25, + ), + filter: { + if (_userNameQuery.isNotEmpty) + 'name': { + r'$autocomplete': _userNameQuery, + }, + 'id': { + r'$ne': StreamChat.of(context).user.id, + }, + }, + sort: [ + SortOption( + 'name', + direction: 1, + ), + ], + emptyBuilder: (_) { + return LayoutBuilder( + builder: (context, viewportConstraints) { + return SingleChildScrollView( + physics: AlwaysScrollableScrollPhysics(), + child: ConstrainedBox( + constraints: BoxConstraints( + minHeight: viewportConstraints.maxHeight, + ), + child: Center( + child: Column( + children: [ + Padding( + padding: const EdgeInsets.all(24), + child: Icon( + StreamIcons.search, + size: 96, + color: Colors.grey, + ), + ), + Text( + 'No user matches these keywords...'), + ], ), ), - Text('No user matches these keywords...'), - ], - ), - ), - ), - ); - }, - ); - }, - ), - ), - MessageInput( - preMessageSending: (message) async { - channel.extraData = { - 'members': [ - ..._selectedUsers.map((e) => e.id), - channel.client.state.user.id, - ], - }; - await channel.watch(); - return message; - }, - onMessageSent: (_) { - Navigator.pushReplacement( - context, - MaterialPageRoute( - builder: (context) { - return StreamChannel( - child: ChannelPage(), - channel: channel, - ); - }, - ), - ); - }, - ), - ], - ), + ), + ); + }, + ); + }, + ), + ) + : MessageListView(), + ), + MessageInput( + focusNode: _messageInputFocusNode, + onMessageSent: (m) { + if (!m.isEphemeral) { + _updateChannelAndNavigate(context); + } else { + channel.on('message.new').first.then((_) { + _updateChannelAndNavigate(context); + }); + } + }, + ), + ], ), ), ); } + + void _updateChannelAndNavigate(BuildContext context) { + channel.update({ + 'draft': false, + }); + Navigator.pushReplacement( + context, + MaterialPageRoute( + builder: (context) { + return StreamChannel( + child: ChannelPage(), + channel: channel, + ); + }, + ), + ); + } } class NewGroupChatScreen extends StatefulWidget { @@ -761,7 +822,10 @@ class _NewGroupChatScreenState extends State { if (_userNameQuery.isNotEmpty) 'name': { r'$autocomplete': _userNameQuery, - } + }, + 'id': { + r'$ne': StreamChat.of(context).user.id, + } }, sort: [ SortOption( @@ -832,9 +896,11 @@ class _GroupChatDetailsScreenState extends State { void _groupNameListener() { final name = _groupNameController.text; - setState(() { - _isGroupNameEmpty = name.isEmpty; - }); + if (mounted) { + setState(() { + _isGroupNameEmpty = name.isEmpty; + }); + } } @override diff --git a/example/pubspec.yaml b/example/pubspec.yaml index e5c11897..0fe6a0ad 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -1,6 +1,6 @@ name: example description: A new Flutter project. -version: 1.0.61+63 +version: 1.0.62+64 environment: sdk: ">=2.2.2 <3.0.0" diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 423d4c8f..6845d1a4 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -104,6 +104,7 @@ class MessageInput extends StatefulWidget { this.actions, this.actionsLocation = ActionsLocation.left, this.attachmentThumbnailBuilders, + this.focusNode, }) : super(key: key); /// Message to edit @@ -149,6 +150,9 @@ class MessageInput extends StatefulWidget { /// Map that defines a thumbnail builder for an attachment type final Map attachmentThumbnailBuilders; + /// The focus node associated to the TextField + final FocusNode focusNode; + @override MessageInputState createState() => MessageInputState(); @@ -169,10 +173,10 @@ class MessageInput extends StatefulWidget { class MessageInputState extends State { final List<_SendingAttachment> _attachments = []; - final _focusNode = FocusNode(); final List _mentionedUsers = []; final _imagePicker = ImagePicker(); + FocusNode _focusNode; bool _inputEnabled = true; bool _messageIsPresent = false; bool _animateContainer = true; @@ -1708,6 +1712,8 @@ class MessageInputState extends State { void initState() { super.initState(); + _focusNode = widget.focusNode ?? FocusNode(); + _emojiNames = Emoji.all().map((e) => e.name); if (!kIsWeb) { diff --git a/lib/src/message_list_view.dart b/lib/src/message_list_view.dart index 2a60b75b..4a5e445b 100644 --- a/lib/src/message_list_view.dart +++ b/lib/src/message_list_view.dart @@ -180,7 +180,26 @@ class _MessageListViewState extends State { ? streamChannel.channel.state.threads[widget.parentMessage.id] : streamChannel.channel.state.messages, builder: (context, snapshot) { + if (!snapshot.hasData) { + return Center( + child: CircularProgressIndicator(), + ); + } + final messages = snapshot.data?.reversed?.toList() ?? []; + + if (messages.isEmpty) { + return Center( + child: Text( + 'No chats here yet...', + style: TextStyle( + fontSize: 12, + color: Colors.black.withOpacity(.5), + ), + ), + ); + } + return Stack( alignment: Alignment.center, children: [ diff --git a/lib/src/url_attachment.dart b/lib/src/url_attachment.dart index a873217f..d735ad67 100644 --- a/lib/src/url_attachment.dart +++ b/lib/src/url_attachment.dart @@ -4,9 +4,9 @@ import 'package:stream_chat_flutter/src/utils.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; class UrlAttachment extends StatelessWidget { - Attachment urlAttachment; - String hostDisplayName; - EdgeInsets textPadding; + final Attachment urlAttachment; + final String hostDisplayName; + final EdgeInsets textPadding; UrlAttachment({ @required this.urlAttachment, From d7a8d4f3f9111fbacf40e26bda15cefc072cb20a Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Sat, 21 Nov 2020 11:24:38 +0100 Subject: [PATCH 0438/1140] extract screens --- example/lib/group_chat_details_screen.dart | 221 ++++++ example/lib/main.dart | 822 +-------------------- example/lib/new_chat_screen.dart | 331 +++++++++ example/lib/new_group_chat_screen.dart | 285 +++++++ example/pubspec.yaml | 2 +- 5 files changed, 840 insertions(+), 821 deletions(-) create mode 100644 example/lib/group_chat_details_screen.dart create mode 100644 example/lib/new_chat_screen.dart create mode 100644 example/lib/new_group_chat_screen.dart diff --git a/example/lib/group_chat_details_screen.dart b/example/lib/group_chat_details_screen.dart new file mode 100644 index 00000000..8ba8c71f --- /dev/null +++ b/example/lib/group_chat_details_screen.dart @@ -0,0 +1,221 @@ +import 'package:flutter/material.dart'; +import 'package:stream_chat_flutter/stream_chat_flutter.dart'; + +import 'main.dart'; +import 'neumorphic_button.dart'; + +class GroupChatDetailsScreen extends StatefulWidget { + final List selectedUsers; + + const GroupChatDetailsScreen({ + Key key, + @required this.selectedUsers, + }) : super(key: key); + + @override + _GroupChatDetailsScreenState createState() => _GroupChatDetailsScreenState(); +} + +class _GroupChatDetailsScreenState extends State { + final _selectedUsers = []; + + TextEditingController _groupNameController; + + Channel _channel; + + bool _isGroupNameEmpty = true; + + int get _totalUsers => _selectedUsers.length; + + void _groupNameListener() { + final name = _groupNameController.text; + if (mounted) { + setState(() { + _isGroupNameEmpty = name.isEmpty; + }); + } + } + + @override + void initState() { + super.initState(); + _channel = StreamChat.of(context).client.channel('messaging'); + _selectedUsers.addAll(widget.selectedUsers); + _groupNameController = TextEditingController() + ..addListener(_groupNameListener); + } + + @override + void dispose() { + _groupNameController?.clear(); + _groupNameController?.removeListener(_groupNameListener); + _groupNameController?.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: Color.fromRGBO(252, 252, 252, 1), + appBar: AppBar( + elevation: 1, + backgroundColor: Colors.white, + leading: const StreamBackButton(), + title: Text( + 'Name of Group Chat', + style: TextStyle( + color: Colors.black, + fontSize: 16, + ), + ), + centerTitle: true, + bottom: PreferredSize( + preferredSize: Size.fromHeight(kToolbarHeight), + child: Padding( + padding: const EdgeInsets.symmetric(vertical: 18, horizontal: 16), + child: Row( + children: [ + Text( + 'NAME', + style: TextStyle( + fontSize: 12, + color: Colors.black.withOpacity(0.5), + ), + ), + SizedBox(width: 16), + Expanded( + child: TextField( + controller: _groupNameController, + decoration: InputDecoration( + isDense: true, + border: InputBorder.none, + focusedBorder: InputBorder.none, + enabledBorder: InputBorder.none, + errorBorder: InputBorder.none, + disabledBorder: InputBorder.none, + contentPadding: const EdgeInsets.all(0), + hintText: 'Choose a group chat name', + hintStyle: TextStyle( + fontSize: 14, color: Colors.black.withOpacity(.5)), + ), + ), + ), + ], + ), + ), + ), + actions: [ + NeumorphicButton( + child: IconButton( + padding: const EdgeInsets.all(0), + icon: Icon(StreamIcons.check), + color: Color(0xFF006CFF), + onPressed: _isGroupNameEmpty + ? null + : () async { + final groupName = _groupNameController.text; + final client = _channel.client; + _channel.extraData = { + 'members': [ + client.state.user.id, + ..._selectedUsers.map((e) => e.id), + ], + 'name': groupName, + }; + await _channel.watch(); + Navigator.of(context) + ..pop() + ..pushReplacement( + MaterialPageRoute( + builder: (context) { + return StreamChannel( + child: ChannelPage(), + channel: _channel, + ); + }, + ), + ); + }, + ), + ), + ], + ), + body: Column( + children: [ + Container( + width: double.maxFinite, + color: Colors.grey.shade50, + child: Padding( + padding: const EdgeInsets.symmetric( + vertical: 8, + horizontal: 8, + ), + child: Text( + '$_totalUsers ${_totalUsers > 1 ? 'Members' : 'Member'}', + style: TextStyle( + fontWeight: FontWeight.w500, + ), + ), + ), + ), + Expanded( + child: ListView.separated( + itemCount: _selectedUsers.length + 1, + separatorBuilder: (_, __) => Container( + height: 1, + color: Theme.of(context).brightness == Brightness.dark + ? Colors.white.withOpacity(0.1) + : Colors.black.withOpacity(0.1), + ), + itemBuilder: (_, index) { + if (index == _selectedUsers.length) { + return Container( + height: 1, + color: Theme.of(context).brightness == Brightness.dark + ? Colors.white.withOpacity(0.1) + : Colors.black.withOpacity(0.1), + ); + } + final user = _selectedUsers[index]; + return ListTile( + key: ObjectKey(user), + leading: UserAvatar( + user: user, + constraints: BoxConstraints.tightFor( + width: 40, + height: 40, + ), + ), + title: Text( + user.name, + style: TextStyle(fontWeight: FontWeight.bold), + ), + contentPadding: const EdgeInsets.symmetric( + horizontal: 12, + vertical: 8, + ), + trailing: IconButton( + icon: Icon( + Icons.clear_rounded, + color: Colors.black, + ), + padding: const EdgeInsets.all(0), + splashRadius: 24, + onPressed: () { + setState(() { + _selectedUsers.remove(user); + }); + if (_selectedUsers.isEmpty) { + Navigator.pop(context); + } + }, + ), + ); + }, + ), + ), + ], + ), + ); + } +} diff --git a/example/lib/main.dart b/example/lib/main.dart index e2a8a5f7..7b547659 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -1,4 +1,3 @@ -import 'dart:async'; import 'dart:io'; import 'package:example/choose_user_page.dart'; @@ -8,8 +7,8 @@ import 'package:flutter/material.dart'; import 'package:flutter_secure_storage/flutter_secure_storage.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; -import 'chips_input_text_field.dart'; -import 'neumorphic_button.dart'; +import 'new_chat_screen.dart'; +import 'new_group_chat_screen.dart'; import 'notifications_service.dart'; void main() async { @@ -269,820 +268,3 @@ class ThreadPage extends StatelessWidget { ); } } - -class NewChatScreen extends StatefulWidget { - @override - _NewChatScreenState createState() => _NewChatScreenState(); -} - -class _NewChatScreenState extends State { - final _chipInputTextFieldStateKey = - GlobalKey>(); - - TextEditingController _controller; - - ChipInputTextFieldState get _chipInputTextFieldState => - _chipInputTextFieldStateKey.currentState; - - String _userNameQuery = ''; - - final _selectedUsers = {}; - - final _searchFocusNode = FocusNode(); - final _messageInputFocusNode = FocusNode(); - - bool _isSearchActive = false; - - Channel channel; - - Timer _debounce; - - bool _showUserList = true; - - void _userNameListener() { - if (_debounce?.isActive ?? false) _debounce.cancel(); - _debounce = Timer(const Duration(milliseconds: 350), () { - if (mounted) - setState(() { - _userNameQuery = _controller.text; - _isSearchActive = _userNameQuery.isNotEmpty; - }); - }); - } - - @override - void initState() { - super.initState(); - channel = StreamChat.of(context).client.channel('messaging'); - _controller = TextEditingController()..addListener(_userNameListener); - - _searchFocusNode.addListener(() async { - if (_searchFocusNode.hasFocus && !_showUserList) { - if (channel.extraData['draft'] == true) { - await channel.stopWatching(); - channel.dispose(); - channel.client.state.channels.remove(channel.cid); - } - setState(() { - _showUserList = true; - }); - } - }); - - _messageInputFocusNode.addListener(() async { - if (_messageInputFocusNode.hasFocus && _selectedUsers.isNotEmpty) { - final chatState = StreamChat.of(context); - - channel = chatState.client.channel( - 'messaging', - extraData: { - 'members': [ - ..._selectedUsers.map((e) => e.id), - chatState.user.id, - ], - 'draft': true, - }, - ); - - if (!chatState.client.state.channels.containsKey(channel.cid)) { - await channel.watch(); - } - - setState(() { - _showUserList = false; - }); - } - }); - } - - @override - void dispose() { - _searchFocusNode.dispose(); - _messageInputFocusNode.dispose(); - _controller?.clear(); - _controller?.removeListener(_userNameListener); - _controller?.dispose(); - super.dispose(); - } - - @override - Widget build(BuildContext context) { - return Scaffold( - backgroundColor: Color.fromRGBO(252, 252, 252, 1), - appBar: AppBar( - elevation: 0, - backgroundColor: Colors.white, - leading: const StreamBackButton(), - title: Text( - 'New Chat', - style: TextStyle( - color: Colors.black, - fontSize: 16, - ), - ), - centerTitle: true, - ), - body: StreamChannel( - showLoading: false, - channel: channel, - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - ChipsInputTextField( - key: _chipInputTextFieldStateKey, - controller: _controller, - focusNode: _searchFocusNode, - chipBuilder: (context, user) { - return Stack( - alignment: AlignmentDirectional.centerStart, - children: [ - Container( - decoration: BoxDecoration( - color: Colors.black.withOpacity(0.05), - borderRadius: BorderRadius.circular(12), - ), - padding: const EdgeInsets.only(left: 24), - child: Padding( - padding: const EdgeInsets.fromLTRB(8, 4, 12, 4), - child: Text( - user.name, - style: TextStyle(color: Colors.black), - ), - ), - ), - UserAvatar( - user: user, - constraints: BoxConstraints.tightFor( - height: 24, - width: 24, - ), - ), - ], - ); - }, - onChipAdded: (user) { - setState(() => _selectedUsers.add(user)); - }, - onChipRemoved: (user) { - setState(() => _selectedUsers.remove(user)); - }, - ), - if (!_isSearchActive && !_selectedUsers.isNotEmpty) - Container( - child: InkWell( - onTap: () { - Navigator.push( - context, - MaterialPageRoute(builder: (_) => NewGroupChatScreen()), - ); - }, - child: Padding( - padding: const EdgeInsets.symmetric(vertical: 8), - child: Row( - children: [ - NeumorphicButton( - child: Icon( - StreamIcons.group, - color: Color(0xFF006CFF), - ), - ), - SizedBox(width: 8), - Text( - 'Create a Group', - style: TextStyle( - fontWeight: FontWeight.bold, - fontSize: 16, - ), - ), - ], - ), - ), - ), - ), - if (_showUserList) - Container( - width: double.maxFinite, - decoration: BoxDecoration( - gradient: LinearGradient( - begin: Alignment.centerLeft, - end: Alignment.centerRight, - colors: [ - Colors.black.withOpacity(0.02), - Colors.white.withOpacity(0.05), - ], - stops: [0, 1], - ), - ), - child: Padding( - padding: const EdgeInsets.symmetric( - vertical: 8, - horizontal: 8, - ), - child: Text( - _isSearchActive - ? "Matches for \"$_userNameQuery\"" - : 'On the platform', - style: TextStyle( - color: Colors.black.withOpacity(0.5), - ), - ), - ), - ), - Expanded( - child: _showUserList - ? UsersBloc( - child: UserListView( - selectedUsers: _selectedUsers, - groupAlphabetically: _isSearchActive ? false : true, - onUserTap: (user, _) { - _controller.clear(); - if (!_selectedUsers.contains(user)) { - _chipInputTextFieldState - ..addItem(user) - ..pauseItemAddition(); - } else { - _chipInputTextFieldState.removeItem(user); - } - }, - pagination: PaginationParams( - limit: 25, - ), - filter: { - if (_userNameQuery.isNotEmpty) - 'name': { - r'$autocomplete': _userNameQuery, - }, - 'id': { - r'$ne': StreamChat.of(context).user.id, - }, - }, - sort: [ - SortOption( - 'name', - direction: 1, - ), - ], - emptyBuilder: (_) { - return LayoutBuilder( - builder: (context, viewportConstraints) { - return SingleChildScrollView( - physics: AlwaysScrollableScrollPhysics(), - child: ConstrainedBox( - constraints: BoxConstraints( - minHeight: viewportConstraints.maxHeight, - ), - child: Center( - child: Column( - children: [ - Padding( - padding: const EdgeInsets.all(24), - child: Icon( - StreamIcons.search, - size: 96, - color: Colors.grey, - ), - ), - Text( - 'No user matches these keywords...'), - ], - ), - ), - ), - ); - }, - ); - }, - ), - ) - : MessageListView(), - ), - MessageInput( - focusNode: _messageInputFocusNode, - onMessageSent: (m) { - if (!m.isEphemeral) { - _updateChannelAndNavigate(context); - } else { - channel.on('message.new').first.then((_) { - _updateChannelAndNavigate(context); - }); - } - }, - ), - ], - ), - ), - ); - } - - void _updateChannelAndNavigate(BuildContext context) { - channel.update({ - 'draft': false, - }); - Navigator.pushReplacement( - context, - MaterialPageRoute( - builder: (context) { - return StreamChannel( - child: ChannelPage(), - channel: channel, - ); - }, - ), - ); - } -} - -class NewGroupChatScreen extends StatefulWidget { - @override - _NewGroupChatScreenState createState() => _NewGroupChatScreenState(); -} - -class _NewGroupChatScreenState extends State { - TextEditingController _controller; - - String _userNameQuery = ''; - - final _selectedUsers = {}; - - bool _isSearchActive = false; - - Timer _debounce; - - void _userNameListener() { - if (_debounce?.isActive ?? false) _debounce.cancel(); - _debounce = Timer(const Duration(milliseconds: 350), () { - if (mounted) - setState(() { - _userNameQuery = _controller.text; - _isSearchActive = _userNameQuery.isNotEmpty; - }); - }); - } - - @override - void initState() { - super.initState(); - _controller = TextEditingController()..addListener(_userNameListener); - } - - @override - void dispose() { - _controller?.clear(); - _controller?.removeListener(_userNameListener); - _controller?.dispose(); - super.dispose(); - } - - @override - Widget build(BuildContext context) { - return Scaffold( - backgroundColor: Color.fromRGBO(252, 252, 252, 1), - appBar: AppBar( - elevation: 1, - backgroundColor: Colors.white, - leading: const StreamBackButton(), - title: Text( - 'Add Group Members', - style: TextStyle( - color: Colors.black, - fontSize: 16, - ), - ), - centerTitle: true, - actions: [ - if (_selectedUsers.isNotEmpty) - IconButton( - icon: Icon( - StreamIcons.arrow_right, - color: Color(0xFF006CFF), - ), - onPressed: () { - Navigator.push( - context, - MaterialPageRoute( - builder: (_) => GroupChatDetailsScreen( - selectedUsers: _selectedUsers.toList(growable: false), - ), - ), - ); - }, - ) - ], - ), - body: UsersBloc( - child: Column( - children: [ - Container( - height: 36, - decoration: BoxDecoration( - color: Colors.white, - border: Border.all( - color: Colors.grey.shade300, - ), - borderRadius: BorderRadius.circular(24), - ), - margin: const EdgeInsets.symmetric( - vertical: 8, - horizontal: 8, - ), - child: TextField( - controller: _controller, - decoration: InputDecoration( - prefixIcon: Icon( - StreamIcons.search, - color: Colors.black, - size: 24, - ), - hintText: 'Search', - hintStyle: TextStyle( - color: Colors.black.withOpacity(0.5), - fontSize: 14, - ), - contentPadding: const EdgeInsets.all(0), - border: OutlineInputBorder( - borderSide: BorderSide.none, - borderRadius: BorderRadius.circular(24), - ), - ), - ), - ), - if (_selectedUsers.isNotEmpty) - Container( - height: 104, - child: ListView.separated( - scrollDirection: Axis.horizontal, - itemCount: _selectedUsers.length, - padding: const EdgeInsets.all(8), - separatorBuilder: (_, __) => SizedBox(width: 16), - itemBuilder: (_, index) { - final user = _selectedUsers.elementAt(index); - return Column( - children: [ - Stack( - children: [ - UserAvatar( - onlineIndicatorAlignment: Alignment(0.9, 0.9), - user: user, - showOnlineStatus: true, - borderRadius: BorderRadius.circular(32), - constraints: BoxConstraints.tightFor( - height: 64, - width: 64, - ), - ), - Positioned( - top: -4, - right: -4, - child: GestureDetector( - onTap: () { - if (_selectedUsers.contains(user)) { - setState(() => _selectedUsers.remove(user)); - } - }, - child: Container( - decoration: BoxDecoration( - color: Colors.white, - shape: BoxShape.circle, - border: Border.all( - color: Colors.grey.shade100, - ), - ), - child: Padding( - padding: const EdgeInsets.all(0.0), - child: Icon( - StreamIcons.close, - size: 24, - ), - ), - ), - ), - ) - ], - ), - SizedBox(height: 4), - Text( - user.name.split(' ')[0], - style: TextStyle( - fontWeight: FontWeight.bold, - fontSize: 12, - ), - ), - ], - ); - }, - ), - ), - Container( - width: double.maxFinite, - decoration: BoxDecoration( - gradient: LinearGradient( - begin: Alignment.centerLeft, - end: Alignment.centerRight, - colors: [ - Colors.black.withOpacity(0.02), - Colors.white.withOpacity(0.05), - ], - stops: [0, 1], - ), - ), - child: Padding( - padding: const EdgeInsets.symmetric( - vertical: 8, - horizontal: 8, - ), - child: Text( - _isSearchActive - ? 'Matches for \"$_userNameQuery\"' - : 'On the platform', - style: TextStyle( - color: Colors.black.withOpacity(0.5), - ), - ), - ), - ), - Expanded( - child: UserListView( - selectedUsers: _selectedUsers, - groupAlphabetically: _isSearchActive ? false : true, - onUserTap: (user, _) { - if (!_selectedUsers.contains(user)) { - setState(() { - _selectedUsers.add(user); - }); - } else { - setState(() { - _selectedUsers.remove(user); - }); - } - }, - pagination: PaginationParams( - limit: 25, - ), - filter: { - if (_userNameQuery.isNotEmpty) - 'name': { - r'$autocomplete': _userNameQuery, - }, - 'id': { - r'$ne': StreamChat.of(context).user.id, - } - }, - sort: [ - SortOption( - 'name', - direction: 1, - ), - ], - emptyBuilder: (_) { - return LayoutBuilder( - builder: (context, viewportConstraints) { - return SingleChildScrollView( - physics: AlwaysScrollableScrollPhysics(), - child: ConstrainedBox( - constraints: BoxConstraints( - minHeight: viewportConstraints.maxHeight, - ), - child: Center( - child: Column( - children: [ - Padding( - padding: const EdgeInsets.all(24), - child: Icon( - StreamIcons.search, - size: 96, - color: Colors.grey, - ), - ), - Text('No user matches these keywords...'), - ], - ), - ), - ), - ); - }, - ); - }, - ), - ), - ], - ), - ), - ); - } -} - -class GroupChatDetailsScreen extends StatefulWidget { - final List selectedUsers; - - const GroupChatDetailsScreen({ - Key key, - @required this.selectedUsers, - }) : super(key: key); - - @override - _GroupChatDetailsScreenState createState() => _GroupChatDetailsScreenState(); -} - -class _GroupChatDetailsScreenState extends State { - final _selectedUsers = []; - - TextEditingController _groupNameController; - - Channel _channel; - - bool _isGroupNameEmpty = true; - - int get _totalUsers => _selectedUsers.length; - - void _groupNameListener() { - final name = _groupNameController.text; - if (mounted) { - setState(() { - _isGroupNameEmpty = name.isEmpty; - }); - } - } - - @override - void initState() { - super.initState(); - _channel = StreamChat.of(context).client.channel('messaging'); - _selectedUsers.addAll(widget.selectedUsers); - _groupNameController = TextEditingController() - ..addListener(_groupNameListener); - } - - @override - void dispose() { - _groupNameController?.clear(); - _groupNameController?.removeListener(_groupNameListener); - _groupNameController?.dispose(); - super.dispose(); - } - - @override - Widget build(BuildContext context) { - return Scaffold( - backgroundColor: Color.fromRGBO(252, 252, 252, 1), - appBar: AppBar( - elevation: 1, - backgroundColor: Colors.white, - leading: const StreamBackButton(), - title: Text( - 'Name of Group Chat', - style: TextStyle( - color: Colors.black, - fontSize: 16, - ), - ), - centerTitle: true, - bottom: PreferredSize( - preferredSize: Size.fromHeight(kToolbarHeight), - child: Padding( - padding: const EdgeInsets.symmetric(vertical: 18, horizontal: 16), - child: Row( - children: [ - Text( - 'NAME', - style: TextStyle( - fontSize: 12, - color: Colors.black.withOpacity(0.5), - ), - ), - SizedBox(width: 16), - Expanded( - child: TextField( - controller: _groupNameController, - decoration: InputDecoration( - isDense: true, - border: InputBorder.none, - focusedBorder: InputBorder.none, - enabledBorder: InputBorder.none, - errorBorder: InputBorder.none, - disabledBorder: InputBorder.none, - contentPadding: const EdgeInsets.all(0), - hintText: 'Choose a group chat name', - hintStyle: TextStyle( - fontSize: 14, color: Colors.black.withOpacity(.5)), - ), - ), - ), - ], - ), - ), - ), - actions: [ - NeumorphicButton( - child: IconButton( - padding: const EdgeInsets.all(0), - icon: Icon(StreamIcons.check), - color: Color(0xFF006CFF), - onPressed: _isGroupNameEmpty - ? null - : () async { - final groupName = _groupNameController.text; - final client = _channel.client; - _channel.extraData = { - 'members': [ - client.state.user.id, - ..._selectedUsers.map((e) => e.id), - ], - 'name': groupName, - }; - await _channel.watch(); - Navigator.of(context) - ..pop() - ..pushReplacement( - MaterialPageRoute( - builder: (context) { - return StreamChannel( - child: ChannelPage(), - channel: _channel, - ); - }, - ), - ); - }, - ), - ), - ], - ), - body: Column( - children: [ - Container( - width: double.maxFinite, - color: Colors.grey.shade50, - child: Padding( - padding: const EdgeInsets.symmetric( - vertical: 8, - horizontal: 8, - ), - child: Text( - '$_totalUsers ${_totalUsers > 1 ? 'Members' : 'Member'}', - style: TextStyle( - fontWeight: FontWeight.w500, - ), - ), - ), - ), - Expanded( - child: ListView.separated( - itemCount: _selectedUsers.length + 1, - separatorBuilder: (_, __) => Container( - height: 1, - color: Theme.of(context).brightness == Brightness.dark - ? Colors.white.withOpacity(0.1) - : Colors.black.withOpacity(0.1), - ), - itemBuilder: (_, index) { - if (index == _selectedUsers.length) { - return Container( - height: 1, - color: Theme.of(context).brightness == Brightness.dark - ? Colors.white.withOpacity(0.1) - : Colors.black.withOpacity(0.1), - ); - } - final user = _selectedUsers[index]; - return ListTile( - key: ObjectKey(user), - leading: UserAvatar( - user: user, - constraints: BoxConstraints.tightFor( - width: 40, - height: 40, - ), - ), - title: Text( - user.name, - style: TextStyle(fontWeight: FontWeight.bold), - ), - contentPadding: const EdgeInsets.symmetric( - horizontal: 12, - vertical: 8, - ), - trailing: IconButton( - icon: Icon( - Icons.clear_rounded, - color: Colors.black, - ), - padding: const EdgeInsets.all(0), - splashRadius: 24, - onPressed: () { - setState(() { - _selectedUsers.remove(user); - }); - if (_selectedUsers.isEmpty) { - Navigator.pop(context); - } - }, - ), - ); - }, - ), - ), - ], - ), - ); - } -} diff --git a/example/lib/new_chat_screen.dart b/example/lib/new_chat_screen.dart new file mode 100644 index 00000000..286f9a36 --- /dev/null +++ b/example/lib/new_chat_screen.dart @@ -0,0 +1,331 @@ +import 'dart:async'; + +import 'package:flutter/material.dart'; +import 'package:stream_chat_flutter/stream_chat_flutter.dart'; + +import 'chips_input_text_field.dart'; +import 'main.dart'; +import 'neumorphic_button.dart'; +import 'new_group_chat_screen.dart'; + +class NewChatScreen extends StatefulWidget { + @override + _NewChatScreenState createState() => _NewChatScreenState(); +} + +class _NewChatScreenState extends State { + final _chipInputTextFieldStateKey = + GlobalKey>(); + + TextEditingController _controller; + + ChipInputTextFieldState get _chipInputTextFieldState => + _chipInputTextFieldStateKey.currentState; + + String _userNameQuery = ''; + + final _selectedUsers = {}; + + final _searchFocusNode = FocusNode(); + final _messageInputFocusNode = FocusNode(); + + bool _isSearchActive = false; + + Channel channel; + + Timer _debounce; + + bool _showUserList = true; + + void _userNameListener() { + if (_debounce?.isActive ?? false) _debounce.cancel(); + _debounce = Timer(const Duration(milliseconds: 350), () { + if (mounted) + setState(() { + _userNameQuery = _controller.text; + _isSearchActive = _userNameQuery.isNotEmpty; + }); + }); + } + + @override + void initState() { + super.initState(); + channel = StreamChat.of(context).client.channel('messaging'); + _controller = TextEditingController()..addListener(_userNameListener); + + _searchFocusNode.addListener(() async { + if (_searchFocusNode.hasFocus && !_showUserList) { + if (channel.extraData['draft'] == true) { + await channel.stopWatching(); + channel.dispose(); + channel.client.state.channels.remove(channel.cid); + } + setState(() { + _showUserList = true; + }); + } + }); + + _messageInputFocusNode.addListener(() async { + if (_messageInputFocusNode.hasFocus && _selectedUsers.isNotEmpty) { + final chatState = StreamChat.of(context); + + channel = chatState.client.channel( + 'messaging', + extraData: { + 'members': [ + ..._selectedUsers.map((e) => e.id), + chatState.user.id, + ], + 'draft': true, + }, + ); + + if (!chatState.client.state.channels.containsKey(channel.cid)) { + await channel.watch(); + } + + setState(() { + _showUserList = false; + }); + } + }); + } + + @override + void dispose() { + _searchFocusNode.dispose(); + _messageInputFocusNode.dispose(); + _controller?.clear(); + _controller?.removeListener(_userNameListener); + _controller?.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: Color.fromRGBO(252, 252, 252, 1), + appBar: AppBar( + elevation: 0, + backgroundColor: Colors.white, + leading: const StreamBackButton(), + title: Text( + 'New Chat', + style: TextStyle( + color: Colors.black, + fontSize: 16, + ), + ), + centerTitle: true, + ), + body: StreamChannel( + showLoading: false, + channel: channel, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + ChipsInputTextField( + key: _chipInputTextFieldStateKey, + controller: _controller, + focusNode: _searchFocusNode, + chipBuilder: (context, user) { + return Stack( + alignment: AlignmentDirectional.centerStart, + children: [ + Container( + decoration: BoxDecoration( + color: Colors.black.withOpacity(0.05), + borderRadius: BorderRadius.circular(12), + ), + padding: const EdgeInsets.only(left: 24), + child: Padding( + padding: const EdgeInsets.fromLTRB(8, 4, 12, 4), + child: Text( + user.name, + style: TextStyle(color: Colors.black), + ), + ), + ), + UserAvatar( + user: user, + constraints: BoxConstraints.tightFor( + height: 24, + width: 24, + ), + ), + ], + ); + }, + onChipAdded: (user) { + setState(() => _selectedUsers.add(user)); + }, + onChipRemoved: (user) { + setState(() => _selectedUsers.remove(user)); + }, + ), + if (!_isSearchActive && !_selectedUsers.isNotEmpty) + Container( + child: InkWell( + onTap: () { + Navigator.push( + context, + MaterialPageRoute(builder: (_) => NewGroupChatScreen()), + ); + }, + child: Padding( + padding: const EdgeInsets.symmetric(vertical: 8), + child: Row( + children: [ + NeumorphicButton( + child: Icon( + StreamIcons.group, + color: Color(0xFF006CFF), + ), + ), + SizedBox(width: 8), + Text( + 'Create a Group', + style: TextStyle( + fontWeight: FontWeight.bold, + fontSize: 16, + ), + ), + ], + ), + ), + ), + ), + if (_showUserList) + Container( + width: double.maxFinite, + decoration: BoxDecoration( + gradient: LinearGradient( + begin: Alignment.centerLeft, + end: Alignment.centerRight, + colors: [ + Colors.black.withOpacity(0.02), + Colors.white.withOpacity(0.05), + ], + stops: [0, 1], + ), + ), + child: Padding( + padding: const EdgeInsets.symmetric( + vertical: 8, + horizontal: 8, + ), + child: Text( + _isSearchActive + ? "Matches for \"$_userNameQuery\"" + : 'On the platform', + style: TextStyle( + color: Colors.black.withOpacity(0.5), + ), + ), + ), + ), + Expanded( + child: _showUserList + ? UsersBloc( + child: UserListView( + selectedUsers: _selectedUsers, + groupAlphabetically: _isSearchActive ? false : true, + onUserTap: (user, _) { + _controller.clear(); + if (!_selectedUsers.contains(user)) { + _chipInputTextFieldState + ..addItem(user) + ..pauseItemAddition(); + } else { + _chipInputTextFieldState.removeItem(user); + } + }, + pagination: PaginationParams( + limit: 25, + ), + filter: { + if (_userNameQuery.isNotEmpty) + 'name': { + r'$autocomplete': _userNameQuery, + }, + 'id': { + r'$ne': StreamChat.of(context).user.id, + }, + }, + sort: [ + SortOption( + 'name', + direction: 1, + ), + ], + emptyBuilder: (_) { + return LayoutBuilder( + builder: (context, viewportConstraints) { + return SingleChildScrollView( + physics: AlwaysScrollableScrollPhysics(), + child: ConstrainedBox( + constraints: BoxConstraints( + minHeight: viewportConstraints.maxHeight, + ), + child: Center( + child: Column( + children: [ + Padding( + padding: const EdgeInsets.all(24), + child: Icon( + StreamIcons.search, + size: 96, + color: Colors.grey, + ), + ), + Text( + 'No user matches these keywords...'), + ], + ), + ), + ), + ); + }, + ); + }, + ), + ) + : MessageListView(), + ), + MessageInput( + focusNode: _messageInputFocusNode, + onMessageSent: (m) { + if (!m.isEphemeral) { + _updateChannelAndNavigate(context); + } else { + channel.on('message.new').first.then((_) { + _updateChannelAndNavigate(context); + }); + } + }, + ), + ], + ), + ), + ); + } + + void _updateChannelAndNavigate(BuildContext context) { + channel.update({ + 'draft': false, + }); + Navigator.pushReplacement( + context, + MaterialPageRoute( + builder: (context) { + return StreamChannel( + child: ChannelPage(), + channel: channel, + ); + }, + ), + ); + } +} diff --git a/example/lib/new_group_chat_screen.dart b/example/lib/new_group_chat_screen.dart new file mode 100644 index 00000000..b75e7510 --- /dev/null +++ b/example/lib/new_group_chat_screen.dart @@ -0,0 +1,285 @@ +import 'dart:async'; + +import 'package:flutter/material.dart'; +import 'package:stream_chat_flutter/stream_chat_flutter.dart'; + +import 'group_chat_details_screen.dart'; + +class NewGroupChatScreen extends StatefulWidget { + @override + _NewGroupChatScreenState createState() => _NewGroupChatScreenState(); +} + +class _NewGroupChatScreenState extends State { + TextEditingController _controller; + + String _userNameQuery = ''; + + final _selectedUsers = {}; + + bool _isSearchActive = false; + + Timer _debounce; + + void _userNameListener() { + if (_debounce?.isActive ?? false) _debounce.cancel(); + _debounce = Timer(const Duration(milliseconds: 350), () { + if (mounted) + setState(() { + _userNameQuery = _controller.text; + _isSearchActive = _userNameQuery.isNotEmpty; + }); + }); + } + + @override + void initState() { + super.initState(); + _controller = TextEditingController()..addListener(_userNameListener); + } + + @override + void dispose() { + _controller?.clear(); + _controller?.removeListener(_userNameListener); + _controller?.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: Color.fromRGBO(252, 252, 252, 1), + appBar: AppBar( + elevation: 1, + backgroundColor: Colors.white, + leading: const StreamBackButton(), + title: Text( + 'Add Group Members', + style: TextStyle( + color: Colors.black, + fontSize: 16, + ), + ), + centerTitle: true, + actions: [ + if (_selectedUsers.isNotEmpty) + IconButton( + icon: Icon( + StreamIcons.arrow_right, + color: Color(0xFF006CFF), + ), + onPressed: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (_) => GroupChatDetailsScreen( + selectedUsers: _selectedUsers.toList(growable: false), + ), + ), + ); + }, + ) + ], + ), + body: UsersBloc( + child: Column( + children: [ + Container( + height: 36, + decoration: BoxDecoration( + color: Colors.white, + border: Border.all( + color: Colors.grey.shade300, + ), + borderRadius: BorderRadius.circular(24), + ), + margin: const EdgeInsets.symmetric( + vertical: 8, + horizontal: 8, + ), + child: TextField( + controller: _controller, + decoration: InputDecoration( + prefixIcon: Icon( + StreamIcons.search, + color: Colors.black, + size: 24, + ), + hintText: 'Search', + hintStyle: TextStyle( + color: Colors.black.withOpacity(0.5), + fontSize: 14, + ), + contentPadding: const EdgeInsets.all(0), + border: OutlineInputBorder( + borderSide: BorderSide.none, + borderRadius: BorderRadius.circular(24), + ), + ), + ), + ), + if (_selectedUsers.isNotEmpty) + Container( + height: 104, + child: ListView.separated( + scrollDirection: Axis.horizontal, + itemCount: _selectedUsers.length, + padding: const EdgeInsets.all(8), + separatorBuilder: (_, __) => SizedBox(width: 16), + itemBuilder: (_, index) { + final user = _selectedUsers.elementAt(index); + return Column( + children: [ + Stack( + children: [ + UserAvatar( + onlineIndicatorAlignment: Alignment(0.9, 0.9), + user: user, + showOnlineStatus: true, + borderRadius: BorderRadius.circular(32), + constraints: BoxConstraints.tightFor( + height: 64, + width: 64, + ), + ), + Positioned( + top: -4, + right: -4, + child: GestureDetector( + onTap: () { + if (_selectedUsers.contains(user)) { + setState(() => _selectedUsers.remove(user)); + } + }, + child: Container( + decoration: BoxDecoration( + color: Colors.white, + shape: BoxShape.circle, + border: Border.all( + color: Colors.grey.shade100, + ), + ), + child: Padding( + padding: const EdgeInsets.all(0.0), + child: Icon( + StreamIcons.close, + size: 24, + ), + ), + ), + ), + ) + ], + ), + SizedBox(height: 4), + Text( + user.name.split(' ')[0], + style: TextStyle( + fontWeight: FontWeight.bold, + fontSize: 12, + ), + ), + ], + ); + }, + ), + ), + Container( + width: double.maxFinite, + decoration: BoxDecoration( + gradient: LinearGradient( + begin: Alignment.centerLeft, + end: Alignment.centerRight, + colors: [ + Colors.black.withOpacity(0.02), + Colors.white.withOpacity(0.05), + ], + stops: [0, 1], + ), + ), + child: Padding( + padding: const EdgeInsets.symmetric( + vertical: 8, + horizontal: 8, + ), + child: Text( + _isSearchActive + ? 'Matches for \"$_userNameQuery\"' + : 'On the platform', + style: TextStyle( + color: Colors.black.withOpacity(0.5), + ), + ), + ), + ), + Expanded( + child: UserListView( + selectedUsers: _selectedUsers, + groupAlphabetically: _isSearchActive ? false : true, + onUserTap: (user, _) { + if (!_selectedUsers.contains(user)) { + setState(() { + _selectedUsers.add(user); + }); + } else { + setState(() { + _selectedUsers.remove(user); + }); + } + }, + pagination: PaginationParams( + limit: 25, + ), + filter: { + if (_userNameQuery.isNotEmpty) + 'name': { + r'$autocomplete': _userNameQuery, + }, + 'id': { + r'$ne': StreamChat.of(context).user.id, + } + }, + sort: [ + SortOption( + 'name', + direction: 1, + ), + ], + emptyBuilder: (_) { + return LayoutBuilder( + builder: (context, viewportConstraints) { + return SingleChildScrollView( + physics: AlwaysScrollableScrollPhysics(), + child: ConstrainedBox( + constraints: BoxConstraints( + minHeight: viewportConstraints.maxHeight, + ), + child: Center( + child: Column( + children: [ + Padding( + padding: const EdgeInsets.all(24), + child: Icon( + StreamIcons.search, + size: 96, + color: Colors.grey, + ), + ), + Text('No user matches these keywords...'), + ], + ), + ), + ), + ); + }, + ); + }, + ), + ), + ], + ), + ), + ); + } +} diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 0fe6a0ad..9ded2435 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -1,6 +1,6 @@ name: example description: A new Flutter project. -version: 1.0.62+64 +version: 1.0.63+65 environment: sdk: ">=2.2.2 <3.0.0" From 4b317d719c80e326a4e641234315b574860280c1 Mon Sep 17 00:00:00 2001 From: xsahil03x Date: Mon, 23 Nov 2020 12:57:20 +0530 Subject: [PATCH 0439/1140] Refactor UserListView to support (crossAxisCount > 1) i.e: GridViews --- lib/src/user_avatar.dart | 75 ++++++++++++++++++----------- lib/src/user_list_view.dart | 94 ++++++++++++++++++++++++++++++++++--- 2 files changed, 135 insertions(+), 34 deletions(-) diff --git a/lib/src/user_avatar.dart b/lib/src/user_avatar.dart index 566ef603..2e1f3e0e 100644 --- a/lib/src/user_avatar.dart +++ b/lib/src/user_avatar.dart @@ -11,9 +11,13 @@ class UserAvatar extends StatelessWidget { this.constraints, this.onlineIndicatorConstraints, this.onTap, + this.onLongPress, this.showOnlineStatus = true, this.borderRadius, this.onlineIndicatorAlignment = Alignment.topRight, + this.selected = false, + this.selectionColor = const Color(0xFF006CFF), + this.selectionThickness = 4, }) : super(key: key); final User user; @@ -22,7 +26,11 @@ class UserAvatar extends StatelessWidget { final BorderRadius borderRadius; final BoxConstraints onlineIndicatorConstraints; final void Function(User) onTap; + final void Function(User) onLongPress; final bool showOnlineStatus; + final bool selected; + final Color selectionColor; + final double selectionThickness; @override Widget build(BuildContext context) { @@ -30,37 +38,48 @@ class UserAvatar extends StatelessWidget { user.extraData['image'] != null && user.extraData['image'] != ''; final streamChatTheme = StreamChatTheme.of(context); + + Widget avatar = ClipRRect( + borderRadius: borderRadius ?? + streamChatTheme.ownMessageTheme.avatarTheme.borderRadius, + child: Container( + constraints: constraints ?? + streamChatTheme.ownMessageTheme.avatarTheme.constraints, + decoration: BoxDecoration( + color: streamChatTheme.accentColor, + ), + child: hasImage + ? CachedNetworkImage( + filterQuality: FilterQuality.high, + imageUrl: user.extraData['image'], + errorWidget: (_, __, ___) { + return streamChatTheme.defaultUserImage(context, user); + }, + fit: BoxFit.cover, + ) + : streamChatTheme.defaultUserImage(context, user), + ), + ); + if (selected) { + avatar = ClipRRect( + borderRadius: (borderRadius ?? + streamChatTheme.ownMessageTheme.avatarTheme.borderRadius) + + BorderRadius.circular(selectionThickness), + child: Container( + color: selectionColor, + child: Padding( + padding: EdgeInsets.all(selectionThickness), + child: avatar, + ), + ), + ); + } return GestureDetector( - onTap: onTap != null - ? () { - if (onTap != null) { - onTap(user); - } - } - : null, + onTap: onTap != null ? () => onTap(user) : null, + onLongPress: onLongPress != null ? () => onLongPress(user) : null, child: Stack( children: [ - ClipRRect( - borderRadius: borderRadius ?? - streamChatTheme.ownMessageTheme.avatarTheme.borderRadius, - child: Container( - constraints: constraints ?? - streamChatTheme.ownMessageTheme.avatarTheme.constraints, - decoration: BoxDecoration( - color: streamChatTheme.accentColor, - ), - child: hasImage - ? CachedNetworkImage( - filterQuality: FilterQuality.high, - imageUrl: user.extraData['image'], - errorWidget: (_, __, ___) { - return streamChatTheme.defaultUserImage(context, user); - }, - fit: BoxFit.cover, - ) - : streamChatTheme.defaultUserImage(context, user), - ), - ), + avatar, if (showOnlineStatus && user.online == true) Positioned.fill( child: Align( diff --git a/lib/src/user_list_view.dart b/lib/src/user_list_view.dart index 0f7b969e..51c645c3 100644 --- a/lib/src/user_list_view.dart +++ b/lib/src/user_list_view.dart @@ -65,7 +65,12 @@ class UserListView extends StatefulWidget { this.swipeToAction = false, this.pullToRefresh = true, this.groupAlphabetically = false, - }) : super(key: key); + this.crossAxisCount = 1, + }) : assert( + crossAxisCount == 1 || groupAlphabetically == false, + 'Cannot group alphabetically when crossAxisCount > 1', + ), + super(key: key); /// The builder that will be used in case of error final Widget Function(Error error) errorBuilder; @@ -130,6 +135,8 @@ class UserListView extends StatefulWidget { /// defaults to false final bool groupAlphabetically; + final int crossAxisCount; + @override _UserListViewState createState() => _UserListViewState(); } @@ -138,6 +145,8 @@ class _UserListViewState extends State with WidgetsBindingObserver { final ScrollController _scrollController = ScrollController(); + bool get _isListView => widget.crossAxisCount == 1; + @override void initState() { super.initState(); @@ -317,19 +326,40 @@ class _UserListViewState extends State ); } - return ListView.custom( + if (_isListView) { + return ListView.custom( + physics: AlwaysScrollableScrollPhysics(), + controller: _scrollController, + childrenDelegate: SliverChildBuilderDelegate( + (context, i) { + return _listItemBuilder(context, i, items); + }, + childCount: (items.length * 2) + 1, + findChildIndexCallback: (key) { + final ValueKey valueKey = key; + final index = + items.indexWhere((item) => item.key == valueKey.value); + return index != -1 ? (index * 2) : null; + }, + ), + ); + } + return GridView.custom( + gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: widget.crossAxisCount, + ), physics: AlwaysScrollableScrollPhysics(), controller: _scrollController, childrenDelegate: SliverChildBuilderDelegate( (context, i) { - return _itemBuilder(context, i, items); + return _gridItemBuilder(context, i, items); }, - childCount: (items.length * 2) + 1, + childCount: items.length, findChildIndexCallback: (key) { final ValueKey valueKey = key; final index = items.indexWhere((item) => item.key == valueKey.value); - return index != -1 ? (index * 2) : null; + return index != -1 ? index : null; }, ), ); @@ -337,7 +367,7 @@ class _UserListViewState extends State ); } - Widget _itemBuilder(BuildContext context, int i, List items) { + Widget _listItemBuilder(BuildContext context, int i, List items) { if (i % 2 != 0) { if (widget.separatorBuilder != null) { return widget.separatorBuilder(context, i); @@ -388,6 +418,58 @@ class _UserListViewState extends State } } + Widget _gridItemBuilder(BuildContext context, int i, List items) { + final usersProvider = UsersBloc.of(context); + if (i < items.length) { + final item = items[i]; + return item.when( + headerItem: (_) => Offstage(), + userItem: (user) { + final selected = widget.selectedUsers?.contains(user) ?? false; + return Container( + key: ValueKey('USER-${user.id}'), + child: widget.userItemBuilder != null + ? widget.userItemBuilder(context, user, selected) + : Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + UserAvatar( + user: user, + borderRadius: BorderRadius.circular(32), + selected: selected, + constraints: BoxConstraints.tightFor( + height: 64, + width: 64, + ), + onTap: (user) => + widget.onUserTap(user, widget.userWidget), + onLongPress: widget.onUserLongPress, + ), + SizedBox(height: 4), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 8), + child: Text( + user.name, + textAlign: TextAlign.center, + maxLines: 2, + overflow: TextOverflow.ellipsis, + style: TextStyle( + fontWeight: FontWeight.bold, + fontSize: 12, + ), + ), + ), + ], + ), + ); + }, + ); + } else { + return _buildQueryProgressIndicator(context, usersProvider); + } + } + Widget _buildQueryProgressIndicator(context, UsersBlocState usersProvider) { return StreamBuilder( stream: usersProvider.queryUsersLoading, From 06037acede27eb596fd5f2dd095dbba3f01413ce Mon Sep 17 00:00:00 2001 From: xsahil03x Date: Mon, 23 Nov 2020 13:48:47 +0530 Subject: [PATCH 0440/1140] [UserListView] Add docComment --- lib/src/user_list_view.dart | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/src/user_list_view.dart b/lib/src/user_list_view.dart index 51c645c3..63285d8b 100644 --- a/lib/src/user_list_view.dart +++ b/lib/src/user_list_view.dart @@ -135,6 +135,7 @@ class UserListView extends StatefulWidget { /// defaults to false final bool groupAlphabetically; + /// The number of children in the cross axis. final int crossAxisCount; @override From e87c94586386cea4bf3c8ae006941486ee715e1a Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Mon, 23 Nov 2020 10:02:30 +0100 Subject: [PATCH 0441/1140] add id for new groups --- example/lib/group_chat_details_screen.dart | 17 ++++++++--------- example/pubspec.yaml | 3 ++- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/example/lib/group_chat_details_screen.dart b/example/lib/group_chat_details_screen.dart index 8ba8c71f..6aff5711 100644 --- a/example/lib/group_chat_details_screen.dart +++ b/example/lib/group_chat_details_screen.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; +import 'package:uuid/uuid.dart'; import 'main.dart'; import 'neumorphic_button.dart'; @@ -21,8 +22,6 @@ class _GroupChatDetailsScreenState extends State { TextEditingController _groupNameController; - Channel _channel; - bool _isGroupNameEmpty = true; int get _totalUsers => _selectedUsers.length; @@ -39,7 +38,6 @@ class _GroupChatDetailsScreenState extends State { @override void initState() { super.initState(); - _channel = StreamChat.of(context).client.channel('messaging'); _selectedUsers.addAll(widget.selectedUsers); _groupNameController = TextEditingController() ..addListener(_groupNameListener); @@ -47,8 +45,8 @@ class _GroupChatDetailsScreenState extends State { @override void dispose() { - _groupNameController?.clear(); _groupNameController?.removeListener(_groupNameListener); + _groupNameController?.clear(); _groupNameController?.dispose(); super.dispose(); } @@ -114,15 +112,16 @@ class _GroupChatDetailsScreenState extends State { ? null : () async { final groupName = _groupNameController.text; - final client = _channel.client; - _channel.extraData = { + final client = StreamChat.of(context).client; + final channel = client + .channel('messaging', id: Uuid().v4(), extraData: { 'members': [ client.state.user.id, ..._selectedUsers.map((e) => e.id), ], 'name': groupName, - }; - await _channel.watch(); + }); + await channel.watch(); Navigator.of(context) ..pop() ..pushReplacement( @@ -130,7 +129,7 @@ class _GroupChatDetailsScreenState extends State { builder: (context) { return StreamChannel( child: ChannelPage(), - channel: _channel, + channel: channel, ); }, ), diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 9ded2435..574345c2 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -1,6 +1,6 @@ name: example description: A new Flutter project. -version: 1.0.63+65 +version: 1.0.64+66 environment: sdk: ">=2.2.2 <3.0.0" @@ -15,6 +15,7 @@ dependencies: flutter_svg: ^0.19.1 flutter_secure_storage: ^3.3.5 yaml: ^2.2.1 + uuid: ^2.2.2 dev_dependencies: flutter_test: From 37891ae3c53cb9ff2ca2a051770cabce541f8c0e Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Mon, 23 Nov 2020 10:30:58 +0100 Subject: [PATCH 0442/1140] remove chips tapping on them --- example/lib/new_chat_screen.dart | 59 ++++++++++++++++++++------------ example/pubspec.yaml | 2 +- 2 files changed, 38 insertions(+), 23 deletions(-) diff --git a/example/lib/new_chat_screen.dart b/example/lib/new_chat_screen.dart index 286f9a36..9ec2ca7e 100644 --- a/example/lib/new_chat_screen.dart +++ b/example/lib/new_chat_screen.dart @@ -131,31 +131,46 @@ class _NewChatScreenState extends State { controller: _controller, focusNode: _searchFocusNode, chipBuilder: (context, user) { - return Stack( - alignment: AlignmentDirectional.centerStart, - children: [ - Container( - decoration: BoxDecoration( - color: Colors.black.withOpacity(0.05), - borderRadius: BorderRadius.circular(12), - ), - padding: const EdgeInsets.only(left: 24), - child: Padding( - padding: const EdgeInsets.fromLTRB(8, 4, 12, 4), - child: Text( - user.name, - style: TextStyle(color: Colors.black), + return GestureDetector( + onTap: () { + _chipInputTextFieldState.removeItem(user); + }, + child: Stack( + alignment: AlignmentDirectional.centerStart, + children: [ + Container( + decoration: BoxDecoration( + color: Colors.black.withOpacity(0.05), + borderRadius: BorderRadius.circular(12), + ), + padding: const EdgeInsets.only(left: 24), + child: Padding( + padding: const EdgeInsets.fromLTRB(8, 4, 12, 4), + child: Text( + user.name, + style: TextStyle(color: Colors.black), + ), ), ), - ), - UserAvatar( - user: user, - constraints: BoxConstraints.tightFor( - height: 24, - width: 24, + Opacity( + opacity: .8, + child: UserAvatar( + showOnlineStatus: false, + user: user, + constraints: BoxConstraints.tightFor( + height: 24, + width: 24, + ), + ), ), - ), - ], + Positioned( + child: Icon( + StreamIcons.close, + color: Colors.white, + ), + ), + ], + ), ); }, onChipAdded: (user) { diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 574345c2..b491fb92 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -1,6 +1,6 @@ name: example description: A new Flutter project. -version: 1.0.64+66 +version: 1.0.65+67 environment: sdk: ">=2.2.2 <3.0.0" From 0ba45d82beb88ca2e49a9b0534e8522806096299 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Mon, 23 Nov 2020 15:46:38 +0530 Subject: [PATCH 0443/1140] fix: Fixed dispose errors --- lib/src/reaction_picker.dart | 9 ++++++++- pubspec.yaml | 2 +- test/src/message_action_modal_test.dart | 1 + test/src/message_reaction_modal_test.dart | 1 + 4 files changed, 11 insertions(+), 2 deletions(-) diff --git a/lib/src/reaction_picker.dart b/lib/src/reaction_picker.dart index 8d337498..83698e46 100644 --- a/lib/src/reaction_picker.dart +++ b/lib/src/reaction_picker.dart @@ -127,7 +127,6 @@ class _ReactionPickerState extends State void pop() async { for (var a in animations) { a.stop(); - //a.dispose(); } Navigator.of(context).pop(); } @@ -145,4 +144,12 @@ class _ReactionPickerState extends State StreamChannel.of(context).channel.deleteReaction(widget.message, reaction); pop(); } + + @override + void dispose() { + for (var a in animations) { + a?.dispose(); + } + super.dispose(); + } } diff --git a/pubspec.yaml b/pubspec.yaml index 689a54b8..85f164b8 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -38,7 +38,7 @@ dependencies: media_gallery: ^0.1.5 permission_handler: ^5.0.1+1 transparent_image: ^1.0.0 - ezanimation: ^0.4.0 + ezanimation: ^0.4.1 flutter: assets: diff --git a/test/src/message_action_modal_test.dart b/test/src/message_action_modal_test.dart index 1427edd6..b186ab91 100644 --- a/test/src/message_action_modal_test.dart +++ b/test/src/message_action_modal_test.dart @@ -40,6 +40,7 @@ void main() { ); await tester.pump(); + await tester.pump(Duration(milliseconds: 1000)); expect(find.byKey(Key('MessageWidget')), findsOneWidget); expect(find.byIcon(StreamIcons.sorting_up), findsOneWidget); expect(find.byIcon(StreamIcons.edit), findsOneWidget); diff --git a/test/src/message_reaction_modal_test.dart b/test/src/message_reaction_modal_test.dart index e270793e..4cf3dafa 100644 --- a/test/src/message_reaction_modal_test.dart +++ b/test/src/message_reaction_modal_test.dart @@ -87,6 +87,7 @@ void main() { ); await tester.pump(); + await tester.pump(Duration(milliseconds: 1000)); expect(find.byKey(Key('MessageWidget')), findsOneWidget); expect(find.byIcon(StreamIcons.thumbs_up_reaction), findsNWidgets(2)); expect(find.byIcon(StreamIcons.love_reaction), findsNWidgets(2)); From cb4bd6849d0dfc9ece7c2d5982bb247ac2c1b308 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Mon, 23 Nov 2020 16:05:16 +0530 Subject: [PATCH 0444/1140] fmt --- lib/src/message_actions_modal.dart | 129 +++++++++++++++-------------- 1 file changed, 66 insertions(+), 63 deletions(-) diff --git a/lib/src/message_actions_modal.dart b/lib/src/message_actions_modal.dart index 049f1be7..8b53a973 100644 --- a/lib/src/message_actions_modal.dart +++ b/lib/src/message_actions_modal.dart @@ -96,78 +96,81 @@ class MessageActionsModal extends StatelessWidget { ), ), TweenAnimationBuilder( - tween: Tween(begin: 0.0, end: 1.0), - duration: Duration(milliseconds: 300), - builder: (context, val, snapshot) { - return Transform.scale( - scale: val, - child: IgnorePointer( - child: MessageWidget( - key: Key('MessageWidget'), - reverse: reverse, - message: message.copyWith( - text: message.text.length > 200 - ? '${message.text.substring(0, 200)}...' - : message.text, + tween: Tween(begin: 0.0, end: 1.0), + duration: Duration(milliseconds: 300), + builder: (context, val, snapshot) { + return Transform.scale( + scale: val, + child: 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, + showUserAvatar: showUserAvatar, + showTimestamp: false, + translateUserAvatar: false, + showReactionPickerIndicator: true, + showSendingIndicator: DisplayWidget.gone, + shape: messageShape, ), - messageTheme: messageTheme, - showReactions: false, - showUsername: false, - showReplyIndicator: false, - showUserAvatar: showUserAvatar, - showTimestamp: false, - translateUserAvatar: false, - showReactionPickerIndicator: true, - showSendingIndicator: DisplayWidget.gone, - shape: messageShape, ), - ), - ); - } - ), + ); + }), SizedBox( height: 8, ), TweenAnimationBuilder( - tween: Tween(begin: 0.0, end: 1.0), - duration: Duration(milliseconds: 300), - curve: Curves.easeInOut, - builder: (context, val, wid) { - return Transform( - transform: Matrix4.identity()..scale(val)..rotateZ(-1.0 + val), - alignment: Alignment.topRight, - child: Padding( - padding: const EdgeInsets.symmetric( - horizontal: 48.0, - ), - child: Material( - clipBehavior: Clip.hardEdge, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(16), + tween: Tween(begin: 0.0, end: 1.0), + duration: Duration(milliseconds: 300), + curve: Curves.easeInOut, + builder: (context, val, wid) { + return Transform( + transform: Matrix4.identity() + ..scale(val) + ..rotateZ(-1.0 + val), + alignment: Alignment.topRight, + child: 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(), + ), ), ), - ), - ); - } - ) + ); + }) ], ), ), From 162971636e5be112929cf4c3bc73310879e08af8 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Mon, 23 Nov 2020 16:13:13 +0530 Subject: [PATCH 0445/1140] fix: Fixed tests --- test/src/message_action_modal_test.dart | 1 + test/src/message_reaction_modal_test.dart | 2 ++ 2 files changed, 3 insertions(+) diff --git a/test/src/message_action_modal_test.dart b/test/src/message_action_modal_test.dart index b186ab91..97709e70 100644 --- a/test/src/message_action_modal_test.dart +++ b/test/src/message_action_modal_test.dart @@ -85,6 +85,7 @@ void main() { ); await tester.pump(); + await tester.pump(Duration(milliseconds: 1000)); expect(find.byKey(Key('MessageWidget')), findsOneWidget); expect(find.byIcon(StreamIcons.sorting_up), findsNothing); expect(find.byIcon(StreamIcons.edit), findsNothing); diff --git a/test/src/message_reaction_modal_test.dart b/test/src/message_reaction_modal_test.dart index 4cf3dafa..622b57c3 100644 --- a/test/src/message_reaction_modal_test.dart +++ b/test/src/message_reaction_modal_test.dart @@ -39,6 +39,8 @@ void main() { ), ); + await tester.pump(Duration(milliseconds: 1000)); + expect(find.byKey(Key('MessageWidget')), findsOneWidget); expect(find.byIcon(StreamIcons.thumbs_up_reaction), findsOneWidget); }, From 525991f24b64448094e236c32a60321d8b67a6db Mon Sep 17 00:00:00 2001 From: xsahil03x Date: Mon, 23 Nov 2020 16:36:50 +0530 Subject: [PATCH 0446/1140] feat : ChannelListHeader --- example/lib/group_chat_details_screen.dart | 3 +- example/lib/main.dart | 8 +- example/lib/new_chat_screen.dart | 3 +- lib/src/channel_list_header.dart | 158 ++++++++++++++++++ .../src/stream_neumorphic_button.dart | 4 +- lib/stream_chat_flutter.dart | 2 + 6 files changed, 165 insertions(+), 13 deletions(-) create mode 100644 lib/src/channel_list_header.dart rename example/lib/neumorphic_button.dart => lib/src/stream_neumorphic_button.dart (90%) diff --git a/example/lib/group_chat_details_screen.dart b/example/lib/group_chat_details_screen.dart index 6aff5711..5fca35b4 100644 --- a/example/lib/group_chat_details_screen.dart +++ b/example/lib/group_chat_details_screen.dart @@ -3,7 +3,6 @@ import 'package:stream_chat_flutter/stream_chat_flutter.dart'; import 'package:uuid/uuid.dart'; import 'main.dart'; -import 'neumorphic_button.dart'; class GroupChatDetailsScreen extends StatefulWidget { final List selectedUsers; @@ -103,7 +102,7 @@ class _GroupChatDetailsScreenState extends State { ), ), actions: [ - NeumorphicButton( + StreamNeumorphicButton( child: IconButton( padding: const EdgeInsets.all(0), icon: Icon(StreamIcons.check), diff --git a/example/lib/main.dart b/example/lib/main.dart index a7d5e473..7592cfab 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -69,13 +69,7 @@ class ChannelListPage extends StatelessWidget { Widget build(BuildContext context) { final user = StreamChat.of(context).user; return Scaffold( - appBar: AppBar( - backgroundColor: Colors.white, - title: Text( - 'Stream Chat', - style: TextStyle(color: Colors.black), - ), - ), + appBar: ChannelListHeader(), drawer: _buildDrawer(context, user), drawerEdgeDragWidth: 50, body: ChannelsBloc( diff --git a/example/lib/new_chat_screen.dart b/example/lib/new_chat_screen.dart index 9ec2ca7e..deff2a3c 100644 --- a/example/lib/new_chat_screen.dart +++ b/example/lib/new_chat_screen.dart @@ -5,7 +5,6 @@ import 'package:stream_chat_flutter/stream_chat_flutter.dart'; import 'chips_input_text_field.dart'; import 'main.dart'; -import 'neumorphic_button.dart'; import 'new_group_chat_screen.dart'; class NewChatScreen extends StatefulWidget { @@ -193,7 +192,7 @@ class _NewChatScreenState extends State { padding: const EdgeInsets.symmetric(vertical: 8), child: Row( children: [ - NeumorphicButton( + StreamNeumorphicButton( child: Icon( StreamIcons.group, color: Color(0xFF006CFF), diff --git a/lib/src/channel_list_header.dart b/lib/src/channel_list_header.dart new file mode 100644 index 00000000..94266045 --- /dev/null +++ b/lib/src/channel_list_header.dart @@ -0,0 +1,158 @@ +import 'dart:ui'; + +import 'package:flutter/material.dart'; +import 'package:stream_chat/stream_chat.dart'; +import 'package:stream_chat_flutter/src/stream_neumorphic_button.dart'; +import 'package:stream_chat_flutter/stream_chat_flutter.dart'; + +import 'stream_chat.dart'; + +typedef TitleBuilder = Widget Function( + BuildContext context, + ConnectionStatus status, + Client client, +); + +class ChannelListHeader extends StatelessWidget implements PreferredSizeWidget { + const ChannelListHeader({ + Key key, + this.client, + this.titleBuilder, + }) : super(key: key); + + final Client client; + + final TitleBuilder titleBuilder; + + @override + Widget build(BuildContext context) { + final _client = client ?? StreamChat.of(context).client; + final user = _client.state.user; + return AppBar( + brightness: Theme.of(context).brightness, + elevation: 1, + backgroundColor: + StreamChatTheme.of(context).channelTheme.channelHeaderTheme.color, + centerTitle: true, + leading: Center( + child: UserAvatar( + user: user, + onTap: (_) => Scaffold.of(context).openDrawer(), + constraints: BoxConstraints.tightFor( + height: 40, + width: 40, + ), + ), + ), + actions: [ + StreamNeumorphicButton( + child: IconButton( + icon: ValueListenableBuilder( + valueListenable: _client.wsConnectionStatus, + builder: (context, status, child) { + var color; + switch (status) { + case ConnectionStatus.connected: + color = Color(0xFF006CFF); + break; + case ConnectionStatus.connecting: + color = Colors.grey; + break; + case ConnectionStatus.disconnected: + color = Colors.grey; + break; + } + return Icon( + StreamIcons.pen_write, + color: color, + ); + }, + ), + onPressed: () {}, + ), + ) + ], + title: ValueListenableBuilder( + valueListenable: _client.wsConnectionStatus, + builder: (context, status, child) { + if (titleBuilder != null) { + return titleBuilder(context, status, _client); + } + switch (status) { + case ConnectionStatus.connected: + return _buildConnectedTitleState(); + case ConnectionStatus.connecting: + return _buildConnectingTitleState(); + case ConnectionStatus.disconnected: + return _buildDisconnectedTitleState(_client); + default: + return Offstage(); + } + }, + ), + ); + } + + Widget _buildConnectedTitleState() => Text( + 'Stream Chat', + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.bold, + color: Colors.black, + ), + ); + + Widget _buildConnectingTitleState() { + return Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Container( + height: 16, + width: 16, + child: Center( + child: CircularProgressIndicator(), + ), + ), + SizedBox(width: 10), + Text( + 'Searching for Network', + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.bold, + color: Colors.black, + ), + ) + ], + ); + } + + Widget _buildDisconnectedTitleState(Client client) { + return Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + 'Offline...', + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.bold, + color: Colors.black, + ), + ), + TextButton( + onPressed: () => client.connect(), + child: Text( + 'Try Again', + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.bold, + color: Color(0xFF006CFF), + ), + ), + ), + ], + ); + } + + @override + Size get preferredSize => Size.fromHeight(kToolbarHeight); +} diff --git a/example/lib/neumorphic_button.dart b/lib/src/stream_neumorphic_button.dart similarity index 90% rename from example/lib/neumorphic_button.dart rename to lib/src/stream_neumorphic_button.dart index 69454fb2..bf3e8e97 100644 --- a/example/lib/neumorphic_button.dart +++ b/lib/src/stream_neumorphic_button.dart @@ -1,10 +1,10 @@ import 'package:flutter/material.dart'; -class NeumorphicButton extends StatelessWidget { +class StreamNeumorphicButton extends StatelessWidget { final Widget child; final Color backgroundColor; - const NeumorphicButton({ + const StreamNeumorphicButton({ Key key, @required this.child, this.backgroundColor = Colors.white, diff --git a/lib/stream_chat_flutter.dart b/lib/stream_chat_flutter.dart index 91ac68c8..1399bf08 100644 --- a/lib/stream_chat_flutter.dart +++ b/lib/stream_chat_flutter.dart @@ -33,3 +33,5 @@ export 'src/video_attachment.dart'; export 'src/users_bloc.dart'; export 'src/user_list_view.dart'; export 'src/user_item.dart'; +export 'src/stream_neumorphic_button.dart'; +export 'src/channel_list_header.dart'; From d9507214d772cd5be6e199a9c6662ec89d30529c Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Mon, 23 Nov 2020 16:44:44 +0530 Subject: [PATCH 0447/1140] fmt --- lib/src/full_screen_image.dart | 8 +- lib/src/giphy_attachment.dart | 28 ++--- lib/src/image_attachment.dart | 8 +- lib/src/image_footer.dart | 185 +++++++++++++++++---------------- lib/src/image_group.dart | 22 ++-- 5 files changed, 135 insertions(+), 116 deletions(-) diff --git a/lib/src/full_screen_image.dart b/lib/src/full_screen_image.dart index 52e75871..8ab0415f 100644 --- a/lib/src/full_screen_image.dart +++ b/lib/src/full_screen_image.dart @@ -132,9 +132,13 @@ class _FullScreenImageState extends State String getDay(DateTime dateTime) { var now = DateTime.now(); - if(DateTime(dateTime.year, dateTime.month, dateTime.day) == DateTime(now.year, now.month, now.day)) { + if (DateTime(dateTime.year, dateTime.month, dateTime.day) == + DateTime(now.year, now.month, now.day)) { return 'today'; - } else if(DateTime(now.year, now.month, now.day).difference(dateTime).inHours < 24) { + } else if (DateTime(now.year, now.month, now.day) + .difference(dateTime) + .inHours < + 24) { return 'yesterday'; } else { return 'on ${Jiffy(dateTime).format("MMM do")}'; diff --git a/lib/src/giphy_attachment.dart b/lib/src/giphy_attachment.dart index f6d1d473..bb859263 100644 --- a/lib/src/giphy_attachment.dart +++ b/lib/src/giphy_attachment.dart @@ -64,12 +64,14 @@ class GiphyAttachment extends StatelessWidget { onTap: () { Navigator.push(context, MaterialPageRoute(builder: (_) { return FullScreenImage( - urls: [attachment.imageUrl ?? - attachment.assetUrl ?? - attachment.thumbUrl], - userName: message.user.name, - sentAt: message.createdAt, - message: message, + urls: [ + attachment.imageUrl ?? + attachment.assetUrl ?? + attachment.thumbUrl + ], + userName: message.user.name, + sentAt: message.createdAt, + message: message, ); })); }, @@ -285,12 +287,14 @@ class GiphyAttachment extends StatelessWidget { onTap: () { Navigator.push(context, MaterialPageRoute(builder: (_) { return FullScreenImage( - urls: [attachment.imageUrl ?? - attachment.assetUrl ?? - attachment.thumbUrl], - userName: message.user.name, - sentAt: message.createdAt, - message: message, + urls: [ + attachment.imageUrl ?? + attachment.assetUrl ?? + attachment.thumbUrl + ], + userName: message.user.name, + sentAt: message.createdAt, + message: message, ); })); }, diff --git a/lib/src/image_attachment.dart b/lib/src/image_attachment.dart index b429e064..83f747db 100644 --- a/lib/src/image_attachment.dart +++ b/lib/src/image_attachment.dart @@ -48,9 +48,11 @@ class ImageAttachment extends StatelessWidget { return StreamChannel( channel: channel, child: FullScreenImage( - urls: [attachment.imageUrl ?? - attachment.assetUrl ?? - attachment.thumbUrl], + urls: [ + attachment.imageUrl ?? + attachment.assetUrl ?? + attachment.thumbUrl + ], userName: message.user.name, sentAt: message.createdAt, message: message, diff --git a/lib/src/image_footer.dart b/lib/src/image_footer.dart index 5f4710d1..d71ee3af 100644 --- a/lib/src/image_footer.dart +++ b/lib/src/image_footer.dart @@ -378,8 +378,9 @@ class _ImageFooterState extends State { child: Material( child: InkWell( onTap: () async { - await GallerySaver.saveImage( - widget.urls[widget.currentPage].split('?')[0]); + await GallerySaver.saveImage(widget + .urls[widget.currentPage] + .split('?')[0]); Navigator.pop(context); }, child: SizedBox.expand( @@ -434,7 +435,8 @@ class _ImageFooterState extends State { autofocus: true, decoration: InputDecoration( isDense: true, - prefixIconConstraints: BoxConstraints.tight(Size(38.0, 38.0)), + prefixIconConstraints: + BoxConstraints.tight(Size(38.0, 38.0)), prefixIcon: Transform.scale( scale: 1.2, alignment: Alignment.center, @@ -462,7 +464,10 @@ class _ImageFooterState extends State { width: 8.0, ), IconButton( - icon: Icon(StreamIcons.close_circle, color: Colors.black.withOpacity(0.5),), + icon: Icon( + StreamIcons.close_circle, + color: Colors.black.withOpacity(0.5), + ), onPressed: () { modalSetState(() { _userSearchMode = false; @@ -533,98 +538,100 @@ class _ImageFooterState extends State { child: Container( color: Colors.white, height: 56.0, - child: _loading ? Center( - child: Padding( - padding: const EdgeInsets.all(8.0), - child: CircularProgressIndicator(), - ), - ) : Row( - children: [ - Expanded( - child: Padding( - padding: const EdgeInsets.only(left: 8.0), - child: TextField( - controller: _messageController, - onChanged: (val) { - modalSetState(() {}); - }, - onTap: () { - modalSetState(() {}); - setState(() {}); - }, - decoration: InputDecoration( - isDense: true, - prefixText: ' ', - hintText: 'Add a comment', - border: OutlineInputBorder( - borderRadius: BorderRadius.circular(32.0), - borderSide: BorderSide( - color: Colors.black.withOpacity(0.16), - ), - ), - focusedBorder: OutlineInputBorder( - borderRadius: BorderRadius.circular(32.0), - borderSide: BorderSide( - color: Colors.black.withOpacity(0.16), - )), - contentPadding: EdgeInsets.symmetric(vertical: 12.0), - ), + child: _loading + ? Center( + child: Padding( + padding: const EdgeInsets.all(8.0), + child: CircularProgressIndicator(), ), - ), - ), - AnimatedCrossFade( - crossFadeState: _messageController.text.isNotEmpty - ? CrossFadeState.showFirst - : CrossFadeState.showSecond, - firstChild: IconTheme( - data: StreamChatTheme.of(context) - .channelTheme - .messageInputButtonIconTheme, - child: Center( - child: Padding( - padding: const EdgeInsets.all(8.0), - child: InkWell( - onTap: () async { - modalSetState(() { - _loading = true; - }); - await sendMessage(); - modalSetState(() { - _loading = false; - }); - }, - child: Transform.rotate( - angle: -pi / 2, - child: Icon( - StreamIcons.send_message, - color: StreamChatTheme.of(context).accentColor, + ) + : Row( + children: [ + Expanded( + child: Padding( + padding: const EdgeInsets.only(left: 8.0), + child: TextField( + controller: _messageController, + onChanged: (val) { + modalSetState(() {}); + }, + onTap: () { + modalSetState(() {}); + setState(() {}); + }, + decoration: InputDecoration( + isDense: true, + prefixText: ' ', + hintText: 'Add a comment', + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(32.0), + borderSide: BorderSide( + color: Colors.black.withOpacity(0.16), + ), + ), + focusedBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(32.0), + borderSide: BorderSide( + color: Colors.black.withOpacity(0.16), + )), + contentPadding: EdgeInsets.symmetric(vertical: 12.0), ), ), ), ), - ), - ), - secondChild: IconTheme( - data: StreamChatTheme.of(context) - .channelTheme - .messageInputButtonIconTheme, - child: Padding( - padding: const EdgeInsets.all(8.0), - child: Center( - child: InkWell( - onTap: () {}, - child: Icon( - StreamIcons.send_message, - color: Colors.grey, + AnimatedCrossFade( + crossFadeState: _messageController.text.isNotEmpty + ? CrossFadeState.showFirst + : CrossFadeState.showSecond, + firstChild: IconTheme( + data: StreamChatTheme.of(context) + .channelTheme + .messageInputButtonIconTheme, + child: Center( + child: Padding( + padding: const EdgeInsets.all(8.0), + child: InkWell( + onTap: () async { + modalSetState(() { + _loading = true; + }); + await sendMessage(); + modalSetState(() { + _loading = false; + }); + }, + child: Transform.rotate( + angle: -pi / 2, + child: Icon( + StreamIcons.send_message, + color: StreamChatTheme.of(context).accentColor, + ), + ), + ), + ), + ), ), - )), - ), + secondChild: IconTheme( + data: StreamChatTheme.of(context) + .channelTheme + .messageInputButtonIconTheme, + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Center( + child: InkWell( + onTap: () {}, + child: Icon( + StreamIcons.send_message, + color: Colors.grey, + ), + )), + ), + ), + duration: Duration(milliseconds: 300), + alignment: Alignment.center, + ), + ], ), - duration: Duration(milliseconds: 300), - alignment: Alignment.center, - ), - ], - ), ), ); } diff --git a/lib/src/image_group.dart b/lib/src/image_group.dart index afccaf7a..1b6e48f2 100644 --- a/lib/src/image_group.dart +++ b/lib/src/image_group.dart @@ -113,16 +113,18 @@ class ImageGroup extends StatelessWidget { Navigator.push( context, MaterialPageRoute( - builder: (context) => - StreamChannel( - channel: channel, - child: FullScreenImage(urls: images.map((e) => e.imageUrl ?? e.thumbUrl ?? e.assetUrl).toList(), - startIndex: index, - userName: message.user.name, - sentAt: message.createdAt, - message: message, - ), - ), + builder: (context) => StreamChannel( + channel: channel, + child: FullScreenImage( + urls: images + .map((e) => e.imageUrl ?? e.thumbUrl ?? e.assetUrl) + .toList(), + startIndex: index, + userName: message.user.name, + sentAt: message.createdAt, + message: message, + ), + ), ), ); } From a30565e0e1784d031efc82ceda1c5242dacc6585 Mon Sep 17 00:00:00 2001 From: xsahil03x Date: Mon, 23 Nov 2020 17:40:41 +0530 Subject: [PATCH 0448/1140] [ChannelListHeader] Refactor, Add support for trailing, leading widget taps. --- lib/src/channel_list_header.dart | 111 ++++++++++++++++++++++--------- 1 file changed, 80 insertions(+), 31 deletions(-) diff --git a/lib/src/channel_list_header.dart b/lib/src/channel_list_header.dart index 94266045..147f9340 100644 --- a/lib/src/channel_list_header.dart +++ b/lib/src/channel_list_header.dart @@ -7,22 +7,57 @@ import 'package:stream_chat_flutter/stream_chat_flutter.dart'; import 'stream_chat.dart'; -typedef TitleBuilder = Widget Function( +typedef _TitleBuilder = Widget Function( BuildContext context, ConnectionStatus status, Client client, ); +/// +/// It shows the current [Client] status. +/// +/// ```dart +/// class MyApp extends StatelessWidget { +/// final Client client; +/// +/// MyApp(this.client); +/// +/// @override +/// Widget build(BuildContext context) { +/// return MaterialApp( +/// home: StreamChat( +/// client: client, +/// child: Scaffold( +/// appBar: ChannelListHeader(), +/// ), +/// ), +/// ); +/// } +/// } +/// ``` +/// +/// Usually you would use this widget as an [AppBar] inside a [Scaffold]. +/// However you can also use it as a normal widget. +/// +/// The widget components render the ui based on the first ancestor of type [StreamChatTheme] and on its [ChannelTheme.channelHeaderTheme] property. +/// Modify it to change the widget appearance. class ChannelListHeader extends StatelessWidget implements PreferredSizeWidget { + /// Instantiates a ChannelListHeader const ChannelListHeader({ Key key, this.client, this.titleBuilder, + this.onUserAvatarTap, + this.onNewChatButtonTap, }) : super(key: key); final Client client; - final TitleBuilder titleBuilder; + final _TitleBuilder titleBuilder; + + final Function(User) onUserAvatarTap; + + final VoidCallback onNewChatButtonTap; @override Widget build(BuildContext context) { @@ -37,7 +72,8 @@ class ChannelListHeader extends StatelessWidget implements PreferredSizeWidget { leading: Center( child: UserAvatar( user: user, - onTap: (_) => Scaffold.of(context).openDrawer(), + onTap: onUserAvatarTap ?? (_) => Scaffold.of(context).openDrawer(), + borderRadius: BorderRadius.circular(20), constraints: BoxConstraints.tightFor( height: 40, width: 40, @@ -68,7 +104,7 @@ class ChannelListHeader extends StatelessWidget implements PreferredSizeWidget { ); }, ), - onPressed: () {}, + onPressed: onNewChatButtonTap, ), ) ], @@ -80,11 +116,11 @@ class ChannelListHeader extends StatelessWidget implements PreferredSizeWidget { } switch (status) { case ConnectionStatus.connected: - return _buildConnectedTitleState(); + return _buildConnectedTitleState(context); case ConnectionStatus.connecting: - return _buildConnectingTitleState(); + return _buildConnectingTitleState(context); case ConnectionStatus.disconnected: - return _buildDisconnectedTitleState(_client); + return _buildDisconnectedTitleState(context, _client); default: return Offstage(); } @@ -93,16 +129,19 @@ class ChannelListHeader extends StatelessWidget implements PreferredSizeWidget { ); } - Widget _buildConnectedTitleState() => Text( + Widget _buildConnectedTitleState(BuildContext context) => Text( 'Stream Chat', - style: TextStyle( - fontSize: 16, - fontWeight: FontWeight.bold, - color: Colors.black, - ), + style: StreamChatTheme.of(context) + .channelTheme + .channelHeaderTheme + .title + .copyWith( + fontSize: 16, + fontWeight: FontWeight.bold, + ), ); - Widget _buildConnectingTitleState() { + Widget _buildConnectingTitleState(BuildContext context) { return Row( mainAxisAlignment: MainAxisAlignment.center, children: [ @@ -116,37 +155,47 @@ class ChannelListHeader extends StatelessWidget implements PreferredSizeWidget { SizedBox(width: 10), Text( 'Searching for Network', - style: TextStyle( - fontSize: 16, - fontWeight: FontWeight.bold, - color: Colors.black, - ), - ) + style: StreamChatTheme.of(context) + .channelTheme + .channelHeaderTheme + .title + .copyWith( + fontSize: 16, + fontWeight: FontWeight.bold, + ), + ), ], ); } - Widget _buildDisconnectedTitleState(Client client) { + Widget _buildDisconnectedTitleState(BuildContext context, Client client) { return Row( mainAxisAlignment: MainAxisAlignment.center, children: [ Text( 'Offline...', - style: TextStyle( - fontSize: 16, - fontWeight: FontWeight.bold, - color: Colors.black, - ), + style: StreamChatTheme.of(context) + .channelTheme + .channelHeaderTheme + .title + .copyWith( + fontSize: 16, + fontWeight: FontWeight.bold, + ), ), TextButton( onPressed: () => client.connect(), child: Text( 'Try Again', - style: TextStyle( - fontSize: 16, - fontWeight: FontWeight.bold, - color: Color(0xFF006CFF), - ), + style: StreamChatTheme.of(context) + .channelTheme + .channelHeaderTheme + .title + .copyWith( + fontSize: 16, + fontWeight: FontWeight.bold, + color: Color(0xFF006CFF), + ), ), ), ], From 942250d517971c28bbaed7eb4ac3d374e1b2b1f2 Mon Sep 17 00:00:00 2001 From: xsahil03x Date: Mon, 23 Nov 2020 17:49:42 +0530 Subject: [PATCH 0449/1140] [ChannelListHeader] Add docComments --- lib/src/channel_list_header.dart | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/lib/src/channel_list_header.dart b/lib/src/channel_list_header.dart index 147f9340..b44097c2 100644 --- a/lib/src/channel_list_header.dart +++ b/lib/src/channel_list_header.dart @@ -39,6 +39,9 @@ typedef _TitleBuilder = Widget Function( /// Usually you would use this widget as an [AppBar] inside a [Scaffold]. /// However you can also use it as a normal widget. /// +/// The widget by default uses the inherited [Client] to fetch information about the status. +/// However you can also pass your own [Client] if you don't have it in the widget tree. +/// /// The widget components render the ui based on the first ancestor of type [StreamChatTheme] and on its [ChannelTheme.channelHeaderTheme] property. /// Modify it to change the widget appearance. class ChannelListHeader extends StatelessWidget implements PreferredSizeWidget { @@ -51,12 +54,17 @@ class ChannelListHeader extends StatelessWidget implements PreferredSizeWidget { this.onNewChatButtonTap, }) : super(key: key); + /// Pass this if you don't have a [Client] in your widget tree. final Client client; + /// Use this to build your own title as per different [ConnectionStatus] final _TitleBuilder titleBuilder; + /// Callback to call when pressing the user avatar button. + /// By default it calls Scaffold.of(context).openDrawer() final Function(User) onUserAvatarTap; + /// Callback to call when pressing the new chat button. final VoidCallback onNewChatButtonTap; @override From f789975844b69f1aca1b96a46ccb735813268834 Mon Sep 17 00:00:00 2001 From: xsahil03x Date: Mon, 23 Nov 2020 17:51:37 +0530 Subject: [PATCH 0450/1140] Open new chat screen page when new chat button is pressed. --- example/lib/main.dart | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/example/lib/main.dart b/example/lib/main.dart index 7592cfab..9bcf63b5 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -69,7 +69,15 @@ class ChannelListPage extends StatelessWidget { Widget build(BuildContext context) { final user = StreamChat.of(context).user; return Scaffold( - appBar: ChannelListHeader(), + appBar: ChannelListHeader( + onNewChatButtonTap: () { + Navigator.of(context).push( + MaterialPageRoute( + builder: (context) => NewChatScreen(), + ), + ); + }, + ), drawer: _buildDrawer(context, user), drawerEdgeDragWidth: 50, body: ChannelsBloc( From 515b9734cbcb97d0266f0d84285d4ca2968f04a6 Mon Sep 17 00:00:00 2001 From: xsahil03x Date: Mon, 23 Nov 2020 20:40:09 +0530 Subject: [PATCH 0451/1140] [NewGroupChatScreen] Maintain selectedUsersList when going back and forward in the flow --- example/lib/group_chat_details_screen.dart | 310 +++++++++++---------- example/lib/new_group_chat_screen.dart | 11 +- lib/src/back_button.dart | 2 +- 3 files changed, 168 insertions(+), 155 deletions(-) diff --git a/example/lib/group_chat_details_screen.dart b/example/lib/group_chat_details_screen.dart index 6aff5711..0aba4578 100644 --- a/example/lib/group_chat_details_screen.dart +++ b/example/lib/group_chat_details_screen.dart @@ -53,167 +53,173 @@ class _GroupChatDetailsScreenState extends State { @override Widget build(BuildContext context) { - return Scaffold( - backgroundColor: Color.fromRGBO(252, 252, 252, 1), - appBar: AppBar( - elevation: 1, - backgroundColor: Colors.white, - leading: const StreamBackButton(), - title: Text( - 'Name of Group Chat', - style: TextStyle( - color: Colors.black, - fontSize: 16, - ), - ), - centerTitle: true, - bottom: PreferredSize( - preferredSize: Size.fromHeight(kToolbarHeight), - child: Padding( - padding: const EdgeInsets.symmetric(vertical: 18, horizontal: 16), - child: Row( - children: [ - Text( - 'NAME', - style: TextStyle( - fontSize: 12, - color: Colors.black.withOpacity(0.5), - ), - ), - SizedBox(width: 16), - Expanded( - child: TextField( - controller: _groupNameController, - decoration: InputDecoration( - isDense: true, - border: InputBorder.none, - focusedBorder: InputBorder.none, - enabledBorder: InputBorder.none, - errorBorder: InputBorder.none, - disabledBorder: InputBorder.none, - contentPadding: const EdgeInsets.all(0), - hintText: 'Choose a group chat name', - hintStyle: TextStyle( - fontSize: 14, color: Colors.black.withOpacity(.5)), - ), - ), - ), - ], + return WillPopScope( + onWillPop: () async { + Navigator.pop(context, _selectedUsers); + return false; + }, + child: Scaffold( + backgroundColor: Color.fromRGBO(252, 252, 252, 1), + appBar: AppBar( + elevation: 1, + backgroundColor: Colors.white, + leading: const StreamBackButton(), + title: Text( + 'Name of Group Chat', + style: TextStyle( + color: Colors.black, + fontSize: 16, ), ), - ), - actions: [ - NeumorphicButton( - child: IconButton( - padding: const EdgeInsets.all(0), - icon: Icon(StreamIcons.check), - color: Color(0xFF006CFF), - onPressed: _isGroupNameEmpty - ? null - : () async { - final groupName = _groupNameController.text; - final client = StreamChat.of(context).client; - final channel = client - .channel('messaging', id: Uuid().v4(), extraData: { - 'members': [ - client.state.user.id, - ..._selectedUsers.map((e) => e.id), - ], - 'name': groupName, - }); - await channel.watch(); - Navigator.of(context) - ..pop() - ..pushReplacement( - MaterialPageRoute( - builder: (context) { - return StreamChannel( - child: ChannelPage(), - channel: channel, - ); - }, - ), - ); - }, - ), - ), - ], - ), - body: Column( - children: [ - Container( - width: double.maxFinite, - color: Colors.grey.shade50, + centerTitle: true, + bottom: PreferredSize( + preferredSize: Size.fromHeight(kToolbarHeight), child: Padding( - padding: const EdgeInsets.symmetric( - vertical: 8, - horizontal: 8, + padding: const EdgeInsets.symmetric(vertical: 18, horizontal: 16), + child: Row( + children: [ + Text( + 'NAME', + style: TextStyle( + fontSize: 12, + color: Colors.black.withOpacity(0.5), + ), + ), + SizedBox(width: 16), + Expanded( + child: TextField( + controller: _groupNameController, + decoration: InputDecoration( + isDense: true, + border: InputBorder.none, + focusedBorder: InputBorder.none, + enabledBorder: InputBorder.none, + errorBorder: InputBorder.none, + disabledBorder: InputBorder.none, + contentPadding: const EdgeInsets.all(0), + hintText: 'Choose a group chat name', + hintStyle: TextStyle( + fontSize: 14, color: Colors.black.withOpacity(.5)), + ), + ), + ), + ], ), - child: Text( - '$_totalUsers ${_totalUsers > 1 ? 'Members' : 'Member'}', - style: TextStyle( - fontWeight: FontWeight.w500, + ), + ), + actions: [ + NeumorphicButton( + child: IconButton( + padding: const EdgeInsets.all(0), + icon: Icon(StreamIcons.check), + color: Color(0xFF006CFF), + onPressed: _isGroupNameEmpty + ? null + : () async { + final groupName = _groupNameController.text; + final client = StreamChat.of(context).client; + final channel = client + .channel('messaging', id: Uuid().v4(), extraData: { + 'members': [ + client.state.user.id, + ..._selectedUsers.map((e) => e.id), + ], + 'name': groupName, + }); + await channel.watch(); + Navigator.of(context) + ..pop() + ..pushReplacement( + MaterialPageRoute( + builder: (context) { + return StreamChannel( + child: ChannelPage(), + channel: channel, + ); + }, + ), + ); + }, + ), + ), + ], + ), + body: Column( + children: [ + Container( + width: double.maxFinite, + color: Colors.grey.shade50, + child: Padding( + padding: const EdgeInsets.symmetric( + vertical: 8, + horizontal: 8, + ), + child: Text( + '$_totalUsers ${_totalUsers > 1 ? 'Members' : 'Member'}', + style: TextStyle( + fontWeight: FontWeight.w500, + ), ), ), ), - ), - Expanded( - child: ListView.separated( - itemCount: _selectedUsers.length + 1, - separatorBuilder: (_, __) => Container( - height: 1, - color: Theme.of(context).brightness == Brightness.dark - ? Colors.white.withOpacity(0.1) - : Colors.black.withOpacity(0.1), - ), - itemBuilder: (_, index) { - if (index == _selectedUsers.length) { - return Container( - height: 1, - color: Theme.of(context).brightness == Brightness.dark - ? Colors.white.withOpacity(0.1) - : Colors.black.withOpacity(0.1), + Expanded( + child: ListView.separated( + itemCount: _selectedUsers.length + 1, + separatorBuilder: (_, __) => Container( + height: 1, + color: Theme.of(context).brightness == Brightness.dark + ? Colors.white.withOpacity(0.1) + : Colors.black.withOpacity(0.1), + ), + itemBuilder: (_, index) { + if (index == _selectedUsers.length) { + return Container( + height: 1, + color: Theme.of(context).brightness == Brightness.dark + ? Colors.white.withOpacity(0.1) + : Colors.black.withOpacity(0.1), + ); + } + final user = _selectedUsers[index]; + return ListTile( + key: ObjectKey(user), + leading: UserAvatar( + user: user, + constraints: BoxConstraints.tightFor( + width: 40, + height: 40, + ), + ), + title: Text( + user.name, + style: TextStyle(fontWeight: FontWeight.bold), + ), + contentPadding: const EdgeInsets.symmetric( + horizontal: 12, + vertical: 8, + ), + trailing: IconButton( + icon: Icon( + Icons.clear_rounded, + color: Colors.black, + ), + padding: const EdgeInsets.all(0), + splashRadius: 24, + onPressed: () { + setState(() { + _selectedUsers.remove(user); + }); + if (_selectedUsers.isEmpty) { + Navigator.pop(context, _selectedUsers); + } + }, + ), ); - } - final user = _selectedUsers[index]; - return ListTile( - key: ObjectKey(user), - leading: UserAvatar( - user: user, - constraints: BoxConstraints.tightFor( - width: 40, - height: 40, - ), - ), - title: Text( - user.name, - style: TextStyle(fontWeight: FontWeight.bold), - ), - contentPadding: const EdgeInsets.symmetric( - horizontal: 12, - vertical: 8, - ), - trailing: IconButton( - icon: Icon( - Icons.clear_rounded, - color: Colors.black, - ), - padding: const EdgeInsets.all(0), - splashRadius: 24, - onPressed: () { - setState(() { - _selectedUsers.remove(user); - }); - if (_selectedUsers.isEmpty) { - Navigator.pop(context); - } - }, - ), - ); - }, + }, + ), ), - ), - ], + ], + ), ), ); } diff --git a/example/lib/new_group_chat_screen.dart b/example/lib/new_group_chat_screen.dart index b75e7510..3c6ad2ba 100644 --- a/example/lib/new_group_chat_screen.dart +++ b/example/lib/new_group_chat_screen.dart @@ -69,8 +69,8 @@ class _NewGroupChatScreenState extends State { StreamIcons.arrow_right, color: Color(0xFF006CFF), ), - onPressed: () { - Navigator.push( + onPressed: () async { + final updatedList = await Navigator.push( context, MaterialPageRoute( builder: (_) => GroupChatDetailsScreen( @@ -78,6 +78,13 @@ class _NewGroupChatScreenState extends State { ), ), ); + if (updatedList != null) { + setState(() { + _selectedUsers + ..clear() + ..addAll(updatedList); + }); + } }, ) ], diff --git a/lib/src/back_button.dart b/lib/src/back_button.dart index 78b86ae5..303ad8a9 100644 --- a/lib/src/back_button.dart +++ b/lib/src/back_button.dart @@ -33,7 +33,7 @@ class StreamBackButton extends StatelessWidget { if (onPressed != null) { onPressed(); } else { - Navigator.of(context).pop(); + Navigator.maybePop(context); } }, child: Icon( From 6508c040dd0d9316b29d087c0fa55c351504ab63 Mon Sep 17 00:00:00 2001 From: xsahil03x Date: Mon, 23 Nov 2020 20:48:46 +0530 Subject: [PATCH 0452/1140] [ChipsInputTextField] Request focus and vice versa when item addition is resumed/paused. --- example/lib/chips_input_text_field.dart | 2 ++ 1 file changed, 2 insertions(+) diff --git a/example/lib/chips_input_text_field.dart b/example/lib/chips_input_text_field.dart index 317a68f7..76501d05 100644 --- a/example/lib/chips_input_text_field.dart +++ b/example/lib/chips_input_text_field.dart @@ -51,12 +51,14 @@ class ChipInputTextFieldState extends State> { if (!_pauseItemAddition) { setState(() => _pauseItemAddition = true); } + widget.focusNode.unfocus(); } void resumeItemAddition() { if (_pauseItemAddition) { setState(() => _pauseItemAddition = false); } + widget.focusNode.requestFocus(); } @override From bcb6515ea89ff9ef9e1951ebfe4c136bad6d05a9 Mon Sep 17 00:00:00 2001 From: xsahil03x Date: Mon, 23 Nov 2020 20:51:03 +0530 Subject: [PATCH 0453/1140] minor fixes --- example/lib/chips_input_text_field.dart | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/example/lib/chips_input_text_field.dart b/example/lib/chips_input_text_field.dart index 76501d05..7ee0568c 100644 --- a/example/lib/chips_input_text_field.dart +++ b/example/lib/chips_input_text_field.dart @@ -43,7 +43,6 @@ class ChipInputTextFieldState extends State> { _chips.remove(item); if (_chips.isEmpty) resumeItemAddition(); }); - if (widget.focusNode != null) widget.focusNode.requestFocus(); if (widget.onChipRemoved != null) widget.onChipRemoved(item); } @@ -51,14 +50,14 @@ class ChipInputTextFieldState extends State> { if (!_pauseItemAddition) { setState(() => _pauseItemAddition = true); } - widget.focusNode.unfocus(); + if (widget.focusNode != null) widget.focusNode.unfocus(); } void resumeItemAddition() { if (_pauseItemAddition) { setState(() => _pauseItemAddition = false); } - widget.focusNode.requestFocus(); + if (widget.focusNode != null) widget.focusNode.requestFocus(); } @override From 7aac92e890d78a6b93378a73bce7d24103c6589f Mon Sep 17 00:00:00 2001 From: xsahil03x Date: Mon, 23 Nov 2020 20:57:32 +0530 Subject: [PATCH 0454/1140] minor fixes --- example/lib/chips_input_text_field.dart | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/example/lib/chips_input_text_field.dart b/example/lib/chips_input_text_field.dart index 7ee0568c..857782fe 100644 --- a/example/lib/chips_input_text_field.dart +++ b/example/lib/chips_input_text_field.dart @@ -50,27 +50,20 @@ class ChipInputTextFieldState extends State> { if (!_pauseItemAddition) { setState(() => _pauseItemAddition = true); } - if (widget.focusNode != null) widget.focusNode.unfocus(); + widget.focusNode?.unfocus(); } void resumeItemAddition() { if (_pauseItemAddition) { setState(() => _pauseItemAddition = false); } - if (widget.focusNode != null) widget.focusNode.requestFocus(); + widget.focusNode?.requestFocus(); } @override Widget build(BuildContext context) { return GestureDetector( - onTap: _pauseItemAddition - ? () { - setState(() { - _pauseItemAddition = false; - widget.focusNode?.requestFocus(); - }); - } - : null, + onTap: _pauseItemAddition ? resumeItemAddition : null, child: Material( elevation: 1, color: Colors.white, From d68c02066e51ebe3a3cb0220f9fa6651f835a316 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Mon, 23 Nov 2020 17:00:51 +0100 Subject: [PATCH 0455/1140] change reconnection logic --- lib/src/channel_list_header.dart | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/src/channel_list_header.dart b/lib/src/channel_list_header.dart index b44097c2..0df8ea06 100644 --- a/lib/src/channel_list_header.dart +++ b/lib/src/channel_list_header.dart @@ -192,7 +192,10 @@ class ChannelListHeader extends StatelessWidget implements PreferredSizeWidget { ), ), TextButton( - onPressed: () => client.connect(), + onPressed: () async { + await client.disconnect(); + return client.connect(); + }, child: Text( 'Try Again', style: StreamChatTheme.of(context) From f61d42bf3a61f926b2621bde1786e25355ce3dda Mon Sep 17 00:00:00 2001 From: xsahil03x Date: Tue, 24 Nov 2020 12:44:34 +0530 Subject: [PATCH 0456/1140] [Channel List Header] Hide online status from user avatar --- lib/src/channel_list_header.dart | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/src/channel_list_header.dart b/lib/src/channel_list_header.dart index 0df8ea06..6a838265 100644 --- a/lib/src/channel_list_header.dart +++ b/lib/src/channel_list_header.dart @@ -80,6 +80,7 @@ class ChannelListHeader extends StatelessWidget implements PreferredSizeWidget { leading: Center( child: UserAvatar( user: user, + showOnlineStatus: false, onTap: onUserAvatarTap ?? (_) => Scaffold.of(context).openDrawer(), borderRadius: BorderRadius.circular(20), constraints: BoxConstraints.tightFor( From 8640f2b4f91b1376afa00115408747a44e74e729 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Tue, 24 Nov 2020 14:21:08 +0530 Subject: [PATCH 0457/1140] fix: Fixed listtile splash --- lib/src/image_actions_modal.dart | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/lib/src/image_actions_modal.dart b/lib/src/image_actions_modal.dart index 0328209e..1bfb6aa3 100644 --- a/lib/src/image_actions_modal.dart +++ b/lib/src/image_actions_modal.dart @@ -152,19 +152,22 @@ class ImageActionsModal extends StatelessWidget { color: Colors.black, ); - return ListTile( - dense: true, - title: Text( - title, - style: color == null ? titleStyle : titleStyle.copyWith(color: color), + return Material( + child: InkWell( + onTap: onTap, + child: ListTile( + dense: true, + title: Text( + title, + style: color == null ? titleStyle : titleStyle.copyWith(color: color), + ), + leading: Icon( + iconData, + color: color ?? StreamChatTheme.of(context).primaryIconTheme.color, + size: 24.0, + ), + ), ), - leading: Icon( - iconData, - color: color ?? StreamChatTheme.of(context).primaryIconTheme.color, - size: 24.0, - ), - onTap: onTap, - tileColor: Colors.white, ); } } From b20caeee8fa0606926e61f96afc27209de1ced60 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Mon, 23 Nov 2020 13:15:37 +0100 Subject: [PATCH 0458/1140] add cacheextent and placeholder --- images/placeholder.png | Bin 0 -> 981 bytes lib/src/media_list_view.dart | 12 ++++++++---- lib/src/message_input.dart | 5 +++++ 3 files changed, 13 insertions(+), 4 deletions(-) create mode 100644 images/placeholder.png diff --git a/images/placeholder.png b/images/placeholder.png new file mode 100644 index 0000000000000000000000000000000000000000..deca84745564e52a2d1da32eb4bbd07eb7c46323 GIT binary patch literal 981 zcmeAS@N?(olHy`uVBq!ia0vp^WgyJK1|(&drwalp&H|6fVg?3oVGw3ym^DWND9BhG z5$Qp10} zV<*^{94~dnZrOafvSGr3pN3VB-W6$97Fx*29X+v8$4#hP^k|an#)v?jFcDfaueHv& z{WeUl|M=&Gq>T|a{a3R>BNmEO?~ObCv}mDl6!Xs6XP2$HUbB2+o{K=2GV_iP=bnH5 ztjuEUI5pYWb8eHN@+kvHWwG#Dx0Q@(@BY^5>s)AgH1EpOBG2$84hmemrOw=XTNW*` zK=8Iz;ECv*o!SR@)*jA(UH>CIp!Jc|u`J_^*aDwWo6=^c)0|;5j0GF58rQsHXX566KN&V}x*mGyeR|fHeh>9+s-;{<9=%p(+?%ACR-6CXCV1%_uQ%E& z8J9RYv2rS$guG6c>!;yYhSk6(mtnbQ<%!p?S zCI3<^g^pg*u9|9Od?o3**W7)4JBwAW07WA5jo&)jCucukGn+-4 zTvoxv#YyR<^dg^EL>~9$Bd*{7bP0l+XkK+2Exx literal 0 HcmV?d00001 diff --git a/lib/src/media_list_view.dart b/lib/src/media_list_view.dart index cd414fa9..371428d4 100644 --- a/lib/src/media_list_view.dart +++ b/lib/src/media_list_view.dart @@ -2,7 +2,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_svg/flutter_svg.dart'; import 'package:media_gallery/media_gallery.dart'; import 'package:stream_chat_flutter/src/stream_icons.dart'; -import 'package:transparent_image/transparent_image.dart'; class MediaListView extends StatefulWidget { final List selectedIds; @@ -26,8 +25,10 @@ class _MediaListViewState extends State { return GridView.builder( itemCount: _media.length, controller: _scrollController, - gridDelegate: - SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 3), + gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: 3, + ), + cacheExtent: 1000, itemBuilder: ( context, position, @@ -42,7 +43,10 @@ class _MediaListViewState extends State { aspectRatio: 1.0, child: FadeInImage( fadeInDuration: Duration(milliseconds: 300), - placeholder: MemoryImage(kTransparentImage), + placeholder: AssetImage( + 'images/placeholder.png', + package: 'stream_chat_flutter', + ), image: MediaThumbnailProvider( media: media, highQuality: true, diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 8b77a5cf..af4b8979 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -201,6 +201,11 @@ class MessageInputState extends State { onPanUpdate: (details) { if (details.delta.dy > 0) { _focusNode.unfocus(); + if (_openFilePickerSection) { + setState(() { + _openFilePickerSection = false; + }); + } } }, child: Column( From 5ec2b20a0d6b1658bfe98e2903e3cba6848218c5 Mon Sep 17 00:00:00 2001 From: xsahil03x Date: Tue, 24 Nov 2020 14:55:37 +0530 Subject: [PATCH 0459/1140] [Channel List Header] Replace pen_write icon with correct svg icon. --- images/icon_pen-write.svg | 5 +++++ lib/src/channel_list_header.dart | 8 ++++++-- 2 files changed, 11 insertions(+), 2 deletions(-) create mode 100644 images/icon_pen-write.svg diff --git a/images/icon_pen-write.svg b/images/icon_pen-write.svg new file mode 100644 index 00000000..b2711dad --- /dev/null +++ b/images/icon_pen-write.svg @@ -0,0 +1,5 @@ + + + diff --git a/lib/src/channel_list_header.dart b/lib/src/channel_list_header.dart index 6a838265..7ae84eec 100644 --- a/lib/src/channel_list_header.dart +++ b/lib/src/channel_list_header.dart @@ -1,6 +1,7 @@ import 'dart:ui'; import 'package:flutter/material.dart'; +import 'package:flutter_svg/flutter_svg.dart'; import 'package:stream_chat/stream_chat.dart'; import 'package:stream_chat_flutter/src/stream_neumorphic_button.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; @@ -107,8 +108,11 @@ class ChannelListHeader extends StatelessWidget implements PreferredSizeWidget { color = Colors.grey; break; } - return Icon( - StreamIcons.pen_write, + return SvgPicture.asset( + 'images/icon_pen-write.svg', + package: 'stream_chat_flutter', + width: 24.0, + height: 24.0, color: color, ); }, From a0afe4d0911b6f843dd7783db979e2d8dbebfe0b Mon Sep 17 00:00:00 2001 From: xsahil03x Date: Tue, 24 Nov 2020 15:06:18 +0530 Subject: [PATCH 0460/1140] [UserListView] Replace ListView.custom, GridView.custom with separated,builder respectively, --- lib/src/user_list_view.dart | 51 ++++++++++++------------------------- 1 file changed, 16 insertions(+), 35 deletions(-) diff --git a/lib/src/user_list_view.dart b/lib/src/user_list_view.dart index 63285d8b..046ad9c7 100644 --- a/lib/src/user_list_view.dart +++ b/lib/src/user_list_view.dart @@ -328,56 +328,37 @@ class _UserListViewState extends State } if (_isListView) { - return ListView.custom( + return ListView.separated( physics: AlwaysScrollableScrollPhysics(), controller: _scrollController, - childrenDelegate: SliverChildBuilderDelegate( - (context, i) { - return _listItemBuilder(context, i, items); - }, - childCount: (items.length * 2) + 1, - findChildIndexCallback: (key) { - final ValueKey valueKey = key; - final index = - items.indexWhere((item) => item.key == valueKey.value); - return index != -1 ? (index * 2) : null; - }, - ), + itemCount: items.isNotEmpty ? items.length + 1 : items.length, + separatorBuilder: (_, index) { + if (widget.separatorBuilder != null) { + return widget.separatorBuilder(context, index); + } + return _separatorBuilder(context, index); + }, + itemBuilder: (context, index) { + return _listItemBuilder(context, index, items); + }, ); } - return GridView.custom( + return GridView.builder( gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: widget.crossAxisCount, ), + itemCount: items.isNotEmpty ? items.length + 1 : items.length, physics: AlwaysScrollableScrollPhysics(), controller: _scrollController, - childrenDelegate: SliverChildBuilderDelegate( - (context, i) { - return _gridItemBuilder(context, i, items); - }, - childCount: items.length, - findChildIndexCallback: (key) { - final ValueKey valueKey = key; - final index = - items.indexWhere((item) => item.key == valueKey.value); - return index != -1 ? index : null; - }, - ), + itemBuilder: (context, index) { + return _gridItemBuilder(context, index, items); + }, ); }, ); } Widget _listItemBuilder(BuildContext context, int i, List items) { - if (i % 2 != 0) { - if (widget.separatorBuilder != null) { - return widget.separatorBuilder(context, i); - } - return _separatorBuilder(context, i); - } - - i = i ~/ 2; - final usersProvider = UsersBloc.of(context); if (i < items.length) { final item = items[i]; From 92b88c505eac8de6165b19cadb0702cd59fb730b Mon Sep 17 00:00:00 2001 From: xsahil03x Date: Tue, 24 Nov 2020 15:33:48 +0530 Subject: [PATCH 0461/1140] Minor fix --- lib/src/channel_list_header.dart | 2 +- images/icon_pen-write.svg => svgs/icon_pen_write.svg | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename images/icon_pen-write.svg => svgs/icon_pen_write.svg (100%) diff --git a/lib/src/channel_list_header.dart b/lib/src/channel_list_header.dart index 7ae84eec..0a01733b 100644 --- a/lib/src/channel_list_header.dart +++ b/lib/src/channel_list_header.dart @@ -109,7 +109,7 @@ class ChannelListHeader extends StatelessWidget implements PreferredSizeWidget { break; } return SvgPicture.asset( - 'images/icon_pen-write.svg', + 'svgs/icon_pen_write.svg', package: 'stream_chat_flutter', width: 24.0, height: 24.0, diff --git a/images/icon_pen-write.svg b/svgs/icon_pen_write.svg similarity index 100% rename from images/icon_pen-write.svg rename to svgs/icon_pen_write.svg From 146204ed3a3f27bed9bfec76462b52a14af27496 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Tue, 24 Nov 2020 16:32:50 +0530 Subject: [PATCH 0462/1140] fix: giphy fix, fmt --- lib/src/giphy_attachment.dart | 46 +++++++++++++++++++------------- lib/src/image_actions_modal.dart | 3 ++- 2 files changed, 30 insertions(+), 19 deletions(-) diff --git a/lib/src/giphy_attachment.dart b/lib/src/giphy_attachment.dart index bb859263..43e0ce68 100644 --- a/lib/src/giphy_attachment.dart +++ b/lib/src/giphy_attachment.dart @@ -63,15 +63,20 @@ class GiphyAttachment extends StatelessWidget { child: GestureDetector( onTap: () { Navigator.push(context, MaterialPageRoute(builder: (_) { - return FullScreenImage( - urls: [ - attachment.imageUrl ?? - attachment.assetUrl ?? - attachment.thumbUrl - ], - userName: message.user.name, - sentAt: message.createdAt, - message: message, + final channel = StreamChannel.of(context).channel; + + return StreamChannel( + channel: channel, + child: FullScreenImage( + urls: [ + attachment.imageUrl ?? + attachment.assetUrl ?? + attachment.thumbUrl + ], + userName: message.user.name, + sentAt: message.createdAt, + message: message, + ), ); })); }, @@ -286,15 +291,20 @@ class GiphyAttachment extends StatelessWidget { child: GestureDetector( onTap: () { Navigator.push(context, MaterialPageRoute(builder: (_) { - return FullScreenImage( - urls: [ - attachment.imageUrl ?? - attachment.assetUrl ?? - attachment.thumbUrl - ], - userName: message.user.name, - sentAt: message.createdAt, - message: message, + var channel = StreamChannel.of(context).channel; + + return StreamChannel( + channel: channel, + child: FullScreenImage( + urls: [ + attachment.imageUrl ?? + attachment.assetUrl ?? + attachment.thumbUrl + ], + userName: message.user.name, + sentAt: message.createdAt, + message: message, + ), ); })); }, diff --git a/lib/src/image_actions_modal.dart b/lib/src/image_actions_modal.dart index 1bfb6aa3..c1163af8 100644 --- a/lib/src/image_actions_modal.dart +++ b/lib/src/image_actions_modal.dart @@ -159,7 +159,8 @@ class ImageActionsModal extends StatelessWidget { dense: true, title: Text( title, - style: color == null ? titleStyle : titleStyle.copyWith(color: color), + style: + color == null ? titleStyle : titleStyle.copyWith(color: color), ), leading: Icon( iconData, From f1b7c6f39fee0fc6e91b397b81bd2bea802c4d02 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Tue, 24 Nov 2020 12:52:54 +0100 Subject: [PATCH 0463/1140] use StreamSvgIcon widget --- example/lib/advanced_options_page.dart | 4 +- example/lib/chips_input_text_field.dart | 13 +- example/lib/choose_user_page.dart | 4 +- example/lib/group_chat_details_screen.dart | 4 +- example/lib/main.dart | 15 +- example/lib/new_chat_screen.dart | 15 +- example/lib/new_group_chat_screen.dart | 25 +- example/pubspec.yaml | 2 +- fonts/stream-icons.ttf | Bin 52024 -> 0 bytes lib/src/back_button.dart | 12 +- lib/src/channel_bottom_sheet.dart | 17 +- lib/src/channel_list_view.dart | 16 +- lib/src/channel_preview.dart | 8 +- lib/src/giphy_attachment.dart | 36 +- lib/src/media_list_view.dart | 9 +- lib/src/message_actions_modal.dart | 25 +- lib/src/message_input.dart | 158 ++- lib/src/message_list_view.dart | 5 +- lib/src/reaction_bubble.dart | 27 +- lib/src/reaction_icon.dart | 6 +- lib/src/reaction_picker.dart | 9 +- lib/src/stream_chat_theme.dart | 11 +- lib/src/stream_icons.dart | 1184 -------------------- lib/src/stream_svg_icon.dart | 40 + lib/src/thread_header.dart | 13 +- lib/src/user_item.dart | 8 +- lib/stream_chat_flutter.dart | 8 +- lib/svgs/Empty State_Camera.svg | 3 + lib/svgs/Empty State_Files.svg | 3 + lib/svgs/Empty State_No channel.svg | 3 + lib/svgs/Empty State_Search.svg | 3 + lib/svgs/Empty State_picture.svg | 3 + lib/svgs/Giphy icon.svg | 8 + lib/svgs/Icon_LOL_reaction.svg | 3 + lib/svgs/Icon_Thread_Reply.svg | 3 + lib/svgs/Icon_User_add.svg | 3 + lib/svgs/Icon_User_deselect.svg | 3 + lib/svgs/Icon_arrow_right.svg | 3 + lib/svgs/Icon_attach.svg | 3 + lib/svgs/Icon_camera.svg | 3 + lib/svgs/Icon_check.svg | 3 + lib/svgs/Icon_check_all.svg | 3 + lib/svgs/Icon_check_big.svg | 3 + lib/svgs/Icon_check_send.svg | 3 + lib/svgs/Icon_circle_right.svg | 3 + lib/svgs/Icon_circle_up.svg | 3 + lib/svgs/Icon_close.svg | 3 + lib/svgs/Icon_close_black.svg | 3 + lib/svgs/Icon_close_sml.svg | 3 + lib/svgs/Icon_cloud_download.svg | 3 + lib/svgs/Icon_contacts.svg | 3 + lib/svgs/Icon_copy.svg | 3 + lib/svgs/Icon_curve_line_left_up.svg | 3 + lib/svgs/Icon_curve_line_left_up_big.svg | 3 + lib/svgs/Icon_delete.svg | 3 + lib/svgs/Icon_down.svg | 3 + lib/svgs/Icon_download.svg | 3 + lib/svgs/Icon_edit.svg | 3 + lib/svgs/Icon_empty_circle_left.svg | 3 + lib/svgs/Icon_error.svg | 3 + lib/svgs/Icon_eye-off.svg | 3 + lib/svgs/Icon_grid.svg | 3 + lib/svgs/Icon_left.svg | 3 + lib/svgs/Icon_lightning-command runner.svg | 3 + lib/svgs/Icon_love_reaction.svg | 3 + lib/svgs/Icon_message.svg | 3 + lib/svgs/Icon_mute.svg | 3 + lib/svgs/Icon_pen-write.svg | 3 + lib/svgs/Icon_record.svg | 3 + lib/svgs/Icon_right.svg | 3 + lib/svgs/Icon_search.svg | 3 + lib/svgs/Icon_smile.svg | 3 + lib/svgs/Icon_thumbs_down_reaction.svg | 3 + lib/svgs/Icon_thumbs_up_reaction.svg | 3 + lib/svgs/Icon_time.svg | 3 + lib/svgs/Icon_user.svg | 3 + lib/svgs/Icon_user_delete.svg | 3 + lib/svgs/Icon_wut_reaction.svg | 3 + lib/svgs/STREAM MARK 1.svg | 10 + lib/svgs/UI_Reverse Pagination Loading.svg | 14 + lib/svgs/eye-line_big.svg | 3 + lib/svgs/files.svg | 3 + lib/svgs/filetype_7z.svg | 7 + lib/svgs/filetype_CSV.svg | 7 + lib/svgs/filetype_DOC.svg | 12 + lib/svgs/filetype_DOCX.svg | 12 + lib/svgs/filetype_Generic.svg | 11 + lib/svgs/filetype_MD.svg | 7 + lib/svgs/filetype_ODT.svg | 7 + lib/svgs/filetype_PDF.svg | 7 + lib/svgs/filetype_PPT.svg | 12 + lib/svgs/filetype_PPTX-1.svg | 12 + lib/svgs/filetype_PPTX.svg | 12 + lib/svgs/filetype_RAR.svg | 7 + lib/svgs/filetype_RTF.svg | 7 + lib/svgs/filetype_TAR.svg | 7 + lib/svgs/filetype_TXT.svg | 7 + lib/svgs/filetype_XLS.svg | 12 + lib/svgs/filetype_XLSX.svg | 12 + lib/svgs/filetype_ZIP.svg | 7 + lib/svgs/filetype_html.svg | 8 + lib/svgs/giphy icon blue.svg | 3 + lib/svgs/icon_SHARE.svg | 3 + lib/svgs/icon_delete_grey.svg | 4 + lib/svgs/icon_mentions.svg | 3 + lib/svgs/mentions.svg | 3 + lib/svgs/pictures.svg | 3 + lib/svgs/settings.svg | 3 + lib/svgs/share_arrow.svg | 3 + pubspec.yaml | 5 +- 110 files changed, 673 insertions(+), 1392 deletions(-) delete mode 100644 fonts/stream-icons.ttf delete mode 100644 lib/src/stream_icons.dart create mode 100644 lib/src/stream_svg_icon.dart create mode 100644 lib/svgs/Empty State_Camera.svg create mode 100644 lib/svgs/Empty State_Files.svg create mode 100644 lib/svgs/Empty State_No channel.svg create mode 100644 lib/svgs/Empty State_Search.svg create mode 100644 lib/svgs/Empty State_picture.svg create mode 100644 lib/svgs/Giphy icon.svg create mode 100644 lib/svgs/Icon_LOL_reaction.svg create mode 100644 lib/svgs/Icon_Thread_Reply.svg create mode 100644 lib/svgs/Icon_User_add.svg create mode 100644 lib/svgs/Icon_User_deselect.svg create mode 100644 lib/svgs/Icon_arrow_right.svg create mode 100644 lib/svgs/Icon_attach.svg create mode 100644 lib/svgs/Icon_camera.svg create mode 100644 lib/svgs/Icon_check.svg create mode 100644 lib/svgs/Icon_check_all.svg create mode 100644 lib/svgs/Icon_check_big.svg create mode 100644 lib/svgs/Icon_check_send.svg create mode 100644 lib/svgs/Icon_circle_right.svg create mode 100644 lib/svgs/Icon_circle_up.svg create mode 100644 lib/svgs/Icon_close.svg create mode 100644 lib/svgs/Icon_close_black.svg create mode 100644 lib/svgs/Icon_close_sml.svg create mode 100644 lib/svgs/Icon_cloud_download.svg create mode 100644 lib/svgs/Icon_contacts.svg create mode 100644 lib/svgs/Icon_copy.svg create mode 100644 lib/svgs/Icon_curve_line_left_up.svg create mode 100644 lib/svgs/Icon_curve_line_left_up_big.svg create mode 100644 lib/svgs/Icon_delete.svg create mode 100644 lib/svgs/Icon_down.svg create mode 100644 lib/svgs/Icon_download.svg create mode 100644 lib/svgs/Icon_edit.svg create mode 100644 lib/svgs/Icon_empty_circle_left.svg create mode 100644 lib/svgs/Icon_error.svg create mode 100644 lib/svgs/Icon_eye-off.svg create mode 100644 lib/svgs/Icon_grid.svg create mode 100644 lib/svgs/Icon_left.svg create mode 100644 lib/svgs/Icon_lightning-command runner.svg create mode 100644 lib/svgs/Icon_love_reaction.svg create mode 100644 lib/svgs/Icon_message.svg create mode 100644 lib/svgs/Icon_mute.svg create mode 100644 lib/svgs/Icon_pen-write.svg create mode 100644 lib/svgs/Icon_record.svg create mode 100644 lib/svgs/Icon_right.svg create mode 100644 lib/svgs/Icon_search.svg create mode 100644 lib/svgs/Icon_smile.svg create mode 100644 lib/svgs/Icon_thumbs_down_reaction.svg create mode 100644 lib/svgs/Icon_thumbs_up_reaction.svg create mode 100644 lib/svgs/Icon_time.svg create mode 100644 lib/svgs/Icon_user.svg create mode 100644 lib/svgs/Icon_user_delete.svg create mode 100644 lib/svgs/Icon_wut_reaction.svg create mode 100644 lib/svgs/STREAM MARK 1.svg create mode 100644 lib/svgs/UI_Reverse Pagination Loading.svg create mode 100644 lib/svgs/eye-line_big.svg create mode 100644 lib/svgs/files.svg create mode 100644 lib/svgs/filetype_7z.svg create mode 100644 lib/svgs/filetype_CSV.svg create mode 100644 lib/svgs/filetype_DOC.svg create mode 100644 lib/svgs/filetype_DOCX.svg create mode 100644 lib/svgs/filetype_Generic.svg create mode 100644 lib/svgs/filetype_MD.svg create mode 100644 lib/svgs/filetype_ODT.svg create mode 100644 lib/svgs/filetype_PDF.svg create mode 100644 lib/svgs/filetype_PPT.svg create mode 100644 lib/svgs/filetype_PPTX-1.svg create mode 100644 lib/svgs/filetype_PPTX.svg create mode 100644 lib/svgs/filetype_RAR.svg create mode 100644 lib/svgs/filetype_RTF.svg create mode 100644 lib/svgs/filetype_TAR.svg create mode 100644 lib/svgs/filetype_TXT.svg create mode 100644 lib/svgs/filetype_XLS.svg create mode 100644 lib/svgs/filetype_XLSX.svg create mode 100644 lib/svgs/filetype_ZIP.svg create mode 100644 lib/svgs/filetype_html.svg create mode 100644 lib/svgs/giphy icon blue.svg create mode 100644 lib/svgs/icon_SHARE.svg create mode 100644 lib/svgs/icon_delete_grey.svg create mode 100644 lib/svgs/icon_mentions.svg create mode 100644 lib/svgs/mentions.svg create mode 100644 lib/svgs/pictures.svg create mode 100644 lib/svgs/settings.svg create mode 100644 lib/svgs/share_arrow.svg diff --git a/example/lib/advanced_options_page.dart b/example/lib/advanced_options_page.dart index c84ef58e..57ed1f06 100644 --- a/example/lib/advanced_options_page.dart +++ b/example/lib/advanced_options_page.dart @@ -44,8 +44,8 @@ class _AdvancedOptionsPageState extends State { ), ), leading: IconButton( - icon: Icon( - StreamIcons.left, + icon: StreamSvgIcon( + assetName: 'Icon_left.svg', color: Colors.black, ), onPressed: () { diff --git a/example/lib/chips_input_text_field.dart b/example/lib/chips_input_text_field.dart index 317a68f7..0310de5b 100644 --- a/example/lib/chips_input_text_field.dart +++ b/example/lib/chips_input_text_field.dart @@ -1,5 +1,5 @@ import 'package:flutter/material.dart'; -import 'package:stream_chat_flutter/src/stream_icons.dart'; +import 'package:stream_chat_flutter/stream_chat_flutter.dart'; typedef ChipBuilder = Widget Function(BuildContext context, T chip); typedef OnChipAdded = void Function(T chip); @@ -130,12 +130,13 @@ class ChipInputTextFieldState extends State> { Align( alignment: Alignment.bottomCenter, child: IconButton( - icon: Icon( - _chips.isEmpty - ? StreamIcons.user - : StreamIcons.user_add, + icon: StreamSvgIcon( + assetName: _chips.isEmpty + ? 'Icon_user.svg' + : 'Icon_User_add.svg', color: Colors.black.withOpacity(0.5), - size: 24, + height: 24, + width: 24, ), onPressed: !_pauseItemAddition ? null : resumeItemAddition, diff --git a/example/lib/choose_user_page.dart b/example/lib/choose_user_page.dart index 4583a2a6..0a0d67b9 100644 --- a/example/lib/choose_user_page.dart +++ b/example/lib/choose_user_page.dart @@ -196,8 +196,8 @@ class ChooseUserPage extends StatelessWidget { ); }, leading: CircleAvatar( - child: Icon( - StreamIcons.settings, + child: StreamSvgIcon( + assetName: 'settings.svg', color: Colors.black, ), backgroundColor: diff --git a/example/lib/group_chat_details_screen.dart b/example/lib/group_chat_details_screen.dart index 6aff5711..d5c65a9e 100644 --- a/example/lib/group_chat_details_screen.dart +++ b/example/lib/group_chat_details_screen.dart @@ -106,7 +106,9 @@ class _GroupChatDetailsScreenState extends State { NeumorphicButton( child: IconButton( padding: const EdgeInsets.all(0), - icon: Icon(StreamIcons.check), + icon: StreamSvgIcon( + assetName: 'Icon_check.svg', + ), color: Color(0xFF006CFF), onPressed: _isGroupNameEmpty ? null diff --git a/example/lib/main.dart b/example/lib/main.dart index a7d5e473..1984c3dd 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -141,7 +141,10 @@ class ChannelListPage extends StatelessWidget { ), ), ListTile( - leading: Icon(StreamIcons.edit), + leading: StreamSvgIcon( + assetName: 'Icon_pen-write.svg', + color: Colors.black.withOpacity(.5), + ), onTap: () { Navigator.of(context) ..pop() @@ -157,7 +160,10 @@ class ChannelListPage extends StatelessWidget { ), ), ListTile( - leading: Icon(StreamIcons.group), + leading: StreamSvgIcon( + assetName: 'Icon_contacts.svg', + color: Colors.black.withOpacity(.5), + ), onTap: () { Navigator.of(context) ..pop() @@ -189,7 +195,10 @@ class ChannelListPage extends StatelessWidget { ), ); }, - leading: Icon(StreamIcons.user), + leading: StreamSvgIcon( + assetName: 'Icon_user.svg', + color: Colors.black.withOpacity(.5), + ), title: Text( 'Sign out', style: TextStyle( diff --git a/example/lib/new_chat_screen.dart b/example/lib/new_chat_screen.dart index 9ec2ca7e..6f8e53cd 100644 --- a/example/lib/new_chat_screen.dart +++ b/example/lib/new_chat_screen.dart @@ -164,8 +164,8 @@ class _NewChatScreenState extends State { ), ), Positioned( - child: Icon( - StreamIcons.close, + child: StreamSvgIcon( + assetName: 'Icon_close.svg', color: Colors.white, ), ), @@ -194,8 +194,8 @@ class _NewChatScreenState extends State { child: Row( children: [ NeumorphicButton( - child: Icon( - StreamIcons.group, + child: StreamSvgIcon( + assetName: 'Icon_contacts.svg', color: Color(0xFF006CFF), ), ), @@ -289,9 +289,10 @@ class _NewChatScreenState extends State { children: [ Padding( padding: const EdgeInsets.all(24), - child: Icon( - StreamIcons.search, - size: 96, + child: StreamSvgIcon( + assetName: 'Icon_search.svg', + height: 96, + width: 96, color: Colors.grey, ), ), diff --git a/example/lib/new_group_chat_screen.dart b/example/lib/new_group_chat_screen.dart index b75e7510..3d7c418a 100644 --- a/example/lib/new_group_chat_screen.dart +++ b/example/lib/new_group_chat_screen.dart @@ -65,8 +65,8 @@ class _NewGroupChatScreenState extends State { actions: [ if (_selectedUsers.isNotEmpty) IconButton( - icon: Icon( - StreamIcons.arrow_right, + icon: StreamSvgIcon( + assetName: 'Icon_right.svg', color: Color(0xFF006CFF), ), onPressed: () { @@ -101,10 +101,11 @@ class _NewGroupChatScreenState extends State { child: TextField( controller: _controller, decoration: InputDecoration( - prefixIcon: Icon( - StreamIcons.search, + prefixIcon: StreamSvgIcon( + assetName: 'Icon_search.svg', color: Colors.black, - size: 24, + height: 24, + width: 24, ), hintText: 'Search', hintStyle: TextStyle( @@ -162,9 +163,10 @@ class _NewGroupChatScreenState extends State { ), child: Padding( padding: const EdgeInsets.all(0.0), - child: Icon( - StreamIcons.close, - size: 24, + child: StreamSvgIcon( + assetName: 'Icon_close.svg', + height: 24, + width: 24, ), ), ), @@ -260,9 +262,10 @@ class _NewGroupChatScreenState extends State { children: [ Padding( padding: const EdgeInsets.all(24), - child: Icon( - StreamIcons.search, - size: 96, + child: StreamSvgIcon( + assetName: 'Icon_search.svg', + height: 96, + width: 96, color: Colors.grey, ), ), diff --git a/example/pubspec.yaml b/example/pubspec.yaml index e5daa043..8700c861 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -1,6 +1,6 @@ name: example description: A new Flutter project. -version: 1.0.66+68 +version: 1.0.67+69 environment: sdk: ">=2.2.2 <3.0.0" diff --git a/fonts/stream-icons.ttf b/fonts/stream-icons.ttf deleted file mode 100644 index 80660da49b37da1994c6044eb58c4b76501db4ee..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 52024 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 children: [ Padding( padding: const EdgeInsets.all(8.0), - child: Icon( - StreamIcons.message, - size: 136, + child: StreamSvgIcon( + assetName: 'Icon_message.svg', + height: 136, + width: 136, color: Color(0xffDBDBDB), ), ), @@ -517,7 +519,9 @@ class _ChannelListViewState extends State ), IconSlideAction( color: backgroundColor, - icon: StreamIcons.mute, + iconWidget: StreamSvgIcon( + assetName: 'Icon_mute.svg', + ), onTap: () async { if (!channel.isMuted) { await channel.mute(); @@ -529,7 +533,9 @@ class _ChannelListViewState extends State if (channel.isGroup && !channel.isDistinct) IconSlideAction( color: backgroundColor, - icon: StreamIcons.user_minus, + iconWidget: StreamSvgIcon( + assetName: 'Icon_User_deselect.svg', + ), onTap: () async { final confirm = await showConfirmationDialog( context, diff --git a/lib/src/channel_preview.dart b/lib/src/channel_preview.dart index ba3090c2..c61e469e 100644 --- a/lib/src/channel_preview.dart +++ b/lib/src/channel_preview.dart @@ -2,6 +2,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/widgets.dart'; import 'package:jiffy/jiffy.dart'; import 'package:stream_chat/stream_chat.dart'; +import 'package:stream_chat_flutter/src/stream_svg_icon.dart'; import '../stream_chat_flutter.dart'; import 'channel_name.dart'; @@ -152,9 +153,10 @@ class ChannelPreview extends StatelessWidget { return Row( crossAxisAlignment: CrossAxisAlignment.end, children: [ - Icon( - StreamIcons.mute, - size: 16, + StreamSvgIcon( + assetName: 'Icon_mute.svg', + height: 16, + width: 16, ), Text( ' Channel is muted', diff --git a/lib/src/giphy_attachment.dart b/lib/src/giphy_attachment.dart index df4708c5..0f3b9e7e 100644 --- a/lib/src/giphy_attachment.dart +++ b/lib/src/giphy_attachment.dart @@ -1,6 +1,7 @@ import 'package:cached_network_image/cached_network_image.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; +import 'package:stream_chat_flutter/src/stream_svg_icon.dart'; import '../stream_chat_flutter.dart'; import 'attachment_error.dart'; @@ -111,10 +112,11 @@ class GiphyAttachment extends StatelessWidget { ), child: Row( children: [ - Icon( - StreamIcons.lightning, + StreamSvgIcon( + assetName: 'Icon_lightning-command runner.svg', color: StreamChatTheme.of(context).accentColor, - size: 16.0, + height: 16.0, + width: 16.0, ), Text( 'GIPHY', @@ -144,9 +146,10 @@ class GiphyAttachment extends StatelessWidget { child: IconButton( padding: const EdgeInsets.all(0), constraints: BoxConstraints.tight(Size(32, 32)), - icon: Icon( - StreamIcons.left, - size: 24.0, + icon: StreamSvgIcon( + assetName: 'Icon_left.svg', + height: 24.0, + width: 24.0, ), splashRadius: 16, onPressed: () { @@ -172,9 +175,10 @@ class GiphyAttachment extends StatelessWidget { child: IconButton( padding: const EdgeInsets.all(0), constraints: BoxConstraints.tight(Size(32, 32)), - icon: Icon( - StreamIcons.right, - size: 24.0, + icon: StreamSvgIcon( + assetName: 'Icon_right.svg', + height: 24.0, + width: 24.0, ), splashRadius: 16, onPressed: () { @@ -253,10 +257,11 @@ class GiphyAttachment extends StatelessWidget { child: Row( mainAxisSize: MainAxisSize.min, children: [ - Icon( - StreamIcons.eye, + StreamSvgIcon( + assetName: 'Icon_eye-off.svg', color: Colors.black.withOpacity(0.5), - size: 16.0, + height: 16.0, + width: 16.0, ), SizedBox( width: 8.0, @@ -326,10 +331,11 @@ class GiphyAttachment extends StatelessWidget { ), child: Row( children: [ - Icon( - StreamIcons.lightning, + StreamSvgIcon( + assetName: 'Icon_lightning-command runner.svg', color: Colors.white, - size: 16, + height: 16, + width: 16, ), Text( 'GIPHY', diff --git a/lib/src/media_list_view.dart b/lib/src/media_list_view.dart index 371428d4..c4ae4981 100644 --- a/lib/src/media_list_view.dart +++ b/lib/src/media_list_view.dart @@ -1,7 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_svg/flutter_svg.dart'; import 'package:media_gallery/media_gallery.dart'; -import 'package:stream_chat_flutter/src/stream_icons.dart'; +import 'package:stream_chat_flutter/src/stream_svg_icon.dart'; class MediaListView extends StatefulWidget { final List selectedIds; @@ -71,9 +71,10 @@ class _MediaListViewState extends State { child: CircleAvatar( radius: 12, backgroundColor: Colors.white, - child: Icon( - StreamIcons.check, - size: 24, + child: StreamSvgIcon( + assetName: 'Icon_check.svg', + height: 24, + width: 24, color: Colors.black, ), ), diff --git a/lib/src/message_actions_modal.dart b/lib/src/message_actions_modal.dart index 8b53a973..d95b63ea 100644 --- a/lib/src/message_actions_modal.dart +++ b/lib/src/message_actions_modal.dart @@ -6,7 +6,7 @@ import 'package:flutter/services.dart'; import 'package:stream_chat/stream_chat.dart'; import 'package:stream_chat_flutter/src/reaction_picker.dart'; import 'package:stream_chat_flutter/src/stream_channel.dart'; -import 'package:stream_chat_flutter/src/stream_icons.dart'; +import 'package:stream_chat_flutter/src/stream_svg_icon.dart'; import 'message_input.dart'; import 'message_widget.dart'; @@ -188,8 +188,8 @@ class MessageActionsModal extends StatelessWidget { style: Theme.of(context).textTheme.headline6.copyWith(color: Colors.red), ), - leading: Icon( - StreamIcons.delete, + leading: StreamSvgIcon( + assetName: 'Icon_delete.svg', color: Colors.red, ), onTap: () { @@ -208,8 +208,8 @@ class MessageActionsModal extends StatelessWidget { 'Copy message', style: Theme.of(context).textTheme.headline6, ), - leading: Icon( - StreamIcons.copy, + leading: StreamSvgIcon( + assetName: 'Icon_copy.svg', color: StreamChatTheme.of(context).primaryIconTheme.color, ), onTap: () async { @@ -225,8 +225,8 @@ class MessageActionsModal extends StatelessWidget { 'Edit message', style: Theme.of(context).textTheme.headline6, ), - leading: Icon( - StreamIcons.edit, + leading: StreamSvgIcon( + assetName: 'Icon_edit.svg', color: StreamChatTheme.of(context).primaryIconTheme.color, ), onTap: () async { @@ -267,9 +267,10 @@ class MessageActionsModal extends StatelessWidget { mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ IconButton( - icon: Icon( - StreamIcons.edit, - size: 22, + icon: StreamSvgIcon( + assetName: 'Icon_edit.svg', + height: 22, + width: 22, color: StreamChatTheme.of(context).primaryIconTheme.color, ), @@ -323,8 +324,8 @@ class MessageActionsModal extends StatelessWidget { 'Thread reply', style: Theme.of(context).textTheme.headline6, ), - leading: Icon( - StreamIcons.sorting_up, + leading: StreamSvgIcon( + assetName: 'Icon_Thread_Reply.svg', color: StreamChatTheme.of(context).primaryIconTheme.color, ), onTap: () { diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index af4b8979..a7d8db5e 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -1,6 +1,5 @@ import 'dart:async'; import 'dart:io'; -import 'dart:math'; import 'package:emojis/emoji.dart'; import 'package:file_picker/file_picker.dart'; @@ -18,6 +17,7 @@ import 'package:stream_chat/stream_chat.dart'; import 'package:stream_chat_flutter/src/media_list_view.dart'; import 'package:stream_chat_flutter/src/message_list_view.dart'; import 'package:stream_chat_flutter/src/stream_chat_theme.dart'; +import 'package:stream_chat_flutter/src/stream_svg_icon.dart'; import 'package:stream_chat_flutter/src/user_avatar.dart'; import 'package:stream_chat_flutter/src/video_thumbnail.dart'; import 'package:substring_highlight/substring_highlight.dart'; @@ -284,9 +284,10 @@ class MessageInputState extends State { crossFadeState: _sendAsDm ? CrossFadeState.showFirst : CrossFadeState.showSecond, - firstChild: Icon( - StreamIcons.check, - size: 16.0, + firstChild: StreamSvgIcon( + assetName: 'Icon_check.svg', + height: 16.0, + width: 16.0, color: Colors.white, ), secondChild: SizedBox( @@ -330,8 +331,8 @@ class MessageInputState extends State { _actionsShrunk = false; }); }, - icon: Icon( - StreamIcons.circle_left, + icon: StreamSvgIcon( + assetName: 'Icon_empty_circle_left.svg', color: StreamChatTheme.of(context).accentColor, ), ), @@ -403,8 +404,8 @@ class MessageInputState extends State { _chosenCommand?.name ?? "", style: TextStyle(color: Colors.white), ), - avatar: Icon( - StreamIcons.lightning, + avatar: StreamSvgIcon( + assetName: 'Icon_lightning-command runner.svg', color: Colors.white, ), ), @@ -579,9 +580,11 @@ class MessageInputState extends State { children: [ Padding( padding: const EdgeInsets.symmetric( - horizontal: 8.0), - child: Icon( - StreamIcons.lightning, + horizontal: 8.0, + ), + child: StreamSvgIcon( + assetName: + 'Icon_lightning-command runner.svg', color: StreamChatTheme.of(context) .accentColor, ), @@ -619,10 +622,12 @@ class MessageInputState extends State { trailing: CircleAvatar( backgroundColor: StreamChatTheme.of(context).accentColor, - child: Icon( - StreamIcons.lightning, + child: StreamSvgIcon( + assetName: + 'Icon_lightning-command runner.svg', color: Colors.white, - size: 12.5, + height: 12.5, + width: 12.5, ), maxRadius: 12, ), @@ -656,9 +661,10 @@ class MessageInputState extends State { mainAxisAlignment: MainAxisAlignment.start, children: [ IconButton( - icon: Icon( - StreamIcons.picture, - size: 24, + icon: StreamSvgIcon( + assetName: 'pictures.svg', + height: 24, + width: 24, color: _filePickerIndex == 0 ? StreamChatTheme.of(context).accentColor : Colors.black.withOpacity(0.5), @@ -670,9 +676,10 @@ class MessageInputState extends State { }, ), IconButton( - icon: Icon( - StreamIcons.folder, - size: 24, + icon: StreamSvgIcon( + assetName: 'files.svg', + height: 24, + width: 24, color: _filePickerIndex == 1 ? StreamChatTheme.of(context).accentColor : Colors.black.withOpacity(0.5), @@ -682,9 +689,8 @@ class MessageInputState extends State { }, ), IconButton( - icon: SvgPicture.asset( - 'svgs/icon_camera.svg', - package: 'stream_chat_flutter', + icon: StreamSvgIcon( + assetName: 'Icon_camera.svg', height: 24, width: 24, color: _filePickerIndex == 2 @@ -696,10 +702,11 @@ class MessageInputState extends State { }, ), IconButton( - icon: Icon( - StreamIcons.record, - size: 24, - color: _filePickerIndex == 2 + icon: StreamSvgIcon( + assetName: 'Icon_record.svg', + height: 24, + width: 24, + color: _filePickerIndex == 3 ? StreamChatTheme.of(context).accentColor : Colors.black.withOpacity(0.5), ), @@ -993,8 +1000,8 @@ class MessageInputState extends State { fontWeight: FontWeight.bold), ), subtitle: Text('@${m.userId}'), - trailing: Icon( - StreamIcons.at_mention, + trailing: StreamSvgIcon( + assetName: 'mentions.svg', color: StreamChatTheme.of(context) .accentColor, ), @@ -1091,8 +1098,8 @@ class MessageInputState extends State { Padding( padding: const EdgeInsets.symmetric(horizontal: 8.0), - child: Icon( - StreamIcons.smile, + child: StreamSvgIcon( + assetName: 'Icon_smile.svg', color: StreamChatTheme.of(context).accentColor, ), ), @@ -1227,9 +1234,10 @@ class MessageInputState extends State { }, fillColor: Colors.black.withOpacity(.5), child: Center( - child: Icon( - StreamIcons.close, - size: 24, + child: StreamSvgIcon( + assetName: 'Icon_close.svg', + height: 24, + width: 24, color: Colors.white, ), ), @@ -1299,8 +1307,8 @@ class MessageInputState extends State { child: Padding( padding: const EdgeInsets.only(left: 4.0, right: 8.0, top: 8.0, bottom: 8.0), - child: Icon( - StreamIcons.lightning, + child: StreamSvgIcon( + assetName: 'Icon_lightning-command runner.svg', color: Color(0xFF000000).withAlpha(128), ), ), @@ -1323,8 +1331,8 @@ class MessageInputState extends State { child: Padding( padding: EdgeInsets.only(left: 8.0, right: padding, top: 8.0, bottom: 8.0), - child: Icon( - StreamIcons.attach, + child: StreamSvgIcon( + assetName: 'Icon_attach.svg', color: _openFilePickerSection ? StreamChatTheme.of(context).accentColor : Color(0xFF000000).withAlpha(128), @@ -1594,69 +1602,53 @@ class MessageInputState extends State { } Widget _buildIdleSendButton(BuildContext context) { - return IconTheme( - data: - StreamChatTheme.of(context).channelTheme.messageInputButtonIconTheme, - child: Padding( - padding: const EdgeInsets.all(8.0), - child: Center( - child: InkWell( - onTap: () { - sendMessage(); - }, - child: Icon( - _getIdleSendIcon(), - color: Colors.grey, - ), - )), - ), + return Padding( + padding: const EdgeInsets.all(8.0), + child: Center( + child: InkWell( + onTap: () { + sendMessage(); + }, + child: StreamSvgIcon( + assetName: _getIdleSendIcon(), + color: Colors.grey, + ), + )), ); } Widget _buildSendButton(BuildContext context) { - return IconTheme( - data: - StreamChatTheme.of(context).channelTheme.messageInputButtonIconTheme, - child: Center( - child: Padding( - padding: const EdgeInsets.all(8.0), - child: InkWell( - onTap: () { - sendMessage(); - }, - child: _getSendIcon(), + return Center( + child: Padding( + padding: const EdgeInsets.all(8.0), + child: InkWell( + onTap: () { + sendMessage(); + }, + child: StreamSvgIcon( + assetName: _getSendIcon(), + color: StreamChatTheme.of(context).accentColor, ), ), ), ); } - IconData _getIdleSendIcon() { + String _getIdleSendIcon() { if (_commandEnabled) { - return StreamIcons.search; + return 'Icon_search.svg'; } else { - return StreamIcons.send_message; + return 'Icon_circle_up.svg'; } } - Widget _getSendIcon() { + String _getSendIcon() { if (widget.editMessage != null) { - return Icon( - StreamIcons.check_send, - color: StreamChatTheme.of(context).accentColor, - ); + return 'Icon_circle_right.svg'; } else if (_commandEnabled) { - return Icon( - StreamIcons.search, - color: StreamChatTheme.of(context).accentColor, - ); + return 'Icon_search.svg'; } else { - return Transform.rotate( - angle: -pi / 2, - child: Icon( - StreamIcons.send_message, - color: StreamChatTheme.of(context).accentColor, - )); + return 'Icon_circle_right.svg'; } } diff --git a/lib/src/message_list_view.dart b/lib/src/message_list_view.dart index 4a5e445b..2954f043 100644 --- a/lib/src/message_list_view.dart +++ b/lib/src/message_list_view.dart @@ -6,6 +6,7 @@ import 'package:jiffy/jiffy.dart'; import 'package:scrollable_positioned_list/scrollable_positioned_list.dart'; import 'package:stream_chat/stream_chat.dart'; import 'package:stream_chat_flutter/src/message_widget.dart'; +import 'package:stream_chat_flutter/src/stream_svg_icon.dart'; import 'package:stream_chat_flutter/src/system_message.dart'; import 'package:visibility_detector/visibility_detector.dart'; @@ -374,8 +375,8 @@ class _MessageListViewState extends State { children: [ FloatingActionButton( backgroundColor: Colors.white, - child: Icon( - StreamIcons.down, + child: StreamSvgIcon( + assetName: 'Icon_down.svg', color: Colors.black, ), onPressed: () { diff --git a/lib/src/reaction_bubble.dart b/lib/src/reaction_bubble.dart index 83593afc..87dc7a92 100644 --- a/lib/src/reaction_bubble.dart +++ b/lib/src/reaction_bubble.dart @@ -3,6 +3,7 @@ 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/src/stream_svg_icon.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; class ReactionBubble extends StatelessWidget { @@ -99,14 +100,24 @@ class ReactionBubble extends StatelessWidget { padding: const EdgeInsets.symmetric( horizontal: 4.0, ), - child: Icon( - reactionIcon?.iconData ?? Icons.help_outline_rounded, - size: 16, - color: (!highlightOwnReactions || - reaction.user.id == StreamChat.of(context).user.id) - ? StreamChatTheme.of(context).accentColor - : Colors.black.withOpacity(.5), - ), + child: reactionIcon != null + ? StreamSvgIcon( + assetName: reactionIcon.assetName, + width: 16, + height: 16, + color: (!highlightOwnReactions || + reaction.user.id == StreamChat.of(context).user.id) + ? StreamChatTheme.of(context).accentColor + : Colors.black.withOpacity(.5), + ) + : Icon( + Icons.help_outline_rounded, + size: 16, + color: (!highlightOwnReactions || + reaction.user.id == StreamChat.of(context).user.id) + ? StreamChatTheme.of(context).accentColor + : Colors.black.withOpacity(.5), + ), ); } diff --git a/lib/src/reaction_icon.dart b/lib/src/reaction_icon.dart index 5f885643..99b93328 100644 --- a/lib/src/reaction_icon.dart +++ b/lib/src/reaction_icon.dart @@ -1,11 +1,9 @@ -import 'package:flutter/material.dart'; - class ReactionIcon { final String type; - final IconData iconData; + final String assetName; ReactionIcon({ this.type, - this.iconData, + this.assetName, }); } diff --git a/lib/src/reaction_picker.dart b/lib/src/reaction_picker.dart index 83698e46..ff23b8a3 100644 --- a/lib/src/reaction_picker.dart +++ b/lib/src/reaction_picker.dart @@ -1,6 +1,6 @@ import 'package:ezanimation/ezanimation.dart'; import 'package:flutter/material.dart'; -import 'package:flutter/physics.dart'; +import 'package:stream_chat_flutter/src/stream_svg_icon.dart'; import '../stream_chat_flutter.dart'; @@ -84,9 +84,10 @@ class _ReactionPickerState extends State ..scale(animations[index].value, animations[index].value) ..rotateZ(1.0 - animations[index].value), - child: Icon( - reactionIcon.iconData, - size: animations[index].value * 24.0, + child: StreamSvgIcon( + assetName: reactionIcon.assetName, + height: animations[index].value * 24.0, + width: animations[index].value * 24.0, color: ownReactionIndex != -1 ? StreamChatTheme.of(context).accentColor : Theme.of(context) diff --git a/lib/src/stream_chat_theme.dart b/lib/src/stream_chat_theme.dart index 967cbbbf..d5b2c1c2 100644 --- a/lib/src/stream_chat_theme.dart +++ b/lib/src/stream_chat_theme.dart @@ -5,7 +5,6 @@ import 'package:stream_chat_flutter/src/channel_header.dart'; import 'package:stream_chat_flutter/src/channel_preview.dart'; import 'package:stream_chat_flutter/src/message_input.dart'; import 'package:stream_chat_flutter/src/reaction_icon.dart'; -import 'package:stream_chat_flutter/src/stream_icons.dart'; import 'package:stream_chat_flutter/src/utils.dart'; /// Inherited widget providing the [StreamChatThemeData] to the widget tree @@ -353,23 +352,23 @@ class StreamChatThemeData { reactionIcons: [ ReactionIcon( type: 'love', - iconData: StreamIcons.love_reaction, + assetName: 'Icon_love_reaction.svg', ), ReactionIcon( type: 'thumbs_up', - iconData: StreamIcons.thumbs_up_reaction, + assetName: 'Icon_thumbs_up_reaction.svg', ), ReactionIcon( type: 'thumbs_down', - iconData: StreamIcons.thumbs_down_reaction, + assetName: 'Icon_thumbs_down_reaction.svg', ), ReactionIcon( type: 'lol', - iconData: StreamIcons.LOL_reaction, + assetName: 'Icon_LOL_reaction.svg', ), ReactionIcon( type: 'wut', - iconData: StreamIcons.wut_reaction, + assetName: 'Icon_wut_reaction.svg', ), ], ); diff --git a/lib/src/stream_icons.dart b/lib/src/stream_icons.dart deleted file mode 100644 index c8fc6493..00000000 --- a/lib/src/stream_icons.dart +++ /dev/null @@ -1,1184 +0,0 @@ -import 'package:flutter/widgets.dart'; - -class StreamIcons { - StreamIcons._(); - - static const String _fontFamily = 'stream-icons'; - static const String _fontPackage = 'stream_chat_flutter'; - - static const IconData ambulance_car = IconData( - 0xe900, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData ambulance_signal = IconData( - 0xe901, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData ambulance = IconData( - 0xe902, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData apps = IconData( - 0xe903, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData archive = IconData( - 0xe904, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData arrow_down_left = IconData( - 0xe905, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData arrow_down = IconData( - 0xe906, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData arrow_drop_down = IconData( - 0xe907, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData arrow_drop_up = IconData( - 0xe908, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData arrow_left_up = IconData( - 0xe909, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData arrow_left = IconData( - 0xe90a, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData arrow_right_down = IconData( - 0xe90b, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData arrow_right = IconData( - 0xe90c, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData arrow_up_right = IconData( - 0xe90d, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData arrow_up = IconData( - 0xe90e, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData at_mention = IconData( - 0xe90f, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData atom = IconData( - 0xe910, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData attach = IconData( - 0xe911, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData attention = IconData( - 0xe912, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData basket = IconData( - 0xe913, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData blank_empty = IconData( - 0xe914, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData blank = IconData( - 0xe915, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData blood_add = IconData( - 0xe916, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData blood_delete = IconData( - 0xe917, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData brain = IconData( - 0xe918, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData building = IconData( - 0xe919, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData calculator = IconData( - 0xe91a, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData calendar = IconData( - 0xe91b, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData call_in = IconData( - 0xe91c, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData call_out = IconData( - 0xe91d, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData call = IconData( - 0xe91e, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData camera = IconData( - 0xe91f, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData car = IconData( - 0xe920, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData card = IconData( - 0xe921, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData cards = IconData( - 0xe922, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData cash = IconData( - 0xe923, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData chart_line = IconData( - 0xe924, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData chart = IconData( - 0xe925, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData check_all = IconData( - 0xe926, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData check_send = IconData( - 0xe927, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData check = IconData( - 0xe928, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData chemical = IconData( - 0xe929, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData circle_down = IconData( - 0xe92a, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData circle_left = IconData( - 0xe92b, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData circle_right = IconData( - 0xe92c, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData circle_up = IconData( - 0xe92d, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData close_circle = IconData( - 0xe92e, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData close = IconData( - 0xe92f, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData closed = IconData( - 0xe930, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData coin = IconData( - 0xe931, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData command_runner_rocket = IconData( - 0xe932, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData compass = IconData( - 0xe933, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData copy = IconData( - 0xe934, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData couch = IconData( - 0xe935, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData curve_left_down = IconData( - 0xe936, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData curve_line_down_left = IconData( - 0xe937, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData curve_line_down_right = IconData( - 0xe938, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData curve_line_left_up = IconData( - 0xe939, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData curve_line_right_up = IconData( - 0xe93a, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData curve_line_up_left = IconData( - 0xe93b, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData curve_line_up_right = IconData( - 0xe93c, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData curve_right_down = IconData( - 0xe93d, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData daily_planner = IconData( - 0xe93e, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData date = IconData( - 0xe93f, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData delete = IconData( - 0xe940, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData desktop = IconData( - 0xe941, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData disabled = IconData( - 0xe942, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData dna = IconData( - 0xe943, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData doc = IconData( - 0xe944, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData documents = IconData( - 0xe945, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData down = IconData( - 0xe946, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData download_1 = IconData( - 0xe947, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData download = IconData( - 0xe948, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData edit = IconData( - 0xe949, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData emergency_call_add = IconData( - 0xe94a, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData emergency_call = IconData( - 0xe94b, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData emergency = IconData( - 0xe94c, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData error = IconData( - 0xe94d, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData exit = IconData( - 0xe94e, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData experiment = IconData( - 0xe94f, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData eye_off = IconData( - 0xe950, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData eye = IconData( - 0xe951, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData face = IconData( - 0xe952, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData female = IconData( - 0xe953, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData filter_hor = IconData( - 0xe954, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData filter = IconData( - 0xe955, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData first_aid = IconData( - 0xe956, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData flag = IconData( - 0xe957, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData flash = IconData( - 0xe958, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData folder = IconData( - 0xe959, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData form_edit = IconData( - 0xe95a, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData grid = IconData( - 0xe95b, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData group = IconData( - 0xe95c, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData heart_1 = IconData( - 0xe95d, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData heart_outline_add = IconData( - 0xe95e, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData heart_outline_delete = IconData( - 0xe95f, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData heart_pill = IconData( - 0xe960, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData heart = IconData( - 0xe961, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData help = IconData( - 0xe962, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData home_1 = IconData( - 0xe963, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData home = IconData( - 0xe964, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData hospital = IconData( - 0xe965, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData hourglass_empty = IconData( - 0xe966, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData hourglass_full = IconData( - 0xe967, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData hourglass = IconData( - 0xe968, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData insurance_outline = IconData( - 0xe969, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData insurance = IconData( - 0xe96a, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData left_right = IconData( - 0xe96b, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData left = IconData( - 0xe96c, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData light = IconData( - 0xe96d, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData lightning = IconData( - 0xe96e, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData link = IconData( - 0xe96f, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData location_map = IconData( - 0xe970, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData location = IconData( - 0xe971, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData LOL_reaction = IconData( - 0xe972, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData love_reaction = IconData( - 0xe973, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData love = IconData( - 0xe974, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData lungs = IconData( - 0xe975, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData mail_open = IconData( - 0xe976, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData mail = IconData( - 0xe977, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData male = IconData( - 0xe978, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData medical_bed = IconData( - 0xe979, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData medical_blank = IconData( - 0xe97a, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData medical_card_add = IconData( - 0xe97b, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData medical_card = IconData( - 0xe97c, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData medical_cross = IconData( - 0xe97d, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData medical_load = IconData( - 0xe97e, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData menu_point_1 = IconData( - 0xe97f, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData menu_point_v = IconData( - 0xe980, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData menu_point = IconData( - 0xe981, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData menu = IconData( - 0xe982, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData message = IconData( - 0xe983, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData mic_1 = IconData( - 0xe984, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData mic = IconData( - 0xe985, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData minus_circle = IconData( - 0xe986, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData minus = IconData( - 0xe987, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData molecule = IconData( - 0xe988, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData money = IconData( - 0xe989, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData multiply_circle = IconData( - 0xe98a, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData mute = IconData( - 0xe98b, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData notification_off = IconData( - 0xe98c, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData notification = IconData( - 0xe98d, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData nurse = IconData( - 0xe98e, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData open = IconData( - 0xe98f, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData patch = IconData( - 0xe990, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData payment = IconData( - 0xe991, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData pc_graph = IconData( - 0xe992, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData pen_write = IconData( - 0xe993, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData photo = IconData( - 0xe994, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData picture = IconData( - 0xe995, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData pie_chart_empty = IconData( - 0xe996, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData pie_chart_line = IconData( - 0xe997, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData pie_chart = IconData( - 0xe998, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData pill = IconData( - 0xe999, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData pin = IconData( - 0xe99a, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData plus_circle = IconData( - 0xe99b, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData plus = IconData( - 0xe99c, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData podium = IconData( - 0xe99d, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData pointer_leftright = IconData( - 0xe99e, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData pointer = IconData( - 0xe99f, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData potion_circle = IconData( - 0xe9a0, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData potion_health = IconData( - 0xe9a1, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData potion = IconData( - 0xe9a2, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData print = IconData( - 0xe9a3, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData pulse = IconData( - 0xe9a4, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData pyramid = IconData( - 0xe9a5, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData radiation = IconData( - 0xe9a6, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData rating = IconData( - 0xe9a7, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData record = IconData( - 0xe9a8, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData refresh_back = IconData( - 0xe9a9, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData refresh = IconData( - 0xe9aa, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData reload_vert = IconData( - 0xe9ab, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData reload = IconData( - 0xe9ac, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData right = IconData( - 0xe9ad, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData roll = IconData( - 0xe9ae, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData sale = IconData( - 0xe9af, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData save_1 = IconData( - 0xe9b0, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData save_check = IconData( - 0xe9b1, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData save = IconData( - 0xe9b2, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData schedule_square = IconData( - 0xe9b3, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData schedule = IconData( - 0xe9b4, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData scissors = IconData( - 0xe9b5, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData search = IconData( - 0xe9b6, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData send_message = IconData( - 0xe9b7, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData settings = IconData( - 0xe9b8, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData share_1 = IconData( - 0xe9b9, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData share = IconData( - 0xe9ba, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData signboard = IconData( - 0xe9bb, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData smile_sad = IconData( - 0xe9bc, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData smile = IconData( - 0xe9bd, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData sorting_down = IconData( - 0xe9be, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData sorting_up = IconData( - 0xe9bf, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData sorting = IconData( - 0xe9c0, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData square_down = IconData( - 0xe9c1, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData square_left = IconData( - 0xe9c2, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData square_right = IconData( - 0xe9c3, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData square_up = IconData( - 0xe9c4, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData stand = IconData( - 0xe9c5, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData star = IconData( - 0xe9c6, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData stats = IconData( - 0xe9c7, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData stethoscope = IconData( - 0xe9c8, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData sticker = IconData( - 0xe9c9, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData storage = IconData( - 0xe9ca, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData strl_down = IconData( - 0xe9cb, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData strl_left = IconData( - 0xe9cc, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData strl_right = IconData( - 0xe9cd, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData strl_up = IconData( - 0xe9ce, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData syringe = IconData( - 0xe9cf, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData tablet = IconData( - 0xe9d0, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData target = IconData( - 0xe9d1, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData test_tube = IconData( - 0xe9d2, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData thumbs_down_reaction = IconData( - 0xe9d3, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData thumbs_up_reaction = IconData( - 0xe9d4, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData time_1 = IconData( - 0xe9d5, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData time_wait = IconData( - 0xe9d6, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData time = IconData( - 0xe9d7, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData tooth = IconData( - 0xe9d8, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData tube_full = IconData( - 0xe9d9, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData tv_check = IconData( - 0xe9da, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData tv_rating = IconData( - 0xe9db, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData unfold_less_h = IconData( - 0xe9dc, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData unfold_less = IconData( - 0xe9dd, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData unfold_more_h = IconData( - 0xe9de, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData unfold_more = IconData( - 0xe9df, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData unread = IconData( - 0xe9e0, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData up_down = IconData( - 0xe9e1, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData up = IconData( - 0xe9e2, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData upload = IconData( - 0xe9e3, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData user_add = IconData( - 0xe9e4, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData user_delete = IconData( - 0xe9e5, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData user_minus = IconData( - 0xe9e6, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData user = IconData( - 0xe9e7, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData voice = IconData( - 0xe9e8, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData world = IconData( - 0xe9e9, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); - static const IconData wut_reaction = IconData( - 0xe9ea, - fontFamily: _fontFamily, - fontPackage: _fontPackage, - ); -} diff --git a/lib/src/stream_svg_icon.dart b/lib/src/stream_svg_icon.dart new file mode 100644 index 00000000..25571150 --- /dev/null +++ b/lib/src/stream_svg_icon.dart @@ -0,0 +1,40 @@ +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_svg/flutter_svg.dart'; + +class StreamSvgIcon extends StatelessWidget { + final String assetName; + final double width; + final double height; + final Color color; + + const StreamSvgIcon({ + Key key, + this.assetName, + this.width, + this.height, + this.color, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + return kIsWeb + ? Image.network( + 'packages/stream_chat_flutter/svgs/$assetName', + width: width, + height: height, + color: color, + fit: BoxFit.cover, + alignment: Alignment.center, + ) + : SvgPicture.asset( + 'lib/svgs/$assetName', + package: 'stream_chat_flutter', + width: width, + height: height, + fit: BoxFit.cover, + color: color, + alignment: Alignment.center, + ); + } +} diff --git a/lib/src/thread_header.dart b/lib/src/thread_header.dart index 993a3047..9ad71a47 100644 --- a/lib/src/thread_header.dart +++ b/lib/src/thread_header.dart @@ -1,7 +1,7 @@ import 'package:flutter/material.dart'; import 'package:stream_chat/stream_chat.dart'; -import 'package:stream_chat_flutter/src/back_button.dart'; import 'package:stream_chat_flutter/src/stream_chat_theme.dart'; +import 'package:stream_chat_flutter/src/stream_svg_icon.dart'; /// ![screenshot](https://raw.githubusercontent.com/GetStream/stream-chat-flutter/master/screenshots/thread_header.png) /// ![screenshot](https://raw.githubusercontent.com/GetStream/stream-chat-flutter/master/screenshots/thread_header_paint.png) @@ -84,9 +84,16 @@ class ThreadHeader extends StatelessWidget implements PreferredSizeWidget { child: showBackButton ? AspectRatio( aspectRatio: 1, - child: StreamBackButton( + child: IconButton( onPressed: onBackPressed, - icon: Icons.close, + icon: StreamSvgIcon( + assetName: 'Icon_close.svg', + height: 24, + width: 24, + color: Theme.of(context).brightness == Brightness.dark + ? Colors.white + : Colors.black, + ), ), ) : SizedBox(), diff --git a/lib/src/user_item.dart b/lib/src/user_item.dart index 06ab0848..8ddd3d99 100644 --- a/lib/src/user_item.dart +++ b/lib/src/user_item.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:jiffy/jiffy.dart'; import 'package:stream_chat/stream_chat.dart'; +import 'package:stream_chat_flutter/src/stream_svg_icon.dart'; import 'package:stream_chat_flutter/src/user_list_view.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; @@ -73,9 +74,10 @@ class UserItem extends StatelessWidget { ), trailing: selected ? CircleAvatar( - child: Icon( - StreamIcons.check, - size: 20, + child: StreamSvgIcon( + assetName: 'Icon_check.svg', + height: 20, + width: 20, ), radius: 10, ) diff --git a/lib/stream_chat_flutter.dart b/lib/stream_chat_flutter.dart index 91ac68c8..ce5edca7 100644 --- a/lib/stream_chat_flutter.dart +++ b/lib/stream_chat_flutter.dart @@ -23,13 +23,13 @@ export 'src/sending_indicator.dart'; export 'src/stream_channel.dart'; export 'src/stream_chat.dart'; export 'src/stream_chat_theme.dart'; -export 'src/stream_icons.dart'; export 'src/system_message.dart'; export 'src/thread_header.dart'; export 'src/typing_indicator.dart'; export 'src/user_avatar.dart'; +export 'src/user_item.dart'; +export 'src/stream_svg_icon.dart'; +export 'src/user_list_view.dart'; +export 'src/users_bloc.dart'; export 'src/utils.dart'; export 'src/video_attachment.dart'; -export 'src/users_bloc.dart'; -export 'src/user_list_view.dart'; -export 'src/user_item.dart'; diff --git a/lib/svgs/Empty State_Camera.svg b/lib/svgs/Empty State_Camera.svg new file mode 100644 index 00000000..170ff7d4 --- /dev/null +++ b/lib/svgs/Empty State_Camera.svg @@ -0,0 +1,3 @@ + + + diff --git a/lib/svgs/Empty State_Files.svg b/lib/svgs/Empty State_Files.svg new file mode 100644 index 00000000..658bcb1d --- /dev/null +++ b/lib/svgs/Empty State_Files.svg @@ -0,0 +1,3 @@ + + + diff --git a/lib/svgs/Empty State_No channel.svg b/lib/svgs/Empty State_No channel.svg new file mode 100644 index 00000000..d7979534 --- /dev/null +++ b/lib/svgs/Empty State_No channel.svg @@ -0,0 +1,3 @@ + + + diff --git a/lib/svgs/Empty State_Search.svg b/lib/svgs/Empty State_Search.svg new file mode 100644 index 00000000..d0026388 --- /dev/null +++ b/lib/svgs/Empty State_Search.svg @@ -0,0 +1,3 @@ + + + diff --git a/lib/svgs/Empty State_picture.svg b/lib/svgs/Empty State_picture.svg new file mode 100644 index 00000000..fc82db46 --- /dev/null +++ b/lib/svgs/Empty State_picture.svg @@ -0,0 +1,3 @@ + + + diff --git a/lib/svgs/Giphy icon.svg b/lib/svgs/Giphy icon.svg new file mode 100644 index 00000000..a9419e59 --- /dev/null +++ b/lib/svgs/Giphy icon.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/lib/svgs/Icon_LOL_reaction.svg b/lib/svgs/Icon_LOL_reaction.svg new file mode 100644 index 00000000..c0f1d6fc --- /dev/null +++ b/lib/svgs/Icon_LOL_reaction.svg @@ -0,0 +1,3 @@ + + + diff --git a/lib/svgs/Icon_Thread_Reply.svg b/lib/svgs/Icon_Thread_Reply.svg new file mode 100644 index 00000000..7482300d --- /dev/null +++ b/lib/svgs/Icon_Thread_Reply.svg @@ -0,0 +1,3 @@ + + + diff --git a/lib/svgs/Icon_User_add.svg b/lib/svgs/Icon_User_add.svg new file mode 100644 index 00000000..c9db7859 --- /dev/null +++ b/lib/svgs/Icon_User_add.svg @@ -0,0 +1,3 @@ + + + diff --git a/lib/svgs/Icon_User_deselect.svg b/lib/svgs/Icon_User_deselect.svg new file mode 100644 index 00000000..fc5129d7 --- /dev/null +++ b/lib/svgs/Icon_User_deselect.svg @@ -0,0 +1,3 @@ + + + diff --git a/lib/svgs/Icon_arrow_right.svg b/lib/svgs/Icon_arrow_right.svg new file mode 100644 index 00000000..dde29bcb --- /dev/null +++ b/lib/svgs/Icon_arrow_right.svg @@ -0,0 +1,3 @@ + + + diff --git a/lib/svgs/Icon_attach.svg b/lib/svgs/Icon_attach.svg new file mode 100644 index 00000000..e2369d21 --- /dev/null +++ b/lib/svgs/Icon_attach.svg @@ -0,0 +1,3 @@ + + + diff --git a/lib/svgs/Icon_camera.svg b/lib/svgs/Icon_camera.svg new file mode 100644 index 00000000..0bf3122d --- /dev/null +++ b/lib/svgs/Icon_camera.svg @@ -0,0 +1,3 @@ + + + diff --git a/lib/svgs/Icon_check.svg b/lib/svgs/Icon_check.svg new file mode 100644 index 00000000..49cf76be --- /dev/null +++ b/lib/svgs/Icon_check.svg @@ -0,0 +1,3 @@ + + + diff --git a/lib/svgs/Icon_check_all.svg b/lib/svgs/Icon_check_all.svg new file mode 100644 index 00000000..b477edde --- /dev/null +++ b/lib/svgs/Icon_check_all.svg @@ -0,0 +1,3 @@ + + + diff --git a/lib/svgs/Icon_check_big.svg b/lib/svgs/Icon_check_big.svg new file mode 100644 index 00000000..d42503bb --- /dev/null +++ b/lib/svgs/Icon_check_big.svg @@ -0,0 +1,3 @@ + + + diff --git a/lib/svgs/Icon_check_send.svg b/lib/svgs/Icon_check_send.svg new file mode 100644 index 00000000..e62c7099 --- /dev/null +++ b/lib/svgs/Icon_check_send.svg @@ -0,0 +1,3 @@ + + + diff --git a/lib/svgs/Icon_circle_right.svg b/lib/svgs/Icon_circle_right.svg new file mode 100644 index 00000000..1d20c031 --- /dev/null +++ b/lib/svgs/Icon_circle_right.svg @@ -0,0 +1,3 @@ + + + diff --git a/lib/svgs/Icon_circle_up.svg b/lib/svgs/Icon_circle_up.svg new file mode 100644 index 00000000..41ed17dd --- /dev/null +++ b/lib/svgs/Icon_circle_up.svg @@ -0,0 +1,3 @@ + + + diff --git a/lib/svgs/Icon_close.svg b/lib/svgs/Icon_close.svg new file mode 100644 index 00000000..0765c5c3 --- /dev/null +++ b/lib/svgs/Icon_close.svg @@ -0,0 +1,3 @@ + + + diff --git a/lib/svgs/Icon_close_black.svg b/lib/svgs/Icon_close_black.svg new file mode 100644 index 00000000..74eb480c --- /dev/null +++ b/lib/svgs/Icon_close_black.svg @@ -0,0 +1,3 @@ + + + diff --git a/lib/svgs/Icon_close_sml.svg b/lib/svgs/Icon_close_sml.svg new file mode 100644 index 00000000..63e0d016 --- /dev/null +++ b/lib/svgs/Icon_close_sml.svg @@ -0,0 +1,3 @@ + + + diff --git a/lib/svgs/Icon_cloud_download.svg b/lib/svgs/Icon_cloud_download.svg new file mode 100644 index 00000000..7b935f29 --- /dev/null +++ b/lib/svgs/Icon_cloud_download.svg @@ -0,0 +1,3 @@ + + + diff --git a/lib/svgs/Icon_contacts.svg b/lib/svgs/Icon_contacts.svg new file mode 100644 index 00000000..6db40129 --- /dev/null +++ b/lib/svgs/Icon_contacts.svg @@ -0,0 +1,3 @@ + + + diff --git a/lib/svgs/Icon_copy.svg b/lib/svgs/Icon_copy.svg new file mode 100644 index 00000000..83bd7aa5 --- /dev/null +++ b/lib/svgs/Icon_copy.svg @@ -0,0 +1,3 @@ + + + diff --git a/lib/svgs/Icon_curve_line_left_up.svg b/lib/svgs/Icon_curve_line_left_up.svg new file mode 100644 index 00000000..1c3c718c --- /dev/null +++ b/lib/svgs/Icon_curve_line_left_up.svg @@ -0,0 +1,3 @@ + + + diff --git a/lib/svgs/Icon_curve_line_left_up_big.svg b/lib/svgs/Icon_curve_line_left_up_big.svg new file mode 100644 index 00000000..4b6181b1 --- /dev/null +++ b/lib/svgs/Icon_curve_line_left_up_big.svg @@ -0,0 +1,3 @@ + + + diff --git a/lib/svgs/Icon_delete.svg b/lib/svgs/Icon_delete.svg new file mode 100644 index 00000000..3a63cfec --- /dev/null +++ b/lib/svgs/Icon_delete.svg @@ -0,0 +1,3 @@ + + + diff --git a/lib/svgs/Icon_down.svg b/lib/svgs/Icon_down.svg new file mode 100644 index 00000000..60ea59ee --- /dev/null +++ b/lib/svgs/Icon_down.svg @@ -0,0 +1,3 @@ + + + diff --git a/lib/svgs/Icon_download.svg b/lib/svgs/Icon_download.svg new file mode 100644 index 00000000..f42047ba --- /dev/null +++ b/lib/svgs/Icon_download.svg @@ -0,0 +1,3 @@ + + + diff --git a/lib/svgs/Icon_edit.svg b/lib/svgs/Icon_edit.svg new file mode 100644 index 00000000..7fc784fb --- /dev/null +++ b/lib/svgs/Icon_edit.svg @@ -0,0 +1,3 @@ + + + diff --git a/lib/svgs/Icon_empty_circle_left.svg b/lib/svgs/Icon_empty_circle_left.svg new file mode 100644 index 00000000..8f1e8329 --- /dev/null +++ b/lib/svgs/Icon_empty_circle_left.svg @@ -0,0 +1,3 @@ + + + diff --git a/lib/svgs/Icon_error.svg b/lib/svgs/Icon_error.svg new file mode 100644 index 00000000..af3df414 --- /dev/null +++ b/lib/svgs/Icon_error.svg @@ -0,0 +1,3 @@ + + + diff --git a/lib/svgs/Icon_eye-off.svg b/lib/svgs/Icon_eye-off.svg new file mode 100644 index 00000000..8f404ae2 --- /dev/null +++ b/lib/svgs/Icon_eye-off.svg @@ -0,0 +1,3 @@ + + + diff --git a/lib/svgs/Icon_grid.svg b/lib/svgs/Icon_grid.svg new file mode 100644 index 00000000..43bb0489 --- /dev/null +++ b/lib/svgs/Icon_grid.svg @@ -0,0 +1,3 @@ + + + diff --git a/lib/svgs/Icon_left.svg b/lib/svgs/Icon_left.svg new file mode 100644 index 00000000..5a4c5ced --- /dev/null +++ b/lib/svgs/Icon_left.svg @@ -0,0 +1,3 @@ + + + diff --git a/lib/svgs/Icon_lightning-command runner.svg b/lib/svgs/Icon_lightning-command runner.svg new file mode 100644 index 00000000..83045bbb --- /dev/null +++ b/lib/svgs/Icon_lightning-command runner.svg @@ -0,0 +1,3 @@ + + + diff --git a/lib/svgs/Icon_love_reaction.svg b/lib/svgs/Icon_love_reaction.svg new file mode 100644 index 00000000..4d946544 --- /dev/null +++ b/lib/svgs/Icon_love_reaction.svg @@ -0,0 +1,3 @@ + + + diff --git a/lib/svgs/Icon_message.svg b/lib/svgs/Icon_message.svg new file mode 100644 index 00000000..11eacefa --- /dev/null +++ b/lib/svgs/Icon_message.svg @@ -0,0 +1,3 @@ + + + diff --git a/lib/svgs/Icon_mute.svg b/lib/svgs/Icon_mute.svg new file mode 100644 index 00000000..d1d16aa7 --- /dev/null +++ b/lib/svgs/Icon_mute.svg @@ -0,0 +1,3 @@ + + + diff --git a/lib/svgs/Icon_pen-write.svg b/lib/svgs/Icon_pen-write.svg new file mode 100644 index 00000000..820d28bd --- /dev/null +++ b/lib/svgs/Icon_pen-write.svg @@ -0,0 +1,3 @@ + + + diff --git a/lib/svgs/Icon_record.svg b/lib/svgs/Icon_record.svg new file mode 100644 index 00000000..ff72859f --- /dev/null +++ b/lib/svgs/Icon_record.svg @@ -0,0 +1,3 @@ + + + diff --git a/lib/svgs/Icon_right.svg b/lib/svgs/Icon_right.svg new file mode 100644 index 00000000..6d42a1db --- /dev/null +++ b/lib/svgs/Icon_right.svg @@ -0,0 +1,3 @@ + + + diff --git a/lib/svgs/Icon_search.svg b/lib/svgs/Icon_search.svg new file mode 100644 index 00000000..0865a95e --- /dev/null +++ b/lib/svgs/Icon_search.svg @@ -0,0 +1,3 @@ + + + diff --git a/lib/svgs/Icon_smile.svg b/lib/svgs/Icon_smile.svg new file mode 100644 index 00000000..b803cf22 --- /dev/null +++ b/lib/svgs/Icon_smile.svg @@ -0,0 +1,3 @@ + + + diff --git a/lib/svgs/Icon_thumbs_down_reaction.svg b/lib/svgs/Icon_thumbs_down_reaction.svg new file mode 100644 index 00000000..9036ff72 --- /dev/null +++ b/lib/svgs/Icon_thumbs_down_reaction.svg @@ -0,0 +1,3 @@ + + + diff --git a/lib/svgs/Icon_thumbs_up_reaction.svg b/lib/svgs/Icon_thumbs_up_reaction.svg new file mode 100644 index 00000000..ff4dcc72 --- /dev/null +++ b/lib/svgs/Icon_thumbs_up_reaction.svg @@ -0,0 +1,3 @@ + + + diff --git a/lib/svgs/Icon_time.svg b/lib/svgs/Icon_time.svg new file mode 100644 index 00000000..59aa2c5d --- /dev/null +++ b/lib/svgs/Icon_time.svg @@ -0,0 +1,3 @@ + + + diff --git a/lib/svgs/Icon_user.svg b/lib/svgs/Icon_user.svg new file mode 100644 index 00000000..f50e33fc --- /dev/null +++ b/lib/svgs/Icon_user.svg @@ -0,0 +1,3 @@ + + + diff --git a/lib/svgs/Icon_user_delete.svg b/lib/svgs/Icon_user_delete.svg new file mode 100644 index 00000000..fb47f5e8 --- /dev/null +++ b/lib/svgs/Icon_user_delete.svg @@ -0,0 +1,3 @@ + + + diff --git a/lib/svgs/Icon_wut_reaction.svg b/lib/svgs/Icon_wut_reaction.svg new file mode 100644 index 00000000..f445ec29 --- /dev/null +++ b/lib/svgs/Icon_wut_reaction.svg @@ -0,0 +1,3 @@ + + + diff --git a/lib/svgs/STREAM MARK 1.svg b/lib/svgs/STREAM MARK 1.svg new file mode 100644 index 00000000..57ccef0f --- /dev/null +++ b/lib/svgs/STREAM MARK 1.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/lib/svgs/UI_Reverse Pagination Loading.svg b/lib/svgs/UI_Reverse Pagination Loading.svg new file mode 100644 index 00000000..dfc3754f --- /dev/null +++ b/lib/svgs/UI_Reverse Pagination Loading.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/lib/svgs/eye-line_big.svg b/lib/svgs/eye-line_big.svg new file mode 100644 index 00000000..9eb20a58 --- /dev/null +++ b/lib/svgs/eye-line_big.svg @@ -0,0 +1,3 @@ + + + diff --git a/lib/svgs/files.svg b/lib/svgs/files.svg new file mode 100644 index 00000000..5d72fdd3 --- /dev/null +++ b/lib/svgs/files.svg @@ -0,0 +1,3 @@ + + + diff --git a/lib/svgs/filetype_7z.svg b/lib/svgs/filetype_7z.svg new file mode 100644 index 00000000..787f5f8c --- /dev/null +++ b/lib/svgs/filetype_7z.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/lib/svgs/filetype_CSV.svg b/lib/svgs/filetype_CSV.svg new file mode 100644 index 00000000..d7395e78 --- /dev/null +++ b/lib/svgs/filetype_CSV.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/lib/svgs/filetype_DOC.svg b/lib/svgs/filetype_DOC.svg new file mode 100644 index 00000000..4233055a --- /dev/null +++ b/lib/svgs/filetype_DOC.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/lib/svgs/filetype_DOCX.svg b/lib/svgs/filetype_DOCX.svg new file mode 100644 index 00000000..3077f515 --- /dev/null +++ b/lib/svgs/filetype_DOCX.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/lib/svgs/filetype_Generic.svg b/lib/svgs/filetype_Generic.svg new file mode 100644 index 00000000..3ec0f239 --- /dev/null +++ b/lib/svgs/filetype_Generic.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/lib/svgs/filetype_MD.svg b/lib/svgs/filetype_MD.svg new file mode 100644 index 00000000..560b7c61 --- /dev/null +++ b/lib/svgs/filetype_MD.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/lib/svgs/filetype_ODT.svg b/lib/svgs/filetype_ODT.svg new file mode 100644 index 00000000..6e08875f --- /dev/null +++ b/lib/svgs/filetype_ODT.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/lib/svgs/filetype_PDF.svg b/lib/svgs/filetype_PDF.svg new file mode 100644 index 00000000..c8306ca1 --- /dev/null +++ b/lib/svgs/filetype_PDF.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/lib/svgs/filetype_PPT.svg b/lib/svgs/filetype_PPT.svg new file mode 100644 index 00000000..0541a496 --- /dev/null +++ b/lib/svgs/filetype_PPT.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/lib/svgs/filetype_PPTX-1.svg b/lib/svgs/filetype_PPTX-1.svg new file mode 100644 index 00000000..a50efd64 --- /dev/null +++ b/lib/svgs/filetype_PPTX-1.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/lib/svgs/filetype_PPTX.svg b/lib/svgs/filetype_PPTX.svg new file mode 100644 index 00000000..83339acc --- /dev/null +++ b/lib/svgs/filetype_PPTX.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/lib/svgs/filetype_RAR.svg b/lib/svgs/filetype_RAR.svg new file mode 100644 index 00000000..ae0e14d0 --- /dev/null +++ b/lib/svgs/filetype_RAR.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/lib/svgs/filetype_RTF.svg b/lib/svgs/filetype_RTF.svg new file mode 100644 index 00000000..e9266599 --- /dev/null +++ b/lib/svgs/filetype_RTF.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/lib/svgs/filetype_TAR.svg b/lib/svgs/filetype_TAR.svg new file mode 100644 index 00000000..6796e1f7 --- /dev/null +++ b/lib/svgs/filetype_TAR.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/lib/svgs/filetype_TXT.svg b/lib/svgs/filetype_TXT.svg new file mode 100644 index 00000000..263fdfbe --- /dev/null +++ b/lib/svgs/filetype_TXT.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/lib/svgs/filetype_XLS.svg b/lib/svgs/filetype_XLS.svg new file mode 100644 index 00000000..eec9a05d --- /dev/null +++ b/lib/svgs/filetype_XLS.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/lib/svgs/filetype_XLSX.svg b/lib/svgs/filetype_XLSX.svg new file mode 100644 index 00000000..6203aa27 --- /dev/null +++ b/lib/svgs/filetype_XLSX.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/lib/svgs/filetype_ZIP.svg b/lib/svgs/filetype_ZIP.svg new file mode 100644 index 00000000..daa24576 --- /dev/null +++ b/lib/svgs/filetype_ZIP.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/lib/svgs/filetype_html.svg b/lib/svgs/filetype_html.svg new file mode 100644 index 00000000..9e3cb9cf --- /dev/null +++ b/lib/svgs/filetype_html.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/lib/svgs/giphy icon blue.svg b/lib/svgs/giphy icon blue.svg new file mode 100644 index 00000000..746e50a4 --- /dev/null +++ b/lib/svgs/giphy icon blue.svg @@ -0,0 +1,3 @@ + + + diff --git a/lib/svgs/icon_SHARE.svg b/lib/svgs/icon_SHARE.svg new file mode 100644 index 00000000..6a35ef8d --- /dev/null +++ b/lib/svgs/icon_SHARE.svg @@ -0,0 +1,3 @@ + + + diff --git a/lib/svgs/icon_delete_grey.svg b/lib/svgs/icon_delete_grey.svg new file mode 100644 index 00000000..10689df2 --- /dev/null +++ b/lib/svgs/icon_delete_grey.svg @@ -0,0 +1,4 @@ + + + + diff --git a/lib/svgs/icon_mentions.svg b/lib/svgs/icon_mentions.svg new file mode 100644 index 00000000..ce6c6fa1 --- /dev/null +++ b/lib/svgs/icon_mentions.svg @@ -0,0 +1,3 @@ + + + diff --git a/lib/svgs/mentions.svg b/lib/svgs/mentions.svg new file mode 100644 index 00000000..05bdee3b --- /dev/null +++ b/lib/svgs/mentions.svg @@ -0,0 +1,3 @@ + + + diff --git a/lib/svgs/pictures.svg b/lib/svgs/pictures.svg new file mode 100644 index 00000000..64e6ca34 --- /dev/null +++ b/lib/svgs/pictures.svg @@ -0,0 +1,3 @@ + + + diff --git a/lib/svgs/settings.svg b/lib/svgs/settings.svg new file mode 100644 index 00000000..7dfab209 --- /dev/null +++ b/lib/svgs/settings.svg @@ -0,0 +1,3 @@ + + + diff --git a/lib/svgs/share_arrow.svg b/lib/svgs/share_arrow.svg new file mode 100644 index 00000000..33b99c35 --- /dev/null +++ b/lib/svgs/share_arrow.svg @@ -0,0 +1,3 @@ + + + diff --git a/pubspec.yaml b/pubspec.yaml index f8705c22..c441ca4f 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -46,10 +46,7 @@ flutter: assets: - images/ - svgs/ - fonts: - - family: stream-icons - fonts: - - asset: fonts/stream-icons.ttf + - lib/svgs/ dev_dependencies: pedantic: ^1.9.0 From 800dd02aa27eb30f10ee8bbc8ac9b2f34d06e832 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Tue, 24 Nov 2020 12:55:37 +0100 Subject: [PATCH 0464/1140] update tests --- test/src/message_action_modal_test.dart | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/test/src/message_action_modal_test.dart b/test/src/message_action_modal_test.dart index 97709e70..5b0c1678 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.byIcon(StreamIcons.sorting_up), findsOneWidget); - expect(find.byIcon(StreamIcons.edit), findsOneWidget); - expect(find.byIcon(StreamIcons.delete), findsOneWidget); - expect(find.byIcon(StreamIcons.copy), 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( @@ -87,10 +87,10 @@ void main() { await tester.pump(Duration(milliseconds: 1000)); expect(find.byKey(Key('MessageWidget')), findsOneWidget); - expect(find.byIcon(StreamIcons.sorting_up), findsNothing); - expect(find.byIcon(StreamIcons.edit), findsNothing); - expect(find.byIcon(StreamIcons.delete), findsNothing); - expect(find.byIcon(StreamIcons.copy), findsNothing); + expect(find.text('Thread reply'), findsNothing); + expect(find.text('Edit message'), findsNothing); + expect(find.text('Delete message'), findsNothing); + expect(find.text('Copy message'), findsNothing); }, ); } From 93c324ac56f94ef0190a485a063b433fa7b2df8d Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Tue, 24 Nov 2020 13:07:48 +0100 Subject: [PATCH 0465/1140] fix tests --- example/lib/new_chat_screen.dart | 10 +++++++--- example/pubspec.yaml | 2 +- lib/src/stream_svg_icon.dart | 6 ++++-- test/src/message_reaction_modal_test.dart | 9 ++++++--- test/src/reaction_bubble_test.dart | 12 ++++++++---- 5 files changed, 26 insertions(+), 13 deletions(-) diff --git a/example/lib/new_chat_screen.dart b/example/lib/new_chat_screen.dart index df4b7c3c..aeb4298e 100644 --- a/example/lib/new_chat_screen.dart +++ b/example/lib/new_chat_screen.dart @@ -193,9 +193,13 @@ class _NewChatScreenState extends State { child: Row( children: [ StreamNeumorphicButton( - child: StreamSvgIcon( - assetName: 'Icon_contacts.svg', - color: Color(0xFF006CFF), + child: Center( + child: StreamSvgIcon( + assetName: 'Icon_contacts.svg', + color: Color(0xFF006CFF), + height: 24, + width: 24, + ), ), ), SizedBox(width: 8), diff --git a/example/pubspec.yaml b/example/pubspec.yaml index bc892255..7cd6045a 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -1,6 +1,6 @@ name: example description: A new Flutter project. -version: 1.0.68+70 +version: 1.0.69+71 environment: sdk: ">=2.2.2 <3.0.0" diff --git a/lib/src/stream_svg_icon.dart b/lib/src/stream_svg_icon.dart index 25571150..c0cf5d72 100644 --- a/lib/src/stream_svg_icon.dart +++ b/lib/src/stream_svg_icon.dart @@ -9,20 +9,21 @@ class StreamSvgIcon extends StatelessWidget { final Color color; const StreamSvgIcon({ - Key key, this.assetName, this.width, this.height, this.color, - }) : super(key: key); + }); @override Widget build(BuildContext context) { + final key = Key('StreamSvgIcon-$assetName'); return kIsWeb ? Image.network( 'packages/stream_chat_flutter/svgs/$assetName', width: width, height: height, + key: key, color: color, fit: BoxFit.cover, alignment: Alignment.center, @@ -30,6 +31,7 @@ class StreamSvgIcon extends StatelessWidget { : SvgPicture.asset( 'lib/svgs/$assetName', package: 'stream_chat_flutter', + key: key, width: width, height: height, fit: BoxFit.cover, diff --git a/test/src/message_reaction_modal_test.dart b/test/src/message_reaction_modal_test.dart index 622b57c3..d1c2a49c 100644 --- a/test/src/message_reaction_modal_test.dart +++ b/test/src/message_reaction_modal_test.dart @@ -42,7 +42,8 @@ void main() { await tester.pump(Duration(milliseconds: 1000)); expect(find.byKey(Key('MessageWidget')), findsOneWidget); - expect(find.byIcon(StreamIcons.thumbs_up_reaction), findsOneWidget); + expect(find.byKey(Key('StreamSvgIcon-Icon_thumbs_up_reaction.svg')), + findsOneWidget); }, ); @@ -91,8 +92,10 @@ void main() { await tester.pump(Duration(milliseconds: 1000)); expect(find.byKey(Key('MessageWidget')), findsOneWidget); - expect(find.byIcon(StreamIcons.thumbs_up_reaction), findsNWidgets(2)); - expect(find.byIcon(StreamIcons.love_reaction), findsNWidgets(2)); + expect(find.byKey(Key('StreamSvgIcon-Icon_thumbs_up_reaction.svg')), + findsNWidgets(2)); + expect(find.byKey(Key('StreamSvgIcon-Icon_love_reaction.svg')), + findsNWidgets(2)); expect(find.text(testUserId), findsNWidgets(2)); }, ); diff --git a/test/src/reaction_bubble_test.dart b/test/src/reaction_bubble_test.dart index c524061c..6518dc94 100644 --- a/test/src/reaction_bubble_test.dart +++ b/test/src/reaction_bubble_test.dart @@ -25,7 +25,8 @@ void main() { ), ); - expect(find.byIcon(StreamIcons.thumbs_up_reaction), findsNothing); + expect(find.byKey(Key('StreamSvgIcon-Icon_thumbs_up_reaction.svg')), + findsNothing); }, ); @@ -61,7 +62,8 @@ void main() { ), ); - expect(find.byIcon(StreamIcons.thumbs_up_reaction), findsOneWidget); + expect(find.byKey(Key('StreamSvgIcon-Icon_thumbs_up_reaction.svg')), + findsOneWidget); }, ); testWidgets( @@ -100,8 +102,10 @@ void main() { ), ); - expect(find.byIcon(StreamIcons.thumbs_up_reaction), findsOneWidget); - expect(find.byIcon(StreamIcons.love_reaction), findsOneWidget); + expect(find.byKey(Key('StreamSvgIcon-Icon_thumbs_up_reaction.svg')), + findsOneWidget); + expect(find.byKey(Key('StreamSvgIcon-Icon_love_reaction.svg')), + findsOneWidget); }, ); } From 6b62eadaa4686dadc1a8780766c544cd0d2b7342 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Tue, 24 Nov 2020 13:39:36 +0100 Subject: [PATCH 0466/1140] add factory constructor --- example/lib/advanced_options_page.dart | 3 +- example/lib/chips_input_text_field.dart | 17 +- example/lib/choose_user_page.dart | 3 +- example/lib/group_chat_details_screen.dart | 4 +- example/lib/main.dart | 9 +- example/lib/new_chat_screen.dart | 15 +- example/lib/new_group_chat_screen.dart | 21 +- example/pubspec.yaml | 2 +- lib/src/back_button.dart | 6 +- lib/src/channel_bottom_sheet.dart | 12 +- lib/src/channel_list_view.dart | 14 +- lib/src/channel_preview.dart | 6 +- lib/src/giphy_attachment.dart | 30 +- lib/src/media_list_view.dart | 6 +- lib/src/message_actions_modal.dart | 18 +- lib/src/message_input.dart | 65 ++-- lib/src/message_list_view.dart | 3 +- lib/src/stream_svg_icon.dart | 336 +++++++++++++++++++++ lib/src/thread_header.dart | 6 +- lib/src/user_item.dart | 6 +- lib/svgs/Icon_camera.svg | 4 +- lib/svgs/Icon_record.svg | 4 +- 22 files changed, 424 insertions(+), 166 deletions(-) diff --git a/example/lib/advanced_options_page.dart b/example/lib/advanced_options_page.dart index 57ed1f06..212a15a8 100644 --- a/example/lib/advanced_options_page.dart +++ b/example/lib/advanced_options_page.dart @@ -44,8 +44,7 @@ class _AdvancedOptionsPageState extends State { ), ), leading: IconButton( - icon: StreamSvgIcon( - assetName: 'Icon_left.svg', + icon: StreamSvgIcon.left( color: Colors.black, ), onPressed: () { diff --git a/example/lib/chips_input_text_field.dart b/example/lib/chips_input_text_field.dart index 0310de5b..19c5c761 100644 --- a/example/lib/chips_input_text_field.dart +++ b/example/lib/chips_input_text_field.dart @@ -130,14 +130,15 @@ class ChipInputTextFieldState extends State> { Align( alignment: Alignment.bottomCenter, child: IconButton( - icon: StreamSvgIcon( - assetName: _chips.isEmpty - ? 'Icon_user.svg' - : 'Icon_User_add.svg', - color: Colors.black.withOpacity(0.5), - height: 24, - width: 24, - ), + icon: _chips.isEmpty + ? StreamSvgIcon.user( + color: Colors.black.withOpacity(0.5), + size: 24, + ) + : StreamSvgIcon.userAdd( + color: Colors.black.withOpacity(0.5), + size: 24, + ), onPressed: !_pauseItemAddition ? null : resumeItemAddition, alignment: Alignment.topRight, diff --git a/example/lib/choose_user_page.dart b/example/lib/choose_user_page.dart index 0a0d67b9..f1a53773 100644 --- a/example/lib/choose_user_page.dart +++ b/example/lib/choose_user_page.dart @@ -196,8 +196,7 @@ class ChooseUserPage extends StatelessWidget { ); }, leading: CircleAvatar( - child: StreamSvgIcon( - assetName: 'settings.svg', + child: StreamSvgIcon.settings( color: Colors.black, ), backgroundColor: diff --git a/example/lib/group_chat_details_screen.dart b/example/lib/group_chat_details_screen.dart index 3de87f2d..d11f377a 100644 --- a/example/lib/group_chat_details_screen.dart +++ b/example/lib/group_chat_details_screen.dart @@ -105,9 +105,7 @@ class _GroupChatDetailsScreenState extends State { StreamNeumorphicButton( child: IconButton( padding: const EdgeInsets.all(0), - icon: StreamSvgIcon( - assetName: 'Icon_check.svg', - ), + icon: StreamSvgIcon.check(), color: Color(0xFF006CFF), onPressed: _isGroupNameEmpty ? null diff --git a/example/lib/main.dart b/example/lib/main.dart index dcb4ac27..d2be225a 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -143,8 +143,7 @@ class ChannelListPage extends StatelessWidget { ), ), ListTile( - leading: StreamSvgIcon( - assetName: 'Icon_pen-write.svg', + leading: StreamSvgIcon.penWrite( color: Colors.black.withOpacity(.5), ), onTap: () { @@ -162,8 +161,7 @@ class ChannelListPage extends StatelessWidget { ), ), ListTile( - leading: StreamSvgIcon( - assetName: 'Icon_contacts.svg', + leading: StreamSvgIcon.contacts( color: Colors.black.withOpacity(.5), ), onTap: () { @@ -197,8 +195,7 @@ class ChannelListPage extends StatelessWidget { ), ); }, - leading: StreamSvgIcon( - assetName: 'Icon_user.svg', + leading: StreamSvgIcon.user( color: Colors.black.withOpacity(.5), ), title: Text( diff --git a/example/lib/new_chat_screen.dart b/example/lib/new_chat_screen.dart index aeb4298e..690e831f 100644 --- a/example/lib/new_chat_screen.dart +++ b/example/lib/new_chat_screen.dart @@ -163,8 +163,7 @@ class _NewChatScreenState extends State { ), ), Positioned( - child: StreamSvgIcon( - assetName: 'Icon_close.svg', + child: StreamSvgIcon.close( color: Colors.white, ), ), @@ -194,11 +193,9 @@ class _NewChatScreenState extends State { children: [ StreamNeumorphicButton( child: Center( - child: StreamSvgIcon( - assetName: 'Icon_contacts.svg', + child: StreamSvgIcon.contacts( color: Color(0xFF006CFF), - height: 24, - width: 24, + size: 24, ), ), ), @@ -292,10 +289,8 @@ class _NewChatScreenState extends State { children: [ Padding( padding: const EdgeInsets.all(24), - child: StreamSvgIcon( - assetName: 'Icon_search.svg', - height: 96, - width: 96, + child: StreamSvgIcon.search( + size: 96, color: Colors.grey, ), ), diff --git a/example/lib/new_group_chat_screen.dart b/example/lib/new_group_chat_screen.dart index 3d7c418a..1db848a1 100644 --- a/example/lib/new_group_chat_screen.dart +++ b/example/lib/new_group_chat_screen.dart @@ -65,8 +65,7 @@ class _NewGroupChatScreenState extends State { actions: [ if (_selectedUsers.isNotEmpty) IconButton( - icon: StreamSvgIcon( - assetName: 'Icon_right.svg', + icon: StreamSvgIcon.right( color: Color(0xFF006CFF), ), onPressed: () { @@ -101,11 +100,9 @@ class _NewGroupChatScreenState extends State { child: TextField( controller: _controller, decoration: InputDecoration( - prefixIcon: StreamSvgIcon( - assetName: 'Icon_search.svg', + prefixIcon: StreamSvgIcon.search( color: Colors.black, - height: 24, - width: 24, + size: 24, ), hintText: 'Search', hintStyle: TextStyle( @@ -163,10 +160,8 @@ class _NewGroupChatScreenState extends State { ), child: Padding( padding: const EdgeInsets.all(0.0), - child: StreamSvgIcon( - assetName: 'Icon_close.svg', - height: 24, - width: 24, + child: StreamSvgIcon.close( + size: 24, ), ), ), @@ -262,10 +257,8 @@ class _NewGroupChatScreenState extends State { children: [ Padding( padding: const EdgeInsets.all(24), - child: StreamSvgIcon( - assetName: 'Icon_search.svg', - height: 96, - width: 96, + child: StreamSvgIcon.search( + size: 96, color: Colors.grey, ), ), diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 7cd6045a..6e34335d 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -1,6 +1,6 @@ name: example description: A new Flutter project. -version: 1.0.69+71 +version: 1.0.70+72 environment: sdk: ">=2.2.2 <3.0.0" diff --git a/lib/src/back_button.dart b/lib/src/back_button.dart index cd30c956..25c1c9da 100644 --- a/lib/src/back_button.dart +++ b/lib/src/back_button.dart @@ -33,10 +33,8 @@ class StreamBackButton extends StatelessWidget { Navigator.of(context).pop(); } }, - child: StreamSvgIcon( - assetName: 'Icon_left.svg', - height: 24, - width: 24, + child: StreamSvgIcon.left( + size: 24, color: Theme.of(context).brightness == Brightness.dark ? Colors.white : Colors.black, diff --git a/lib/src/channel_bottom_sheet.dart b/lib/src/channel_bottom_sheet.dart index c3233ff4..c0e32509 100644 --- a/lib/src/channel_bottom_sheet.dart +++ b/lib/src/channel_bottom_sheet.dart @@ -72,10 +72,8 @@ class ChannelBottomSheet extends StatelessWidget { initialData: channel.isMuted, builder: (context, snapshot) { return ListTile( - leading: StreamSvgIcon( - assetName: 'Icon_mute.svg', - height: 22, - width: 22, + leading: StreamSvgIcon.mute( + size: 22, color: StreamChatTheme.of(context).primaryIconTheme.color, ), title: Text('Mute ${channel.isGroup ? 'group' : 'user'}'), @@ -94,10 +92,8 @@ class ChannelBottomSheet extends StatelessWidget { Divider(), if (channel.isGroup && !channel.isDistinct) ListTile( - leading: StreamSvgIcon( - assetName: 'Icon_User_deselect.svg', - height: 22, - width: 22, + leading: StreamSvgIcon.userRemove( + size: 22, color: Colors.black, ), title: Text('Leave Group'), diff --git a/lib/src/channel_list_view.dart b/lib/src/channel_list_view.dart index 503e740d..bfd8e477 100644 --- a/lib/src/channel_list_view.dart +++ b/lib/src/channel_list_view.dart @@ -201,10 +201,8 @@ class _ChannelListViewState extends State children: [ Padding( padding: const EdgeInsets.all(8.0), - child: StreamSvgIcon( - assetName: 'Icon_message.svg', - height: 136, - width: 136, + child: StreamSvgIcon.message( + size: 136, color: Color(0xffDBDBDB), ), ), @@ -519,9 +517,7 @@ class _ChannelListViewState extends State ), IconSlideAction( color: backgroundColor, - iconWidget: StreamSvgIcon( - assetName: 'Icon_mute.svg', - ), + iconWidget: StreamSvgIcon.mute(), onTap: () async { if (!channel.isMuted) { await channel.mute(); @@ -533,9 +529,7 @@ class _ChannelListViewState extends State if (channel.isGroup && !channel.isDistinct) IconSlideAction( color: backgroundColor, - iconWidget: StreamSvgIcon( - assetName: 'Icon_User_deselect.svg', - ), + iconWidget: StreamSvgIcon.userRemove(), onTap: () async { final confirm = await showConfirmationDialog( context, diff --git a/lib/src/channel_preview.dart b/lib/src/channel_preview.dart index c61e469e..3c9eeace 100644 --- a/lib/src/channel_preview.dart +++ b/lib/src/channel_preview.dart @@ -153,10 +153,8 @@ class ChannelPreview extends StatelessWidget { return Row( crossAxisAlignment: CrossAxisAlignment.end, children: [ - StreamSvgIcon( - assetName: 'Icon_mute.svg', - height: 16, - width: 16, + StreamSvgIcon.mute( + size: 16, ), Text( ' Channel is muted', diff --git a/lib/src/giphy_attachment.dart b/lib/src/giphy_attachment.dart index 0f3b9e7e..7abf7057 100644 --- a/lib/src/giphy_attachment.dart +++ b/lib/src/giphy_attachment.dart @@ -112,11 +112,9 @@ class GiphyAttachment extends StatelessWidget { ), child: Row( children: [ - StreamSvgIcon( - assetName: 'Icon_lightning-command runner.svg', + StreamSvgIcon.lightning( color: StreamChatTheme.of(context).accentColor, - height: 16.0, - width: 16.0, + size: 16.0, ), Text( 'GIPHY', @@ -146,10 +144,8 @@ class GiphyAttachment extends StatelessWidget { child: IconButton( padding: const EdgeInsets.all(0), constraints: BoxConstraints.tight(Size(32, 32)), - icon: StreamSvgIcon( - assetName: 'Icon_left.svg', - height: 24.0, - width: 24.0, + icon: StreamSvgIcon.left( + size: 24.0, ), splashRadius: 16, onPressed: () { @@ -175,10 +171,8 @@ class GiphyAttachment extends StatelessWidget { child: IconButton( padding: const EdgeInsets.all(0), constraints: BoxConstraints.tight(Size(32, 32)), - icon: StreamSvgIcon( - assetName: 'Icon_right.svg', - height: 24.0, - width: 24.0, + icon: StreamSvgIcon.right( + size: 24.0, ), splashRadius: 16, onPressed: () { @@ -257,11 +251,9 @@ class GiphyAttachment extends StatelessWidget { child: Row( mainAxisSize: MainAxisSize.min, children: [ - StreamSvgIcon( - assetName: 'Icon_eye-off.svg', + StreamSvgIcon.eye( color: Colors.black.withOpacity(0.5), - height: 16.0, - width: 16.0, + size: 16.0, ), SizedBox( width: 8.0, @@ -331,11 +323,9 @@ class GiphyAttachment extends StatelessWidget { ), child: Row( children: [ - StreamSvgIcon( - assetName: 'Icon_lightning-command runner.svg', + StreamSvgIcon.lightning( color: Colors.white, - height: 16, - width: 16, + size: 16, ), Text( 'GIPHY', diff --git a/lib/src/media_list_view.dart b/lib/src/media_list_view.dart index c4ae4981..e8735d69 100644 --- a/lib/src/media_list_view.dart +++ b/lib/src/media_list_view.dart @@ -71,10 +71,8 @@ class _MediaListViewState extends State { child: CircleAvatar( radius: 12, backgroundColor: Colors.white, - child: StreamSvgIcon( - assetName: 'Icon_check.svg', - height: 24, - width: 24, + child: StreamSvgIcon.check( + size: 24, color: Colors.black, ), ), diff --git a/lib/src/message_actions_modal.dart b/lib/src/message_actions_modal.dart index d95b63ea..1967cd2b 100644 --- a/lib/src/message_actions_modal.dart +++ b/lib/src/message_actions_modal.dart @@ -188,8 +188,7 @@ class MessageActionsModal extends StatelessWidget { style: Theme.of(context).textTheme.headline6.copyWith(color: Colors.red), ), - leading: StreamSvgIcon( - assetName: 'Icon_delete.svg', + leading: StreamSvgIcon.delete( color: Colors.red, ), onTap: () { @@ -208,8 +207,7 @@ class MessageActionsModal extends StatelessWidget { 'Copy message', style: Theme.of(context).textTheme.headline6, ), - leading: StreamSvgIcon( - assetName: 'Icon_copy.svg', + leading: StreamSvgIcon.copy( color: StreamChatTheme.of(context).primaryIconTheme.color, ), onTap: () async { @@ -225,8 +223,7 @@ class MessageActionsModal extends StatelessWidget { 'Edit message', style: Theme.of(context).textTheme.headline6, ), - leading: StreamSvgIcon( - assetName: 'Icon_edit.svg', + leading: StreamSvgIcon.edit( color: StreamChatTheme.of(context).primaryIconTheme.color, ), onTap: () async { @@ -267,10 +264,8 @@ class MessageActionsModal extends StatelessWidget { mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ IconButton( - icon: StreamSvgIcon( - assetName: 'Icon_edit.svg', - height: 22, - width: 22, + icon: StreamSvgIcon.edit( + size: 22, color: StreamChatTheme.of(context).primaryIconTheme.color, ), @@ -324,8 +319,7 @@ class MessageActionsModal extends StatelessWidget { 'Thread reply', style: Theme.of(context).textTheme.headline6, ), - leading: StreamSvgIcon( - assetName: 'Icon_Thread_Reply.svg', + leading: StreamSvgIcon.thread( color: StreamChatTheme.of(context).primaryIconTheme.color, ), onTap: () { diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index a7d8db5e..4b634ab7 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -284,10 +284,8 @@ class MessageInputState extends State { crossFadeState: _sendAsDm ? CrossFadeState.showFirst : CrossFadeState.showSecond, - firstChild: StreamSvgIcon( - assetName: 'Icon_check.svg', - height: 16.0, - width: 16.0, + firstChild: StreamSvgIcon.check( + size: 16.0, color: Colors.white, ), secondChild: SizedBox( @@ -331,8 +329,7 @@ class MessageInputState extends State { _actionsShrunk = false; }); }, - icon: StreamSvgIcon( - assetName: 'Icon_empty_circle_left.svg', + icon: StreamSvgIcon.emptyCircleLeft( color: StreamChatTheme.of(context).accentColor, ), ), @@ -404,8 +401,7 @@ class MessageInputState extends State { _chosenCommand?.name ?? "", style: TextStyle(color: Colors.white), ), - avatar: StreamSvgIcon( - assetName: 'Icon_lightning-command runner.svg', + avatar: StreamSvgIcon.lightning( color: Colors.white, ), ), @@ -582,9 +578,7 @@ class MessageInputState extends State { padding: const EdgeInsets.symmetric( horizontal: 8.0, ), - child: StreamSvgIcon( - assetName: - 'Icon_lightning-command runner.svg', + child: StreamSvgIcon.lightning( color: StreamChatTheme.of(context) .accentColor, ), @@ -622,12 +616,9 @@ class MessageInputState extends State { trailing: CircleAvatar( backgroundColor: StreamChatTheme.of(context).accentColor, - child: StreamSvgIcon( - assetName: - 'Icon_lightning-command runner.svg', + child: StreamSvgIcon.lightning( color: Colors.white, - height: 12.5, - width: 12.5, + size: 12.5, ), maxRadius: 12, ), @@ -661,10 +652,8 @@ class MessageInputState extends State { mainAxisAlignment: MainAxisAlignment.start, children: [ IconButton( - icon: StreamSvgIcon( - assetName: 'pictures.svg', - height: 24, - width: 24, + icon: StreamSvgIcon.pictures( + size: 24, color: _filePickerIndex == 0 ? StreamChatTheme.of(context).accentColor : Colors.black.withOpacity(0.5), @@ -676,10 +665,8 @@ class MessageInputState extends State { }, ), IconButton( - icon: StreamSvgIcon( - assetName: 'files.svg', - height: 24, - width: 24, + icon: StreamSvgIcon.files( + size: 24, color: _filePickerIndex == 1 ? StreamChatTheme.of(context).accentColor : Colors.black.withOpacity(0.5), @@ -689,10 +676,8 @@ class MessageInputState extends State { }, ), IconButton( - icon: StreamSvgIcon( - assetName: 'Icon_camera.svg', - height: 24, - width: 24, + icon: StreamSvgIcon.camera( + size: 24, color: _filePickerIndex == 2 ? StreamChatTheme.of(context).accentColor : Colors.black.withOpacity(0.5), @@ -702,10 +687,8 @@ class MessageInputState extends State { }, ), IconButton( - icon: StreamSvgIcon( - assetName: 'Icon_record.svg', - height: 24, - width: 24, + icon: StreamSvgIcon.record( + size: 24, color: _filePickerIndex == 3 ? StreamChatTheme.of(context).accentColor : Colors.black.withOpacity(0.5), @@ -1000,8 +983,7 @@ class MessageInputState extends State { fontWeight: FontWeight.bold), ), subtitle: Text('@${m.userId}'), - trailing: StreamSvgIcon( - assetName: 'mentions.svg', + trailing: StreamSvgIcon.mentions( color: StreamChatTheme.of(context) .accentColor, ), @@ -1098,8 +1080,7 @@ class MessageInputState extends State { Padding( padding: const EdgeInsets.symmetric(horizontal: 8.0), - child: StreamSvgIcon( - assetName: 'Icon_smile.svg', + child: StreamSvgIcon.smile( color: StreamChatTheme.of(context).accentColor, ), ), @@ -1234,10 +1215,8 @@ class MessageInputState extends State { }, fillColor: Colors.black.withOpacity(.5), child: Center( - child: StreamSvgIcon( - assetName: 'Icon_close.svg', - height: 24, - width: 24, + child: StreamSvgIcon.close( + size: 24, color: Colors.white, ), ), @@ -1307,8 +1286,7 @@ class MessageInputState extends State { child: Padding( padding: const EdgeInsets.only(left: 4.0, right: 8.0, top: 8.0, bottom: 8.0), - child: StreamSvgIcon( - assetName: 'Icon_lightning-command runner.svg', + child: StreamSvgIcon.lightning( color: Color(0xFF000000).withAlpha(128), ), ), @@ -1331,8 +1309,7 @@ class MessageInputState extends State { child: Padding( padding: EdgeInsets.only(left: 8.0, right: padding, top: 8.0, bottom: 8.0), - child: StreamSvgIcon( - assetName: 'Icon_attach.svg', + child: StreamSvgIcon.attach( color: _openFilePickerSection ? StreamChatTheme.of(context).accentColor : Color(0xFF000000).withAlpha(128), diff --git a/lib/src/message_list_view.dart b/lib/src/message_list_view.dart index 2954f043..1be1d0aa 100644 --- a/lib/src/message_list_view.dart +++ b/lib/src/message_list_view.dart @@ -375,8 +375,7 @@ class _MessageListViewState extends State { children: [ FloatingActionButton( backgroundColor: Colors.white, - child: StreamSvgIcon( - assetName: 'Icon_down.svg', + child: StreamSvgIcon.down( color: Colors.black, ), onPressed: () { diff --git a/lib/src/stream_svg_icon.dart b/lib/src/stream_svg_icon.dart index c0cf5d72..6d97f2b6 100644 --- a/lib/src/stream_svg_icon.dart +++ b/lib/src/stream_svg_icon.dart @@ -39,4 +39,340 @@ class StreamSvgIcon extends StatelessWidget { alignment: Alignment.center, ); } + + factory StreamSvgIcon.settings({ + double size, + Color color, + }) { + return StreamSvgIcon( + assetName: 'settings.svg', + color: color, + width: size, + height: size, + ); + } + + factory StreamSvgIcon.down({ + double size, + Color color, + }) { + return StreamSvgIcon( + assetName: 'Icon_down.svg', + color: color, + width: size, + height: size, + ); + } + + factory StreamSvgIcon.attach({ + double size, + Color color, + }) { + return StreamSvgIcon( + assetName: 'Icon_attach.svg', + color: color, + width: size, + height: size, + ); + } + + factory StreamSvgIcon.smile({ + double size, + Color color, + }) { + return StreamSvgIcon( + assetName: 'Icon_smile.svg', + color: color, + width: size, + height: size, + ); + } + + factory StreamSvgIcon.mentions({ + double size, + Color color, + }) { + return StreamSvgIcon( + assetName: 'mentions.svg', + color: color, + width: size, + height: size, + ); + } + + factory StreamSvgIcon.record({ + double size, + Color color, + }) { + return StreamSvgIcon( + assetName: 'Icon_record.svg', + color: color, + width: size, + height: size, + ); + } + + factory StreamSvgIcon.camera({ + double size, + Color color, + }) { + return StreamSvgIcon( + assetName: 'Icon_camera.svg', + color: color, + width: size, + height: size, + ); + } + + factory StreamSvgIcon.files({ + double size, + Color color, + }) { + return StreamSvgIcon( + assetName: 'files.svg', + color: color, + width: size, + height: size, + ); + } + + factory StreamSvgIcon.pictures({ + double size, + Color color, + }) { + return StreamSvgIcon( + assetName: 'pictures.svg', + color: color, + width: size, + height: size, + ); + } + + factory StreamSvgIcon.left({ + double size, + Color color, + }) { + return StreamSvgIcon( + assetName: 'Icon_left.svg', + color: color, + width: size, + height: size, + ); + } + + factory StreamSvgIcon.user({ + double size, + Color color, + }) { + return StreamSvgIcon( + assetName: 'Icon_user.svg', + color: color, + width: size, + height: size, + ); + } + + factory StreamSvgIcon.userAdd({ + double size, + Color color, + }) { + return StreamSvgIcon( + assetName: 'Icon_User_add.svg', + color: color, + width: size, + height: size, + ); + } + + factory StreamSvgIcon.check({ + double size, + Color color, + }) { + return StreamSvgIcon( + assetName: 'Icon_check.svg', + color: color, + width: size, + height: size, + ); + } + + factory StreamSvgIcon.penWrite({ + double size, + Color color, + }) { + return StreamSvgIcon( + assetName: 'Icon_pen-write.svg', + color: color, + width: size, + height: size, + ); + } + + factory StreamSvgIcon.contacts({ + double size, + Color color, + }) { + return StreamSvgIcon( + assetName: 'Icon_contacts.svg', + color: color, + width: size, + height: size, + ); + } + + factory StreamSvgIcon.close({ + double size, + Color color, + }) { + return StreamSvgIcon( + assetName: 'Icon_close.svg', + color: color, + width: size, + height: size, + ); + } + + factory StreamSvgIcon.search({ + double size, + Color color, + }) { + return StreamSvgIcon( + assetName: 'Icon_search.svg', + color: color, + width: size, + height: size, + ); + } + + factory StreamSvgIcon.right({ + double size, + Color color, + }) { + return StreamSvgIcon( + assetName: 'Icon_right.svg', + color: color, + width: size, + height: size, + ); + } + + factory StreamSvgIcon.mute({ + double size, + Color color, + }) { + return StreamSvgIcon( + assetName: 'Icon_mute.svg', + color: color, + width: size, + height: size, + ); + } + + factory StreamSvgIcon.userRemove({ + double size, + Color color, + }) { + return StreamSvgIcon( + assetName: 'Icon_User_deselect.svg', + color: color, + width: size, + height: size, + ); + } + + factory StreamSvgIcon.lightning({ + double size, + Color color, + }) { + return StreamSvgIcon( + assetName: 'Icon_lightning-command runner.svg', + color: color, + width: size, + height: size, + ); + } + + factory StreamSvgIcon.emptyCircleLeft({ + double size, + Color color, + }) { + return StreamSvgIcon( + assetName: 'Icon_empty_circle_left.svg', + color: color, + width: size, + height: size, + ); + } + + factory StreamSvgIcon.message({ + double size, + Color color, + }) { + return StreamSvgIcon( + assetName: 'Icon_message.svg', + color: color, + width: size, + height: size, + ); + } + + factory StreamSvgIcon.thread({ + double size, + Color color, + }) { + return StreamSvgIcon( + assetName: 'Icon_Thread_Reply.svg', + color: color, + width: size, + height: size, + ); + } + + factory StreamSvgIcon.edit({ + double size, + Color color, + }) { + return StreamSvgIcon( + assetName: 'Icon_edit.svg', + color: color, + width: size, + height: size, + ); + } + + factory StreamSvgIcon.copy({ + double size, + Color color, + }) { + return StreamSvgIcon( + assetName: 'Icon_copy.svg', + color: color, + width: size, + height: size, + ); + } + + factory StreamSvgIcon.delete({ + double size, + Color color, + }) { + return StreamSvgIcon( + assetName: 'Icon_delete.svg', + color: color, + width: size, + height: size, + ); + } + + factory StreamSvgIcon.eye({ + double size, + Color color, + }) { + return StreamSvgIcon( + assetName: 'Icon_eye-off.svg', + color: color, + width: size, + height: size, + ); + } } diff --git a/lib/src/thread_header.dart b/lib/src/thread_header.dart index 9ad71a47..c6cce13e 100644 --- a/lib/src/thread_header.dart +++ b/lib/src/thread_header.dart @@ -86,10 +86,8 @@ class ThreadHeader extends StatelessWidget implements PreferredSizeWidget { aspectRatio: 1, child: IconButton( onPressed: onBackPressed, - icon: StreamSvgIcon( - assetName: 'Icon_close.svg', - height: 24, - width: 24, + icon: StreamSvgIcon.close( + size: 24, color: Theme.of(context).brightness == Brightness.dark ? Colors.white : Colors.black, diff --git a/lib/src/user_item.dart b/lib/src/user_item.dart index 8ddd3d99..03c275ac 100644 --- a/lib/src/user_item.dart +++ b/lib/src/user_item.dart @@ -74,10 +74,8 @@ class UserItem extends StatelessWidget { ), trailing: selected ? CircleAvatar( - child: StreamSvgIcon( - assetName: 'Icon_check.svg', - height: 20, - width: 20, + child: StreamSvgIcon.check( + size: 20, ), radius: 10, ) diff --git a/lib/svgs/Icon_camera.svg b/lib/svgs/Icon_camera.svg index 0bf3122d..a5a7d99d 100644 --- a/lib/svgs/Icon_camera.svg +++ b/lib/svgs/Icon_camera.svg @@ -1,3 +1,3 @@ - - + + diff --git a/lib/svgs/Icon_record.svg b/lib/svgs/Icon_record.svg index ff72859f..64d02895 100644 --- a/lib/svgs/Icon_record.svg +++ b/lib/svgs/Icon_record.svg @@ -1,3 +1,3 @@ - - + + From 987ad4e5baf4a9ec64880d9602ffaf97eacbb17b Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Tue, 24 Nov 2020 13:44:42 +0100 Subject: [PATCH 0467/1140] fix search icon --- lib/src/stream_svg_icon.dart | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/src/stream_svg_icon.dart b/lib/src/stream_svg_icon.dart index 6d97f2b6..2851df3a 100644 --- a/lib/src/stream_svg_icon.dart +++ b/lib/src/stream_svg_icon.dart @@ -25,7 +25,6 @@ class StreamSvgIcon extends StatelessWidget { height: height, key: key, color: color, - fit: BoxFit.cover, alignment: Alignment.center, ) : SvgPicture.asset( @@ -34,7 +33,6 @@ class StreamSvgIcon extends StatelessWidget { key: key, width: width, height: height, - fit: BoxFit.cover, color: color, alignment: Alignment.center, ); From 74e399bcc006900a1e5952f943f616c50366f512 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Tue, 24 Nov 2020 13:48:58 +0100 Subject: [PATCH 0468/1140] fix icons --- example/lib/group_chat_details_screen.dart | 6 ++++-- example/lib/new_group_chat_screen.dart | 1 + example/pubspec.yaml | 2 +- lib/src/user_item.dart | 1 + 4 files changed, 7 insertions(+), 3 deletions(-) diff --git a/example/lib/group_chat_details_screen.dart b/example/lib/group_chat_details_screen.dart index d11f377a..e8a88bac 100644 --- a/example/lib/group_chat_details_screen.dart +++ b/example/lib/group_chat_details_screen.dart @@ -105,8 +105,10 @@ class _GroupChatDetailsScreenState extends State { StreamNeumorphicButton( child: IconButton( padding: const EdgeInsets.all(0), - icon: StreamSvgIcon.check(), - color: Color(0xFF006CFF), + icon: StreamSvgIcon.check( + size: 24, + color: _isGroupNameEmpty ? Colors.grey : Color(0xFF006CFF), + ), onPressed: _isGroupNameEmpty ? null : () async { diff --git a/example/lib/new_group_chat_screen.dart b/example/lib/new_group_chat_screen.dart index 1db848a1..a11767c3 100644 --- a/example/lib/new_group_chat_screen.dart +++ b/example/lib/new_group_chat_screen.dart @@ -161,6 +161,7 @@ class _NewGroupChatScreenState extends State { child: Padding( padding: const EdgeInsets.all(0.0), child: StreamSvgIcon.close( + color: Colors.black, size: 24, ), ), diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 6e34335d..dab13883 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -1,6 +1,6 @@ name: example description: A new Flutter project. -version: 1.0.70+72 +version: 1.0.71+73 environment: sdk: ">=2.2.2 <3.0.0" diff --git a/lib/src/user_item.dart b/lib/src/user_item.dart index 03c275ac..f12e3e61 100644 --- a/lib/src/user_item.dart +++ b/lib/src/user_item.dart @@ -76,6 +76,7 @@ class UserItem extends StatelessWidget { ? CircleAvatar( child: StreamSvgIcon.check( size: 20, + color: Colors.white, ), radius: 10, ) From 2ee8b72a319d8357ac4709a1fc97c2e9ad745962 Mon Sep 17 00:00:00 2001 From: xsahil03x Date: Tue, 24 Nov 2020 21:45:42 +0530 Subject: [PATCH 0469/1140] [UserListView] Use LazyLoadScrollView for pagination rather than listening scroll controller --- lib/src/lazy_load_scroll_view.dart | 81 ++++++++++++++++++++++++++++ lib/src/user_list_view.dart | 86 +++++++++++++----------------- 2 files changed, 119 insertions(+), 48 deletions(-) create mode 100644 lib/src/lazy_load_scroll_view.dart diff --git a/lib/src/lazy_load_scroll_view.dart b/lib/src/lazy_load_scroll_view.dart new file mode 100644 index 00000000..e83fc777 --- /dev/null +++ b/lib/src/lazy_load_scroll_view.dart @@ -0,0 +1,81 @@ +import 'package:flutter/widgets.dart'; + +enum LoadingStatus { LOADING, STABLE } + +/// Signature for EndOfPageListeners +typedef EndOfPageListenerCallback = void Function(); + +/// A widget that wraps a [Widget] and will trigger [onEndOfPage] when it +/// reaches the bottom of the list +class LazyLoadScrollView extends StatefulWidget { + /// The [Widget] that this widget watches for changes on + final Widget child; + + /// Called when the [child] reaches the end of the list + final EndOfPageListenerCallback onEndOfPage; + + /// The offset to take into account when triggering [onEndOfPage] in pixels + final int scrollOffset; + + /// Used to determine if loading of new data has finished. You should use set this if you aren't using a FutureBuilder or StreamBuilder + final bool isLoading; + + LazyLoadScrollView({ + Key key, + @required this.child, + @required this.onEndOfPage, + this.isLoading = false, + this.scrollOffset = 100, + }) : assert(onEndOfPage != null), + assert(child != null), + super(key: key); + + @override + State createState() => _LazyLoadScrollViewState(); +} + +class _LazyLoadScrollViewState extends State { + LoadingStatus _loadMoreStatus = LoadingStatus.STABLE; + + @override + void didUpdateWidget(LazyLoadScrollView oldWidget) { + super.didUpdateWidget(oldWidget); + if (!widget.isLoading) { + _loadMoreStatus = LoadingStatus.STABLE; + } + } + + @override + Widget build(BuildContext context) { + return NotificationListener( + child: widget.child, + onNotification: _onNotification, + ); + } + + bool _onNotification(Notification notification) { + if (notification is ScrollUpdateNotification) { + if (notification.metrics.maxScrollExtent > notification.metrics.pixels && + notification.metrics.maxScrollExtent - notification.metrics.pixels <= + widget.scrollOffset) { + if (_loadMoreStatus != null && + _loadMoreStatus == LoadingStatus.STABLE) { + _loadMoreStatus = LoadingStatus.LOADING; + widget.onEndOfPage(); + } + } + return true; + } + if (notification is OverscrollNotification) { + if (notification.overscroll > 0) { + if (_loadMoreStatus != null && + _loadMoreStatus == LoadingStatus.STABLE) { + _loadMoreStatus = LoadingStatus.LOADING; + widget.onEndOfPage(); + } + } + return true; + } + return false; + } +} diff --git a/lib/src/user_list_view.dart b/lib/src/user_list_view.dart index 046ad9c7..569eb38a 100644 --- a/lib/src/user_list_view.dart +++ b/lib/src/user_list_view.dart @@ -2,6 +2,7 @@ import 'dart:convert'; import 'package:flutter/material.dart'; import 'package:stream_chat/stream_chat.dart'; +import 'package:stream_chat_flutter/src/lazy_load_scroll_view.dart'; import 'package:stream_chat_flutter/src/users_bloc.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; @@ -144,8 +145,6 @@ class UserListView extends StatefulWidget { class _UserListViewState extends State with WidgetsBindingObserver { - final ScrollController _scrollController = ScrollController(); - bool get _isListView => widget.crossAxisCount == 1; @override @@ -158,14 +157,6 @@ class _UserListViewState extends State pagination: widget.pagination, options: widget.options, ); - - _scrollController.addListener(() { - usersBloc.queryUsersLoading.first.then((loading) { - if (!loading) { - _listenUserPagination(usersBloc); - } - }); - }); } @override @@ -327,32 +318,35 @@ class _UserListViewState extends State ); } - if (_isListView) { - return ListView.separated( - physics: AlwaysScrollableScrollPhysics(), - controller: _scrollController, - itemCount: items.isNotEmpty ? items.length + 1 : items.length, - separatorBuilder: (_, index) { - if (widget.separatorBuilder != null) { - return widget.separatorBuilder(context, index); - } - return _separatorBuilder(context, index); - }, - itemBuilder: (context, index) { - return _listItemBuilder(context, index, items); - }, - ); - } - return GridView.builder( - gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( - crossAxisCount: widget.crossAxisCount, - ), - itemCount: items.isNotEmpty ? items.length + 1 : items.length, - physics: AlwaysScrollableScrollPhysics(), - controller: _scrollController, - itemBuilder: (context, index) { - return _gridItemBuilder(context, index, items); - }, + final child = _isListView + ? ListView.separated( + physics: AlwaysScrollableScrollPhysics(), + // controller: _scrollController, + itemCount: items.isNotEmpty ? items.length + 1 : items.length, + separatorBuilder: (_, index) { + if (widget.separatorBuilder != null) { + return widget.separatorBuilder(context, index); + } + return _separatorBuilder(context, index); + }, + itemBuilder: (context, index) { + return _listItemBuilder(context, index, items); + }, + ) + : GridView.builder( + gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: widget.crossAxisCount, + ), + itemCount: items.isNotEmpty ? items.length + 1 : items.length, + physics: AlwaysScrollableScrollPhysics(), + itemBuilder: (context, index) { + return _gridItemBuilder(context, index, items); + }, + ); + + return LazyLoadScrollView( + onEndOfPage: () => _listenUserPagination(usersBlocState), + child: child, ); }, ); @@ -488,18 +482,14 @@ class _UserListViewState extends State } void _listenUserPagination(UsersBlocState usersProvider) { - if (_scrollController.position.maxScrollExtent == - _scrollController.offset && - _scrollController.offset != 0) { - usersProvider.queryUsers( - filter: widget.filter, - sort: widget.sort, - pagination: widget.pagination.copyWith( - offset: usersProvider.users?.length ?? 0, - ), - options: widget.options, - ); - } + usersProvider.queryUsers( + filter: widget.filter, + sort: widget.sort, + pagination: widget.pagination.copyWith( + offset: usersProvider.users?.length ?? 0, + ), + options: widget.options, + ); } @override From fbc279f9dd900dd52cc00ed2f3f7baf0daf74d96 Mon Sep 17 00:00:00 2001 From: xsahil03x Date: Tue, 24 Nov 2020 21:46:31 +0530 Subject: [PATCH 0470/1140] [NewGroupChatScreen] Float selected users and searchField when list is scrolling. --- example/lib/new_group_chat_screen.dart | 498 ++++++++++++++----------- 1 file changed, 273 insertions(+), 225 deletions(-) diff --git a/example/lib/new_group_chat_screen.dart b/example/lib/new_group_chat_screen.dart index 3c6ad2ba..f9cf1cba 100644 --- a/example/lib/new_group_chat_screen.dart +++ b/example/lib/new_group_chat_screen.dart @@ -24,11 +24,12 @@ class _NewGroupChatScreenState extends State { void _userNameListener() { if (_debounce?.isActive ?? false) _debounce.cancel(); _debounce = Timer(const Duration(milliseconds: 350), () { - if (mounted) + if (mounted) { setState(() { _userNameQuery = _controller.text; _isSearchActive = _userNameQuery.isNotEmpty; }); + } }); } @@ -46,247 +47,294 @@ class _NewGroupChatScreenState extends State { super.dispose(); } - @override Widget build(BuildContext context) { - return Scaffold( - backgroundColor: Color.fromRGBO(252, 252, 252, 1), - appBar: AppBar( - elevation: 1, - backgroundColor: Colors.white, - leading: const StreamBackButton(), - title: Text( - 'Add Group Members', - style: TextStyle( - color: Colors.black, - fontSize: 16, - ), - ), - centerTitle: true, - actions: [ - if (_selectedUsers.isNotEmpty) - IconButton( - icon: Icon( - StreamIcons.arrow_right, - color: Color(0xFF006CFF), - ), - onPressed: () async { - final updatedList = await Navigator.push( - context, - MaterialPageRoute( - builder: (_) => GroupChatDetailsScreen( - selectedUsers: _selectedUsers.toList(growable: false), + return SafeArea( + child: UsersBloc( + child: Scaffold( + body: NestedScrollView( + floatHeaderSlivers: true, + headerSliverBuilder: + (BuildContext context, bool innerBoxIsScrolled) { + return [ + SliverAppBar( + // floating: true, + pinned: true, + forceElevated: true, + elevation: 1, + backgroundColor: Colors.white, + leading: const StreamBackButton(), + title: Text( + 'Add Group Members', + style: TextStyle( + color: Colors.black, + fontSize: 16, ), ), - ); - if (updatedList != null) { + centerTitle: true, + actions: [ + if (_selectedUsers.isNotEmpty) + IconButton( + icon: Icon( + StreamIcons.arrow_right, + color: Color(0xFF006CFF), + ), + onPressed: () async { + final updatedList = await Navigator.push( + context, + MaterialPageRoute( + builder: (_) => GroupChatDetailsScreen( + selectedUsers: + _selectedUsers.toList(growable: false), + ), + ), + ); + if (updatedList != null) { + setState(() { + _selectedUsers + ..clear() + ..addAll(updatedList); + }); + } + }, + ) + ], + ), + SliverToBoxAdapter( + child: Container( + height: 36, + decoration: BoxDecoration( + color: Colors.white, + border: Border.all( + color: Colors.grey.shade300, + ), + borderRadius: BorderRadius.circular(24), + ), + margin: const EdgeInsets.symmetric( + vertical: 8, + horizontal: 8, + ), + child: TextField( + controller: _controller, + decoration: InputDecoration( + prefixIcon: Icon( + StreamIcons.search, + color: Colors.black, + size: 24, + ), + hintText: 'Search', + hintStyle: TextStyle( + color: Colors.black.withOpacity(0.5), + fontSize: 14, + ), + contentPadding: const EdgeInsets.all(0), + border: OutlineInputBorder( + borderSide: BorderSide.none, + borderRadius: BorderRadius.circular(24), + ), + ), + ), + ), + ), + if (_selectedUsers.isNotEmpty) + SliverToBoxAdapter( + child: Container( + height: 104, + child: ListView.separated( + scrollDirection: Axis.horizontal, + itemCount: _selectedUsers.length, + padding: const EdgeInsets.all(8), + separatorBuilder: (_, __) => SizedBox(width: 16), + itemBuilder: (_, index) { + final user = _selectedUsers.elementAt(index); + return Column( + children: [ + Stack( + children: [ + UserAvatar( + onlineIndicatorAlignment: + Alignment(0.9, 0.9), + user: user, + showOnlineStatus: true, + borderRadius: BorderRadius.circular(32), + constraints: BoxConstraints.tightFor( + height: 64, + width: 64, + ), + ), + Positioned( + top: -4, + right: -4, + child: GestureDetector( + onTap: () { + if (_selectedUsers.contains(user)) { + setState(() => + _selectedUsers.remove(user)); + } + }, + child: Container( + decoration: BoxDecoration( + color: Colors.white, + shape: BoxShape.circle, + border: Border.all( + color: Colors.grey.shade100, + ), + ), + child: Padding( + padding: const EdgeInsets.all(0.0), + child: Icon( + StreamIcons.close, + size: 24, + ), + ), + ), + ), + ) + ], + ), + SizedBox(height: 4), + Text( + user.name.split(' ')[0], + style: TextStyle( + fontWeight: FontWeight.bold, + fontSize: 12, + ), + ), + ], + ); + }, + ), + ), + ), + SliverPersistentHeader( + pinned: true, + delegate: _HeaderDelegate( + height: 30, + child: Container( + width: double.maxFinite, + decoration: BoxDecoration( + gradient: LinearGradient( + begin: Alignment.centerLeft, + end: Alignment.centerRight, + colors: [ + Colors.black.withOpacity(0.02), + Colors.white.withOpacity(0.05), + ], + stops: [0, 1], + ), + ), + child: Padding( + padding: const EdgeInsets.symmetric( + vertical: 8, + horizontal: 8, + ), + child: Text( + _isSearchActive + ? 'Matches for \"$_userNameQuery\"' + : 'On the platform', + style: TextStyle( + color: Colors.black.withOpacity(0.5), + ), + ), + ), + ), + ), + ), + ]; + }, + body: UserListView( + selectedUsers: _selectedUsers, + pullToRefresh: false, + groupAlphabetically: _isSearchActive ? false : true, + onUserTap: (user, _) { + if (!_selectedUsers.contains(user)) { setState(() { - _selectedUsers - ..clear() - ..addAll(updatedList); + _selectedUsers.add(user); + }); + } else { + setState(() { + _selectedUsers.remove(user); }); } }, - ) - ], - ), - body: UsersBloc( - child: Column( - children: [ - Container( - height: 36, - decoration: BoxDecoration( - color: Colors.white, - border: Border.all( - color: Colors.grey.shade300, + pagination: PaginationParams( + limit: 25, + ), + filter: { + if (_userNameQuery.isNotEmpty) + 'name': { + r'$autocomplete': _userNameQuery, + }, + 'id': { + r'$ne': StreamChat.of(context).user.id, + } + }, + sort: [ + SortOption( + 'name', + direction: 1, ), - borderRadius: BorderRadius.circular(24), - ), - margin: const EdgeInsets.symmetric( - vertical: 8, - horizontal: 8, - ), - child: TextField( - controller: _controller, - decoration: InputDecoration( - prefixIcon: Icon( - StreamIcons.search, - color: Colors.black, - size: 24, - ), - hintText: 'Search', - hintStyle: TextStyle( - color: Colors.black.withOpacity(0.5), - fontSize: 14, - ), - contentPadding: const EdgeInsets.all(0), - border: OutlineInputBorder( - borderSide: BorderSide.none, - borderRadius: BorderRadius.circular(24), - ), - ), - ), - ), - if (_selectedUsers.isNotEmpty) - Container( - height: 104, - child: ListView.separated( - scrollDirection: Axis.horizontal, - itemCount: _selectedUsers.length, - padding: const EdgeInsets.all(8), - separatorBuilder: (_, __) => SizedBox(width: 16), - itemBuilder: (_, index) { - final user = _selectedUsers.elementAt(index); - return Column( - children: [ - Stack( - children: [ - UserAvatar( - onlineIndicatorAlignment: Alignment(0.9, 0.9), - user: user, - showOnlineStatus: true, - borderRadius: BorderRadius.circular(32), - constraints: BoxConstraints.tightFor( - height: 64, - width: 64, - ), - ), - Positioned( - top: -4, - right: -4, - child: GestureDetector( - onTap: () { - if (_selectedUsers.contains(user)) { - setState(() => _selectedUsers.remove(user)); - } - }, - child: Container( - decoration: BoxDecoration( - color: Colors.white, - shape: BoxShape.circle, - border: Border.all( - color: Colors.grey.shade100, - ), - ), - child: Padding( - padding: const EdgeInsets.all(0.0), - child: Icon( - StreamIcons.close, - size: 24, - ), - ), + ], + emptyBuilder: (_) { + return LayoutBuilder( + builder: (context, viewportConstraints) { + return SingleChildScrollView( + physics: AlwaysScrollableScrollPhysics(), + child: ConstrainedBox( + constraints: BoxConstraints( + minHeight: viewportConstraints.maxHeight, + ), + child: Center( + child: Column( + children: [ + Padding( + padding: const EdgeInsets.all(24), + child: Icon( + StreamIcons.search, + size: 96, + color: Colors.grey, ), ), - ) - ], - ), - SizedBox(height: 4), - Text( - user.name.split(' ')[0], - style: TextStyle( - fontWeight: FontWeight.bold, - fontSize: 12, + Text('No user matches these keywords...'), + ], ), ), - ], + ), ); }, - ), - ), - Container( - width: double.maxFinite, - decoration: BoxDecoration( - gradient: LinearGradient( - begin: Alignment.centerLeft, - end: Alignment.centerRight, - colors: [ - Colors.black.withOpacity(0.02), - Colors.white.withOpacity(0.05), - ], - stops: [0, 1], - ), - ), - child: Padding( - padding: const EdgeInsets.symmetric( - vertical: 8, - horizontal: 8, - ), - child: Text( - _isSearchActive - ? 'Matches for \"$_userNameQuery\"' - : 'On the platform', - style: TextStyle( - color: Colors.black.withOpacity(0.5), - ), - ), - ), + ); + }, ), - Expanded( - child: UserListView( - selectedUsers: _selectedUsers, - groupAlphabetically: _isSearchActive ? false : true, - onUserTap: (user, _) { - if (!_selectedUsers.contains(user)) { - setState(() { - _selectedUsers.add(user); - }); - } else { - setState(() { - _selectedUsers.remove(user); - }); - } - }, - pagination: PaginationParams( - limit: 25, - ), - filter: { - if (_userNameQuery.isNotEmpty) - 'name': { - r'$autocomplete': _userNameQuery, - }, - 'id': { - r'$ne': StreamChat.of(context).user.id, - } - }, - sort: [ - SortOption( - 'name', - direction: 1, - ), - ], - emptyBuilder: (_) { - return LayoutBuilder( - builder: (context, viewportConstraints) { - return SingleChildScrollView( - physics: AlwaysScrollableScrollPhysics(), - child: ConstrainedBox( - constraints: BoxConstraints( - minHeight: viewportConstraints.maxHeight, - ), - child: Center( - child: Column( - children: [ - Padding( - padding: const EdgeInsets.all(24), - child: Icon( - StreamIcons.search, - size: 96, - color: Colors.grey, - ), - ), - Text('No user matches these keywords...'), - ], - ), - ), - ), - ); - }, - ); - }, - ), - ), - ], + ), ), ), ); } } + +class _HeaderDelegate extends SliverPersistentHeaderDelegate { + final Widget child; + final double height; + + const _HeaderDelegate({ + @required this.child, + @required this.height, + }); + + @override + Widget build( + BuildContext context, double shrinkOffset, bool overlapsContent) { + return Container( + color: Colors.white, + child: child, + ); + } + + @override + double get maxExtent => height; + + @override + double get minExtent => height; + + @override + bool shouldRebuild(_HeaderDelegate oldDelegate) => true; +} From dc7a436e96730405621e659a70d9ffbd23c2362b Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Tue, 24 Nov 2020 17:59:33 +0100 Subject: [PATCH 0471/1140] align with master --- example/ios/Podfile.lock | 2 +- example/pubspec.yaml | 2 +- lib/src/message_input.dart | 38 ++++++++++++++++++++++++-------------- 3 files changed, 26 insertions(+), 16 deletions(-) diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock index 131e8aec..29b026b2 100644 --- a/example/ios/Podfile.lock +++ b/example/ios/Podfile.lock @@ -284,4 +284,4 @@ SPEC CHECKSUMS: PODFILE CHECKSUM: eb001256612a59f8f9e4d083ad8b9671e69dd184 -COCOAPODS: 1.10.0.rc.1 +COCOAPODS: 1.10.0 diff --git a/example/pubspec.yaml b/example/pubspec.yaml index dab13883..43eb867e 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -1,6 +1,6 @@ name: example description: A new Flutter project. -version: 1.0.71+73 +version: 1.0.72+74 environment: sdk: ">=2.2.2 <3.0.0" diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 4b634ab7..b4c79033 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -428,26 +428,36 @@ class MessageInputState extends State { ); } + Timer _debounce; void _onChanged(BuildContext context, String s) { - StreamChannel.of(context).channel.keyStroke().catchError((e) {}); + if (_debounce?.isActive == true) _debounce.cancel(); + _debounce = Timer( + const Duration(milliseconds: 350), + () { + if (!mounted) { + return; + } + StreamChannel.of(context).channel.keyStroke().catchError((e) {}); - setState(() { - _messageIsPresent = s.trim().isNotEmpty; - _actionsShrunk = s.trim().isNotEmpty; - }); + setState(() { + _messageIsPresent = s.trim().isNotEmpty; + _actionsShrunk = s.trim().isNotEmpty; + }); - _commandsOverlay?.remove(); - _commandsOverlay = null; - _mentionsOverlay?.remove(); - _mentionsOverlay = null; - _emojiOverlay?.remove(); - _emojiOverlay = null; + _commandsOverlay?.remove(); + _commandsOverlay = null; + _mentionsOverlay?.remove(); + _mentionsOverlay = null; + _emojiOverlay?.remove(); + _emojiOverlay = null; - _checkCommands(s.trim(), context); + _checkCommands(s.trim(), context); - _checkMentions(s, context); + _checkMentions(s, context); - _checkEmoji(s, context); + _checkEmoji(s, context); + }, + ); } String _getHint() { From 3cda66a255f7a70d6aa57f8ba2fa1f2133ad1ce8 Mon Sep 17 00:00:00 2001 From: xsahil03x Date: Wed, 25 Nov 2020 11:41:07 +0530 Subject: [PATCH 0472/1140] Minor merge fixes --- example/lib/group_chat_details_screen.dart | 314 ++++++++++--------- example/lib/new_group_chat_screen.dart | 344 ++++++++++----------- 2 files changed, 331 insertions(+), 327 deletions(-) diff --git a/example/lib/group_chat_details_screen.dart b/example/lib/group_chat_details_screen.dart index 050ea993..fc8a6890 100644 --- a/example/lib/group_chat_details_screen.dart +++ b/example/lib/group_chat_details_screen.dart @@ -52,169 +52,175 @@ class _GroupChatDetailsScreenState extends State { @override Widget build(BuildContext context) { - return Scaffold( - backgroundColor: Color.fromRGBO(252, 252, 252, 1), - appBar: AppBar( - elevation: 1, - backgroundColor: Colors.white, - leading: const StreamBackButton(), - title: Text( - 'Name of Group Chat', - style: TextStyle( - color: Colors.black, - fontSize: 16, - ), - ), - centerTitle: true, - bottom: PreferredSize( - preferredSize: Size.fromHeight(kToolbarHeight), - child: Padding( - padding: const EdgeInsets.symmetric(vertical: 18, horizontal: 16), - child: Row( - children: [ - Text( - 'NAME', - style: TextStyle( - fontSize: 12, - color: Colors.black.withOpacity(0.5), - ), - ), - SizedBox(width: 16), - Expanded( - child: TextField( - controller: _groupNameController, - decoration: InputDecoration( - isDense: true, - border: InputBorder.none, - focusedBorder: InputBorder.none, - enabledBorder: InputBorder.none, - errorBorder: InputBorder.none, - disabledBorder: InputBorder.none, - contentPadding: const EdgeInsets.all(0), - hintText: 'Choose a group chat name', - hintStyle: TextStyle( - fontSize: 14, color: Colors.black.withOpacity(.5)), - ), - ), - ), - ], + return WillPopScope( + onWillPop: () async { + Navigator.pop(context, _selectedUsers); + return false; + }, + child: Scaffold( + backgroundColor: Color.fromRGBO(252, 252, 252, 1), + appBar: AppBar( + elevation: 1, + backgroundColor: Colors.white, + leading: const StreamBackButton(), + title: Text( + 'Name of Group Chat', + style: TextStyle( + color: Colors.black, + fontSize: 16, ), ), - ), - actions: [ - NeumorphicButton( - child: IconButton( - padding: const EdgeInsets.all(0), - icon: StreamSvgIcon.check( - size: 24, - color: _isGroupNameEmpty ? Colors.grey : Color(0xFF006CFF), - ), - onPressed: _isGroupNameEmpty - ? null - : () async { - final groupName = _groupNameController.text; - final client = StreamChat.of(context).client; - final channel = client - .channel('messaging', id: Uuid().v4(), extraData: { - 'members': [ - client.state.user.id, - ..._selectedUsers.map((e) => e.id), - ], - 'name': groupName, - }); - await channel.watch(); - Navigator.of(context) - ..pop() - ..pushReplacement( - MaterialPageRoute( - builder: (context) { - return StreamChannel( - child: ChannelPage(), - channel: channel, - ); - }, - ), - ); - }, - ), - ), - ], - ), - body: Column( - children: [ - Container( - width: double.maxFinite, - color: Colors.grey.shade50, + centerTitle: true, + bottom: PreferredSize( + preferredSize: Size.fromHeight(kToolbarHeight), child: Padding( - padding: const EdgeInsets.symmetric( - vertical: 8, - horizontal: 8, + padding: const EdgeInsets.symmetric(vertical: 18, horizontal: 16), + child: Row( + children: [ + Text( + 'NAME', + style: TextStyle( + fontSize: 12, + color: Colors.black.withOpacity(0.5), + ), + ), + SizedBox(width: 16), + Expanded( + child: TextField( + controller: _groupNameController, + decoration: InputDecoration( + isDense: true, + border: InputBorder.none, + focusedBorder: InputBorder.none, + enabledBorder: InputBorder.none, + errorBorder: InputBorder.none, + disabledBorder: InputBorder.none, + contentPadding: const EdgeInsets.all(0), + hintText: 'Choose a group chat name', + hintStyle: TextStyle( + fontSize: 14, color: Colors.black.withOpacity(.5)), + ), + ), + ), + ], ), - child: Text( - '$_totalUsers ${_totalUsers > 1 ? 'Members' : 'Member'}', - style: TextStyle( - fontWeight: FontWeight.w500, + ), + ), + actions: [ + StreamNeumorphicButton( + child: IconButton( + padding: const EdgeInsets.all(0), + icon: StreamSvgIcon.check( + size: 24, + color: _isGroupNameEmpty ? Colors.grey : Color(0xFF006CFF), + ), + onPressed: _isGroupNameEmpty + ? null + : () async { + final groupName = _groupNameController.text; + final client = StreamChat.of(context).client; + final channel = client + .channel('messaging', id: Uuid().v4(), extraData: { + 'members': [ + client.state.user.id, + ..._selectedUsers.map((e) => e.id), + ], + 'name': groupName, + }); + await channel.watch(); + Navigator.of(context) + ..pop() + ..pushReplacement( + MaterialPageRoute( + builder: (context) { + return StreamChannel( + child: ChannelPage(), + channel: channel, + ); + }, + ), + ); + }, + ), + ), + ], + ), + body: Column( + children: [ + Container( + width: double.maxFinite, + color: Colors.grey.shade50, + child: Padding( + padding: const EdgeInsets.symmetric( + vertical: 8, + horizontal: 8, + ), + child: Text( + '$_totalUsers ${_totalUsers > 1 ? 'Members' : 'Member'}', + style: TextStyle( + fontWeight: FontWeight.w500, + ), ), ), ), - ), - Expanded( - child: ListView.separated( - itemCount: _selectedUsers.length + 1, - separatorBuilder: (_, __) => Container( - height: 1, - color: Theme.of(context).brightness == Brightness.dark - ? Colors.white.withOpacity(0.1) - : Colors.black.withOpacity(0.1), - ), - itemBuilder: (_, index) { - if (index == _selectedUsers.length) { - return Container( - height: 1, - color: Theme.of(context).brightness == Brightness.dark - ? Colors.white.withOpacity(0.1) - : Colors.black.withOpacity(0.1), + Expanded( + child: ListView.separated( + itemCount: _selectedUsers.length + 1, + separatorBuilder: (_, __) => Container( + height: 1, + color: Theme.of(context).brightness == Brightness.dark + ? Colors.white.withOpacity(0.1) + : Colors.black.withOpacity(0.1), + ), + itemBuilder: (_, index) { + if (index == _selectedUsers.length) { + return Container( + height: 1, + color: Theme.of(context).brightness == Brightness.dark + ? Colors.white.withOpacity(0.1) + : Colors.black.withOpacity(0.1), + ); + } + final user = _selectedUsers[index]; + return ListTile( + key: ObjectKey(user), + leading: UserAvatar( + user: user, + constraints: BoxConstraints.tightFor( + width: 40, + height: 40, + ), + ), + title: Text( + user.name, + style: TextStyle(fontWeight: FontWeight.bold), + ), + contentPadding: const EdgeInsets.symmetric( + horizontal: 12, + vertical: 8, + ), + trailing: IconButton( + icon: Icon( + Icons.clear_rounded, + color: Colors.black, + ), + padding: const EdgeInsets.all(0), + splashRadius: 24, + onPressed: () { + setState(() { + _selectedUsers.remove(user); + }); + if (_selectedUsers.isEmpty) { + Navigator.pop(context, _selectedUsers); + } + }, + ), ); - } - final user = _selectedUsers[index]; - return ListTile( - key: ObjectKey(user), - leading: UserAvatar( - user: user, - constraints: BoxConstraints.tightFor( - width: 40, - height: 40, - ), - ), - title: Text( - user.name, - style: TextStyle(fontWeight: FontWeight.bold), - ), - contentPadding: const EdgeInsets.symmetric( - horizontal: 12, - vertical: 8, - ), - trailing: IconButton( - icon: Icon( - Icons.clear_rounded, - color: Colors.black, - ), - padding: const EdgeInsets.all(0), - splashRadius: 24, - onPressed: () { - setState(() { - _selectedUsers.remove(user); - }); - if (_selectedUsers.isEmpty) { - Navigator.pop(context); - } - }, - ), - ); - }, + }, + ), ), - ), - ], + ], + ), ), ); } diff --git a/example/lib/new_group_chat_screen.dart b/example/lib/new_group_chat_screen.dart index 003aa431..1587c464 100644 --- a/example/lib/new_group_chat_screen.dart +++ b/example/lib/new_group_chat_screen.dart @@ -50,198 +50,196 @@ class _NewGroupChatScreenState extends State { @override Widget build(BuildContext context) { return SafeArea( - child: UsersBloc( - child: Scaffold( - backgroundColor: Color.fromRGBO(252, 252, 252, 1), - body: NestedScrollView( - floatHeaderSlivers: true, - headerSliverBuilder: - (BuildContext context, bool innerBoxIsScrolled) { - return [ - SliverAppBar( - // floating: true, - pinned: true, - forceElevated: true, - elevation: 1, - backgroundColor: Colors.white, - leading: const StreamBackButton(), - title: Text( - 'Add Group Members', - style: TextStyle( - color: Colors.black, - fontSize: 16, + child: Scaffold( + backgroundColor: Color.fromRGBO(252, 252, 252, 1), + body: NestedScrollView( + floatHeaderSlivers: true, + headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) { + return [ + SliverAppBar( + // floating: true, + pinned: true, + forceElevated: true, + elevation: 1, + backgroundColor: Colors.white, + leading: const StreamBackButton(), + title: Text( + 'Add Group Members', + style: TextStyle( + color: Colors.black, + fontSize: 16, + ), + ), + centerTitle: true, + actions: [ + if (_selectedUsers.isNotEmpty) + IconButton( + icon: StreamSvgIcon.right( + color: Color(0xFF006CFF), + ), + onPressed: () async { + final updatedList = await Navigator.push( + context, + MaterialPageRoute( + builder: (_) => GroupChatDetailsScreen( + selectedUsers: + _selectedUsers.toList(growable: false), + ), + ), + ); + if (updatedList != null) { + setState(() { + _selectedUsers + ..clear() + ..addAll(updatedList); + }); + } + }, + ) + ], + ), + SliverToBoxAdapter( + child: Container( + height: 36, + decoration: BoxDecoration( + color: Colors.white, + border: Border.all( + color: Colors.grey.shade300, + ), + borderRadius: BorderRadius.circular(24), + ), + margin: const EdgeInsets.symmetric( + vertical: 8, + horizontal: 8, + ), + child: TextField( + controller: _controller, + decoration: InputDecoration( + prefixIcon: StreamSvgIcon.search( + color: Colors.black, + size: 24, + ), + hintText: 'Search', + hintStyle: TextStyle( + color: Colors.black.withOpacity(0.5), + fontSize: 14, + ), + contentPadding: const EdgeInsets.all(0), + border: OutlineInputBorder( + borderSide: BorderSide.none, + borderRadius: BorderRadius.circular(24), + ), ), ), - centerTitle: true, - actions: [ - if (_selectedUsers.isNotEmpty) - IconButton( - icon: StreamSvgIcon.right( - color: Color(0xFF006CFF), - ), - onPressed: () async { - final updatedList = await Navigator.push( - context, - MaterialPageRoute( - builder: (_) => GroupChatDetailsScreen( - selectedUsers: - _selectedUsers.toList(growable: false), - ), - ), - ); - if (updatedList != null) { - setState(() { - _selectedUsers - ..clear() - ..addAll(updatedList); - }); - } - }, - ) - ], ), + ), + if (_selectedUsers.isNotEmpty) SliverToBoxAdapter( child: Container( - height: 36, - decoration: BoxDecoration( - color: Colors.white, - border: Border.all( - color: Colors.grey.shade300, - ), - borderRadius: BorderRadius.circular(24), - ), - margin: const EdgeInsets.symmetric( - vertical: 8, - horizontal: 8, - ), - child: TextField( - controller: _controller, - decoration: InputDecoration( - prefixIcon: StreamSvgIcon.search( - color: Colors.black, - size: 24, - ), - hintText: 'Search', - hintStyle: TextStyle( - color: Colors.black.withOpacity(0.5), - fontSize: 14, - ), - contentPadding: const EdgeInsets.all(0), - border: OutlineInputBorder( - borderSide: BorderSide.none, - borderRadius: BorderRadius.circular(24), - ), - ), - ), - ), - ), - if (_selectedUsers.isNotEmpty) - SliverToBoxAdapter( - child: Container( - height: 104, - child: ListView.separated( - scrollDirection: Axis.horizontal, - itemCount: _selectedUsers.length, - padding: const EdgeInsets.all(8), - separatorBuilder: (_, __) => SizedBox(width: 16), - itemBuilder: (_, index) { - final user = _selectedUsers.elementAt(index); - return Column( - children: [ - Stack( - children: [ - UserAvatar( - onlineIndicatorAlignment: - Alignment(0.9, 0.9), - user: user, - showOnlineStatus: true, - borderRadius: BorderRadius.circular(32), - constraints: BoxConstraints.tightFor( - height: 64, - width: 64, - ), + height: 104, + child: ListView.separated( + scrollDirection: Axis.horizontal, + itemCount: _selectedUsers.length, + padding: const EdgeInsets.all(8), + separatorBuilder: (_, __) => SizedBox(width: 16), + itemBuilder: (_, index) { + final user = _selectedUsers.elementAt(index); + return Column( + children: [ + Stack( + children: [ + UserAvatar( + onlineIndicatorAlignment: Alignment(0.9, 0.9), + user: user, + showOnlineStatus: true, + borderRadius: BorderRadius.circular(32), + constraints: BoxConstraints.tightFor( + height: 64, + width: 64, ), - Positioned( - top: -4, - right: -4, - child: GestureDetector( - onTap: () { - if (_selectedUsers.contains(user)) { - setState(() => - _selectedUsers.remove(user)); - } - }, - child: Container( - decoration: BoxDecoration( - color: Colors.white, - shape: BoxShape.circle, - border: Border.all( - color: Colors.grey.shade100, - ), + ), + Positioned( + top: -4, + right: -4, + child: GestureDetector( + onTap: () { + if (_selectedUsers.contains(user)) { + setState( + () => _selectedUsers.remove(user)); + } + }, + child: Container( + decoration: BoxDecoration( + color: Colors.white, + shape: BoxShape.circle, + border: Border.all( + color: Colors.grey.shade100, ), - child: Padding( - padding: const EdgeInsets.all(0.0), - child: StreamSvgIcon.close( - color: Colors.black, - size: 24, - ), + ), + child: Padding( + padding: const EdgeInsets.all(0.0), + child: StreamSvgIcon.close( + color: Colors.black, + size: 24, ), ), ), - ) - ], + ), + ) + ], + ), + SizedBox(height: 4), + Text( + user.name.split(' ')[0], + style: TextStyle( + fontWeight: FontWeight.bold, + fontSize: 12, ), - SizedBox(height: 4), - Text( - user.name.split(' ')[0], - style: TextStyle( - fontWeight: FontWeight.bold, - fontSize: 12, - ), - ), - ], - ); - }, - ), + ), + ], + ); + }, ), ), - SliverPersistentHeader( - pinned: true, - delegate: _HeaderDelegate( - height: 30, - child: Container( - width: double.maxFinite, - decoration: BoxDecoration( - gradient: LinearGradient( - begin: Alignment.centerLeft, - end: Alignment.centerRight, - colors: [ - Colors.black.withOpacity(0.02), - Colors.white.withOpacity(0.05), - ], - stops: [0, 1], - ), + ), + SliverPersistentHeader( + pinned: true, + delegate: _HeaderDelegate( + height: 30, + child: Container( + width: double.maxFinite, + decoration: BoxDecoration( + gradient: LinearGradient( + begin: Alignment.centerLeft, + end: Alignment.centerRight, + colors: [ + Colors.black.withOpacity(0.02), + Colors.white.withOpacity(0.05), + ], + stops: [0, 1], ), - child: Padding( - padding: const EdgeInsets.symmetric( - vertical: 8, - horizontal: 8, - ), - child: Text( - _isSearchActive - ? 'Matches for \"$_userNameQuery\"' - : 'On the platform', - style: TextStyle( - color: Colors.black.withOpacity(0.5), - ), + ), + child: Padding( + padding: const EdgeInsets.symmetric( + vertical: 8, + horizontal: 8, + ), + child: Text( + _isSearchActive + ? 'Matches for \"$_userNameQuery\"' + : 'On the platform', + style: TextStyle( + color: Colors.black.withOpacity(0.5), ), ), ), ), ), - ]; - }, - body: UserListView( + ), + ]; + }, + body: UsersBloc( + child: UserListView( selectedUsers: _selectedUsers, pullToRefresh: false, groupAlphabetically: _isSearchActive ? false : true, From 6edfbb2e98916f5708ed9ac8e222f8f0481d466e Mon Sep 17 00:00:00 2001 From: xsahil03x Date: Wed, 25 Nov 2020 15:08:51 +0530 Subject: [PATCH 0473/1140] feat : channel header status --- lib/src/channel_header.dart | 1 + lib/src/channel_info.dart | 121 +++++++++++++++++++++++++++++------- 2 files changed, 100 insertions(+), 22 deletions(-) diff --git a/lib/src/channel_header.dart b/lib/src/channel_header.dart index ee0fd179..267ee20b 100644 --- a/lib/src/channel_header.dart +++ b/lib/src/channel_header.dart @@ -114,6 +114,7 @@ class ChannelHeader extends StatelessWidget implements PreferredSizeWidget { .channelHeaderTheme .title, ), + SizedBox(height: 2), ChannelInfo( channel: channel, textStyle: diff --git a/lib/src/channel_info.dart b/lib/src/channel_info.dart index a4f0272e..2aa1b2cd 100644 --- a/lib/src/channel_info.dart +++ b/lib/src/channel_info.dart @@ -16,6 +16,7 @@ class ChannelInfo extends StatelessWidget { @override Widget build(BuildContext context) { + final client = StreamChat.of(context).client; if (channel.memberCount != null && channel.memberCount > 2) { return Text( '${channel.memberCount} Members, ${channel.state.watcherCount} Online', @@ -29,31 +30,107 @@ class ChannelInfo extends StatelessWidget { stream: channel.state.membersStream, initialData: channel.state.members, builder: (context, snapshot) { - final otherMember = snapshot.data.firstWhere( - (element) => element.userId != StreamChat.of(context).user.id, - orElse: () => null, - ); - - if (otherMember == null) { - return SizedBox(); - } - - if (otherMember.user.online) { - return Text( - 'Online', - style: StreamChatTheme.of(context) - .channelTheme - .channelHeaderTheme - .lastMessageAt, - ); - } - - return Text( - 'Last seen ${Jiffy(otherMember.user.lastActive).fromNow()}', - style: textStyle, + return ValueListenableBuilder( + valueListenable: client.wsConnectionStatus, + builder: (context, status, child) { + switch (status) { + case ConnectionStatus.connected: + return _buildConnectedTitleState(context, snapshot.data); + case ConnectionStatus.connecting: + return _buildConnectingTitleState(context); + case ConnectionStatus.disconnected: + return _buildDisconnectedTitleState(context, client); + default: + return Offstage(); + } + }, ); }, ); } } + + Widget _buildConnectedTitleState(BuildContext context, List members) { + var alternativeWidget; + + final otherMember = members.firstWhere( + (element) => element.userId != StreamChat.of(context).user.id, + orElse: () => null, + ); + + if (otherMember != null) { + if (otherMember.user.online) { + alternativeWidget = Text( + 'Online', + style: StreamChatTheme.of(context) + .channelTheme + .channelHeaderTheme + .lastMessageAt, + ); + } else { + alternativeWidget = Text( + 'Last seen ${Jiffy(otherMember.user.lastActive).fromNow()}', + style: textStyle, + ); + } + } + + return TypingIndicator( + alignment: Alignment.center, + alternativeWidget: alternativeWidget, + style: textStyle, + ); + } + + Widget _buildConnectingTitleState(BuildContext context) { + return Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Container( + height: 16, + width: 16, + child: Center( + child: CircularProgressIndicator(), + ), + ), + SizedBox(width: 10), + Text( + 'Searching for Network', + style: textStyle, + ), + ], + ); + } + + Widget _buildDisconnectedTitleState(BuildContext context, Client client) { + return Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + 'Offline...', + style: textStyle, + ), + TextButton( + style: TextButton.styleFrom( + padding: const EdgeInsets.all(0), + tapTargetSize: MaterialTapTargetSize.shrinkWrap, + visualDensity: VisualDensity( + horizontal: VisualDensity.minimumDensity, + vertical: VisualDensity.minimumDensity, + ), + ), + onPressed: () async { + await client.disconnect(); + return client.connect(); + }, + child: Text( + 'Try Again', + style: textStyle.copyWith( + color: Color(0xFF006CFF), + ), + ), + ), + ], + ); + } } From d15a11b0880e8e4a0d08bd3456a3f10f48fca33c Mon Sep 17 00:00:00 2001 From: xsahil03x Date: Wed, 25 Nov 2020 15:19:02 +0530 Subject: [PATCH 0474/1140] minor changes --- lib/src/typing_indicator.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/src/typing_indicator.dart b/lib/src/typing_indicator.dart index 69a16b98..3f80ac9c 100644 --- a/lib/src/typing_indicator.dart +++ b/lib/src/typing_indicator.dart @@ -8,7 +8,7 @@ class TypingIndicator extends StatelessWidget { const TypingIndicator({ Key key, this.channel, - this.alternativeWidget = const SizedBox(), + this.alternativeWidget, this.style, this.alignment = Alignment.centerLeft, }) : super(key: key); @@ -48,7 +48,7 @@ class TypingIndicator extends StatelessWidget { key: Key('alternative'), alignment: alignment, child: Container( - child: alternativeWidget, + child: alternativeWidget ?? Offstage(), ), ), ); From 177d50a51153d71b183a98784c925945e8cc7dcf Mon Sep 17 00:00:00 2001 From: xsahil03x Date: Wed, 25 Nov 2020 15:41:06 +0530 Subject: [PATCH 0475/1140] Hide keyboard on scrolling user list --- example/lib/group_chat_details_screen.dart | 108 ++++++++++--------- example/lib/new_chat_screen.dart | 116 ++++++++++---------- example/lib/new_group_chat_screen.dart | 120 +++++++++++---------- 3 files changed, 178 insertions(+), 166 deletions(-) diff --git a/example/lib/group_chat_details_screen.dart b/example/lib/group_chat_details_screen.dart index fc8a6890..36999c7f 100644 --- a/example/lib/group_chat_details_screen.dart +++ b/example/lib/group_chat_details_screen.dart @@ -164,59 +164,63 @@ class _GroupChatDetailsScreenState extends State { ), ), Expanded( - child: ListView.separated( - itemCount: _selectedUsers.length + 1, - separatorBuilder: (_, __) => Container( - height: 1, - color: Theme.of(context).brightness == Brightness.dark - ? Colors.white.withOpacity(0.1) - : Colors.black.withOpacity(0.1), - ), - itemBuilder: (_, index) { - if (index == _selectedUsers.length) { - return Container( - height: 1, - color: Theme.of(context).brightness == Brightness.dark - ? Colors.white.withOpacity(0.1) - : Colors.black.withOpacity(0.1), + child: GestureDetector( + behavior: HitTestBehavior.opaque, + onPanDown: (_) => FocusScope.of(context).unfocus(), + child: ListView.separated( + itemCount: _selectedUsers.length + 1, + separatorBuilder: (_, __) => Container( + height: 1, + color: Theme.of(context).brightness == Brightness.dark + ? Colors.white.withOpacity(0.1) + : Colors.black.withOpacity(0.1), + ), + itemBuilder: (_, index) { + if (index == _selectedUsers.length) { + return Container( + height: 1, + color: Theme.of(context).brightness == Brightness.dark + ? Colors.white.withOpacity(0.1) + : Colors.black.withOpacity(0.1), + ); + } + final user = _selectedUsers[index]; + return ListTile( + key: ObjectKey(user), + leading: UserAvatar( + user: user, + constraints: BoxConstraints.tightFor( + width: 40, + height: 40, + ), + ), + title: Text( + user.name, + style: TextStyle(fontWeight: FontWeight.bold), + ), + contentPadding: const EdgeInsets.symmetric( + horizontal: 12, + vertical: 8, + ), + trailing: IconButton( + icon: Icon( + Icons.clear_rounded, + color: Colors.black, + ), + padding: const EdgeInsets.all(0), + splashRadius: 24, + onPressed: () { + setState(() { + _selectedUsers.remove(user); + }); + if (_selectedUsers.isEmpty) { + Navigator.pop(context, _selectedUsers); + } + }, + ), ); - } - final user = _selectedUsers[index]; - return ListTile( - key: ObjectKey(user), - leading: UserAvatar( - user: user, - constraints: BoxConstraints.tightFor( - width: 40, - height: 40, - ), - ), - title: Text( - user.name, - style: TextStyle(fontWeight: FontWeight.bold), - ), - contentPadding: const EdgeInsets.symmetric( - horizontal: 12, - vertical: 8, - ), - trailing: IconButton( - icon: Icon( - Icons.clear_rounded, - color: Colors.black, - ), - padding: const EdgeInsets.all(0), - splashRadius: 24, - onPressed: () { - setState(() { - _selectedUsers.remove(user); - }); - if (_selectedUsers.isEmpty) { - Navigator.pop(context, _selectedUsers); - } - }, - ), - ); - }, + }, + ), ), ), ], diff --git a/example/lib/new_chat_screen.dart b/example/lib/new_chat_screen.dart index 690e831f..5e6af8fc 100644 --- a/example/lib/new_chat_screen.dart +++ b/example/lib/new_chat_screen.dart @@ -243,67 +243,71 @@ class _NewChatScreenState extends State { ), Expanded( child: _showUserList - ? UsersBloc( - child: UserListView( - selectedUsers: _selectedUsers, - groupAlphabetically: _isSearchActive ? false : true, - onUserTap: (user, _) { - _controller.clear(); - if (!_selectedUsers.contains(user)) { - _chipInputTextFieldState - ..addItem(user) - ..pauseItemAddition(); - } else { - _chipInputTextFieldState.removeItem(user); - } - }, - pagination: PaginationParams( - limit: 25, - ), - filter: { - if (_userNameQuery.isNotEmpty) - 'name': { - r'$autocomplete': _userNameQuery, - }, - 'id': { - r'$ne': StreamChat.of(context).user.id, + ? GestureDetector( + behavior: HitTestBehavior.opaque, + onPanDown: (_) => FocusScope.of(context).unfocus(), + child: UsersBloc( + child: UserListView( + selectedUsers: _selectedUsers, + groupAlphabetically: _isSearchActive ? false : true, + onUserTap: (user, _) { + _controller.clear(); + if (!_selectedUsers.contains(user)) { + _chipInputTextFieldState + ..addItem(user) + ..pauseItemAddition(); + } else { + _chipInputTextFieldState.removeItem(user); + } }, - }, - sort: [ - SortOption( - 'name', - direction: 1, + pagination: PaginationParams( + limit: 25, ), - ], - emptyBuilder: (_) { - return LayoutBuilder( - builder: (context, viewportConstraints) { - return SingleChildScrollView( - physics: AlwaysScrollableScrollPhysics(), - child: ConstrainedBox( - constraints: BoxConstraints( - minHeight: viewportConstraints.maxHeight, - ), - child: Center( - child: Column( - children: [ - Padding( - padding: const EdgeInsets.all(24), - child: StreamSvgIcon.search( - size: 96, - color: Colors.grey, + filter: { + if (_userNameQuery.isNotEmpty) + 'name': { + r'$autocomplete': _userNameQuery, + }, + 'id': { + r'$ne': StreamChat.of(context).user.id, + }, + }, + sort: [ + SortOption( + 'name', + direction: 1, + ), + ], + emptyBuilder: (_) { + return LayoutBuilder( + builder: (context, viewportConstraints) { + return SingleChildScrollView( + physics: AlwaysScrollableScrollPhysics(), + child: ConstrainedBox( + constraints: BoxConstraints( + minHeight: viewportConstraints.maxHeight, + ), + child: Center( + child: Column( + children: [ + Padding( + padding: const EdgeInsets.all(24), + child: StreamSvgIcon.search( + size: 96, + color: Colors.grey, + ), ), - ), - Text( - 'No user matches these keywords...'), - ], + Text( + 'No user matches these keywords...'), + ], + ), ), ), - ), - ); - }, - ); - }, + ); + }, + ); + }, + ), ), ) : MessageListView(), diff --git a/example/lib/new_group_chat_screen.dart b/example/lib/new_group_chat_screen.dart index 1587c464..e954f08f 100644 --- a/example/lib/new_group_chat_screen.dart +++ b/example/lib/new_group_chat_screen.dart @@ -238,68 +238,72 @@ class _NewGroupChatScreenState extends State { ), ]; }, - body: UsersBloc( - child: UserListView( - selectedUsers: _selectedUsers, - pullToRefresh: false, - groupAlphabetically: _isSearchActive ? false : true, - onUserTap: (user, _) { - if (!_selectedUsers.contains(user)) { - setState(() { - _selectedUsers.add(user); - }); - } else { - setState(() { - _selectedUsers.remove(user); - }); - } - }, - pagination: PaginationParams( - limit: 25, - ), - filter: { - if (_userNameQuery.isNotEmpty) - 'name': { - r'$autocomplete': _userNameQuery, - }, - 'id': { - r'$ne': StreamChat.of(context).user.id, - } - }, - sort: [ - SortOption( - 'name', - direction: 1, + body: GestureDetector( + behavior: HitTestBehavior.opaque, + onPanDown: (_) => FocusScope.of(context).unfocus(), + child: UsersBloc( + child: UserListView( + selectedUsers: _selectedUsers, + pullToRefresh: false, + groupAlphabetically: _isSearchActive ? false : true, + onUserTap: (user, _) { + if (!_selectedUsers.contains(user)) { + setState(() { + _selectedUsers.add(user); + }); + } else { + setState(() { + _selectedUsers.remove(user); + }); + } + }, + pagination: PaginationParams( + limit: 25, ), - ], - emptyBuilder: (_) { - return LayoutBuilder( - builder: (context, viewportConstraints) { - return SingleChildScrollView( - physics: AlwaysScrollableScrollPhysics(), - child: ConstrainedBox( - constraints: BoxConstraints( - minHeight: viewportConstraints.maxHeight, - ), - child: Center( - child: Column( - children: [ - Padding( - padding: const EdgeInsets.all(24), - child: StreamSvgIcon.search( - size: 96, - color: Colors.grey, + filter: { + if (_userNameQuery.isNotEmpty) + 'name': { + r'$autocomplete': _userNameQuery, + }, + 'id': { + r'$ne': StreamChat.of(context).user.id, + } + }, + sort: [ + SortOption( + 'name', + direction: 1, + ), + ], + emptyBuilder: (_) { + return LayoutBuilder( + builder: (context, viewportConstraints) { + return SingleChildScrollView( + physics: AlwaysScrollableScrollPhysics(), + child: ConstrainedBox( + constraints: BoxConstraints( + minHeight: viewportConstraints.maxHeight, + ), + child: Center( + child: Column( + children: [ + Padding( + padding: const EdgeInsets.all(24), + child: StreamSvgIcon.search( + size: 96, + color: Colors.grey, + ), ), - ), - Text('No user matches these keywords...'), - ], + Text('No user matches these keywords...'), + ], + ), ), ), - ), - ); - }, - ); - }, + ); + }, + ); + }, + ), ), ), ), From ef403d53c9595f69a609567a34f82c3a344b4963 Mon Sep 17 00:00:00 2001 From: xsahil03x Date: Wed, 25 Nov 2020 15:49:59 +0530 Subject: [PATCH 0476/1140] remove comments --- example/lib/new_group_chat_screen.dart | 1 - 1 file changed, 1 deletion(-) diff --git a/example/lib/new_group_chat_screen.dart b/example/lib/new_group_chat_screen.dart index e954f08f..dfa4b000 100644 --- a/example/lib/new_group_chat_screen.dart +++ b/example/lib/new_group_chat_screen.dart @@ -57,7 +57,6 @@ class _NewGroupChatScreenState extends State { headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) { return [ SliverAppBar( - // floating: true, pinned: true, forceElevated: true, elevation: 1, From 850657cc638a0a95640bcbff5961cf81b00e7884 Mon Sep 17 00:00:00 2001 From: xsahil03x Date: Wed, 25 Nov 2020 15:54:19 +0530 Subject: [PATCH 0477/1140] fix icon --- example/lib/new_group_chat_screen.dart | 2 +- lib/src/stream_svg_icon.dart | 12 ++++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/example/lib/new_group_chat_screen.dart b/example/lib/new_group_chat_screen.dart index dfa4b000..11b6aa14 100644 --- a/example/lib/new_group_chat_screen.dart +++ b/example/lib/new_group_chat_screen.dart @@ -73,7 +73,7 @@ class _NewGroupChatScreenState extends State { actions: [ if (_selectedUsers.isNotEmpty) IconButton( - icon: StreamSvgIcon.right( + icon: StreamSvgIcon.arrow_right( color: Color(0xFF006CFF), ), onPressed: () async { diff --git a/lib/src/stream_svg_icon.dart b/lib/src/stream_svg_icon.dart index 2851df3a..7ed1fca8 100644 --- a/lib/src/stream_svg_icon.dart +++ b/lib/src/stream_svg_icon.dart @@ -373,4 +373,16 @@ class StreamSvgIcon extends StatelessWidget { height: size, ); } + + factory StreamSvgIcon.arrow_right({ + double size, + Color color, + }) { + return StreamSvgIcon( + assetName: 'Icon_arrow_right.svg', + color: color, + width: size, + height: size, + ); + } } From e5dfdaac21b2cf68539549bf6dfc4f938671892e Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Wed, 25 Nov 2020 11:53:44 +0100 Subject: [PATCH 0478/1140] fix icon boxfit --- lib/src/stream_svg_icon.dart | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/src/stream_svg_icon.dart b/lib/src/stream_svg_icon.dart index 2851df3a..19daca34 100644 --- a/lib/src/stream_svg_icon.dart +++ b/lib/src/stream_svg_icon.dart @@ -25,6 +25,7 @@ class StreamSvgIcon extends StatelessWidget { height: height, key: key, color: color, + fit: BoxFit.scaleDown, alignment: Alignment.center, ) : SvgPicture.asset( @@ -34,6 +35,7 @@ class StreamSvgIcon extends StatelessWidget { width: width, height: height, color: color, + fit: BoxFit.scaleDown, alignment: Alignment.center, ); } From cd84555f74b3c18654c16585ebf9d61b6a530754 Mon Sep 17 00:00:00 2001 From: xsahil03x Date: Wed, 25 Nov 2020 16:43:35 +0530 Subject: [PATCH 0479/1140] extract searchTextField into a separate widget --- example/lib/new_group_chat_screen.dart | 35 +---------- example/lib/search_text_field.dart | 81 ++++++++++++++++++++++++++ 2 files changed, 84 insertions(+), 32 deletions(-) create mode 100644 example/lib/search_text_field.dart diff --git a/example/lib/new_group_chat_screen.dart b/example/lib/new_group_chat_screen.dart index 11b6aa14..ece3ca9a 100644 --- a/example/lib/new_group_chat_screen.dart +++ b/example/lib/new_group_chat_screen.dart @@ -4,6 +4,7 @@ import 'package:flutter/material.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; import 'group_chat_details_screen.dart'; +import 'search_text_field.dart'; class NewGroupChatScreen extends StatefulWidget { @override @@ -98,38 +99,8 @@ class _NewGroupChatScreenState extends State { ], ), SliverToBoxAdapter( - child: Container( - height: 36, - decoration: BoxDecoration( - color: Colors.white, - border: Border.all( - color: Colors.grey.shade300, - ), - borderRadius: BorderRadius.circular(24), - ), - margin: const EdgeInsets.symmetric( - vertical: 8, - horizontal: 8, - ), - child: TextField( - controller: _controller, - decoration: InputDecoration( - prefixIcon: StreamSvgIcon.search( - color: Colors.black, - size: 24, - ), - hintText: 'Search', - hintStyle: TextStyle( - color: Colors.black.withOpacity(0.5), - fontSize: 14, - ), - contentPadding: const EdgeInsets.all(0), - border: OutlineInputBorder( - borderSide: BorderSide.none, - borderRadius: BorderRadius.circular(24), - ), - ), - ), + child: SearchTextField( + controller: _controller, ), ), if (_selectedUsers.isNotEmpty) diff --git a/example/lib/search_text_field.dart b/example/lib/search_text_field.dart new file mode 100644 index 00000000..7fcd3727 --- /dev/null +++ b/example/lib/search_text_field.dart @@ -0,0 +1,81 @@ +import 'package:flutter/material.dart'; +import 'package:stream_chat_flutter/stream_chat_flutter.dart'; + +class SearchTextField extends StatelessWidget { + final TextEditingController controller; + final ValueChanged onChanged; + final String hintText; + final VoidCallback onTap; + + const SearchTextField({ + Key key, + @required this.controller, + this.onChanged, + this.onTap, + this.hintText = 'Search', + }) : super(key: key); + + @override + Widget build(BuildContext context) { + return Container( + height: 36, + decoration: BoxDecoration( + color: Colors.white, + border: Border.all( + color: Colors.grey.shade300, + ), + borderRadius: BorderRadius.circular(24), + ), + margin: const EdgeInsets.symmetric( + vertical: 8, + horizontal: 8, + ), + child: Row( + children: [ + Expanded( + child: TextField( + onTap: onTap, + controller: controller, + onChanged: onChanged, + decoration: InputDecoration( + prefixIcon: StreamSvgIcon.search( + color: Colors.black, + size: 24, + ), + hintText: hintText, + hintStyle: TextStyle( + color: Colors.black.withOpacity(0.5), + fontSize: 14, + ), + contentPadding: const EdgeInsets.all(0), + border: OutlineInputBorder( + borderSide: BorderSide.none, + borderRadius: BorderRadius.circular(24), + ), + ), + ), + ), + // Material( + // + // child: IconButton( + // icon: StreamSvgIcon.close( + // color: Colors.grey, + // ), + // splashRadius: 24, + // onPressed: () { + // if (controller.text.isNotEmpty) { + // Future.microtask( + // () => [ + // controller.clear(), + // onChanged(''), + // ], + // ); + // } + // }, + // ), + // ), + ], + ), + ); + } +} From 9fd7a6a7f81275ef4d7a0fae1901516d6f18f873 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Wed, 25 Nov 2020 12:15:25 +0100 Subject: [PATCH 0480/1140] update channel info fro groups --- lib/src/channel_info.dart | 90 +++++++++++++++++++-------------------- 1 file changed, 45 insertions(+), 45 deletions(-) diff --git a/lib/src/channel_info.dart b/lib/src/channel_info.dart index 2aa1b2cd..402dd73f 100644 --- a/lib/src/channel_info.dart +++ b/lib/src/channel_info.dart @@ -17,8 +17,34 @@ class ChannelInfo extends StatelessWidget { @override Widget build(BuildContext context) { final client = StreamChat.of(context).client; + return StreamBuilder>( + stream: channel.state.membersStream, + initialData: channel.state.members, + builder: (context, snapshot) { + return ValueListenableBuilder( + valueListenable: client.wsConnectionStatus, + builder: (context, status, child) { + switch (status) { + case ConnectionStatus.connected: + return _buildConnectedTitleState(context, snapshot.data); + case ConnectionStatus.connecting: + return _buildConnectingTitleState(context); + case ConnectionStatus.disconnected: + return _buildDisconnectedTitleState(context, client); + default: + return Offstage(); + } + }, + ); + }, + ); + } + + Widget _buildConnectedTitleState(BuildContext context, List members) { + var alternativeWidget; + if (channel.memberCount != null && channel.memberCount > 2) { - return Text( + alternativeWidget = Text( '${channel.memberCount} Members, ${channel.state.watcherCount} Online', style: StreamChatTheme.of(context) .channelTheme @@ -26,52 +52,26 @@ class ChannelInfo extends StatelessWidget { .lastMessageAt, ); } else { - return StreamBuilder>( - stream: channel.state.membersStream, - initialData: channel.state.members, - builder: (context, snapshot) { - return ValueListenableBuilder( - valueListenable: client.wsConnectionStatus, - builder: (context, status, child) { - switch (status) { - case ConnectionStatus.connected: - return _buildConnectedTitleState(context, snapshot.data); - case ConnectionStatus.connecting: - return _buildConnectingTitleState(context); - case ConnectionStatus.disconnected: - return _buildDisconnectedTitleState(context, client); - default: - return Offstage(); - } - }, - ); - }, + final otherMember = members.firstWhere( + (element) => element.userId != StreamChat.of(context).user.id, + orElse: () => null, ); - } - } - Widget _buildConnectedTitleState(BuildContext context, List members) { - var alternativeWidget; - - final otherMember = members.firstWhere( - (element) => element.userId != StreamChat.of(context).user.id, - orElse: () => null, - ); - - if (otherMember != null) { - if (otherMember.user.online) { - alternativeWidget = Text( - 'Online', - style: StreamChatTheme.of(context) - .channelTheme - .channelHeaderTheme - .lastMessageAt, - ); - } else { - alternativeWidget = Text( - 'Last seen ${Jiffy(otherMember.user.lastActive).fromNow()}', - style: textStyle, - ); + if (otherMember != null) { + if (otherMember.user.online) { + alternativeWidget = Text( + 'Online', + style: StreamChatTheme.of(context) + .channelTheme + .channelHeaderTheme + .lastMessageAt, + ); + } else { + alternativeWidget = Text( + 'Last seen ${Jiffy(otherMember.user.lastActive).fromNow()}', + style: textStyle, + ); + } } } From 24c5e39bdaccfdf3a0a4445c459b8a854fe6411e Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Wed, 25 Nov 2020 12:25:43 +0100 Subject: [PATCH 0481/1140] add lottie animation for typing indicator --- animations/typing_dots.json | 1 + example/lib/main.dart | 27 ++++++--------------------- example/pubspec.yaml | 2 +- lib/src/typing_indicator.dart | 20 ++++++++++++++++---- pubspec.yaml | 2 ++ 5 files changed, 26 insertions(+), 26 deletions(-) create mode 100644 animations/typing_dots.json diff --git a/animations/typing_dots.json b/animations/typing_dots.json new file mode 100644 index 00000000..b210c24b --- /dev/null +++ b/animations/typing_dots.json @@ -0,0 +1 @@ +{"v":"5.7.1","fr":29.9700012207031,"ip":0,"op":95.0000038694293,"w":132,"h":34,"nm":"Typing indicator","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Shape Layer 6","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[65.938,24.75,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[],"ip":0,"op":900.000036657751,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Shape Layer 5","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[200.438,19.75,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[142.227,142.227,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[44.691,44.691],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":0,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.511611519608,0.511611519608,0.511611519608,1],"ix":4},"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":53,"s":[33]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":53.5,"s":[33.66]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":54,"s":[34.333]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":54.5,"s":[35.019]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":55,"s":[35.72]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":55.5,"s":[36.434]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":56,"s":[37.162]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":56.5,"s":[37.905]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":57,"s":[38.663]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":57.5,"s":[39.436]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":58,"s":[40.225]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":58.5,"s":[41.029]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":59,"s":[41.849]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":59.5,"s":[42.686]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":60,"s":[43.54]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":60.5,"s":[44.41]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":61,"s":[45.298]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":61.5,"s":[46.204]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":62,"s":[47.128]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":62.5,"s":[48.07]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":63,"s":[49.031]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":63.5,"s":[50.012]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":64,"s":[51.012]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":64.5,"s":[52.032]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":65,"s":[53.072]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":65.5,"s":[54.133]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":66,"s":[55.216]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":66.5,"s":[56.32]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":67,"s":[57.446]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":67.5,"s":[58.594]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":68,"s":[59.766]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":68.5,"s":[60.961]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":69,"s":[62.18]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":69.5,"s":[63.423]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":70,"s":[64.691]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":70.5,"s":[65.985]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":71,"s":[67.304]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":71.5,"s":[68.65]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":72,"s":[70.022]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":72.5,"s":[71.422]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":73,"s":[72.851]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":73.5,"s":[74.307]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":74,"s":[75.793]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":74.5,"s":[77.308]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":75,"s":[78.854]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":75.5,"s":[80.431]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":76,"s":[82.039]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":76.5,"s":[83.679]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":77,"s":[85.353]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":77.5,"s":[87.059]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":78,"s":[88.8]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":78.5,"s":[90.575]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":79,"s":[92.386]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":79.5,"s":[94.234]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":80,"s":[96.118]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":80.5,"s":[98.04]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"t":81,"s":[100]},{"t":91.000003706506,"s":[33]}],"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-59.729,-1.971],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[50.039,50.039],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":900.000036657751,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"Shape Layer 4","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[151.438,19.75,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[142.227,142.227,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[44.691,44.691],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":0,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.511611519608,0.511611519608,0.511611519608,1],"ix":4},"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":23,"s":[33]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":23.5,"s":[33.66]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":24,"s":[34.333]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":24.5,"s":[35.019]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":25,"s":[35.72]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":25.5,"s":[36.434]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":26,"s":[37.162]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":26.5,"s":[37.905]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":27,"s":[38.663]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":27.5,"s":[39.436]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":28,"s":[40.225]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":28.5,"s":[41.029]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":29,"s":[41.849]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":29.5,"s":[42.686]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":30,"s":[43.54]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":30.5,"s":[44.41]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":31,"s":[45.298]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":31.5,"s":[46.204]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":32,"s":[47.128]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":32.5,"s":[48.07]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":33,"s":[49.031]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":33.5,"s":[50.012]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":34,"s":[51.012]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":34.5,"s":[52.032]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":35,"s":[53.072]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":35.5,"s":[54.133]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":36,"s":[55.216]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":36.5,"s":[56.32]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":37,"s":[57.446]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":37.5,"s":[58.594]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":38,"s":[59.766]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":38.5,"s":[60.961]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":39,"s":[62.18]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":39.5,"s":[63.423]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":40,"s":[64.691]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":40.5,"s":[65.985]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":41,"s":[67.304]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":41.5,"s":[68.65]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":42,"s":[70.022]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":42.5,"s":[71.422]},{"i":{"x":[0.686],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"t":43,"s":[72.851]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0]},"t":44,"s":[89]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":44.5,"s":[77.308]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":45,"s":[78.854]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":45.5,"s":[80.431]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":46,"s":[82.039]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":46.5,"s":[83.679]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":47,"s":[85.353]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":47.5,"s":[87.059]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":48,"s":[88.8]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":48.5,"s":[90.575]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":49,"s":[92.386]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":49.5,"s":[94.234]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":50,"s":[96.118]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":50.5,"s":[98.04]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"t":51,"s":[100]},{"t":85.000003462121,"s":[33]}],"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-59.729,-1.971],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[50.039,50.039],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":900.000036657751,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"Shape Layer 1","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[101.938,19.75,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[142.227,142.227,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[44.691,44.691],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":0,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.511611519608,0.511611519608,0.511611519608,1],"ix":4},"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[33]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":0.5,"s":[33.66]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":1,"s":[34.333]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":1.5,"s":[35.019]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":2,"s":[35.72]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":2.5,"s":[36.434]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":3,"s":[37.162]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":3.5,"s":[37.905]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":4,"s":[38.663]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":4.5,"s":[39.436]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":5,"s":[40.225]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":5.5,"s":[41.029]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":6,"s":[41.849]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":6.5,"s":[42.686]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":7,"s":[43.54]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":7.5,"s":[44.41]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":8,"s":[45.298]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":8.5,"s":[46.204]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":9,"s":[47.128]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":9.5,"s":[48.07]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":10,"s":[49.031]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":10.5,"s":[50.012]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":11,"s":[51.012]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":11.5,"s":[52.032]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":12,"s":[53.072]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":12.5,"s":[54.133]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":13,"s":[55.216]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":13.5,"s":[56.32]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":14,"s":[57.446]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":14.5,"s":[58.594]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":15,"s":[59.766]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":15.5,"s":[60.961]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":16,"s":[62.18]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":16.5,"s":[63.423]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":17,"s":[64.691]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":17.5,"s":[65.985]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":18,"s":[67.304]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":18.5,"s":[68.65]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":19,"s":[70.022]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":19.5,"s":[71.422]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":20,"s":[72.851]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":20.5,"s":[74.307]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":21,"s":[75.793]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":21.5,"s":[77.308]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":22,"s":[78.854]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":22.5,"s":[80.431]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":23,"s":[82.039]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":23.5,"s":[83.679]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":24,"s":[85.353]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":24.5,"s":[87.059]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":25,"s":[88.8]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":25.5,"s":[90.575]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":26,"s":[92.386]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":26.5,"s":[94.234]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":27,"s":[96.118]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":27.5,"s":[98.04]},{"i":{"x":[0.816],"y":[0.991]},"o":{"x":[0.328],"y":[0]},"t":28,"s":[100]},{"i":{"x":[0.686],"y":[1]},"o":{"x":[0.352],"y":[0.66]},"t":89,"s":[33.03]},{"t":90.0000036657751,"s":[33]}],"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-59.729,-1.971],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[50.039,50.039],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":900.000036657751,"st":0,"bm":0}],"markers":[]} \ No newline at end of file diff --git a/example/lib/main.dart b/example/lib/main.dart index d2be225a..991f79ad 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -227,27 +227,12 @@ class ChannelPage extends StatelessWidget { body: Column( children: [ Expanded( - child: Stack( - children: [ - MessageListView( - threadBuilder: (_, parentMessage) { - return ThreadPage( - parent: parentMessage, - ); - }, - ), - Positioned.fill( - child: Padding( - padding: const EdgeInsets.symmetric( - horizontal: 8.0, - vertical: 4, - ), - child: TypingIndicator( - alignment: Alignment.bottomRight, - ), - ), - ), - ], + child: MessageListView( + threadBuilder: (_, parentMessage) { + return ThreadPage( + parent: parentMessage, + ); + }, ), ), MessageInput(), diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 43eb867e..7c76b15f 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -1,6 +1,6 @@ name: example description: A new Flutter project. -version: 1.0.72+74 +version: 1.0.74+76 environment: sdk: ">=2.2.2 <3.0.0" diff --git a/lib/src/typing_indicator.dart b/lib/src/typing_indicator.dart index 3f80ac9c..7a3ad359 100644 --- a/lib/src/typing_indicator.dart +++ b/lib/src/typing_indicator.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:lottie/lottie.dart'; import 'package:stream_chat/stream_chat.dart'; import 'package:stream_chat_flutter/src/stream_channel.dart'; @@ -38,10 +39,21 @@ class TypingIndicator extends StatelessWidget { ? Align( key: Key('typings'), alignment: alignment, - child: Text( - '${snapshot.data.map((u) => u.name).join(',')} ${snapshot.data.length == 1 ? 'is' : 'are'} typing...', - maxLines: 1, - style: style, + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Lottie.asset( + 'animations/typing_dots.json', + package: 'stream_chat_flutter', + alignment: Alignment.center, + height: 4, + ), + Text( + ' ${snapshot.data.map((u) => u.name).join(',')} ${snapshot.data.length == 1 ? 'is' : 'are'} typing', + maxLines: 1, + style: style, + ), + ], ), ) : Align( diff --git a/pubspec.yaml b/pubspec.yaml index c441ca4f..4ea0f4bb 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -32,6 +32,7 @@ dependencies: mime: ^0.9.6+3 visibility_detector: ^0.1.5 http_parser: ^3.1.4 + lottie: ^0.7.0+1 substring_highlight: ^0.1.2 flutter_slidable: ^0.5.4 carousel_slider: ^2.2.1 @@ -47,6 +48,7 @@ flutter: - images/ - svgs/ - lib/svgs/ + - animations/ dev_dependencies: pedantic: ^1.9.0 From 806b34f0922c642e488ab8476f670af195c2d19d Mon Sep 17 00:00:00 2001 From: xsahil03x Date: Wed, 25 Nov 2020 16:59:54 +0530 Subject: [PATCH 0482/1140] minor changes --- example/lib/search_text_field.dart | 42 ++++++++++++++++-------------- lib/src/stream_svg_icon.dart | 12 +++++++++ 2 files changed, 35 insertions(+), 19 deletions(-) diff --git a/example/lib/search_text_field.dart b/example/lib/search_text_field.dart index 7fcd3727..8461d735 100644 --- a/example/lib/search_text_field.dart +++ b/example/lib/search_text_field.dart @@ -6,6 +6,7 @@ class SearchTextField extends StatelessWidget { final ValueChanged onChanged; final String hintText; final VoidCallback onTap; + final bool showCloseButton; const SearchTextField({ Key key, @@ -13,6 +14,7 @@ class SearchTextField extends StatelessWidget { this.onChanged, this.onTap, this.hintText = 'Search', + this.showCloseButton = true, }) : super(key: key); @override @@ -55,25 +57,27 @@ class SearchTextField extends StatelessWidget { ), ), ), - // Material( - // - // child: IconButton( - // icon: StreamSvgIcon.close( - // color: Colors.grey, - // ), - // splashRadius: 24, - // onPressed: () { - // if (controller.text.isNotEmpty) { - // Future.microtask( - // () => [ - // controller.clear(), - // onChanged(''), - // ], - // ); - // } - // }, - // ), - // ), + if (showCloseButton) + Material( + color: Colors.transparent, + child: IconButton( + padding: const EdgeInsets.all(0), + icon: StreamSvgIcon.close_small( + color: Colors.grey, + ), + splashRadius: 24, + onPressed: () { + if (controller.text.isNotEmpty) { + Future.microtask( + () => [ + controller.clear(), + onChanged(''), + ], + ); + } + }, + ), + ), ], ), ); diff --git a/lib/src/stream_svg_icon.dart b/lib/src/stream_svg_icon.dart index 894b868a..1b0c9ae9 100644 --- a/lib/src/stream_svg_icon.dart +++ b/lib/src/stream_svg_icon.dart @@ -387,4 +387,16 @@ class StreamSvgIcon extends StatelessWidget { height: size, ); } + + factory StreamSvgIcon.close_small({ + double size, + Color color, + }) { + return StreamSvgIcon( + assetName: 'Icon_close_sml.svg', + color: color, + width: size, + height: size, + ); + } } From 71123fbafbf375f42df7d4d287b26eaf396ee06b Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Wed, 25 Nov 2020 12:43:42 +0100 Subject: [PATCH 0483/1140] add messagelist typing indicator --- example/lib/main.dart | 36 ++++++++++++++++++++++++------ example/pubspec.yaml | 2 +- lib/src/channel_header.dart | 5 +++++ lib/src/channel_info.dart | 8 +++++++ lib/src/typing_indicator.dart | 42 ++++++++++++++++++++--------------- 5 files changed, 67 insertions(+), 26 deletions(-) diff --git a/example/lib/main.dart b/example/lib/main.dart index 991f79ad..f1263fb8 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -223,16 +223,38 @@ class ChannelPage extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( - appBar: ChannelHeader(), + appBar: ChannelHeader( + showTypingIndicator: false, + ), body: Column( children: [ Expanded( - child: MessageListView( - threadBuilder: (_, parentMessage) { - return ThreadPage( - parent: parentMessage, - ); - }, + child: Stack( + children: [ + MessageListView( + threadBuilder: (_, parentMessage) { + return ThreadPage( + parent: parentMessage, + ); + }, + ), + Positioned( + bottom: 0, + left: 0, + right: 0, + child: Container( + alignment: Alignment.centerLeft, + color: Color(0xffFCFCFC).withOpacity(.9), + child: TypingIndicator( + alignment: Alignment.centerLeft, + padding: const EdgeInsets.symmetric( + horizontal: 8, + vertical: 4, + ), + ), + ), + ), + ], ), ), MessageInput(), diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 7c76b15f..02c2c726 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -1,6 +1,6 @@ name: example description: A new Flutter project. -version: 1.0.74+76 +version: 1.0.75+77 environment: sdk: ">=2.2.2 <3.0.0" diff --git a/lib/src/channel_header.dart b/lib/src/channel_header.dart index 267ee20b..ebaaf20f 100644 --- a/lib/src/channel_header.dart +++ b/lib/src/channel_header.dart @@ -64,12 +64,16 @@ class ChannelHeader extends StatelessWidget implements PreferredSizeWidget { /// Callback to call when the image is tapped. final VoidCallback onImageTap; + /// If true the typing indicator will be rendered if a user is typing + final bool showTypingIndicator; + /// Creates a channel header ChannelHeader({ Key key, this.showBackButton = true, this.onBackPressed, this.onTitleTap, + this.showTypingIndicator = true, this.onImageTap, }) : preferredSize = Size.fromHeight(kToolbarHeight), super(key: key); @@ -116,6 +120,7 @@ class ChannelHeader extends StatelessWidget implements PreferredSizeWidget { ), SizedBox(height: 2), ChannelInfo( + showTypingIndicator: showTypingIndicator, channel: channel, textStyle: StreamChatTheme.of(context).channelPreviewTheme.subtitle, diff --git a/lib/src/channel_info.dart b/lib/src/channel_info.dart index 402dd73f..208fa588 100644 --- a/lib/src/channel_info.dart +++ b/lib/src/channel_info.dart @@ -8,10 +8,14 @@ class ChannelInfo extends StatelessWidget { /// The style of the text displayed final TextStyle textStyle; + /// If true the typing indicator will be rendered if a user is typing + final bool showTypingIndicator; + const ChannelInfo({ Key key, @required this.channel, this.textStyle, + this.showTypingIndicator = true, }) : super(key: key); @override @@ -75,6 +79,10 @@ class ChannelInfo extends StatelessWidget { } } + if (!showTypingIndicator) { + return alternativeWidget; + } + return TypingIndicator( alignment: Alignment.center, alternativeWidget: alternativeWidget, diff --git a/lib/src/typing_indicator.dart b/lib/src/typing_indicator.dart index 7a3ad359..b13eade6 100644 --- a/lib/src/typing_indicator.dart +++ b/lib/src/typing_indicator.dart @@ -12,6 +12,7 @@ class TypingIndicator extends StatelessWidget { this.alternativeWidget, this.style, this.alignment = Alignment.centerLeft, + this.padding = const EdgeInsets.all(0), }) : super(key: key); /// Style of the text widget @@ -23,6 +24,9 @@ class TypingIndicator extends StatelessWidget { /// Widget built when no typings is happening final Widget alternativeWidget; + /// The padding of this widget + final EdgeInsets padding; + final Alignment alignment; @override @@ -36,24 +40,26 @@ class TypingIndicator extends StatelessWidget { return AnimatedSwitcher( duration: Duration(milliseconds: 300), child: snapshot.data?.isNotEmpty == true - ? Align( - key: Key('typings'), - alignment: alignment, - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Lottie.asset( - 'animations/typing_dots.json', - package: 'stream_chat_flutter', - alignment: Alignment.center, - height: 4, - ), - Text( - ' ${snapshot.data.map((u) => u.name).join(',')} ${snapshot.data.length == 1 ? 'is' : 'are'} typing', - maxLines: 1, - style: style, - ), - ], + ? Padding( + padding: padding, + child: Align( + key: Key('typings'), + alignment: alignment, + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Lottie.asset( + 'animations/typing_dots.json', + package: 'stream_chat_flutter', + height: 4, + ), + Text( + ' ${snapshot.data.map((u) => u.name).join(',')} ${snapshot.data.length == 1 ? 'is' : 'are'} typing', + maxLines: 1, + style: style, + ), + ], + ), ), ) : Align( From d59e89c700de55b21907897a4bef77dbcae33d10 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Wed, 25 Nov 2020 12:50:46 +0100 Subject: [PATCH 0484/1140] fix thread back button behaviour --- lib/src/thread_header.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/thread_header.dart b/lib/src/thread_header.dart index c6cce13e..aa14cb61 100644 --- a/lib/src/thread_header.dart +++ b/lib/src/thread_header.dart @@ -85,7 +85,7 @@ class ThreadHeader extends StatelessWidget implements PreferredSizeWidget { ? AspectRatio( aspectRatio: 1, child: IconButton( - onPressed: onBackPressed, + onPressed: onBackPressed ?? () => Navigator.pop(context), icon: StreamSvgIcon.close( size: 24, color: Theme.of(context).brightness == Brightness.dark From 11267248da4af81432b9e0d9325144ea2a5c5317 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Wed, 25 Nov 2020 15:03:22 +0100 Subject: [PATCH 0485/1140] wip --- example/ios/Podfile.lock | 20 +- example/ios/Runner.xcodeproj/project.pbxproj | 2 + example/pubspec.yaml | 2 +- lib/src/channel_list_view.dart | 217 ++++++++++--------- lib/src/message_input.dart | 193 ++++++++++++----- pubspec.yaml | 1 + 6 files changed, 269 insertions(+), 166 deletions(-) diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock index 131e8aec..b028e9b7 100644 --- a/example/ios/Podfile.lock +++ b/example/ios/Podfile.lock @@ -121,9 +121,9 @@ PODS: - Flutter - PromisesObjC (1.2.11) - Protobuf (3.13.0) - - SDWebImage (5.9.4): - - SDWebImage/Core (= 5.9.4) - - SDWebImage/Core (5.9.4) + - SDWebImage (5.10.0): + - SDWebImage/Core (= 5.10.0) + - SDWebImage/Core (5.10.0) - shared_preferences (0.0.1): - Flutter - sqflite (0.0.2): @@ -148,11 +148,13 @@ PODS: - sqlite3/perf-threadsafe - sqlite3/rtree - Starscream (4.0.4) - - StreamChatClient (2.4.1): + - StreamChatClient (2.4.2): - Starscream (~> 4.0) - SwiftyGif (5.3.0) - url_launcher (0.0.1): - Flutter + - video_compress (0.3.0): + - Flutter - video_player (0.0.1): - Flutter - wakelock (0.0.1): @@ -177,6 +179,7 @@ DEPENDENCIES: - sqlite3_flutter_libs (from `.symlinks/plugins/sqlite3_flutter_libs/ios`) - StreamChatClient - url_launcher (from `.symlinks/plugins/url_launcher/ios`) + - video_compress (from `.symlinks/plugins/video_compress/ios`) - video_player (from `.symlinks/plugins/video_player/ios`) - wakelock (from `.symlinks/plugins/wakelock/ios`) @@ -237,6 +240,8 @@ EXTERNAL SOURCES: :path: ".symlinks/plugins/sqlite3_flutter_libs/ios" url_launcher: :path: ".symlinks/plugins/url_launcher/ios" + video_compress: + :path: ".symlinks/plugins/video_compress/ios" video_player: :path: ".symlinks/plugins/video_player/ios" wakelock: @@ -270,18 +275,19 @@ SPEC CHECKSUMS: permission_handler: eac8e15b4a1a3fba55b761d19f3f4e6b005d15b6 PromisesObjC: 8c196f5a328c2cba3e74624585467a557dcb482f Protobuf: 3dac39b34a08151c6d949560efe3f86134a3f748 - SDWebImage: b69257f4ab14e9b6a2ef53e910fdf914d8f757c1 + SDWebImage: 9169792e9eec3e45bba2a0c02f74bf8bd922d1ee shared_preferences: af6bfa751691cdc24be3045c43ec037377ada40d sqflite: 6d358c025f5b867b29ed92fc697fd34924e11904 sqlite3: 8f7d2078ae27778699a622a94b853285793422a2 sqlite3_flutter_libs: 5651f8ff48e3b44d910863c4ea5916085b1b245f Starscream: 5178aed56b316f13fa3bc55694e583d35dd414d9 - StreamChatClient: d061cf52babcd9df930aee9cf864ab0379427eff + StreamChatClient: fc6419fa7ceda9c048188bb7c8e9f07755ced05f SwiftyGif: e466e86c660d343357ab944a819a101c4127cb40 url_launcher: 6fef411d543ceb26efce54b05a0a40bfd74cbbef + video_compress: fce97e4fb1dfd88175aa07d2ffc8a2f297f87fbe video_player: 9cc823b1d9da7e8427ee591e8438bfbcde500e6e wakelock: bfc7955c418d0db797614075aabbc58a39ab5107 PODFILE CHECKSUM: eb001256612a59f8f9e4d083ad8b9671e69dd184 -COCOAPODS: 1.10.0.rc.1 +COCOAPODS: 1.10.0 diff --git a/example/ios/Runner.xcodeproj/project.pbxproj b/example/ios/Runner.xcodeproj/project.pbxproj index 709db931..bb101716 100644 --- a/example/ios/Runner.xcodeproj/project.pbxproj +++ b/example/ios/Runner.xcodeproj/project.pbxproj @@ -335,6 +335,7 @@ "${BUILT_PRODUCTS_DIR}/sqlite3/sqlite3.framework", "${BUILT_PRODUCTS_DIR}/sqlite3_flutter_libs/sqlite3_flutter_libs.framework", "${BUILT_PRODUCTS_DIR}/url_launcher/url_launcher.framework", + "${BUILT_PRODUCTS_DIR}/video_compress/video_compress.framework", "${BUILT_PRODUCTS_DIR}/video_player/video_player.framework", "${BUILT_PRODUCTS_DIR}/wakelock/wakelock.framework", ); @@ -366,6 +367,7 @@ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/sqlite3.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/sqlite3_flutter_libs.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/url_launcher.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/video_compress.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/video_player.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/wakelock.framework", ); diff --git a/example/pubspec.yaml b/example/pubspec.yaml index e5daa043..6e34335d 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -1,6 +1,6 @@ name: example description: A new Flutter project. -version: 1.0.66+68 +version: 1.0.70+72 environment: sdk: ">=2.2.2 <3.0.0" diff --git a/lib/src/channel_list_view.dart b/lib/src/channel_list_view.dart index 9dae4213..ab576b4f 100644 --- a/lib/src/channel_list_view.dart +++ b/lib/src/channel_list_view.dart @@ -166,123 +166,124 @@ class _ChannelListViewState extends State ChannelsBlocState channelsBlocState, ) { return StreamBuilder>( - stream: channelsBlocState.channelsStream, - builder: (context, snapshot) { - var child; - if (snapshot.hasError) { - child = _buildErrorWidget( - snapshot, - context, - channelsBlocState, - ); - } else if (!snapshot.hasData) { - child = _buildLoadingWidget(); - } else { - final channels = snapshot.data; + stream: channelsBlocState.channelsStream, + builder: (context, snapshot) { + var child; + if (snapshot.hasError) { + child = _buildErrorWidget( + snapshot, + context, + channelsBlocState, + ); + } else if (!snapshot.hasData) { + child = _buildLoadingWidget(); + } else { + final channels = snapshot.data; - if (channels.isEmpty && widget.emptyBuilder != null) { - child = widget.emptyBuilder(context); - } + if (channels.isEmpty && widget.emptyBuilder != null) { + child = widget.emptyBuilder(context); + } - if (channels.isEmpty && widget.emptyBuilder == null) { - child = LayoutBuilder( - builder: (context, viewportConstraints) { - return SingleChildScrollView( - physics: AlwaysScrollableScrollPhysics(), - child: Stack( - children: [ - ConstrainedBox( - constraints: BoxConstraints( - minHeight: viewportConstraints.maxHeight, - ), - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Padding( - padding: const EdgeInsets.all(8.0), - child: Icon( - StreamIcons.message, - size: 136, - color: Color(0xffDBDBDB), - ), - ), - Padding( - padding: const EdgeInsets.all(8.0), - child: Text( - 'Let’s start chatting!', - style: TextStyle( - fontSize: 16, - ), - ), - ), - Padding( - padding: const EdgeInsets.symmetric( - vertical: 8.0, - horizontal: 52, - ), - child: Text( - 'How about sending your first message to a friend?', - textAlign: TextAlign.center, - style: TextStyle( - fontSize: 14, - color: Color(0xff7A7A7A), - ), - ), - ), - ], - ), + if (channels.isEmpty && widget.emptyBuilder == null) { + child = LayoutBuilder( + builder: (context, viewportConstraints) { + return SingleChildScrollView( + physics: AlwaysScrollableScrollPhysics(), + child: Stack( + children: [ + ConstrainedBox( + constraints: BoxConstraints( + minHeight: viewportConstraints.maxHeight, ), - if (widget.onStartChatPressed != null) - Positioned( - right: 0, - left: 0, - bottom: 32, - child: Center( - child: FlatButton( - onPressed: widget.onStartChatPressed, - child: Text( - 'Start a chat', - style: TextStyle( - color: - StreamChatTheme.of(context).accentColor, - fontWeight: FontWeight.bold, - ), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Padding( + padding: const EdgeInsets.all(8.0), + child: Icon( + StreamIcons.message, + size: 136, + color: Color(0xffDBDBDB), + ), + ), + Padding( + padding: const EdgeInsets.all(8.0), + child: Text( + 'Let’s start chatting!', + style: TextStyle( + fontSize: 16, + ), + ), + ), + Padding( + padding: const EdgeInsets.symmetric( + vertical: 8.0, + horizontal: 52, + ), + child: Text( + 'How about sending your first message to a friend?', + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 14, + color: Color(0xff7A7A7A), + ), + ), + ), + ], + ), + ), + if (widget.onStartChatPressed != null) + Positioned( + right: 0, + left: 0, + bottom: 32, + child: Center( + child: FlatButton( + onPressed: widget.onStartChatPressed, + child: Text( + 'Start a chat', + style: TextStyle( + color: + StreamChatTheme.of(context).accentColor, + fontWeight: FontWeight.bold, ), ), ), ), - ], - ), - ); - }, - ); - } - - if (channels.isNotEmpty) { - child = ListView.custom( - physics: AlwaysScrollableScrollPhysics(), - controller: _scrollController, - childrenDelegate: SliverChildBuilderDelegate( - (context, i) { - return _itemBuilder(context, i, channels); - }, - childCount: (channels.length * 2) + 1, - findChildIndexCallback: (key) { - final ValueKey valueKey = key; - final index = channels.indexWhere( - (channel) => 'CHANNEL-${channel.id}' == valueKey.value); - return index != -1 ? (index * 2) : null; - }, - ), - ); - } + ), + ], + ), + ); + }, + ); } - return AnimatedSwitcher( - child: child, - duration: Duration(milliseconds: 500), - ); - }); + if (channels.isNotEmpty) { + child = ListView.custom( + physics: AlwaysScrollableScrollPhysics(), + controller: _scrollController, + childrenDelegate: SliverChildBuilderDelegate( + (context, i) { + return _itemBuilder(context, i, channels); + }, + childCount: (channels.length * 2) + 1, + findChildIndexCallback: (key) { + final ValueKey valueKey = key; + final index = channels.indexWhere( + (channel) => 'CHANNEL-${channel.id}' == valueKey.value); + return index != -1 ? (index * 2) : null; + }, + ), + ); + } + } + + return AnimatedSwitcher( + child: child, + duration: Duration(milliseconds: 500), + ); + }, + ); } Widget _buildLoadingWidget() { diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index af4b8979..c9bba5f6 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -21,6 +21,7 @@ import 'package:stream_chat_flutter/src/stream_chat_theme.dart'; import 'package:stream_chat_flutter/src/user_avatar.dart'; import 'package:stream_chat_flutter/src/video_thumbnail.dart'; import 'package:substring_highlight/substring_highlight.dart'; +import 'package:video_compress/video_compress.dart'; import '../stream_chat_flutter.dart'; import 'stream_channel.dart'; @@ -44,6 +45,8 @@ enum DefaultAttachmentTypes { const _kMinMediaPickerSize = 360.0; +const _kMaxAttachmentSize = 20480; //20MB + /// Inactive state /// ![screenshot](https://raw.githubusercontent.com/GetStream/stream-chat-flutter/master/screenshots/message_input.png) /// ![screenshot](https://raw.githubusercontent.com/GetStream/stream-chat-flutter/master/screenshots/message_input_paint.png) @@ -797,7 +800,6 @@ class MessageInputState extends State { var status = await (Platform.isAndroid ? Permission.storage.status : Permission.photos.status); - print('status: ${status}'); if (status.isPermanentlyDenied || status.isDenied) { if (await openAppSettings()) { setState(() {}); @@ -844,55 +846,114 @@ class MessageInputState extends State { } void _addAttachment(Media medium) async { - final attachment = _SendingAttachment( - id: medium.id, - ); - - setState(() { - _attachments.add(attachment); - }); - - final mediaFile = await medium.getFile(); - - final file = PlatformFile( - path: mediaFile.path, - bytes: mediaFile.readAsBytesSync(), - ); - - final channel = StreamChannel.of(context).channel; - setState(() { - attachment - ..file = file - ..attachment = Attachment( - localUri: file.path != null ? Uri.parse(file.path) : null, - type: medium.mediaType == MediaType.image ? 'image' : 'video', - ); - }); - - final url = await _uploadAttachment( - file, - medium.mediaType == MediaType.image - ? DefaultAttachmentTypes.image - : DefaultAttachmentTypes.video, - channel); - - final fileType = medium.mediaType == MediaType.image - ? DefaultAttachmentTypes.image - : DefaultAttachmentTypes.video; - - if (fileType == DefaultAttachmentTypes.image) { - attachment.attachment = attachment.attachment.copyWith( - imageUrl: url, + try { + final attachment = _SendingAttachment( + id: medium.id, ); - } else { - attachment.attachment = attachment.attachment.copyWith( - assetUrl: url, + + setState(() { + _attachments.add(attachment); + }); + + final mediaFile = await medium.getFile(); + + var file = PlatformFile( + path: mediaFile.path, + size: (await mediaFile.length()) ~/ 1024, + bytes: mediaFile.readAsBytesSync(), + ); + + if (file.size > _kMaxAttachmentSize) { + if (medium.mediaType == MediaType.video) { + final mediaInfo = await _compressVideo(file); + file = PlatformFile( + name: file.name, + size: mediaInfo.filesize, + bytes: await mediaInfo.file.readAsBytes(), + path: mediaInfo.path, + ); + } else { + Scaffold.of(context).showSnackBar( + SnackBar( + content: Text( + 'The file is too large to upload. The file size limit is 20MB', + ), + ), + ); + } + } + + final channel = StreamChannel.of(context).channel; + setState(() { + attachment + ..file = file + ..attachment = Attachment( + localUri: file.path != null ? Uri.parse(file.path) : null, + type: medium.mediaType == MediaType.image ? 'image' : 'video', + ); + }); + + final url = await _uploadAttachment( + file, + medium.mediaType == MediaType.image + ? DefaultAttachmentTypes.image + : DefaultAttachmentTypes.video, + channel); + + final fileType = medium.mediaType == MediaType.image + ? DefaultAttachmentTypes.image + : DefaultAttachmentTypes.video; + + if (fileType == DefaultAttachmentTypes.image) { + attachment.attachment = attachment.attachment.copyWith( + imageUrl: url, + ); + } else { + attachment.attachment = attachment.attachment.copyWith( + assetUrl: url, + ); + } + + if (mounted) { + setState(() { + attachment.uploaded = true; + }); + } + } catch (e, s) { + print(s); + Scaffold.of(context).showSnackBar( + SnackBar( + content: Text('Error adding the attachment: $e'), + ), ); } + } - setState(() { - attachment.uploaded = true; - }); + Future _compressVideo(PlatformFile file) async { + print('file.size: ${file.size}'); + print('VideoCompress.isCompressing: ${VideoCompress.isCompressing}'); + if (VideoCompress.isCompressing) { + final compressCompleter = Completer(); + VideoCompress.compressProgress$.subscribe( + (event) { + print('event: ${event}'); + }, + onDone: () { + compressCompleter.complete(); + }, + onError: (e) { + compressCompleter.completeError(e); + }, + ); + await compressCompleter.future; + } + final mediaInfo = await VideoCompress.compressVideo( + file.path, + ); + + print('mediaInfo.filesize: ${mediaInfo.filesize / 1024}'); + + return mediaInfo; } CircleAvatar _buildGiphyIcon() { @@ -1270,9 +1331,10 @@ class MessageInputState extends State { Positioned.fill( child: Container( child: VideoThumbnail( - file: File( - attachment.file.path, - )), + file: File( + attachment.file.path, + ), + ), ), ), Positioned( @@ -1501,7 +1563,6 @@ class MessageInputState extends State { ); if (res?.files?.isNotEmpty == true) { file = res.files.single; - print('file.bytes?.length: ${file.bytes?.length}'); } } @@ -1513,6 +1574,26 @@ class MessageInputState extends State { return; } + if (file.size > _kMaxAttachmentSize) { + if (attachmentType == 'video') { + final mediaInfo = await _compressVideo(file); + file = PlatformFile( + name: mediaInfo.title, + size: mediaInfo.filesize, + bytes: await mediaInfo.file.readAsBytes(), + path: mediaInfo.path, + ); + } else { + Scaffold.of(context).showSnackBar( + SnackBar( + content: Text( + 'The file is too large to upload. The file size limit is 20MB', + ), + ), + ); + } + } + final channel = StreamChannel.of(context).channel; final attachment = _SendingAttachment( file: file, @@ -1740,11 +1821,23 @@ class MessageInputState extends State { } StreamSubscription _keyboardListener; + Subscription _videoCompressSubscription; + Completer _videoCompressCompleter = Completer(); @override void initState() { super.initState(); + VideoCompress.compressProgress$.subscribe( + (event) {}, + onDone: () { + _videoCompressCompleter.complete(); + }, + onError: (e) { + _videoCompressCompleter.completeError(e); + }, + ); + _focusNode = widget.focusNode ?? FocusNode(); _emojiNames = Emoji.all().map((e) => e.name); diff --git a/pubspec.yaml b/pubspec.yaml index f8705c22..1fec50c0 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -30,6 +30,7 @@ dependencies: flutter_keyboard_visibility: ^3.3.0 stream_chat: ^0.2.13+1 mime: ^0.9.6+3 + video_compress: ^2.1.1 visibility_detector: ^0.1.5 http_parser: ^3.1.4 substring_highlight: ^0.1.2 From 58b079abbad26b569a13eef3ab7c7fe005e4596f Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Wed, 25 Nov 2020 15:29:08 +0100 Subject: [PATCH 0486/1140] fix svgs icons --- example/lib/new_group_chat_screen.dart | 18 +++++++++++++++--- example/pubspec.yaml | 2 +- lib/src/stream_svg_icon.dart | 2 -- 3 files changed, 16 insertions(+), 6 deletions(-) diff --git a/example/lib/new_group_chat_screen.dart b/example/lib/new_group_chat_screen.dart index a11767c3..8361c895 100644 --- a/example/lib/new_group_chat_screen.dart +++ b/example/lib/new_group_chat_screen.dart @@ -100,9 +100,21 @@ class _NewGroupChatScreenState extends State { child: TextField( controller: _controller, decoration: InputDecoration( - prefixIcon: StreamSvgIcon.search( - color: Colors.black, - size: 24, + prefixIconConstraints: BoxConstraints.tight( + Size( + 40, + 24, + ), + ), + prefixIcon: Padding( + padding: const EdgeInsets.only( + left: 8, + right: 8, + ), + child: StreamSvgIcon.search( + color: Colors.black, + size: 24, + ), ), hintText: 'Search', hintStyle: TextStyle( diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 43eb867e..491dbbb7 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -1,6 +1,6 @@ name: example description: A new Flutter project. -version: 1.0.72+74 +version: 1.0.73+75 environment: sdk: ">=2.2.2 <3.0.0" diff --git a/lib/src/stream_svg_icon.dart b/lib/src/stream_svg_icon.dart index 19daca34..2851df3a 100644 --- a/lib/src/stream_svg_icon.dart +++ b/lib/src/stream_svg_icon.dart @@ -25,7 +25,6 @@ class StreamSvgIcon extends StatelessWidget { height: height, key: key, color: color, - fit: BoxFit.scaleDown, alignment: Alignment.center, ) : SvgPicture.asset( @@ -35,7 +34,6 @@ class StreamSvgIcon extends StatelessWidget { width: width, height: height, color: color, - fit: BoxFit.scaleDown, alignment: Alignment.center, ); } From 3c9072e81c6d06fec23430963b38d6024375ccee Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Wed, 25 Nov 2020 15:50:00 +0100 Subject: [PATCH 0487/1140] save config for advanced options --- example/lib/advanced_options_page.dart | 16 ++++++++++++++++ example/pubspec.yaml | 2 +- lib/src/channel_preview.dart | 2 +- lib/src/message_widget.dart | 3 ++- lib/src/user_avatar.dart | 1 + 5 files changed, 21 insertions(+), 3 deletions(-) diff --git a/example/lib/advanced_options_page.dart b/example/lib/advanced_options_page.dart index 212a15a8..e07afefd 100644 --- a/example/lib/advanced_options_page.dart +++ b/example/lib/advanced_options_page.dart @@ -7,6 +7,8 @@ import 'package:stream_chat_flutter/stream_chat_flutter.dart'; import 'main.dart'; import 'notifications_service.dart'; +import 'choose_user_page.dart'; +import 'package:flutter_secure_storage/flutter_secure_storage.dart'; class AdvancedOptionsPage extends StatefulWidget { @override @@ -285,6 +287,20 @@ class _AdvancedOptionsPageState extends State { if (!kIsWeb) { initNotifications(client); } + + final secureStorage = FlutterSecureStorage(); + secureStorage.write( + key: kStreamApiKey, + value: apiKey, + ); + secureStorage.write( + key: kStreamUserId, + value: userId, + ); + secureStorage.write( + key: kStreamToken, + value: userToken, + ); } catch (e) { var errorText = 'Error connecting, retry'; if (e is Map) { diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 491dbbb7..7c76b15f 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -1,6 +1,6 @@ name: example description: A new Flutter project. -version: 1.0.73+75 +version: 1.0.74+76 environment: sdk: ">=2.2.2 <3.0.0" diff --git a/lib/src/channel_preview.dart b/lib/src/channel_preview.dart index 3c9eeace..26f68812 100644 --- a/lib/src/channel_preview.dart +++ b/lib/src/channel_preview.dart @@ -104,7 +104,7 @@ class ChannelPreview extends StatelessWidget { .isAfter(channel .state.lastMessage.createdAt)) .length == - (channel.memberCount ?? 0) - 1, + (channel.memberCount ?? 0), ), ); } diff --git a/lib/src/message_widget.dart b/lib/src/message_widget.dart index 86479ebe..280de349 100644 --- a/lib/src/message_widget.dart +++ b/lib/src/message_widget.dart @@ -426,12 +426,13 @@ class _MessageWidgetState extends State { top: 0, child: Material( color: Colors.white, + clipBehavior: Clip.antiAlias, shape: CircleBorder(), child: Padding( padding: const EdgeInsets.all(1.0), child: UserAvatar( user: e.user, - constraints: BoxConstraints.loose(Size.fromRadius(16)), + constraints: BoxConstraints.loose(Size.fromRadius(8)), showOnlineStatus: false, ), ), diff --git a/lib/src/user_avatar.dart b/lib/src/user_avatar.dart index 2e1f3e0e..756252cc 100644 --- a/lib/src/user_avatar.dart +++ b/lib/src/user_avatar.dart @@ -40,6 +40,7 @@ class UserAvatar extends StatelessWidget { final streamChatTheme = StreamChatTheme.of(context); Widget avatar = ClipRRect( + clipBehavior: Clip.antiAlias, borderRadius: borderRadius ?? streamChatTheme.ownMessageTheme.avatarTheme.borderRadius, child: Container( From e936b828be3b73116fdcc69764d13371e06abdca Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Wed, 25 Nov 2020 15:52:32 +0100 Subject: [PATCH 0488/1140] fix api keyy --- example/lib/choose_user_page.dart | 2 +- example/pubspec.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/example/lib/choose_user_page.dart b/example/lib/choose_user_page.dart index f1a53773..48b66b2d 100644 --- a/example/lib/choose_user_page.dart +++ b/example/lib/choose_user_page.dart @@ -132,7 +132,7 @@ class ChooseUserPage extends StatelessWidget { final secureStorage = FlutterSecureStorage(); final client = StreamChat.of(context).client; - + client.apiKey = kDefaultStreamApiKey; await client.setUser( user, token, diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 7c76b15f..02c2c726 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -1,6 +1,6 @@ name: example description: A new Flutter project. -version: 1.0.74+76 +version: 1.0.75+77 environment: sdk: ">=2.2.2 <3.0.0" From 2ea38c128ba1788b26fccd1b6d9be62269cc2afb Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Wed, 25 Nov 2020 17:05:39 +0100 Subject: [PATCH 0489/1140] compress videos --- lib/src/channel_list_view.dart | 39 ++++++++++---------- lib/src/compress_video_service.dart | 19 ++++++++++ lib/src/message_input.dart | 56 ++++++++--------------------- 3 files changed, 53 insertions(+), 61 deletions(-) create mode 100644 lib/src/compress_video_service.dart diff --git a/lib/src/channel_list_view.dart b/lib/src/channel_list_view.dart index b7fbf408..45c53eb6 100644 --- a/lib/src/channel_list_view.dart +++ b/lib/src/channel_list_view.dart @@ -185,26 +185,25 @@ class _ChannelListViewState extends State child = widget.emptyBuilder(context); } - if (channels.isEmpty && widget.emptyBuilder == null) { - child = LayoutBuilder( - builder: (context, viewportConstraints) { - return SingleChildScrollView( - physics: AlwaysScrollableScrollPhysics(), - child: Stack( - children: [ - ConstrainedBox( - constraints: BoxConstraints( - minHeight: viewportConstraints.maxHeight, - ), - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Padding( - padding: const EdgeInsets.all(8.0), - child: StreamSvgIcon.message( - size: 136, - color: Color(0xffDBDBDB), - ), + if (channels.isEmpty && widget.emptyBuilder == null) { + child = LayoutBuilder( + builder: (context, viewportConstraints) { + return SingleChildScrollView( + physics: AlwaysScrollableScrollPhysics(), + child: Stack( + children: [ + ConstrainedBox( + constraints: BoxConstraints( + minHeight: viewportConstraints.maxHeight, + ), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Padding( + padding: const EdgeInsets.all(8.0), + child: StreamSvgIcon.message( + size: 136, + color: Color(0xffDBDBDB), ), ), Padding( diff --git a/lib/src/compress_video_service.dart b/lib/src/compress_video_service.dart new file mode 100644 index 00000000..f8d63e0c --- /dev/null +++ b/lib/src/compress_video_service.dart @@ -0,0 +1,19 @@ +import 'dart:async'; +import 'package:video_compress/video_compress.dart'; + +class CompressVideoService { + static final CompressVideoService instance = CompressVideoService._(); + + CompressVideoService._(); + + Future compressVideo(String path) async { + MediaInfo mediaInfo; + while (VideoCompress.isCompressing) { + await Future.delayed(Duration(seconds: 1)); + } + mediaInfo = await VideoCompress.compressVideo( + path, + ); + return mediaInfo; + } +} diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 25cc12db..9a8b1f75 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -14,6 +14,7 @@ import 'package:media_gallery/media_gallery.dart'; import 'package:mime/mime.dart'; import 'package:permission_handler/permission_handler.dart'; import 'package:stream_chat/stream_chat.dart'; +import 'package:stream_chat_flutter/src/compress_video_service.dart'; import 'package:stream_chat_flutter/src/media_list_view.dart'; import 'package:stream_chat_flutter/src/message_list_view.dart'; import 'package:stream_chat_flutter/src/stream_chat_theme.dart'; @@ -865,7 +866,18 @@ class MessageInputState extends State { if (file.size > _kMaxAttachmentSize) { if (medium.mediaType == MediaType.video) { - final mediaInfo = await _compressVideo(file); + final mediaInfo = + await CompressVideoService.instance.compressVideo(file.path); + + if (mediaInfo.filesize / (1024 * 1024) > _kMaxAttachmentSize) { + Scaffold.of(context).showSnackBar( + SnackBar( + content: Text( + 'The file is too large to upload. The file size limit is 20MB. We tried compressing it, but it was not enough.', + ), + ), + ); + } file = PlatformFile( name: file.name, size: mediaInfo.filesize, @@ -929,33 +941,6 @@ class MessageInputState extends State { } } - Future _compressVideo(PlatformFile file) async { - print('file.size: ${file.size}'); - print('VideoCompress.isCompressing: ${VideoCompress.isCompressing}'); - if (VideoCompress.isCompressing) { - final compressCompleter = Completer(); - VideoCompress.compressProgress$.subscribe( - (event) { - print('event: ${event}'); - }, - onDone: () { - compressCompleter.complete(); - }, - onError: (e) { - compressCompleter.completeError(e); - }, - ); - await compressCompleter.future; - } - final mediaInfo = await VideoCompress.compressVideo( - file.path, - ); - - print('mediaInfo.filesize: ${mediaInfo.filesize / 1024}'); - - return mediaInfo; - } - CircleAvatar _buildGiphyIcon() { if (kIsWeb) { return CircleAvatar( @@ -1571,7 +1556,8 @@ class MessageInputState extends State { if (file.size > _kMaxAttachmentSize) { if (attachmentType == 'video') { - final mediaInfo = await _compressVideo(file); + final mediaInfo = await CompressVideoService.instance + .compressVideo(file.path, _kMaxAttachmentSize); file = PlatformFile( name: mediaInfo.title, size: mediaInfo.filesize, @@ -1800,23 +1786,11 @@ class MessageInputState extends State { } StreamSubscription _keyboardListener; - Subscription _videoCompressSubscription; - Completer _videoCompressCompleter = Completer(); @override void initState() { super.initState(); - VideoCompress.compressProgress$.subscribe( - (event) {}, - onDone: () { - _videoCompressCompleter.complete(); - }, - onError: (e) { - _videoCompressCompleter.completeError(e); - }, - ); - _focusNode = widget.focusNode ?? FocusNode(); _emojiNames = Emoji.all().map((e) => e.name); From efd6bfdc8e64bdbddbb645417ac76cbd193d0b90 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Wed, 25 Nov 2020 17:19:38 +0100 Subject: [PATCH 0490/1140] fix error --- lib/src/message_input.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 9a8b1f75..d3482806 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -1556,8 +1556,8 @@ class MessageInputState extends State { if (file.size > _kMaxAttachmentSize) { if (attachmentType == 'video') { - final mediaInfo = await CompressVideoService.instance - .compressVideo(file.path, _kMaxAttachmentSize); + final mediaInfo = + await CompressVideoService.instance.compressVideo(file.path); file = PlatformFile( name: mediaInfo.title, size: mediaInfo.filesize, From ed3fc88f623738feb69bca81a4bfc760872283e6 Mon Sep 17 00:00:00 2001 From: xsahil03x Date: Wed, 25 Nov 2020 22:37:11 +0530 Subject: [PATCH 0491/1140] Configure routes in example project. --- example/lib/choose_user_page.dart | 22 ++------ example/lib/group_chat_details_screen.dart | 19 +++---- example/lib/main.dart | 62 +++++++++------------ example/lib/new_chat_screen.dart | 18 +++--- example/lib/new_group_chat_screen.dart | 11 ++-- example/lib/routes/app_routes.dart | 64 ++++++++++++++++++++++ example/lib/routes/routes.dart | 10 ++++ 7 files changed, 124 insertions(+), 82 deletions(-) create mode 100644 example/lib/routes/app_routes.dart create mode 100644 example/lib/routes/routes.dart diff --git a/example/lib/choose_user_page.dart b/example/lib/choose_user_page.dart index f1a53773..0e16f012 100644 --- a/example/lib/choose_user_page.dart +++ b/example/lib/choose_user_page.dart @@ -8,6 +8,7 @@ import 'package:flutter_svg/flutter_svg.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; import 'notifications_service.dart'; +import 'routes/routes.dart'; const kStreamApiKey = 'STREAM_API_KEY'; const kStreamUserId = 'STREAM_USER_ID'; @@ -154,18 +155,10 @@ class ChooseUserPage extends StatelessWidget { if (!kIsWeb) { initNotifications(client); } - - Navigator.pop(context); - await Navigator.pushReplacement( + Navigator.pushReplacementNamed( context, - MaterialPageRoute( - builder: (context) { - return StreamChat( - client: client, - child: ChannelListPage(), - ); - }, - ), + Routes.CHANNEL_LIST, + arguments: client, ); }, leading: UserAvatar( @@ -188,12 +181,7 @@ class ChooseUserPage extends StatelessWidget { }), ListTile( onTap: () { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => AdvancedOptionsPage(), - ), - ); + Navigator.pushNamed(context, Routes.ADVANCED_OPTIONS); }, leading: CircleAvatar( child: StreamSvgIcon.settings( diff --git a/example/lib/group_chat_details_screen.dart b/example/lib/group_chat_details_screen.dart index 36999c7f..88de33a9 100644 --- a/example/lib/group_chat_details_screen.dart +++ b/example/lib/group_chat_details_screen.dart @@ -3,6 +3,7 @@ import 'package:stream_chat_flutter/stream_chat_flutter.dart'; import 'package:uuid/uuid.dart'; import 'main.dart'; +import 'routes/routes.dart'; class GroupChatDetailsScreen extends StatefulWidget { final List selectedUsers; @@ -128,18 +129,12 @@ class _GroupChatDetailsScreenState extends State { 'name': groupName, }); await channel.watch(); - Navigator.of(context) - ..pop() - ..pushReplacement( - MaterialPageRoute( - builder: (context) { - return StreamChannel( - child: ChannelPage(), - channel: channel, - ); - }, - ), - ); + Navigator.pushNamedAndRemoveUntil( + context, + Routes.CHANNEL_PAGE, + ModalRoute.withName(Routes.CHANNEL_LIST), + arguments: channel, + ); }, ), ), diff --git a/example/lib/main.dart b/example/lib/main.dart index d2be225a..6cf35e0e 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -10,6 +10,8 @@ import 'package:flutter_secure_storage/flutter_secure_storage.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; import 'notifications_service.dart'; +import 'routes/app_routes.dart'; +import 'routes/routes.dart'; void main() async { WidgetsFlutterBinding.ensureInitialized(); @@ -47,19 +49,19 @@ class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { - return MaterialApp( - debugShowCheckedModeBanner: false, - theme: ThemeData.light(), - darkTheme: ThemeData.dark(), - //TODO change to system once dark theme is implemented - themeMode: ThemeMode.light, - builder: (context, widget) { - return StreamChat( - child: widget, - client: client, - ); - }, - home: client.state.user == null ? ChooseUserPage() : ChannelListPage(), + return StreamChat( + client: client, + child: MaterialApp( + debugShowCheckedModeBanner: false, + theme: ThemeData.light(), + darkTheme: ThemeData.dark(), + //TODO change to system once dark theme is implemented + themeMode: ThemeMode.light, + onGenerateRoute: AppRoutes.generateRoute, + initialRoute: client.state.user == null + ? Routes.CHOOSE_USER + : Routes.CHANNEL_LIST, + ), ); } } @@ -71,11 +73,7 @@ class ChannelListPage extends StatelessWidget { return Scaffold( appBar: ChannelListHeader( onNewChatButtonTap: () { - Navigator.of(context).push( - MaterialPageRoute( - builder: (context) => NewChatScreen(), - ), - ); + Navigator.pushNamed(context, Routes.NEW_CHAT); }, ), drawer: _buildDrawer(context, user), @@ -83,9 +81,7 @@ class ChannelListPage extends StatelessWidget { body: ChannelsBloc( child: ChannelListView( onStartChatPressed: () { - Navigator.of(context).push(MaterialPageRoute(builder: (context) { - return NewChatScreen(); - })); + Navigator.pushNamed(context, Routes.NEW_CHAT); }, swipeToAction: true, filter: { @@ -147,11 +143,10 @@ class ChannelListPage extends StatelessWidget { color: Colors.black.withOpacity(.5), ), onTap: () { - Navigator.of(context) - ..pop() - ..push(MaterialPageRoute(builder: (context) { - return NewChatScreen(); - })); + Navigator.popAndPushNamed( + context, + Routes.NEW_CHAT, + ); }, title: Text( 'New direct message', @@ -165,11 +160,10 @@ class ChannelListPage extends StatelessWidget { color: Colors.black.withOpacity(.5), ), onTap: () { - Navigator.of(context) - ..pop() - ..push(MaterialPageRoute(builder: (context) { - return NewGroupChatScreen(); - })); + Navigator.popAndPushNamed( + context, + Routes.NEW_GROUP_CHAT, + ); }, title: Text( 'New group', @@ -188,11 +182,9 @@ class ChannelListPage extends StatelessWidget { final secureStorage = FlutterSecureStorage(); await secureStorage.deleteAll(); Navigator.pop(context); - await Navigator.pushReplacement( + Navigator.pushReplacementNamed( context, - MaterialPageRoute( - builder: (context) => ChooseUserPage(), - ), + Routes.CHOOSE_USER, ); }, leading: StreamSvgIcon.user( diff --git a/example/lib/new_chat_screen.dart b/example/lib/new_chat_screen.dart index 5e6af8fc..364c8b7e 100644 --- a/example/lib/new_chat_screen.dart +++ b/example/lib/new_chat_screen.dart @@ -6,6 +6,7 @@ import 'package:stream_chat_flutter/stream_chat_flutter.dart'; import 'chips_input_text_field.dart'; import 'main.dart'; import 'new_group_chat_screen.dart'; +import 'routes/routes.dart'; class NewChatScreen extends StatefulWidget { @override @@ -182,9 +183,9 @@ class _NewChatScreenState extends State { Container( child: InkWell( onTap: () { - Navigator.push( + Navigator.pushNamed( context, - MaterialPageRoute(builder: (_) => NewGroupChatScreen()), + Routes.NEW_GROUP_CHAT, ); }, child: Padding( @@ -334,16 +335,11 @@ class _NewChatScreenState extends State { channel.update({ 'draft': false, }); - Navigator.pushReplacement( + Navigator.pushNamedAndRemoveUntil( context, - MaterialPageRoute( - builder: (context) { - return StreamChannel( - child: ChannelPage(), - channel: channel, - ); - }, - ), + Routes.CHANNEL_PAGE, + ModalRoute.withName(Routes.CHANNEL_LIST), + arguments: channel, ); } } diff --git a/example/lib/new_group_chat_screen.dart b/example/lib/new_group_chat_screen.dart index ece3ca9a..ff77e44d 100644 --- a/example/lib/new_group_chat_screen.dart +++ b/example/lib/new_group_chat_screen.dart @@ -5,6 +5,7 @@ import 'package:stream_chat_flutter/stream_chat_flutter.dart'; import 'group_chat_details_screen.dart'; import 'search_text_field.dart'; +import 'routes/routes.dart'; class NewGroupChatScreen extends StatefulWidget { @override @@ -78,14 +79,10 @@ class _NewGroupChatScreenState extends State { color: Color(0xFF006CFF), ), onPressed: () async { - final updatedList = await Navigator.push( + final updatedList = await Navigator.pushNamed( context, - MaterialPageRoute( - builder: (_) => GroupChatDetailsScreen( - selectedUsers: - _selectedUsers.toList(growable: false), - ), - ), + Routes.NEW_GROUP_CHAT_DETAILS, + arguments: _selectedUsers.toList(growable: false), ); if (updatedList != null) { setState(() { diff --git a/example/lib/routes/app_routes.dart b/example/lib/routes/app_routes.dart new file mode 100644 index 00000000..19352319 --- /dev/null +++ b/example/lib/routes/app_routes.dart @@ -0,0 +1,64 @@ +import 'routes.dart'; +import 'package:flutter/material.dart'; +import '../choose_user_page.dart'; +import '../advanced_options_page.dart'; +import 'package:stream_chat_flutter/stream_chat_flutter.dart'; +import '../main.dart'; +import '../group_chat_details_screen.dart'; +import '../new_group_chat_screen.dart'; +import '../new_chat_screen.dart'; + +class AppRoutes { + /// Add entry for new route here + static Route generateRoute(RouteSettings settings) { + final args = settings.arguments; + switch (settings.name) { + case Routes.CHANNEL_LIST: + return MaterialPageRoute( + settings: const RouteSettings(name: Routes.CHANNEL_LIST), + builder: (_) { + return ChannelListPage(); + }); + case Routes.CHOOSE_USER: + return MaterialPageRoute( + settings: const RouteSettings(name: Routes.CHOOSE_USER), + builder: (_) { + return ChooseUserPage(); + }); + case Routes.ADVANCED_OPTIONS: + return MaterialPageRoute( + settings: const RouteSettings(name: Routes.ADVANCED_OPTIONS), + builder: (_) => AdvancedOptionsPage(), + ); + case Routes.CHANNEL_PAGE: + return MaterialPageRoute( + settings: const RouteSettings(name: Routes.CHANNEL_PAGE), + builder: (_) { + return StreamChannel( + channel: args as Channel, + child: ChannelPage(), + ); + }); + case Routes.NEW_CHAT: + return MaterialPageRoute( + settings: const RouteSettings(name: Routes.NEW_CHAT), + builder: (_) { + return NewChatScreen(); + }); + case Routes.NEW_GROUP_CHAT: + return MaterialPageRoute( + settings: const RouteSettings(name: Routes.NEW_GROUP_CHAT), + builder: (_) { + return NewGroupChatScreen(); + }); + case Routes.NEW_GROUP_CHAT_DETAILS: + return MaterialPageRoute( + settings: const RouteSettings(name: Routes.NEW_GROUP_CHAT_DETAILS), + builder: (_) { + return GroupChatDetailsScreen( + selectedUsers: args, + ); + }); + } + } +} diff --git a/example/lib/routes/routes.dart b/example/lib/routes/routes.dart new file mode 100644 index 00000000..f4ace9a4 --- /dev/null +++ b/example/lib/routes/routes.dart @@ -0,0 +1,10 @@ +/// Define all the route names here +class Routes { + static const String CHANNEL_LIST = '/channel_list'; + static const String CHOOSE_USER = '/choose_user'; + static const String ADVANCED_OPTIONS = '/advance_options'; + static const String CHANNEL_PAGE = '/channel_page'; + static const String NEW_CHAT = '/new_chat'; + static const String NEW_GROUP_CHAT = '/new_group_chat'; + static const String NEW_GROUP_CHAT_DETAILS = '/new_group_chat_details'; +} From 1c42db37dae8fb6f8cf98439e28dadff65aa7620 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Thu, 26 Nov 2020 11:56:56 +0530 Subject: [PATCH 0492/1140] Fix search icon Signed-off-by: xsahil03x --- example/lib/search_text_field.dart | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/example/lib/search_text_field.dart b/example/lib/search_text_field.dart index 8461d735..f46a48b0 100644 --- a/example/lib/search_text_field.dart +++ b/example/lib/search_text_field.dart @@ -40,9 +40,16 @@ class SearchTextField extends StatelessWidget { controller: controller, onChanged: onChanged, decoration: InputDecoration( - prefixIcon: StreamSvgIcon.search( - color: Colors.black, - size: 24, + prefixIconConstraints: BoxConstraints.tight(Size(40, 24)), + prefixIcon: Padding( + padding: const EdgeInsets.only( + left: 8, + right: 8, + ), + child: StreamSvgIcon.search( + color: Colors.black, + size: 24, + ), ), hintText: hintText, hintStyle: TextStyle( From a636253e98a87c0dea3dbdbc1792429d3116d5af Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Thu, 26 Nov 2020 11:23:33 +0100 Subject: [PATCH 0493/1140] use lock in compress service --- lib/src/compress_video_service.dart | 17 ++++++++--------- lib/src/message_input.dart | 5 +++++ pubspec.yaml | 1 + 3 files changed, 14 insertions(+), 9 deletions(-) diff --git a/lib/src/compress_video_service.dart b/lib/src/compress_video_service.dart index f8d63e0c..abd4a045 100644 --- a/lib/src/compress_video_service.dart +++ b/lib/src/compress_video_service.dart @@ -1,19 +1,18 @@ import 'dart:async'; +import 'package:synchronized/synchronized.dart'; import 'package:video_compress/video_compress.dart'; class CompressVideoService { static final CompressVideoService instance = CompressVideoService._(); - + final _lock = Lock(); CompressVideoService._(); Future compressVideo(String path) async { - MediaInfo mediaInfo; - while (VideoCompress.isCompressing) { - await Future.delayed(Duration(seconds: 1)); - } - mediaInfo = await VideoCompress.compressVideo( - path, - ); - return mediaInfo; + print('VideoCompress.isCompressing: ${VideoCompress.isCompressing}'); + return _lock.synchronized(() { + return VideoCompress.compressVideo( + path, + ); + }); } } diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index d3482806..3487fb26 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -877,6 +877,11 @@ class MessageInputState extends State { ), ), ); + + setState(() { + _attachments.remove(attachment); + }); + return; } file = PlatformFile( name: file.name, diff --git a/pubspec.yaml b/pubspec.yaml index 88d8f216..412550ef 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -42,6 +42,7 @@ dependencies: permission_handler: ^5.0.1+1 transparent_image: ^1.0.0 ezanimation: ^0.4.1 + synchronized: ^2.2.0+2 flutter: assets: From eca446bcea6d1fcd6c3fc54223556b1a8202dfc2 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Thu, 26 Nov 2020 11:40:29 +0100 Subject: [PATCH 0494/1140] remove log --- lib/src/compress_video_service.dart | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/src/compress_video_service.dart b/lib/src/compress_video_service.dart index abd4a045..56b11d1e 100644 --- a/lib/src/compress_video_service.dart +++ b/lib/src/compress_video_service.dart @@ -8,7 +8,6 @@ class CompressVideoService { CompressVideoService._(); Future compressVideo(String path) async { - print('VideoCompress.isCompressing: ${VideoCompress.isCompressing}'); return _lock.synchronized(() { return VideoCompress.compressVideo( path, From ebcaed87710640c9dfef3ce6c9ec0d787740a665 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Thu, 26 Nov 2020 11:44:14 +0100 Subject: [PATCH 0495/1140] add singleton trick --- lib/src/compress_video_service.dart | 9 ++++++--- lib/src/message_input.dart | 6 ++---- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/lib/src/compress_video_service.dart b/lib/src/compress_video_service.dart index 56b11d1e..43d2c79c 100644 --- a/lib/src/compress_video_service.dart +++ b/lib/src/compress_video_service.dart @@ -2,10 +2,10 @@ import 'dart:async'; import 'package:synchronized/synchronized.dart'; import 'package:video_compress/video_compress.dart'; -class CompressVideoService { - static final CompressVideoService instance = CompressVideoService._(); +class ICompressVideoService { + static final ICompressVideoService instance = ICompressVideoService._(); final _lock = Lock(); - CompressVideoService._(); + ICompressVideoService._(); Future compressVideo(String path) async { return _lock.synchronized(() { @@ -15,3 +15,6 @@ class CompressVideoService { }); } } + +ICompressVideoService get CompressVideoService => + ICompressVideoService.instance; diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 3487fb26..c9ed15bb 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -866,8 +866,7 @@ class MessageInputState extends State { if (file.size > _kMaxAttachmentSize) { if (medium.mediaType == MediaType.video) { - final mediaInfo = - await CompressVideoService.instance.compressVideo(file.path); + final mediaInfo = await CompressVideoService.compressVideo(file.path); if (mediaInfo.filesize / (1024 * 1024) > _kMaxAttachmentSize) { Scaffold.of(context).showSnackBar( @@ -1561,8 +1560,7 @@ class MessageInputState extends State { if (file.size > _kMaxAttachmentSize) { if (attachmentType == 'video') { - final mediaInfo = - await CompressVideoService.instance.compressVideo(file.path); + final mediaInfo = await CompressVideoService.compressVideo(file.path); file = PlatformFile( name: mediaInfo.title, size: mediaInfo.filesize, From 139730d9113204df2da32b60337800f232153d64 Mon Sep 17 00:00:00 2001 From: xsahil03x Date: Thu, 26 Nov 2020 16:28:15 +0530 Subject: [PATCH 0496/1140] minor fix Signed-off-by: xsahil03x --- example/lib/chips_input_text_field.dart | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/example/lib/chips_input_text_field.dart b/example/lib/chips_input_text_field.dart index 26f2d2b5..2ef308f8 100644 --- a/example/lib/chips_input_text_field.dart +++ b/example/lib/chips_input_text_field.dart @@ -133,8 +133,7 @@ class ChipInputTextFieldState extends State> { color: Colors.black.withOpacity(0.5), size: 24, ), - onPressed: - !_pauseItemAddition ? null : resumeItemAddition, + onPressed: resumeItemAddition, alignment: Alignment.topRight, visualDensity: VisualDensity.compact, padding: const EdgeInsets.all(0), From 68f5e5e4dc61a73f1319e168c7eb3a0ff771efe0 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Thu, 26 Nov 2020 13:41:46 +0100 Subject: [PATCH 0497/1140] fix scroll to bottom button --- lib/src/message_list_view.dart | 64 +++++++++++++++++----------------- 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/lib/src/message_list_view.dart b/lib/src/message_list_view.dart index 1be1d0aa..a1b09e43 100644 --- a/lib/src/message_list_view.dart +++ b/lib/src/message_list_view.dart @@ -309,19 +309,8 @@ class _MessageListViewState extends State { return messageWidget; }, ), - if (streamChannel.channel.state.members.contains((Member e) => - e.userId == streamChannel.channel.client.state.user.id) && - widget.showScrollToBottom) - StreamBuilder( - stream: streamChannel.channel.state.unreadCountStream, - builder: (context, snapshot) { - if (!_showScrollToBottom || - !snapshot.hasData || - snapshot.data == 0) { - return SizedBox(); - } - return _buildScrollToBottom(snapshot.data); - }), + if (widget.showScrollToBottom && _showScrollToBottom) + _buildScrollToBottom(), Positioned( top: 20.0, child: ValueListenableBuilder>( @@ -364,7 +353,8 @@ class _MessageListViewState extends State { position.itemLeadingEdge > max.itemLeadingEdge ? position : max); } - Widget _buildScrollToBottom(int unreadCount) { + Widget _buildScrollToBottom() { + final streamChannel = StreamChannel.of(context); return Positioned( bottom: 8, right: 8, @@ -389,24 +379,34 @@ class _MessageListViewState extends State { ); }, ), - Positioned( - width: 20, - height: 20, - left: 10, - top: -10, - child: CircleAvatar( - child: Padding( - padding: const EdgeInsets.all(3.0), - child: Text( - unreadCount.toString(), - style: TextStyle( - fontSize: 11, - fontWeight: FontWeight.bold, - ), - ), - ), - ), - ), + if (streamChannel.channel.state.members.any((Member e) => + e.userId == streamChannel.channel.client.state.user.id)) + StreamBuilder( + stream: streamChannel.channel.state.unreadCountStream, + initialData: streamChannel.channel.state.unreadCount, + builder: (context, snapshot) { + if (!snapshot.hasData || snapshot.data <= 0) { + return Offstage(); + } + return Positioned( + width: 20, + height: 20, + left: 10, + top: -10, + child: CircleAvatar( + child: Padding( + padding: const EdgeInsets.all(3.0), + child: Text( + snapshot.data.toString(), + style: TextStyle( + fontSize: 11, + fontWeight: FontWeight.bold, + ), + ), + ), + ), + ); + }), ], ), ); From 862d7022cb2ddbf7887c1680f2e54f0534e635fa Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Thu, 26 Nov 2020 13:48:06 +0100 Subject: [PATCH 0498/1140] fix intro navigation --- example/lib/choose_user_page.dart | 3 ++- example/pubspec.yaml | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/example/lib/choose_user_page.dart b/example/lib/choose_user_page.dart index 1ff2a268..844a8c77 100644 --- a/example/lib/choose_user_page.dart +++ b/example/lib/choose_user_page.dart @@ -155,9 +155,10 @@ class ChooseUserPage extends StatelessWidget { if (!kIsWeb) { initNotifications(client); } - Navigator.pushReplacementNamed( + Navigator.pushNamedAndRemoveUntil( context, Routes.CHANNEL_LIST, + ModalRoute.withName(Routes.CHANNEL_LIST), arguments: client, ); }, diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 1ca27846..f1d492ed 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -1,6 +1,6 @@ name: example description: A new Flutter project. -version: 1.0.76+78 +version: 1.0.77+79 environment: sdk: ">=2.2.2 <3.0.0" From f409845818f3feaf65edf39538898fda122eaae0 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Thu, 26 Nov 2020 18:32:46 +0530 Subject: [PATCH 0499/1140] feat: Now compatible with videos --- lib/src/full_screen_image.dart | 169 +++++++++++++++++++++++-------- lib/src/giphy_attachment.dart | 16 ++- lib/src/image_actions_modal.dart | 25 ++++- lib/src/image_attachment.dart | 8 +- lib/src/image_footer.dart | 19 +++- lib/src/image_group.dart | 6 +- lib/src/image_header.dart | 2 +- lib/src/message_widget.dart | 1 + lib/src/video_attachment.dart | 10 +- 9 files changed, 186 insertions(+), 70 deletions(-) diff --git a/lib/src/full_screen_image.dart b/lib/src/full_screen_image.dart index 8ab0415f..4ddc8513 100644 --- a/lib/src/full_screen_image.dart +++ b/lib/src/full_screen_image.dart @@ -1,16 +1,18 @@ import 'package:cached_network_image/cached_network_image.dart'; +import 'package:chewie/chewie.dart'; import 'package:flutter/material.dart'; import 'package:jiffy/jiffy.dart'; import 'package:photo_view/photo_view.dart'; import 'package:stream_chat_flutter/src/image_footer.dart'; import 'package:stream_chat_flutter/src/image_header.dart'; +import 'package:video_player/video_player.dart'; import '../stream_chat_flutter.dart'; /// A full screen image widget -class FullScreenImage extends StatefulWidget { +class FullScreenMedia extends StatefulWidget { /// The url of the image - final List urls; + final List mediaAttachments; final Message message; final int startIndex; @@ -18,9 +20,9 @@ class FullScreenImage extends StatefulWidget { final DateTime sentAt; /// Instantiate a new FullScreenImage - const FullScreenImage({ + const FullScreenMedia({ Key key, - @required this.urls, + @required this.mediaAttachments, this.message, this.startIndex = 0, this.userName = '', @@ -28,10 +30,10 @@ class FullScreenImage extends StatefulWidget { }) : super(key: key); @override - _FullScreenImageState createState() => _FullScreenImageState(); + _FullScreenMediaState createState() => _FullScreenMediaState(); } -class _FullScreenImageState extends State +class _FullScreenMediaState extends State with SingleTickerProviderStateMixin { bool _optionsShown = true; @@ -40,6 +42,8 @@ class _FullScreenImageState extends State int _currentPage; + List videoPackages = []; + @override void initState() { super.initState(); @@ -47,6 +51,14 @@ class _FullScreenImageState extends State AnimationController(vsync: this, duration: Duration(milliseconds: 300)); _pageController = PageController(initialPage: widget.startIndex); _currentPage = widget.startIndex; + widget.mediaAttachments + .where((element) => element.type == 'video') + .toList() + .forEach((element) { + videoPackages.add(VideoPackage(context, element, () { + setState(() {}); + })); + }); } @override @@ -66,36 +78,63 @@ class _FullScreenImageState extends State }); }, itemBuilder: (context, position) { - return PhotoView( - imageProvider: - CachedNetworkImageProvider(widget.urls[position]), - maxScale: PhotoViewComputedScale.covered, - minScale: PhotoViewComputedScale.contained, - heroAttributes: PhotoViewHeroAttributes( - tag: widget.urls, - ), - backgroundDecoration: BoxDecoration( - color: ColorTween( - begin: StreamChatTheme.of(context) - .channelTheme - .channelHeaderTheme - .color, - end: Colors.black) - .lerp(_controller.value), - ), - onTapUp: (a, b, c) { - setState(() { - _optionsShown = !_optionsShown; - }); - if (_controller.isCompleted) { - _controller.reverse(); - } else { - _controller.forward(); - } - }, - ); + if (widget.mediaAttachments[position].type == 'image') { + return PhotoView( + imageProvider: CachedNetworkImageProvider( + widget.mediaAttachments[position].imageUrl ?? + widget.mediaAttachments[position].assetUrl ?? + widget.mediaAttachments[position].thumbUrl), + maxScale: PhotoViewComputedScale.covered, + minScale: PhotoViewComputedScale.contained, + heroAttributes: PhotoViewHeroAttributes( + tag: widget.mediaAttachments, + ), + backgroundDecoration: BoxDecoration( + color: ColorTween( + begin: StreamChatTheme.of(context) + .channelTheme + .channelHeaderTheme + .color, + end: Colors.black) + .lerp(_controller.value), + ), + onTapUp: (a, b, c) { + setState(() { + _optionsShown = !_optionsShown; + }); + if (_controller.isCompleted) { + _controller.reverse(); + } else { + _controller.forward(); + } + }, + ); + } else if (widget.mediaAttachments[position].type == + 'video') { + if (!videoPackages[position].initialised) { + return Center( + child: CircularProgressIndicator(), + ); + } + return InkWell( + onTap: () { + setState(() { + _optionsShown = !_optionsShown; + }); + if (_controller.isCompleted) { + _controller.reverse(); + } else { + _controller.forward(); + } + }, + child: Chewie( + controller: videoPackages[position].chewieController, + ), + ); + } + return Container(); }, - itemCount: widget.urls.length, + itemCount: widget.mediaAttachments.length, ); }), AnimatedOpacity( @@ -106,19 +145,20 @@ class _FullScreenImageState extends State children: [ ImageHeader( userName: widget.userName, - sentAt: - 'Sent ${getDay(widget.message.createdAt)} at ${Jiffy(widget.sentAt.toLocal()).format('HH:mm')}', + sentAt: widget.message.createdAt == null + ? '' + : 'Sent ${getDay(widget.message.createdAt)} at ${Jiffy(widget.sentAt.toLocal()).format('HH:mm')}', onBackPressed: () { Navigator.of(context).pop(); }, message: widget.message, - urls: widget.urls, + urls: widget.mediaAttachments, currentIndex: _currentPage, ), ImageFooter( currentPage: _currentPage, - totalPages: widget.urls.length, - urls: widget.urls, + totalPages: widget.mediaAttachments.length, + urls: widget.mediaAttachments, message: widget.message, ), ], @@ -144,4 +184,53 @@ class _FullScreenImageState extends State return 'on ${Jiffy(dateTime).format("MMM do")}'; } } + + @override + void dispose() { + videoPackages.forEach((element) { + element.dispose(); + }); + super.dispose(); + } +} + +class VideoPackage { + VideoPlayerController _videoPlayerController; + ChewieController _chewieController; + bool initialised = false; + VoidCallback onInit; + BuildContext context; + + /// + VideoPackage(this.context, Attachment attachment, this.onInit) { + _videoPlayerController = VideoPlayerController.network(attachment.assetUrl); + _videoPlayerController.initialize().whenComplete(() { + initialised = true; + _chewieController = ChewieController( + videoPlayerController: _videoPlayerController, + autoInitialize: false, + aspectRatio: _videoPlayerController.value.aspectRatio, + ); + onInit(); + }); + + VoidCallback errorListener; + errorListener = () { + if (_videoPlayerController.value.hasError) { + Navigator.pop(context); + launchURL(context, attachment.titleLink); + } + _videoPlayerController.removeListener(errorListener); + }; + _videoPlayerController.addListener(errorListener); + } + + get videoPlayer => _videoPlayerController; + + get chewieController => _chewieController; + + void dispose() { + _videoPlayerController.dispose(); + _chewieController.dispose(); + } } diff --git a/lib/src/giphy_attachment.dart b/lib/src/giphy_attachment.dart index 43e0ce68..323a3ae1 100644 --- a/lib/src/giphy_attachment.dart +++ b/lib/src/giphy_attachment.dart @@ -67,11 +67,9 @@ class GiphyAttachment extends StatelessWidget { return StreamChannel( channel: channel, - child: FullScreenImage( - urls: [ - attachment.imageUrl ?? - attachment.assetUrl ?? - attachment.thumbUrl + child: FullScreenMedia( + mediaAttachments: [ + attachment, ], userName: message.user.name, sentAt: message.createdAt, @@ -295,11 +293,9 @@ class GiphyAttachment extends StatelessWidget { return StreamChannel( channel: channel, - child: FullScreenImage( - urls: [ - attachment.imageUrl ?? - attachment.assetUrl ?? - attachment.thumbUrl + child: FullScreenMedia( + mediaAttachments: [ + attachment, ], userName: message.user.name, sentAt: message.createdAt, diff --git a/lib/src/image_actions_modal.dart b/lib/src/image_actions_modal.dart index c1163af8..415fc22d 100644 --- a/lib/src/image_actions_modal.dart +++ b/lib/src/image_actions_modal.dart @@ -1,16 +1,22 @@ +import 'dart:io'; import 'dart:ui'; +import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:gallery_saver/gallery_saver.dart'; import '../stream_chat_flutter.dart'; import 'stream_icons.dart'; +import 'package:http/http.dart' as http; +import 'package:path_provider/path_provider.dart'; +import 'package:path/path.dart'; + class ImageActionsModal extends StatelessWidget { final Message message; final String userName; final String sentAt; - final List urls; + final List urls; final currentIndex; ImageActionsModal( @@ -118,8 +124,11 @@ class ImageActionsModal extends StatelessWidget { }), _buildButton(context, 'Save Image', StreamIcons.save_1, () async { - await GallerySaver.saveImage( - urls[currentIndex].split('?')[0]); + var url = urls[currentIndex].imageUrl ?? + urls[currentIndex].assetUrl ?? + urls[currentIndex].thumbUrl; + var file = await _downloadFile(url); + Navigator.pop(context); }), if (StreamChat.of(context).user.id == message.user.id) @@ -171,4 +180,14 @@ class ImageActionsModal extends StatelessWidget { ), ); } + + static Future _downloadFile(String url) async { + var _client = http.Client(); + var req = await _client.get(Uri.parse(url)); + var bytes = req.bodyBytes; + var dir = (await getTemporaryDirectory()).path; + var file = File('$dir/${basename(url)}'); + await file.writeAsBytes(bytes); + return file; + } } diff --git a/lib/src/image_attachment.dart b/lib/src/image_attachment.dart index 83f747db..a7dde6ef 100644 --- a/lib/src/image_attachment.dart +++ b/lib/src/image_attachment.dart @@ -47,11 +47,9 @@ class ImageAttachment extends StatelessWidget { return StreamChannel( channel: channel, - child: FullScreenImage( - urls: [ - attachment.imageUrl ?? - attachment.assetUrl ?? - attachment.thumbUrl + child: FullScreenMedia( + mediaAttachments: [ + attachment, ], userName: message.user.name, sentAt: message.createdAt, diff --git a/lib/src/image_footer.dart b/lib/src/image_footer.dart index d71ee3af..459e7b26 100644 --- a/lib/src/image_footer.dart +++ b/lib/src/image_footer.dart @@ -36,7 +36,7 @@ class ImageFooter extends StatefulWidget { final int currentPage; final int totalPages; - final List urls; + final List urls; final Message message; /// Creates a channel header @@ -186,7 +186,9 @@ class _ImageFooterState extends State { padding: const EdgeInsets.all(1.0), child: AspectRatio( child: CachedNetworkImage( - imageUrl: widget.urls[position], + imageUrl: widget.urls[position].imageUrl ?? + widget.urls[position].assetUrl ?? + widget.urls[position].thumbUrl, fit: BoxFit.cover, ), aspectRatio: 1.0, @@ -378,8 +380,13 @@ class _ImageFooterState extends State { child: Material( child: InkWell( onTap: () async { - await GallerySaver.saveImage(widget - .urls[widget.currentPage] + await GallerySaver.saveImage((widget + .urls[widget.currentPage] + .imageUrl ?? + widget.urls[widget.currentPage] + .assetUrl ?? + widget.urls[widget.currentPage] + .thumbUrl) .split('?')[0]); Navigator.pop(context); }, @@ -518,7 +525,9 @@ class _ImageFooterState extends State { ), iconSize: 24.0, onPressed: () async { - var url = widget.urls[widget.currentPage]; + var url = widget.urls[widget.currentPage].imageUrl ?? + widget.urls[widget.currentPage].assetUrl ?? + widget.urls[widget.currentPage].thumbUrl; var type = url?.split('?')?.first?.split('.')?.last ?? 'jpg'; var request = await HttpClient().getUrl(Uri.parse(url)); var response = await request.close(); diff --git a/lib/src/image_group.dart b/lib/src/image_group.dart index 1b6e48f2..6702e839 100644 --- a/lib/src/image_group.dart +++ b/lib/src/image_group.dart @@ -115,10 +115,8 @@ class ImageGroup extends StatelessWidget { MaterialPageRoute( builder: (context) => StreamChannel( channel: channel, - child: FullScreenImage( - urls: images - .map((e) => e.imageUrl ?? e.thumbUrl ?? e.assetUrl) - .toList(), + child: FullScreenMedia( + mediaAttachments: images, startIndex: index, userName: message.user.name, sentAt: message.createdAt, diff --git a/lib/src/image_header.dart b/lib/src/image_header.dart index 707750c5..77f56460 100644 --- a/lib/src/image_header.dart +++ b/lib/src/image_header.dart @@ -30,7 +30,7 @@ class ImageHeader extends StatelessWidget implements PreferredSizeWidget { final String userName; final String sentAt; - final List urls; + final List urls; final currentIndex; /// Creates a channel header diff --git a/lib/src/message_widget.dart b/lib/src/message_widget.dart index 86479ebe..53bc454e 100644 --- a/lib/src/message_widget.dart +++ b/lib/src/message_widget.dart @@ -180,6 +180,7 @@ class MessageWidget extends StatefulWidget { MediaQuery.of(context).size.width * 0.8, MediaQuery.of(context).size.height * 0.3, ), + message: message, ); }, 'giphy': (context, message, attachment) { diff --git a/lib/src/video_attachment.dart b/lib/src/video_attachment.dart index b0d1f60d..b6caed53 100644 --- a/lib/src/video_attachment.dart +++ b/lib/src/video_attachment.dart @@ -1,6 +1,7 @@ import 'package:cached_network_image/cached_network_image.dart'; import 'package:chewie/chewie.dart'; import 'package:flutter/material.dart'; +import 'package:stream_chat_flutter/src/full_screen_image.dart'; import 'package:stream_chat_flutter/src/full_screen_video.dart'; import 'package:stream_chat_flutter/src/utils.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; @@ -13,11 +14,13 @@ class VideoAttachment extends StatefulWidget { final Attachment attachment; final MessageTheme messageTheme; final Size size; + final Message message; VideoAttachment({ Key key, @required this.attachment, @required this.messageTheme, + this.message, this.size, }) : super(key: key); @@ -84,8 +87,11 @@ class _VideoAttachmentState extends State { Navigator.push( context, MaterialPageRoute( - builder: (_) => FullScreenVideo( - attachment: widget.attachment, + builder: (_) => FullScreenMedia( + mediaAttachments: [widget.attachment], + userName: widget.message.user.name, + sentAt: widget.message.createdAt, + message: widget.message, ), ), ); From 8922ab62415df4287a56233c670d8f9538beb921 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Thu, 26 Nov 2020 18:35:20 +0530 Subject: [PATCH 0500/1140] hotfix: giphy --- lib/src/full_screen_image.dart | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/src/full_screen_image.dart b/lib/src/full_screen_image.dart index 4ddc8513..ba2b56bf 100644 --- a/lib/src/full_screen_image.dart +++ b/lib/src/full_screen_image.dart @@ -78,7 +78,8 @@ class _FullScreenMediaState extends State }); }, itemBuilder: (context, position) { - if (widget.mediaAttachments[position].type == 'image') { + print(widget.mediaAttachments[position].type); + if (widget.mediaAttachments[position].type == 'image' || widget.mediaAttachments[position].type == 'giphy') { return PhotoView( imageProvider: CachedNetworkImageProvider( widget.mediaAttachments[position].imageUrl ?? From 4d35c3a1517ba7c8f25a444aacbb1c9dd13af111 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Thu, 26 Nov 2020 14:09:02 +0100 Subject: [PATCH 0501/1140] update deleted message --- lib/src/deleted_message.dart | 49 +++++++++++++++++++++++++++------- lib/src/message_list_view.dart | 10 ++++--- lib/src/message_widget.dart | 32 ++++++++++++++++++++++ 3 files changed, 78 insertions(+), 13 deletions(-) diff --git a/lib/src/deleted_message.dart b/lib/src/deleted_message.dart index 93fd62ff..673d79c8 100644 --- a/lib/src/deleted_message.dart +++ b/lib/src/deleted_message.dart @@ -1,25 +1,56 @@ import 'package:flutter/material.dart'; import 'package:stream_chat_flutter/src/stream_chat_theme.dart'; +import 'package:stream_chat_flutter/src/stream_svg_icon.dart'; class DeletedMessage extends StatelessWidget { const DeletedMessage({ Key key, @required this.messageTheme, + this.borderRadiusGeometry, + this.shape, + this.borderSide, }) : super(key: key); + /// The theme of the message final MessageTheme messageTheme; + /// The border radius of the message text + final BorderRadiusGeometry borderRadiusGeometry; + + /// The shape of the message text + final ShapeBorder shape; + + /// The borderside of the message text + final BorderSide borderSide; + @override Widget build(BuildContext context) { - return Padding( - padding: const EdgeInsets.symmetric(vertical: 8.0), - child: Text( - 'This message was deleted...', - style: messageTheme.messageText.copyWith( - fontStyle: FontStyle.italic, - color: Theme.of(context).brightness == Brightness.dark - ? Colors.white - : Colors.black, + return Material( + color: messageTheme.messageBackgroundColor, + shape: shape ?? + RoundedRectangleBorder( + borderRadius: borderRadiusGeometry ?? BorderRadius.zero, + side: borderSide ?? + BorderSide( + color: Theme.of(context).brightness == Brightness.dark + ? Colors.white.withAlpha(24) + : Colors.black.withAlpha(24), + ), + ), + child: Padding( + padding: const EdgeInsets.symmetric( + vertical: 8.0, + horizontal: 16, + ), + child: Text( + 'Message deleted', + style: messageTheme.messageText.copyWith( + fontStyle: FontStyle.italic, + color: (Theme.of(context).brightness == Brightness.dark + ? Colors.white + : Colors.black) + .withOpacity(.5), + ), ), ), ); diff --git a/lib/src/message_list_view.dart b/lib/src/message_list_view.dart index a1b09e43..3feda8ce 100644 --- a/lib/src/message_list_view.dart +++ b/lib/src/message_list_view.dart @@ -176,10 +176,12 @@ class _MessageListViewState extends State { : streamChannel.channel.state.messagesStream; return StreamBuilder>( - stream: messagesStream, - initialData: widget.parentMessage != null - ? streamChannel.channel.state.threads[widget.parentMessage.id] - : streamChannel.channel.state.messages, + stream: messagesStream.map((messages) => messages + .where((e) => + !e.isDeleted || + (e.isDeleted && + e.user.id == streamChannel.channel.client.state.user.id)) + .toList()), builder: (context, snapshot) { if (!snapshot.hasData) { return Center( diff --git a/lib/src/message_widget.dart b/lib/src/message_widget.dart index 280de349..45f3c62e 100644 --- a/lib/src/message_widget.dart +++ b/lib/src/message_widget.dart @@ -286,6 +286,10 @@ class _MessageWidgetState extends State { transform: Matrix4.rotationY( widget.reverse ? pi : 0), child: DeletedMessage( + borderRadiusGeometry: + widget.borderRadiusGeometry, + borderSide: widget.borderSide, + shape: widget.shape, messageTheme: widget.messageTheme, ), ) @@ -410,6 +414,34 @@ class _MessageWidgetState extends State { ), ), ), + if (widget.message.isDeleted) + Transform( + transform: Matrix4.rotationY(widget.reverse ? pi : 0), + alignment: Alignment.center, + child: Padding( + padding: + const EdgeInsets.symmetric(horizontal: 8.0, vertical: 4.0), + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + StreamSvgIcon.eye( + color: Colors.black.withOpacity(0.5), + size: 16.0, + ), + SizedBox( + width: 8.0, + ), + Text( + 'Only visible to you', + style: TextStyle( + color: Colors.black.withOpacity(0.5), + fontSize: 12.0, + ), + ), + ], + ), + ), + ), ], ), ); From a59dddc514b942b8bbebdc8172f6afd114fa1fc3 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Thu, 26 Nov 2020 15:18:59 +0100 Subject: [PATCH 0502/1140] fix video thumbnail --- lib/src/message_input.dart | 16 ++++++++++++---- lib/src/video_thumbnail.dart | 37 ------------------------------------ 2 files changed, 12 insertions(+), 41 deletions(-) delete mode 100644 lib/src/video_thumbnail.dart diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index c9ed15bb..04161aef 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -1316,10 +1316,18 @@ class MessageInputState extends State { children: [ Positioned.fill( child: Container( - child: VideoThumbnail( - file: File( - attachment.file.path, - ), + child: FutureBuilder( + future: VideoCompress.getFileThumbnail(attachment.file.path), + builder: (context, snapshot) { + if (!snapshot.hasData) { + return Offstage(); + } + + return Image.file( + snapshot.data, + fit: BoxFit.cover, + ); + }, ), ), ), diff --git a/lib/src/video_thumbnail.dart b/lib/src/video_thumbnail.dart deleted file mode 100644 index c36ab327..00000000 --- a/lib/src/video_thumbnail.dart +++ /dev/null @@ -1,37 +0,0 @@ -import 'dart:io'; - -import 'package:flutter/material.dart'; -import 'package:video_player/video_player.dart'; - -class VideoThumbnail extends StatefulWidget { - final File file; - - const VideoThumbnail({ - Key key, - @required this.file, - }) : super(key: key); - - @override - _VideoThumbnailState createState() => _VideoThumbnailState(); -} - -class _VideoThumbnailState extends State { - VideoPlayerController _videoPlayerController; - @override - Widget build(BuildContext context) { - return VideoPlayer(_videoPlayerController); - } - - @override - void initState() { - _videoPlayerController = VideoPlayerController.file(widget.file) - ..initialize(); - super.initState(); - } - - @override - void dispose() { - _videoPlayerController.dispose(); - super.dispose(); - } -} From 953058e325ef7bca9a05bf1d84aec34a5364662d Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Thu, 26 Nov 2020 15:49:48 +0100 Subject: [PATCH 0503/1140] fix tests --- lib/src/message_input.dart | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 04161aef..5314e755 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -20,7 +20,6 @@ import 'package:stream_chat_flutter/src/message_list_view.dart'; import 'package:stream_chat_flutter/src/stream_chat_theme.dart'; import 'package:stream_chat_flutter/src/stream_svg_icon.dart'; import 'package:stream_chat_flutter/src/user_avatar.dart'; -import 'package:stream_chat_flutter/src/video_thumbnail.dart'; import 'package:substring_highlight/substring_highlight.dart'; import 'package:video_compress/video_compress.dart'; @@ -847,15 +846,13 @@ class MessageInputState extends State { } void _addAttachment(Media medium) async { + final attachment = _SendingAttachment( + id: medium.id, + ); try { - final attachment = _SendingAttachment( - id: medium.id, - ); - setState(() { _attachments.add(attachment); }); - final mediaFile = await medium.getFile(); var file = PlatformFile( @@ -936,6 +933,9 @@ class MessageInputState extends State { }); } } catch (e, s) { + setState(() { + _attachments.remove(attachment); + }); print(s); Scaffold.of(context).showSnackBar( SnackBar( From fd9c7e9045c1bc1f1888ad7439dc5363133d4d81 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Thu, 26 Nov 2020 20:42:05 +0530 Subject: [PATCH 0504/1140] feat: Fixed download --- ...reen_image.dart => full_screen_media.dart} | 3 +- lib/src/full_screen_video.dart | 84 ------------------- lib/src/giphy_attachment.dart | 2 +- lib/src/image_actions_modal.dart | 46 ++++++---- lib/src/image_attachment.dart | 2 +- lib/src/image_footer.dart | 47 ++++++++--- lib/src/image_group.dart | 2 +- lib/src/video_attachment.dart | 18 ++-- lib/stream_chat_flutter.dart | 4 +- pubspec.yaml | 2 +- 10 files changed, 88 insertions(+), 122 deletions(-) rename lib/src/{full_screen_image.dart => full_screen_media.dart} (98%) delete mode 100644 lib/src/full_screen_video.dart diff --git a/lib/src/full_screen_image.dart b/lib/src/full_screen_media.dart similarity index 98% rename from lib/src/full_screen_image.dart rename to lib/src/full_screen_media.dart index ba2b56bf..88f8d2b9 100644 --- a/lib/src/full_screen_image.dart +++ b/lib/src/full_screen_media.dart @@ -79,7 +79,8 @@ class _FullScreenMediaState extends State }, itemBuilder: (context, position) { print(widget.mediaAttachments[position].type); - if (widget.mediaAttachments[position].type == 'image' || widget.mediaAttachments[position].type == 'giphy') { + if (widget.mediaAttachments[position].type == 'image' || + widget.mediaAttachments[position].type == 'giphy') { return PhotoView( imageProvider: CachedNetworkImageProvider( widget.mediaAttachments[position].imageUrl ?? diff --git a/lib/src/full_screen_video.dart b/lib/src/full_screen_video.dart deleted file mode 100644 index 98729243..00000000 --- a/lib/src/full_screen_video.dart +++ /dev/null @@ -1,84 +0,0 @@ -import 'package:chewie/chewie.dart'; -import 'package:flutter/material.dart'; -import 'package:stream_chat_flutter/stream_chat_flutter.dart'; -import 'package:video_player/video_player.dart'; - -import 'utils.dart'; - -class FullScreenVideo extends StatefulWidget { - final Attachment attachment; - - FullScreenVideo({ - Key key, - @required this.attachment, - }) : super(key: key); - - @override - _FullScreenVideoState createState() => _FullScreenVideoState(); -} - -class _FullScreenVideoState extends State { - ChewieController _chewieController; - VideoPlayerController _videoPlayerController; - bool initialized = false; - final GlobalKey _scaffoldKey = GlobalKey(); - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - backgroundColor: Colors.black, - iconTheme: IconThemeData( - color: Colors.white, - ), - ), - body: Builder( - key: _scaffoldKey, - builder: (context) { - if (!initialized) { - return Center( - child: CircularProgressIndicator(), - ); - } - return Chewie( - controller: _chewieController, - ); - }, - ), - ); - } - - @override - void initState() { - super.initState(); - _videoPlayerController = - VideoPlayerController.network(widget.attachment.assetUrl); - _videoPlayerController.initialize().whenComplete(() { - setState(() { - initialized = true; - _chewieController = ChewieController( - videoPlayerController: _videoPlayerController, - autoInitialize: false, - aspectRatio: _videoPlayerController.value.aspectRatio, - ); - }); - }); - - VoidCallback errorListener; - errorListener = () { - if (_videoPlayerController.value.hasError) { - Navigator.pop(context); - launchURL(_scaffoldKey.currentContext, widget.attachment.titleLink); - } - _videoPlayerController.removeListener(errorListener); - }; - _videoPlayerController.addListener(errorListener); - } - - @override - void dispose() { - _videoPlayerController?.dispose(); - _chewieController?.dispose(); - super.dispose(); - } -} diff --git a/lib/src/giphy_attachment.dart b/lib/src/giphy_attachment.dart index 323a3ae1..8f02b8a8 100644 --- a/lib/src/giphy_attachment.dart +++ b/lib/src/giphy_attachment.dart @@ -4,7 +4,7 @@ import 'package:flutter/material.dart'; import '../stream_chat_flutter.dart'; import 'attachment_error.dart'; -import 'full_screen_image.dart'; +import 'full_screen_media.dart'; class GiphyAttachment extends StatelessWidget { final Attachment attachment; diff --git a/lib/src/image_actions_modal.dart b/lib/src/image_actions_modal.dart index 415fc22d..c3f699a5 100644 --- a/lib/src/image_actions_modal.dart +++ b/lib/src/image_actions_modal.dart @@ -1,10 +1,10 @@ -import 'dart:io'; +import 'dart:typed_data'; import 'dart:ui'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; -import 'package:gallery_saver/gallery_saver.dart'; - +import 'package:dio/dio.dart'; +import 'package:image_gallery_saver/image_gallery_saver.dart'; import '../stream_chat_flutter.dart'; import 'stream_icons.dart'; @@ -122,14 +122,21 @@ class ImageActionsModal extends StatelessWidget { Navigator.pop(context); Navigator.pop(context); }), - _buildButton(context, 'Save Image', StreamIcons.save_1, - () async { + _buildButton( + context, + 'Save ${urls[currentIndex].type == 'video' ? 'Video' : 'Image'}', + StreamIcons.save_1, () async { var url = urls[currentIndex].imageUrl ?? urls[currentIndex].assetUrl ?? urls[currentIndex].thumbUrl; - var file = await _downloadFile(url); - Navigator.pop(context); + if (urls[currentIndex].type == 'video') { + await _saveVideo(url); + Navigator.pop(context); + } else { + await _saveImage(url); + Navigator.pop(context); + } }), if (StreamChat.of(context).user.id == message.user.id) _buildButton(context, 'Delete', StreamIcons.delete, @@ -181,13 +188,22 @@ class ImageActionsModal extends StatelessWidget { ); } - static Future _downloadFile(String url) async { - var _client = http.Client(); - var req = await _client.get(Uri.parse(url)); - var bytes = req.bodyBytes; - var dir = (await getTemporaryDirectory()).path; - var file = File('$dir/${basename(url)}'); - await file.writeAsBytes(bytes); - return file; + Future _saveImage(String url) async { + var response = await Dio() + .get(url, options: Options(responseType: ResponseType.bytes)); + final result = await ImageGallerySaver.saveImage( + Uint8List.fromList(response.data), + quality: 60, + name: "${DateTime.now().millisecondsSinceEpoch}"); + return result; + } + + Future _saveVideo(String url) async { + var appDocDir = await getTemporaryDirectory(); + var savePath = + appDocDir.path + "/${DateTime.now().millisecondsSinceEpoch}.mp4"; + await Dio().download(url, savePath); + final result = await ImageGallerySaver.saveFile(savePath); + print(result); } } diff --git a/lib/src/image_attachment.dart b/lib/src/image_attachment.dart index a7dde6ef..2345b2b8 100644 --- a/lib/src/image_attachment.dart +++ b/lib/src/image_attachment.dart @@ -4,7 +4,7 @@ import 'package:flutter/material.dart'; import '../stream_chat_flutter.dart'; import 'attachment_error.dart'; import 'attachment_title.dart'; -import 'full_screen_image.dart'; +import 'full_screen_media.dart'; import 'utils.dart'; class ImageAttachment extends StatelessWidget { diff --git a/lib/src/image_footer.dart b/lib/src/image_footer.dart index 459e7b26..ed82e09a 100644 --- a/lib/src/image_footer.dart +++ b/lib/src/image_footer.dart @@ -6,7 +6,10 @@ import 'package:cached_network_image/cached_network_image.dart'; import 'package:esys_flutter_share/esys_flutter_share.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; -import 'package:gallery_saver/gallery_saver.dart'; +import 'package:dio/dio.dart'; +import 'dart:typed_data'; +import 'package:image_gallery_saver/image_gallery_saver.dart'; +import 'package:path_provider/path_provider.dart'; import 'package:stream_chat/stream_chat.dart'; import 'package:stream_chat_flutter/src/back_button.dart'; import 'package:stream_chat_flutter/src/channel_info.dart'; @@ -380,15 +383,20 @@ class _ImageFooterState extends State { child: Material( child: InkWell( onTap: () async { - await GallerySaver.saveImage((widget - .urls[widget.currentPage] - .imageUrl ?? - widget.urls[widget.currentPage] - .assetUrl ?? - widget.urls[widget.currentPage] - .thumbUrl) - .split('?')[0]); - Navigator.pop(context); + var url = widget + .urls[widget.currentPage].imageUrl ?? + widget + .urls[widget.currentPage].assetUrl ?? + widget.urls[widget.currentPage].thumbUrl; + + if (widget.urls[widget.currentPage].type == + 'video') { + await _saveVideo(url); + Navigator.pop(context); + } else { + await _saveImage(url); + Navigator.pop(context); + } }, child: SizedBox.expand( child: Center( @@ -697,6 +705,25 @@ class _ImageFooterState extends State { _selectedUsers.clear(); Navigator.pop(context); } + + Future _saveImage(String url) async { + var response = await Dio() + .get(url, options: Options(responseType: ResponseType.bytes)); + final result = await ImageGallerySaver.saveImage( + Uint8List.fromList(response.data), + quality: 60, + name: "${DateTime.now().millisecondsSinceEpoch}"); + return result; + } + + Future _saveVideo(String url) async { + var appDocDir = await getTemporaryDirectory(); + var savePath = + appDocDir.path + "/${DateTime.now().millisecondsSinceEpoch}.mp4"; + await Dio().download(url, savePath); + final result = await ImageGallerySaver.saveFile(savePath); + print(result); + } } /// Used for clipping textfield prefix icon diff --git a/lib/src/image_group.dart b/lib/src/image_group.dart index 6702e839..44c15623 100644 --- a/lib/src/image_group.dart +++ b/lib/src/image_group.dart @@ -3,7 +3,7 @@ import 'package:carousel_slider/carousel_options.dart'; import 'package:carousel_slider/carousel_slider.dart'; import 'package:flutter/material.dart'; import 'package:stream_chat/stream_chat.dart'; -import 'package:stream_chat_flutter/src/full_screen_image.dart'; +import 'package:stream_chat_flutter/src/full_screen_media.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; class ImageGroup extends StatelessWidget { diff --git a/lib/src/video_attachment.dart b/lib/src/video_attachment.dart index b6caed53..782b81cb 100644 --- a/lib/src/video_attachment.dart +++ b/lib/src/video_attachment.dart @@ -1,8 +1,7 @@ import 'package:cached_network_image/cached_network_image.dart'; import 'package:chewie/chewie.dart'; import 'package:flutter/material.dart'; -import 'package:stream_chat_flutter/src/full_screen_image.dart'; -import 'package:stream_chat_flutter/src/full_screen_video.dart'; +import 'package:stream_chat_flutter/src/full_screen_media.dart'; import 'package:stream_chat_flutter/src/utils.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; import 'package:video_player/video_player.dart'; @@ -84,14 +83,19 @@ class _VideoAttachmentState extends State { return GestureDetector( onTap: () { + final channel = StreamChannel.of(context).channel; + Navigator.push( context, MaterialPageRoute( - builder: (_) => FullScreenMedia( - mediaAttachments: [widget.attachment], - userName: widget.message.user.name, - sentAt: widget.message.createdAt, - message: widget.message, + builder: (_) => StreamChannel( + channel: channel, + child: FullScreenMedia( + mediaAttachments: [widget.attachment], + userName: widget.message.user.name, + sentAt: widget.message.createdAt, + message: widget.message, + ), ), ), ); diff --git a/lib/stream_chat_flutter.dart b/lib/stream_chat_flutter.dart index 91ac68c8..fcb34121 100644 --- a/lib/stream_chat_flutter.dart +++ b/lib/stream_chat_flutter.dart @@ -10,7 +10,9 @@ export 'src/channels_bloc.dart'; export 'src/date_divider.dart'; export 'src/deleted_message.dart'; export 'src/file_attachment.dart'; -export 'src/full_screen_video.dart'; +export 'src/full_screen_media.dart'; +export 'src/image_header.dart'; +export 'src/image_footer.dart'; export 'src/giphy_attachment.dart'; export 'src/image_attachment.dart'; export 'src/message_input.dart'; diff --git a/pubspec.yaml b/pubspec.yaml index 012a0293..b7e11a5b 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -36,7 +36,7 @@ dependencies: flutter_slidable: ^0.5.4 carousel_slider: ^2.2.1 clipboard: ^0.1.2+8 - gallery_saver: ^2.0.1 + image_gallery_saver: ^1.6.6 esys_flutter_share: ^1.0.2 media_gallery: git: https://github.com/imtoori/media_gallery.git From e746a6e16f2f536955a82620a3ef4463a2bd0d89 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Thu, 26 Nov 2020 21:05:32 +0530 Subject: [PATCH 0505/1140] rfac: cleanup --- lib/src/image_actions_modal.dart | 4 ---- lib/src/image_footer.dart | 7 ------- lib/src/image_header.dart | 6 ------ 3 files changed, 17 deletions(-) diff --git a/lib/src/image_actions_modal.dart b/lib/src/image_actions_modal.dart index c3f699a5..19f27055 100644 --- a/lib/src/image_actions_modal.dart +++ b/lib/src/image_actions_modal.dart @@ -6,11 +6,7 @@ import 'package:flutter/material.dart'; import 'package:dio/dio.dart'; import 'package:image_gallery_saver/image_gallery_saver.dart'; import '../stream_chat_flutter.dart'; -import 'stream_icons.dart'; - -import 'package:http/http.dart' as http; import 'package:path_provider/path_provider.dart'; -import 'package:path/path.dart'; class ImageActionsModal extends StatelessWidget { final Message message; diff --git a/lib/src/image_footer.dart b/lib/src/image_footer.dart index ed82e09a..8d2bf30f 100644 --- a/lib/src/image_footer.dart +++ b/lib/src/image_footer.dart @@ -7,22 +7,15 @@ import 'package:esys_flutter_share/esys_flutter_share.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:dio/dio.dart'; -import 'dart:typed_data'; import 'package:image_gallery_saver/image_gallery_saver.dart'; import 'package:path_provider/path_provider.dart'; import 'package:stream_chat/stream_chat.dart'; -import 'package:stream_chat_flutter/src/back_button.dart'; -import 'package:stream_chat_flutter/src/channel_info.dart'; -import 'package:stream_chat_flutter/src/channel_name.dart'; -import 'package:stream_chat_flutter/src/message_input.dart'; import 'package:stream_chat_flutter/src/stream_chat.dart'; import 'package:stream_chat_flutter/src/stream_chat_theme.dart'; import 'package:stream_chat_flutter/src/stream_icons.dart'; import 'package:stream_chat_flutter/src/user_avatar.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; -import './channel_name.dart'; -import 'channel_image.dart'; import 'stream_channel.dart'; class ImageFooter extends StatefulWidget { diff --git a/lib/src/image_header.dart b/lib/src/image_header.dart index 77f56460..512d8b14 100644 --- a/lib/src/image_header.dart +++ b/lib/src/image_header.dart @@ -1,13 +1,7 @@ import 'package:flutter/material.dart'; import 'package:stream_chat/stream_chat.dart'; -import 'package:stream_chat_flutter/src/back_button.dart'; -import 'package:stream_chat_flutter/src/channel_info.dart'; -import 'package:stream_chat_flutter/src/channel_name.dart'; import 'package:stream_chat_flutter/src/stream_chat_theme.dart'; import 'package:stream_chat_flutter/src/stream_icons.dart'; - -import './channel_name.dart'; -import 'channel_image.dart'; import 'image_actions_modal.dart'; import 'stream_channel.dart'; From 5ac0c60d6fa2a299f2af64034b4e3747d35cc081 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Thu, 26 Nov 2020 17:14:30 +0100 Subject: [PATCH 0506/1140] use photo manager --- example/ios/Podfile.lock | 12 +- example/ios/Runner.xcodeproj/project.pbxproj | 4 +- example/pubspec.yaml | 2 +- lib/src/media_list_view.dart | 246 +++++++++++-------- lib/src/message_input.dart | 17 +- pubspec.yaml | 3 +- 6 files changed, 159 insertions(+), 125 deletions(-) diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock index b028e9b7..707e9fcb 100644 --- a/example/ios/Podfile.lock +++ b/example/ios/Podfile.lock @@ -108,8 +108,6 @@ PODS: - GoogleUtilities/Logger - image_picker (0.0.1): - Flutter - - media_gallery (0.0.1): - - Flutter - nanopb (1.30906.0): - nanopb/decode (= 1.30906.0) - nanopb/encode (= 1.30906.0) @@ -119,6 +117,8 @@ PODS: - Flutter - "permission_handler (5.0.1+1)": - Flutter + - photo_manager (0.0.1): + - Flutter - PromisesObjC (1.2.11) - Protobuf (3.13.0) - SDWebImage (5.10.0): @@ -171,9 +171,9 @@ DEPENDENCIES: - flutter_local_notifications (from `.symlinks/plugins/flutter_local_notifications/ios`) - flutter_secure_storage (from `.symlinks/plugins/flutter_secure_storage/ios`) - image_picker (from `.symlinks/plugins/image_picker/ios`) - - media_gallery (from `.symlinks/plugins/media_gallery/ios`) - path_provider (from `.symlinks/plugins/path_provider/ios`) - permission_handler (from `.symlinks/plugins/permission_handler/ios`) + - photo_manager (from `.symlinks/plugins/photo_manager/ios`) - shared_preferences (from `.symlinks/plugins/shared_preferences/ios`) - sqflite (from `.symlinks/plugins/sqflite/ios`) - sqlite3_flutter_libs (from `.symlinks/plugins/sqlite3_flutter_libs/ios`) @@ -226,12 +226,12 @@ EXTERNAL SOURCES: :path: ".symlinks/plugins/flutter_secure_storage/ios" image_picker: :path: ".symlinks/plugins/image_picker/ios" - media_gallery: - :path: ".symlinks/plugins/media_gallery/ios" path_provider: :path: ".symlinks/plugins/path_provider/ios" permission_handler: :path: ".symlinks/plugins/permission_handler/ios" + photo_manager: + :path: ".symlinks/plugins/photo_manager/ios" shared_preferences: :path: ".symlinks/plugins/shared_preferences/ios" sqflite: @@ -269,10 +269,10 @@ SPEC CHECKSUMS: GoogleDataTransport: f56af7caa4ed338dc8e138a5d7c5973e66440833 GoogleUtilities: 7f2f5a07f888cdb145101d6042bc4422f57e70b3 image_picker: 9c3312491f862b28d21ecd8fdf0ee14e601b3f09 - media_gallery: 834a04455a476b975c280aa1f24ed2853dfe36de nanopb: 59317e09cf1f1a0af72f12af412d54edf52603fc path_provider: abfe2b5c733d04e238b0d8691db0cfd63a27a93c permission_handler: eac8e15b4a1a3fba55b761d19f3f4e6b005d15b6 + photo_manager: f7c619c2cc8c2adb8d85c63363babac477de9c67 PromisesObjC: 8c196f5a328c2cba3e74624585467a557dcb482f Protobuf: 3dac39b34a08151c6d949560efe3f86134a3f748 SDWebImage: 9169792e9eec3e45bba2a0c02f74bf8bd922d1ee diff --git a/example/ios/Runner.xcodeproj/project.pbxproj b/example/ios/Runner.xcodeproj/project.pbxproj index bb101716..1a50ae5b 100644 --- a/example/ios/Runner.xcodeproj/project.pbxproj +++ b/example/ios/Runner.xcodeproj/project.pbxproj @@ -327,9 +327,9 @@ "${BUILT_PRODUCTS_DIR}/flutter_local_notifications/flutter_local_notifications.framework", "${BUILT_PRODUCTS_DIR}/flutter_secure_storage/flutter_secure_storage.framework", "${BUILT_PRODUCTS_DIR}/image_picker/image_picker.framework", - "${BUILT_PRODUCTS_DIR}/media_gallery/media_gallery.framework", "${BUILT_PRODUCTS_DIR}/nanopb/nanopb.framework", "${BUILT_PRODUCTS_DIR}/path_provider/path_provider.framework", + "${BUILT_PRODUCTS_DIR}/photo_manager/photo_manager.framework", "${BUILT_PRODUCTS_DIR}/shared_preferences/shared_preferences.framework", "${BUILT_PRODUCTS_DIR}/sqflite/sqflite.framework", "${BUILT_PRODUCTS_DIR}/sqlite3/sqlite3.framework", @@ -359,9 +359,9 @@ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/flutter_local_notifications.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/flutter_secure_storage.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/image_picker.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/media_gallery.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/nanopb.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/path_provider.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/photo_manager.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/shared_preferences.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/sqflite.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/sqlite3.framework", diff --git a/example/pubspec.yaml b/example/pubspec.yaml index f1d492ed..e0be8fc9 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -1,6 +1,6 @@ name: example description: A new Flutter project. -version: 1.0.77+79 +version: 1.0.78+80 environment: sdk: ">=2.2.2 <3.0.0" diff --git a/lib/src/media_list_view.dart b/lib/src/media_list_view.dart index e8735d69..80686d62 100644 --- a/lib/src/media_list_view.dart +++ b/lib/src/media_list_view.dart @@ -1,11 +1,14 @@ +import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_svg/flutter_svg.dart'; -import 'package:media_gallery/media_gallery.dart'; +import 'package:photo_manager/photo_manager.dart'; +import 'package:stream_chat_flutter/src/lazy_load_scroll_view.dart'; import 'package:stream_chat_flutter/src/stream_svg_icon.dart'; +import 'dart:ui' as ui; class MediaListView extends StatefulWidget { final List selectedIds; - final void Function(Media media) onSelect; + final void Function(AssetEntity media) onSelect; const MediaListView({ Key key, @@ -17,88 +20,94 @@ class MediaListView extends StatefulWidget { } class _MediaListViewState extends State { - final _media = []; + final _media = []; final ScrollController _scrollController = ScrollController(); + int _currentPage = 0; + bool _endPagination = false; @override Widget build(BuildContext context) { - return GridView.builder( - itemCount: _media.length, - controller: _scrollController, - gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( - crossAxisCount: 3, - ), - cacheExtent: 1000, - itemBuilder: ( - context, - position, - ) { - final media = _media.elementAt(position); - return Padding( - padding: const EdgeInsets.symmetric(horizontal: 1.0, vertical: 1.0), - child: InkWell( - child: Stack( - children: [ - AspectRatio( - aspectRatio: 1.0, - child: FadeInImage( - fadeInDuration: Duration(milliseconds: 300), - placeholder: AssetImage( - 'images/placeholder.png', - package: 'stream_chat_flutter', + return LazyLoadScrollView( + onEndOfPage: () { + _getMedia(); + }, + child: GridView.builder( + itemCount: _media.length, + controller: _scrollController, + gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: 3, + ), + cacheExtent: 1000, + itemBuilder: ( + context, + position, + ) { + final media = _media.elementAt(position); + return Padding( + padding: const EdgeInsets.symmetric(horizontal: 1.0, vertical: 1.0), + child: InkWell( + child: Stack( + children: [ + AspectRatio( + aspectRatio: 1.0, + child: FadeInImage( + fadeInDuration: Duration(milliseconds: 300), + placeholder: AssetImage( + 'images/placeholder.png', + package: 'stream_chat_flutter', + ), + image: MediaThumbnailProvider( + media: media, + ), + fit: BoxFit.cover, ), - image: MediaThumbnailProvider( - media: media, - highQuality: true, - ), - fit: BoxFit.cover, ), - ), - Positioned.fill( - child: IgnorePointer( - child: AnimatedOpacity( - duration: Duration(milliseconds: 300), - opacity: widget.selectedIds.any((id) => id == media.id) - ? 1.0 - : 0.0, - child: Container( - color: Colors.black.withOpacity(0.5), - alignment: Alignment.topRight, - padding: const EdgeInsets.only( - top: 8, - right: 8, - ), - child: CircleAvatar( - radius: 12, - backgroundColor: Colors.white, - child: StreamSvgIcon.check( - size: 24, - color: Colors.black, + Positioned.fill( + child: IgnorePointer( + child: AnimatedOpacity( + duration: Duration(milliseconds: 300), + opacity: widget.selectedIds.any((id) => id == media.id) + ? 1.0 + : 0.0, + child: Container( + color: Colors.black.withOpacity(0.5), + alignment: Alignment.topRight, + padding: const EdgeInsets.only( + top: 8, + right: 8, + ), + child: CircleAvatar( + radius: 12, + backgroundColor: Colors.white, + child: StreamSvgIcon.check( + size: 24, + color: Colors.black, + ), ), ), ), ), ), - ), - if (media.mediaType == MediaType.video) - Positioned( - left: 8, - bottom: 10, - child: SvgPicture.asset( - 'svgs/video_call_icon.svg', - package: 'stream_chat_flutter', + if (media.type == AssetType.video) + Positioned( + left: 8, + bottom: 10, + child: SvgPicture.asset( + 'svgs/video_call_icon.svg', + package: 'stream_chat_flutter', + ), ), - ), - ], + ], + ), + onTap: () { + if (widget.onSelect != null) { + widget.onSelect(media); + } + }, ), - onTap: () { - if (widget.onSelect != null) { - widget.onSelect(media); - } - }, - ), - ); - }, + ); + }, + ), ); } @@ -109,42 +118,67 @@ class _MediaListViewState extends State { } void _getMedia() async { - final List collections = - await MediaGallery.listMediaCollections( - mediaTypes: [ - MediaType.video, - MediaType.image, - ], - ); + final assetList = await PhotoManager.getAssetPathList( + hasAll: true, + ).then((value) => value.singleWhere((element) => element.isAll)); - if (collections.isEmpty) { - return; + final media = await assetList.getAssetListPaged(_currentPage, 50); + + if (media.isEmpty) { + setState(() { + _endPagination = true; + }); + } else { + setState(() { + _media.addAll(media); + }); } - final collection = collections.firstWhere( - (element) => element.isAllCollection, - orElse: () => collections.first, - ); - - final videoPage = await collection.getMedias( - mediaType: MediaType.video, - take: 500, - ); - final imagePage = await collection.getMedias( - mediaType: MediaType.image, - take: 500, - ); - - final allItems = [ - ...videoPage.items, - ...imagePage.items, - ]..sort(( - a, - b, - ) => - b.creationDate.compareTo(a.creationDate)); - - setState(() { - _media.addAll(allItems); - }); + ++_currentPage; } } + +class MediaThumbnailProvider extends ImageProvider { + const MediaThumbnailProvider({ + @required this.media, + }) : assert(media != null); + + final AssetEntity media; + + @override + ImageStreamCompleter load(key, decode) { + return MultiFrameImageStreamCompleter( + codec: _loadAsync(key, decode), + scale: 1.0, + informationCollector: () sync* { + yield ErrorDescription('Id: ${media?.id}'); + }, + ); + } + + Future _loadAsync( + MediaThumbnailProvider key, DecoderCallback decode) async { + assert(key == this); + final bytes = await media.thumbData; + if (bytes.isEmpty) return null; + + return await decode(bytes); + } + + @override + Future obtainKey(ImageConfiguration configuration) { + return SynchronousFuture(this); + } + + @override + bool operator ==(dynamic other) { + if (other.runtimeType != runtimeType) return false; + final MediaThumbnailProvider typedOther = other; + return media?.id == typedOther.media?.id; + } + + @override + int get hashCode => media?.id?.hashCode ?? 0; + + @override + String toString() => '$runtimeType("${media?.id}")'; +} diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 5314e755..10fe6595 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -10,9 +10,9 @@ import 'package:flutter_keyboard_visibility/flutter_keyboard_visibility.dart'; import 'package:flutter_svg/flutter_svg.dart'; import 'package:http_parser/http_parser.dart' as httpParser; import 'package:image_picker/image_picker.dart'; -import 'package:media_gallery/media_gallery.dart'; import 'package:mime/mime.dart'; import 'package:permission_handler/permission_handler.dart'; +import 'package:photo_manager/photo_manager.dart'; import 'package:stream_chat/stream_chat.dart'; import 'package:stream_chat_flutter/src/compress_video_service.dart'; import 'package:stream_chat_flutter/src/media_list_view.dart'; @@ -845,7 +845,7 @@ class MessageInputState extends State { } } - void _addAttachment(Media medium) async { + void _addAttachment(AssetEntity medium) async { final attachment = _SendingAttachment( id: medium.id, ); @@ -853,16 +853,16 @@ class MessageInputState extends State { setState(() { _attachments.add(attachment); }); - final mediaFile = await medium.getFile(); + final mediaFile = await medium.file; var file = PlatformFile( path: mediaFile.path, - size: (await mediaFile.length()) ~/ 1024, + size: ((await mediaFile.length()) / 1024).ceil(), bytes: mediaFile.readAsBytesSync(), ); if (file.size > _kMaxAttachmentSize) { - if (medium.mediaType == MediaType.video) { + if (medium.type == AssetType.video) { final mediaInfo = await CompressVideoService.compressVideo(file.path); if (mediaInfo.filesize / (1024 * 1024) > _kMaxAttachmentSize) { @@ -902,18 +902,18 @@ class MessageInputState extends State { ..file = file ..attachment = Attachment( localUri: file.path != null ? Uri.parse(file.path) : null, - type: medium.mediaType == MediaType.image ? 'image' : 'video', + type: medium.type == AssetType.image ? 'image' : 'video', ); }); final url = await _uploadAttachment( file, - medium.mediaType == MediaType.image + medium.type == AssetType.image ? DefaultAttachmentTypes.image : DefaultAttachmentTypes.video, channel); - final fileType = medium.mediaType == MediaType.image + final fileType = medium.type == AssetType.image ? DefaultAttachmentTypes.image : DefaultAttachmentTypes.video; @@ -936,6 +936,7 @@ class MessageInputState extends State { setState(() { _attachments.remove(attachment); }); + print(e); print(s); Scaffold.of(context).showSnackBar( SnackBar( diff --git a/pubspec.yaml b/pubspec.yaml index b0f65c71..5ecb60de 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -38,8 +38,7 @@ dependencies: flutter_slidable: ^0.5.4 carousel_slider: ^2.2.1 clipboard: ^0.1.2+8 - media_gallery: - git: https://github.com/imtoori/media_gallery.git + photo_manager: ^0.5.8 permission_handler: ^5.0.1+1 transparent_image: ^1.0.0 ezanimation: ^0.4.1 From 29868aa7a99a5eb732bc8402f58e583623a9c3ed Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Thu, 26 Nov 2020 17:46:41 +0100 Subject: [PATCH 0507/1140] fix messageinput ui --- lib/src/message_input.dart | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 10fe6595..8def16da 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -380,6 +380,7 @@ class MessageInputState extends State { autofocus: false, textAlignVertical: TextAlignVertical.center, decoration: InputDecoration( + isDense: true, hintText: _getHint(), prefixText: _commandEnabled ? null : ' ', border: OutlineInputBorder( @@ -392,7 +393,10 @@ class MessageInputState extends State { borderSide: BorderSide(color: Colors.transparent)), disabledBorder: OutlineInputBorder( borderSide: BorderSide(color: Colors.transparent)), - contentPadding: EdgeInsets.all(8), + contentPadding: EdgeInsets.symmetric( + horizontal: 16, + vertical: 13, + ), prefixIcon: _commandEnabled ? Padding( padding: @@ -665,8 +669,8 @@ class MessageInputState extends State { mainAxisAlignment: MainAxisAlignment.start, children: [ IconButton( + iconSize: 24, icon: StreamSvgIcon.pictures( - size: 24, color: _filePickerIndex == 0 ? StreamChatTheme.of(context).accentColor : Colors.black.withOpacity(0.5), @@ -678,8 +682,8 @@ class MessageInputState extends State { }, ), IconButton( + iconSize: 32, icon: StreamSvgIcon.files( - size: 24, color: _filePickerIndex == 1 ? StreamChatTheme.of(context).accentColor : Colors.black.withOpacity(0.5), @@ -689,8 +693,8 @@ class MessageInputState extends State { }, ), IconButton( + iconSize: 24, icon: StreamSvgIcon.camera( - size: 24, color: _filePickerIndex == 2 ? StreamChatTheme.of(context).accentColor : Colors.black.withOpacity(0.5), @@ -700,8 +704,9 @@ class MessageInputState extends State { }, ), IconButton( + padding: const EdgeInsets.all(0), + iconSize: 24, icon: StreamSvgIcon.record( - size: 24, color: _filePickerIndex == 3 ? StreamChatTheme.of(context).accentColor : Colors.black.withOpacity(0.5), From ded26db306532289498d9048473e0e6e74385721 Mon Sep 17 00:00:00 2001 From: xsahil03x Date: Fri, 27 Nov 2020 12:54:57 +0530 Subject: [PATCH 0508/1140] feat : MessageSearchListView Signed-off-by: xsahil03x --- example/lib/main.dart | 167 ++++++++++++-- lib/src/message_search_bloc.dart | 109 +++++++++ lib/src/message_search_item.dart | 98 +++++++++ lib/src/message_search_list_view.dart | 305 ++++++++++++++++++++++++++ lib/src/stream_chat_theme.dart | 1 + lib/stream_chat_flutter.dart | 3 + 6 files changed, 663 insertions(+), 20 deletions(-) create mode 100644 lib/src/message_search_bloc.dart create mode 100644 lib/src/message_search_item.dart create mode 100644 lib/src/message_search_list_view.dart diff --git a/example/lib/main.dart b/example/lib/main.dart index 50ff18b0..bab4b1e0 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -12,6 +12,8 @@ import 'package:stream_chat_flutter/stream_chat_flutter.dart'; import 'notifications_service.dart'; import 'routes/app_routes.dart'; import 'routes/routes.dart'; +import 'search_text_field.dart'; +import 'dart:async'; void main() async { WidgetsFlutterBinding.ensureInitialized(); @@ -66,7 +68,45 @@ class MyApp extends StatelessWidget { } } -class ChannelListPage extends StatelessWidget { +class ChannelListPage extends StatefulWidget { + @override + _ChannelListPageState createState() => _ChannelListPageState(); +} + +class _ChannelListPageState extends State { + TextEditingController _controller; + + String _channelQuery = ''; + + bool _isSearchActive = false; + + Timer _debounce; + + void _channelQueryListener() { + if (_debounce?.isActive ?? false) _debounce.cancel(); + _debounce = Timer(const Duration(milliseconds: 350), () { + if (mounted) { + setState(() { + _channelQuery = _controller.text; + _isSearchActive = _channelQuery.isNotEmpty; + }); + } + }); + } + + @override + void initState() { + super.initState(); + _controller = TextEditingController()..addListener(_channelQueryListener); + } + + @override + void dispose() { + _controller?.removeListener(_channelQueryListener); + _controller?.dispose(); + super.dispose(); + } + @override Widget build(BuildContext context) { final user = StreamChat.of(context).user; @@ -79,26 +119,50 @@ class ChannelListPage extends StatelessWidget { drawer: _buildDrawer(context, user), drawerEdgeDragWidth: 50, body: ChannelsBloc( - child: ChannelListView( - onStartChatPressed: () { - Navigator.pushNamed(context, Routes.NEW_CHAT); - }, - swipeToAction: true, - filter: { - 'members': { - '\$in': [user.id], - }, - 'draft': { - r'$ne': true, - }, - }, - options: { - 'presence': true, - }, - pagination: PaginationParams( - limit: 20, + child: MessageSearchBloc( + child: Column( + children: [ + SearchTextField( + controller: _controller, + ), + Expanded( + child: AnimatedSwitcher( + duration: const Duration(milliseconds: 350), + child: _isSearchActive + ? MessageSearchListView( + messageQuery: _channelQuery, + filters: { + 'members': { + r'$in': [user.id] + } + }, + paginationParams: PaginationParams(limit: 20), + ) + : ChannelListView( + onStartChatPressed: () { + Navigator.pushNamed(context, Routes.NEW_CHAT); + }, + swipeToAction: true, + filter: { + 'members': { + r'$in': [user.id], + }, + 'draft': { + r'$ne': true, + }, + }, + options: { + 'presence': true, + }, + pagination: PaginationParams( + limit: 20, + ), + channelWidget: ChannelPage(), + ), + ), + ), + ], ), - channelWidget: ChannelPage(), ), ), ); @@ -207,6 +271,68 @@ class ChannelListPage extends StatelessWidget { } } +class ChannelQuerySearchResultPage extends StatelessWidget { + final Stream> searchResultStream; + + const ChannelQuerySearchResultPage({ + Key key, + @required this.searchResultStream, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + return StreamBuilder>( + initialData: const [], + stream: searchResultStream, + builder: (context, snapshot) { + final result = snapshot.data; + return Column( + children: [ + if (result.isNotEmpty) + Container( + width: double.maxFinite, + decoration: BoxDecoration( + gradient: LinearGradient( + begin: Alignment.centerLeft, + end: Alignment.centerRight, + colors: [ + Colors.black.withOpacity(0.02), + Colors.white.withOpacity(0.05), + ], + stops: [0, 1], + ), + ), + child: Padding( + padding: const EdgeInsets.symmetric( + vertical: 8, + horizontal: 8, + ), + child: Text( + '${result.length} results', + style: TextStyle( + color: Colors.black.withOpacity(0.5), + ), + ), + ), + ), + Expanded( + child: ListView.builder( + itemCount: result.length, + itemBuilder: (context, index) { + return ListTile( + leading: UserAvatar(), + title: Text(result[index].toJson().toString()), + ); + }, + ), + ), + ], + ); + }, + ); + } +} + class ChannelPage extends StatelessWidget { const ChannelPage({ Key key, @@ -215,6 +341,7 @@ class ChannelPage extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( + backgroundColor: Color.fromRGBO(252, 252, 252, 1), appBar: ChannelHeader( showTypingIndicator: false, ), diff --git a/lib/src/message_search_bloc.dart b/lib/src/message_search_bloc.dart new file mode 100644 index 00000000..bff2d68e --- /dev/null +++ b/lib/src/message_search_bloc.dart @@ -0,0 +1,109 @@ +import 'package:flutter/material.dart'; +import 'package:rxdart/rxdart.dart'; +import 'package:stream_chat/stream_chat.dart'; + +import 'stream_chat.dart'; + +/// Widget dedicated to the management of a message list with pagination +class MessageSearchBloc extends StatefulWidget { + /// The widget child + final Widget child; + + /// Instantiate a new MessageSearchBloc + const MessageSearchBloc({ + Key key, + @required this.child, + }) : super(key: key); + + @override + MessageSearchBlocState createState() => MessageSearchBlocState(); + + /// Use this method to get the current [MessageSearchBlocState] instance + static MessageSearchBlocState of(BuildContext context) { + MessageSearchBlocState state; + + state = context.findAncestorStateOfType(); + + if (state == null) { + throw Exception('You must have a MessageSearchBloc widget as ancestor'); + } + + return state; + } +} + +/// The current state of the [MessageSearchBloc] +class MessageSearchBlocState extends State + with AutomaticKeepAliveClientMixin { + /// The current messages list + List get messages => _messagesController.value; + + /// The current messages list as a stream + Stream> get messagesStream => _messagesController.stream; + + final BehaviorSubject> _messagesController = BehaviorSubject(); + + final BehaviorSubject _queryMessagesLoadingController = + BehaviorSubject.seeded(false); + + /// The stream notifying the state of queryUsers call + Stream get queryMessagesLoading => + _queryMessagesLoadingController.stream; + + /// Calls [Client.search] updating [queryMessagesLoading] stream + Future search({ + Map filter, + List sort, + String query, + PaginationParams pagination, + }) async { + final client = StreamChat.of(context).client; + + if (client.state?.user == null || + _queryMessagesLoadingController.value == true) { + return; + } + _queryMessagesLoadingController.add(true); + try { + final clear = pagination == null || + pagination.offset == null || + pagination.offset == 0; + + final oldMessages = List.from(messages ?? []); + + final messageResponse = await client.search( + filter, + sort, + query, + pagination, + ); + + if (clear) { + _messagesController.add(messageResponse.results); + } else { + final temp = oldMessages + messageResponse.results; + _messagesController.add(temp); + } + + _queryMessagesLoadingController.add(false); + } catch (err, stackTrace) { + _queryMessagesLoadingController.addError(err, stackTrace); + } + } + + @override + Widget build(BuildContext context) { + super.build(context); + return widget.child; + } + + @override + void dispose() { + _messagesController.close(); + _queryMessagesLoadingController.close(); + super.dispose(); + } + + @override + bool get wantKeepAlive => true; +} diff --git a/lib/src/message_search_item.dart b/lib/src/message_search_item.dart new file mode 100644 index 00000000..d97db708 --- /dev/null +++ b/lib/src/message_search_item.dart @@ -0,0 +1,98 @@ +import 'package:flutter/material.dart'; +import 'package:jiffy/jiffy.dart'; +import 'package:stream_chat/stream_chat.dart'; +import 'package:stream_chat_flutter/stream_chat_flutter.dart'; + +class MessageSearchItem extends StatelessWidget { + final Message message; + + const MessageSearchItem({ + Key key, + @required this.message, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + final data = Message.fromJson(message.extraData['message']); + final user = data.user; + debugPrint(message.toJson().toString()); + return ListTile( + leading: UserAvatar( + user: user, + constraints: BoxConstraints.tightFor( + height: 40, + width: 40, + ), + ), + title: Text( + user.name, + style: StreamChatTheme.of(context).channelPreviewTheme.title, + ), + subtitle: Row( + children: [ + Expanded(child: _buildSubtitle(context, data)), + _buildDate(context, data), + ], + ), + ); + } + + Widget _buildDate(BuildContext context, Message message) { + final lastUpdatedAt = message.updatedAt; + String stringDate; + final now = DateTime.now(); + + if (now.year != lastUpdatedAt.year || + now.month != lastUpdatedAt.month || + now.day != lastUpdatedAt.day) { + stringDate = Jiffy(lastUpdatedAt.toLocal()).format('dd/MM/yyyy'); + } else { + stringDate = Jiffy(lastUpdatedAt.toLocal()).format('HH:mm'); + } + + return Text( + stringDate, + style: StreamChatTheme.of(context).channelPreviewTheme.lastMessageAt, + ); + } + + Widget _buildSubtitle(BuildContext context, Message message) { + if (message == null) { + return SizedBox(); + } + + var text = message.text; + if (message.isDeleted) { + text = 'This message was deleted.'; + } else if (message.attachments != null) { + final parts = [ + ...message.attachments.map((e) { + if (e.type == 'image') { + return '📷'; + } else if (e.type == 'video') { + return '🎬'; + } else if (e.type == 'giphy') { + return '[GIF]'; + } + return null; + }).where((e) => e != null), + message.text ?? '', + ]; + + text = parts.join(' '); + } + + return Text( + text, + maxLines: 1, + overflow: TextOverflow.ellipsis, + style: StreamChatTheme.of(context).channelPreviewTheme.subtitle.copyWith( + color: + StreamChatTheme.of(context).channelPreviewTheme.subtitle.color, + fontStyle: (message.isSystem || message.isDeleted) + ? FontStyle.italic + : FontStyle.normal, + ), + ); + } +} diff --git a/lib/src/message_search_list_view.dart b/lib/src/message_search_list_view.dart new file mode 100644 index 00000000..f317a677 --- /dev/null +++ b/lib/src/message_search_list_view.dart @@ -0,0 +1,305 @@ +import 'dart:convert'; + +import 'package:flutter/material.dart'; +import 'package:stream_chat/stream_chat.dart'; +import 'package:stream_chat_flutter/src/message_search_item.dart'; + +import 'lazy_load_scroll_view.dart'; +import 'message_search_bloc.dart'; + +class MessageSearchListView extends StatefulWidget { + final String messageQuery; + final Map filters; + final List sortOptions; + final PaginationParams paginationParams; + final bool pullToRefresh; + + /// The builder used when the channel list is empty. + final WidgetBuilder emptyBuilder; + + /// The builder that will be used in case of error + final Widget Function(Error error) errorBuilder; + + /// Builder used to create a custom item separator + final IndexedWidgetBuilder separatorBuilder; + + const MessageSearchListView({ + Key key, + @required this.messageQuery, + @required this.filters, + this.sortOptions, + this.paginationParams, + this.emptyBuilder, + this.errorBuilder, + this.separatorBuilder, + this.pullToRefresh = true, + }) : super(key: key); + + @override + _MessageSearchListViewState createState() => _MessageSearchListViewState(); +} + +class _MessageSearchListViewState extends State { + @override + void initState() { + super.initState(); + final messageSearchBloc = MessageSearchBloc.of(context); + messageSearchBloc.search( + filter: widget.filters, + sort: widget.sortOptions, + query: widget.messageQuery, + pagination: widget.paginationParams, + ); + } + + @override + Widget build(BuildContext context) { + final messageSearchBloc = MessageSearchBloc.of(context); + + if (!widget.pullToRefresh) { + return _buildListView(messageSearchBloc); + } + + return RefreshIndicator( + onRefresh: () async { + return messageSearchBloc.search( + filter: widget.filters, + sort: widget.sortOptions, + query: widget.messageQuery, + pagination: widget.paginationParams, + ); + }, + child: _buildListView(messageSearchBloc), + ); + } + + Widget _separatorBuilder(BuildContext context, int index) { + return Container( + height: 1, + color: Theme.of(context).brightness == Brightness.dark + ? Colors.white.withOpacity(0.1) + : Colors.black.withOpacity(0.1), + ); + } + + Widget _listItemBuilder(BuildContext context, Message message) { + return MessageSearchItem(message: message); + } + + Widget _buildQueryProgressIndicator( + context, MessageSearchBlocState messageSearchBloc) { + return StreamBuilder( + stream: messageSearchBloc.queryMessagesLoading, + initialData: false, + builder: (context, snapshot) { + if (snapshot.hasError) { + return Container( + color: Color(0xffd0021B).withAlpha(26), + child: Padding( + padding: const EdgeInsets.symmetric(vertical: 16.0), + child: Center( + child: Text('Error loading messages'), + ), + ), + ); + } + return Container( + height: 100, + padding: EdgeInsets.all(32), + child: Center( + child: snapshot.data ? CircularProgressIndicator() : Container(), + ), + ); + }); + } + + Widget _buildListView(MessageSearchBlocState messageSearchBloc) { + return StreamBuilder>( + stream: messageSearchBloc.messagesStream, + builder: (context, snapshot) { + if (snapshot.hasError) { + if (snapshot.error is Error) { + print((snapshot.error as Error).stackTrace); + } + + if (widget.errorBuilder != null) { + return widget.errorBuilder(snapshot.error); + } + + var message = snapshot.error.toString(); + if (snapshot.error is DioError) { + final dioError = snapshot.error as DioError; + if (dioError.type == DioErrorType.RESPONSE) { + message = dioError.message; + } else { + message = 'Check your connection and retry'; + } + } + return Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text.rich( + TextSpan( + children: [ + WidgetSpan( + child: Padding( + padding: const EdgeInsets.only( + right: 2.0, + ), + child: Icon(Icons.error_outline), + ), + ), + TextSpan(text: 'Error loading messages'), + ], + ), + style: Theme.of(context).textTheme.headline6, + ), + Padding( + padding: const EdgeInsets.only( + top: 16.0, + ), + child: Text(message), + ), + FlatButton( + onPressed: () { + messageSearchBloc.search( + filter: widget.filters, + sort: widget.sortOptions, + query: widget.messageQuery, + pagination: widget.paginationParams, + ); + }, + child: Text('Retry'), + ), + ], + ), + ); + } + + if (!snapshot.hasData) { + return LayoutBuilder( + builder: (context, viewportConstraints) { + return SingleChildScrollView( + physics: AlwaysScrollableScrollPhysics(), + child: ConstrainedBox( + constraints: BoxConstraints( + minHeight: viewportConstraints.maxHeight, + ), + child: Center( + child: CircularProgressIndicator(), + ), + ), + ); + }, + ); + } + + final items = snapshot.data; + + if (items.isEmpty && widget.emptyBuilder != null) { + return widget.emptyBuilder(context); + } + + if (items.isEmpty && widget.emptyBuilder == null) { + return LayoutBuilder( + builder: (context, viewportConstraints) { + return SingleChildScrollView( + physics: AlwaysScrollableScrollPhysics(), + child: ConstrainedBox( + constraints: BoxConstraints( + minHeight: viewportConstraints.maxHeight, + ), + child: Center( + child: Text('There are no messages currently'), + ), + ), + ); + }, + ); + } + + Widget child; + child = LazyLoadScrollView( + onEndOfPage: () => messageSearchBloc.search( + filter: widget.filters, + sort: widget.sortOptions, + pagination: widget.paginationParams.copyWith( + offset: messageSearchBloc.messages?.length ?? 0, + ), + query: widget.messageQuery, + ), + child: ListView.separated( + physics: AlwaysScrollableScrollPhysics(), + itemCount: items.isNotEmpty ? items.length + 1 : items.length, + separatorBuilder: (_, index) { + if (widget.separatorBuilder != null) { + return widget.separatorBuilder(context, index); + } + return _separatorBuilder(context, index); + }, + itemBuilder: (context, index) { + if (index < items.length) { + return _listItemBuilder(context, items[index]); + } + return _buildQueryProgressIndicator(context, messageSearchBloc); + }, + ), + ); + + if (true) { + child = Column( + children: [ + Container( + width: double.maxFinite, + decoration: BoxDecoration( + gradient: LinearGradient( + begin: Alignment.centerLeft, + end: Alignment.centerRight, + colors: [ + Colors.black.withOpacity(0.02), + Colors.white.withOpacity(0.05), + ], + stops: [0, 1], + ), + ), + child: Padding( + padding: const EdgeInsets.symmetric( + vertical: 8, + horizontal: 8, + ), + child: Text( + '${items.length} results', + style: TextStyle( + color: Colors.black.withOpacity(0.5), + ), + ), + ), + ), + Expanded(child: child), + ], + ); + } + return child; + }, + ); + } + + @override + void didUpdateWidget(MessageSearchListView oldWidget) { + super.didUpdateWidget(oldWidget); + if (widget.filters?.toString() != oldWidget.filters?.toString() || + jsonEncode(widget.sortOptions) != jsonEncode(oldWidget.sortOptions) || + widget.paginationParams?.toJson()?.toString() != + oldWidget.paginationParams?.toJson()?.toString() || + widget.messageQuery?.toString() != oldWidget.messageQuery?.toString()) { + final messageSearchBloc = MessageSearchBloc.of(context); + messageSearchBloc.search( + filter: widget.filters, + sort: widget.sortOptions, + query: widget.messageQuery, + pagination: widget.paginationParams, + ); + } + } +} diff --git a/lib/src/stream_chat_theme.dart b/lib/src/stream_chat_theme.dart index d5b2c1c2..9c24525c 100644 --- a/lib/src/stream_chat_theme.dart +++ b/lib/src/stream_chat_theme.dart @@ -245,6 +245,7 @@ class StreamChatThemeData { title: TextStyle( fontSize: 14, color: isDark ? Colors.white : Colors.black, + fontWeight: FontWeight.bold ), subtitle: TextStyle( fontSize: 12.5, diff --git a/lib/stream_chat_flutter.dart b/lib/stream_chat_flutter.dart index f8ad25ea..35239cbd 100644 --- a/lib/stream_chat_flutter.dart +++ b/lib/stream_chat_flutter.dart @@ -38,3 +38,6 @@ export 'src/users_bloc.dart'; export 'src/users_bloc.dart'; export 'src/utils.dart'; export 'src/video_attachment.dart'; +export 'src/message_search_bloc.dart'; +export 'src/message_search_item.dart'; +export 'src/message_search_list_view.dart'; From c6552be54062b0fa0aa724b2056bd926404a754b Mon Sep 17 00:00:00 2001 From: xsahil03x Date: Fri, 27 Nov 2020 13:42:10 +0530 Subject: [PATCH 0509/1140] add docComments Signed-off-by: xsahil03x --- lib/src/message_search_item.dart | 23 +++++++- lib/src/message_search_list_view.dart | 76 +++++++++++++++++++++------ 2 files changed, 82 insertions(+), 17 deletions(-) diff --git a/lib/src/message_search_item.dart b/lib/src/message_search_item.dart index d97db708..a89f2ee0 100644 --- a/lib/src/message_search_item.dart +++ b/lib/src/message_search_item.dart @@ -3,22 +3,40 @@ import 'package:jiffy/jiffy.dart'; import 'package:stream_chat/stream_chat.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; +/// It shows the current [Message] preview. +/// +/// Usually you don't use this widget as it's the default item used by [MessageSearchListView]. +/// +/// The widget renders the ui based on the first ancestor of type [StreamChatTheme]. +/// Modify it to change the widget appearance. class MessageSearchItem extends StatelessWidget { - final Message message; - + /// Instantiate a new MessageSearchItem const MessageSearchItem({ Key key, @required this.message, + this.onTap, + this.showOnlineStatus = true, }) : super(key: key); + /// [Message] displayed + final Message message; + + /// Function called when tapping this widget + final VoidCallback onTap; + + /// If true the [MessageSearchItem] will show the current online Status + final bool showOnlineStatus; + @override Widget build(BuildContext context) { final data = Message.fromJson(message.extraData['message']); final user = data.user; debugPrint(message.toJson().toString()); return ListTile( + onTap: onTap, leading: UserAvatar( user: user, + showOnlineStatus: showOnlineStatus, constraints: BoxConstraints.tightFor( height: 40, width: 40, @@ -31,6 +49,7 @@ class MessageSearchItem extends StatelessWidget { subtitle: Row( children: [ Expanded(child: _buildSubtitle(context, data)), + SizedBox(width: 16), _buildDate(context, data), ], ), diff --git a/lib/src/message_search_list_view.dart b/lib/src/message_search_list_view.dart index f317a677..9ad013db 100644 --- a/lib/src/message_search_list_view.dart +++ b/lib/src/message_search_list_view.dart @@ -7,22 +7,36 @@ import 'package:stream_chat_flutter/src/message_search_item.dart'; import 'lazy_load_scroll_view.dart'; import 'message_search_bloc.dart'; +/// +/// It shows the list of searched messages. +/// +/// ```dart +/// class MessageSearchPage extends StatelessWidget { +/// @override +/// Widget build(BuildContext context) { +/// return Scaffold( +/// body: MessageSearchListView( +/// messageQuery: _channelQuery, +/// filters: { +/// 'members': { +/// r'$in': [user.id] +/// } +/// }, +/// paginationParams: PaginationParams(limit: 20), +/// ), +/// ); +/// } +/// } +/// ``` +/// +/// +/// Make sure to have a [MessageSearchBloc] ancestor in order to provide the information about the messages. +/// The widget uses a [ListView.separated] to render the list of messages. +/// +/// The widget components render the ui based on the first ancestor of type [StreamChatTheme]. +/// Modify it to change the widget appearance. class MessageSearchListView extends StatefulWidget { - final String messageQuery; - final Map filters; - final List sortOptions; - final PaginationParams paginationParams; - final bool pullToRefresh; - - /// The builder used when the channel list is empty. - final WidgetBuilder emptyBuilder; - - /// The builder that will be used in case of error - final Widget Function(Error error) errorBuilder; - - /// Builder used to create a custom item separator - final IndexedWidgetBuilder separatorBuilder; - + /// Instantiate a new MessageSearchListView const MessageSearchListView({ Key key, @required this.messageQuery, @@ -35,6 +49,38 @@ class MessageSearchListView extends StatefulWidget { this.pullToRefresh = true, }) : super(key: key); + /// Message String to search on + final String messageQuery; + + /// The query filters to use. + /// You can query on any of the custom fields you've defined on the [Channel]. + /// You can also filter other built-in channel fields. + final Map filters; + + /// The sorting used for the channels matching the filters. + /// Sorting is based on field and direction, multiple sorting options can be provided. + /// You can sort based on last_updated, last_message_at, updated_at, created_at or member_count. + /// Direction can be ascending or descending. + final List sortOptions; + + /// Pagination parameters + /// limit: the number of users to return (max is 30) + /// offset: the offset (max is 1000) + /// message_limit: how many messages should be included to each channel + final PaginationParams paginationParams; + + /// Set it to false to disable the pull-to-refresh widget + final bool pullToRefresh; + + /// The builder used when the channel list is empty. + final WidgetBuilder emptyBuilder; + + /// The builder that will be used in case of error + final Widget Function(Error error) errorBuilder; + + /// Builder used to create a custom item separator + final IndexedWidgetBuilder separatorBuilder; + @override _MessageSearchListViewState createState() => _MessageSearchListViewState(); } From ad37e1b46542b3485ad578bb7dde60996137f925 Mon Sep 17 00:00:00 2001 From: xsahil03x Date: Fri, 27 Nov 2020 13:44:04 +0530 Subject: [PATCH 0510/1140] [UserListView] fix docComments Signed-off-by: xsahil03x --- lib/src/user_list_view.dart | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/lib/src/user_list_view.dart b/lib/src/user_list_view.dart index 569eb38a..cc763971 100644 --- a/lib/src/user_list_view.dart +++ b/lib/src/user_list_view.dart @@ -6,7 +6,6 @@ import 'package:stream_chat_flutter/src/lazy_load_scroll_view.dart'; import 'package:stream_chat_flutter/src/users_bloc.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; -import 'stream_chat.dart'; import 'user_item.dart'; /// Callback called when tapping on a user @@ -41,8 +40,8 @@ typedef UserItemBuilder = Widget Function(BuildContext, User, bool); /// ``` /// /// -/// Make sure to have a [StreamChat] ancestor in order to provide the information about the channels. -/// The widget uses a [ListView.custom] to render the list of channels. +/// Make sure to have a [UsersBloc] ancestor in order to provide the information about the users. +/// The widget uses a [ListView.separated], [GridView.builder] to render the list, grid of channels. /// /// The widget components render the ui based on the first ancestor of type [StreamChatTheme]. /// Modify it to change the widget appearance. @@ -321,7 +320,6 @@ class _UserListViewState extends State final child = _isListView ? ListView.separated( physics: AlwaysScrollableScrollPhysics(), - // controller: _scrollController, itemCount: items.isNotEmpty ? items.length + 1 : items.length, separatorBuilder: (_, index) { if (widget.separatorBuilder != null) { From 5867dc3317a99c9d30a674ad3411df1be02cec26 Mon Sep 17 00:00:00 2001 From: xsahil03x Date: Fri, 27 Nov 2020 13:45:28 +0530 Subject: [PATCH 0511/1140] [UserListView] remove redundant property Signed-off-by: xsahil03x --- lib/src/user_list_view.dart | 4 ---- 1 file changed, 4 deletions(-) diff --git a/lib/src/user_list_view.dart b/lib/src/user_list_view.dart index cc763971..b57e2d55 100644 --- a/lib/src/user_list_view.dart +++ b/lib/src/user_list_view.dart @@ -62,7 +62,6 @@ class UserListView extends StatefulWidget { this.separatorBuilder, this.onImageTap, this.selectedUsers, - this.swipeToAction = false, this.pullToRefresh = true, this.groupAlphabetically = false, this.crossAxisCount = 1, @@ -75,9 +74,6 @@ class UserListView extends StatefulWidget { /// The builder that will be used in case of error final Widget Function(Error error) errorBuilder; - /// If true a default swipe to action behaviour will be added to this widget - final bool swipeToAction; - /// The builder used when the channel list is empty. final WidgetBuilder emptyBuilder; From 9ca86067903318140990625b0a4cd297cb586fa3 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Fri, 27 Nov 2020 09:23:12 +0100 Subject: [PATCH 0512/1140] fix bottom sheet and channel name --- lib/src/channel_bottom_sheet.dart | 5 +-- lib/src/channel_list_view.dart | 5 ++- lib/src/channel_name.dart | 62 ++++++++++++++++++++----------- 3 files changed, 46 insertions(+), 26 deletions(-) diff --git a/lib/src/channel_bottom_sheet.dart b/lib/src/channel_bottom_sheet.dart index c0e32509..4272b0f3 100644 --- a/lib/src/channel_bottom_sheet.dart +++ b/lib/src/channel_bottom_sheet.dart @@ -2,6 +2,7 @@ import 'package:flutter/material.dart'; import 'package:stream_chat/stream_chat.dart'; import 'package:stream_chat_flutter/src/stream_svg_icon.dart'; import 'package:stream_chat_flutter/src/utils.dart'; +import 'package:stream_chat_flutter/stream_chat_flutter.dart'; import 'channel_info.dart'; import 'channel_name.dart'; @@ -12,13 +13,11 @@ import 'user_avatar.dart'; class ChannelBottomSheet extends StatelessWidget { const ChannelBottomSheet({ Key key, - @required this.channel, }) : super(key: key); - final Channel channel; - @override Widget build(BuildContext context) { + final channel = StreamChannel.of(context).channel; return SafeArea( child: Padding( padding: const EdgeInsets.all(8.0), diff --git a/lib/src/channel_list_view.dart b/lib/src/channel_list_view.dart index 45c53eb6..1a431672 100644 --- a/lib/src/channel_list_view.dart +++ b/lib/src/channel_list_view.dart @@ -511,7 +511,10 @@ class _ChannelListViewState extends State ), context: context, builder: (context) { - return ChannelBottomSheet(channel: channel); + return StreamChannel( + child: ChannelBottomSheet(), + channel: channel, + ); }, ); }, diff --git a/lib/src/channel_name.dart b/lib/src/channel_name.dart index 01abcb81..337321ed 100644 --- a/lib/src/channel_name.dart +++ b/lib/src/channel_name.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; import 'package:stream_chat/stream_chat.dart'; import '../stream_chat_flutter.dart'; @@ -25,29 +26,46 @@ class ChannelName extends StatelessWidget { Widget build(BuildContext context) { final client = StreamChat.of(context); final channel = this.channel ?? StreamChannel.of(context).channel; - return StreamBuilder>( - stream: channel.extraDataStream, - initialData: channel.extraData, - builder: (context, snapshot) { - String title; - if (snapshot.data['name'] == null) { - final otherMembers = channel.state.members - .where((member) => member.userId != client.user.id); - if (otherMembers.isNotEmpty) { - final exceedingMembers = otherMembers.length - 5; - title = - '${otherMembers.take(5).map((e) => e.user.name).join(', ')} ${exceedingMembers > 0 ? '+ $exceedingMembers' : ''}'; - } else { - title = channel.id; - } - } else { - title = snapshot.data['name']; - } + return LayoutBuilder( + builder: (context, constraints) { + return StreamBuilder>( + stream: channel.extraDataStream, + initialData: channel.extraData, + builder: (context, snapshot) { + String title; + if (snapshot.data['name'] == null) { + final otherMembers = channel.state.members + .where((member) => member.userId != client.user.id); + if (otherMembers.isNotEmpty) { + final maxWidth = constraints.maxWidth; + final maxChars = maxWidth / textStyle.fontSize; + int currentChars = 0; + final currentMembers = []; + otherMembers.forEach((element) { + final newLength = currentChars + element.user.name.length; + if (newLength < maxChars) { + currentChars = newLength; + currentMembers.add(element); + } + }); - return Text( - title, - style: textStyle, - overflow: TextOverflow.ellipsis, + final exceedingMembers = + otherMembers.length - currentMembers.length; + title = + '${currentMembers.map((e) => e.user.name).join(', ')} ${exceedingMembers > 0 ? '+ $exceedingMembers' : ''}'; + } else { + title = channel.id; + } + } else { + title = snapshot.data['name']; + } + + return Text( + title, + style: textStyle, + overflow: TextOverflow.ellipsis, + ); + }, ); }, ); From 4df3bf161034e92a0108585513d7b696fef8b272 Mon Sep 17 00:00:00 2001 From: xsahil03x Date: Fri, 27 Nov 2020 13:58:33 +0530 Subject: [PATCH 0513/1140] minor changes Signed-off-by: xsahil03x --- lib/src/message_search_list_view.dart | 35 ++++++++++++--------------- 1 file changed, 15 insertions(+), 20 deletions(-) diff --git a/lib/src/message_search_list_view.dart b/lib/src/message_search_list_view.dart index 9ad013db..285e452b 100644 --- a/lib/src/message_search_list_view.dart +++ b/lib/src/message_search_list_view.dart @@ -7,6 +7,9 @@ import 'package:stream_chat_flutter/src/message_search_item.dart'; import 'lazy_load_scroll_view.dart'; import 'message_search_bloc.dart'; +/// Builder used to create a custom [ListUserItem] from a [User] +typedef MessageSearchItemBuilder = Widget Function(BuildContext, Message); + /// /// It shows the list of searched messages. /// @@ -46,7 +49,8 @@ class MessageSearchListView extends StatefulWidget { this.emptyBuilder, this.errorBuilder, this.separatorBuilder, - this.pullToRefresh = true, + this.itemBuilder, + this.showResultCount = true, }) : super(key: key); /// Message String to search on @@ -69,8 +73,8 @@ class MessageSearchListView extends StatefulWidget { /// message_limit: how many messages should be included to each channel final PaginationParams paginationParams; - /// Set it to false to disable the pull-to-refresh widget - final bool pullToRefresh; + /// Builder used to create a custom item preview + final MessageSearchItemBuilder itemBuilder; /// The builder used when the channel list is empty. final WidgetBuilder emptyBuilder; @@ -81,6 +85,9 @@ class MessageSearchListView extends StatefulWidget { /// Builder used to create a custom item separator final IndexedWidgetBuilder separatorBuilder; + /// Set it to false to hide total results text + final bool showResultCount; + @override _MessageSearchListViewState createState() => _MessageSearchListViewState(); } @@ -101,22 +108,7 @@ class _MessageSearchListViewState extends State { @override Widget build(BuildContext context) { final messageSearchBloc = MessageSearchBloc.of(context); - - if (!widget.pullToRefresh) { - return _buildListView(messageSearchBloc); - } - - return RefreshIndicator( - onRefresh: () async { - return messageSearchBloc.search( - filter: widget.filters, - sort: widget.sortOptions, - query: widget.messageQuery, - pagination: widget.paginationParams, - ); - }, - child: _buildListView(messageSearchBloc), - ); + return _buildListView(messageSearchBloc); } Widget _separatorBuilder(BuildContext context, int index) { @@ -129,6 +121,9 @@ class _MessageSearchListViewState extends State { } Widget _listItemBuilder(BuildContext context, Message message) { + if (widget.itemBuilder != null) { + return widget.itemBuilder(context, message); + } return MessageSearchItem(message: message); } @@ -293,7 +288,7 @@ class _MessageSearchListViewState extends State { ), ); - if (true) { + if (widget.showResultCount) { child = Column( children: [ Container( From 15669e8dd8272eb29587ebe9475ecfed605e2bce Mon Sep 17 00:00:00 2001 From: xsahil03x Date: Fri, 27 Nov 2020 14:02:21 +0530 Subject: [PATCH 0514/1140] [MessageSearchListView] Add itemTap property Signed-off-by: xsahil03x --- lib/src/message_search_list_view.dart | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/lib/src/message_search_list_view.dart b/lib/src/message_search_list_view.dart index 285e452b..d5a282a4 100644 --- a/lib/src/message_search_list_view.dart +++ b/lib/src/message_search_list_view.dart @@ -7,6 +7,9 @@ import 'package:stream_chat_flutter/src/message_search_item.dart'; import 'lazy_load_scroll_view.dart'; import 'message_search_bloc.dart'; +/// Callback called when tapping on a user +typedef MessageSearchItemTapCallback = void Function(Message); + /// Builder used to create a custom [ListUserItem] from a [User] typedef MessageSearchItemBuilder = Widget Function(BuildContext, Message); @@ -50,6 +53,7 @@ class MessageSearchListView extends StatefulWidget { this.errorBuilder, this.separatorBuilder, this.itemBuilder, + this.onItemTap, this.showResultCount = true, }) : super(key: key); @@ -76,6 +80,9 @@ class MessageSearchListView extends StatefulWidget { /// Builder used to create a custom item preview final MessageSearchItemBuilder itemBuilder; + /// Function called when tapping on a [MessageSearchItem] + final MessageSearchItemTapCallback onItemTap; + /// The builder used when the channel list is empty. final WidgetBuilder emptyBuilder; @@ -124,7 +131,10 @@ class _MessageSearchListViewState extends State { if (widget.itemBuilder != null) { return widget.itemBuilder(context, message); } - return MessageSearchItem(message: message); + return MessageSearchItem( + message: message, + onTap: () => widget.onItemTap(message), + ); } Widget _buildQueryProgressIndicator( From 1ef7511f624dbc597297201b4cac2de17283f07c Mon Sep 17 00:00:00 2001 From: xsahil03x Date: Fri, 27 Nov 2020 14:02:59 +0530 Subject: [PATCH 0515/1140] minor changes Signed-off-by: xsahil03x --- example/lib/main.dart | 1 + 1 file changed, 1 insertion(+) diff --git a/example/lib/main.dart b/example/lib/main.dart index bab4b1e0..5804ecb2 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -137,6 +137,7 @@ class _ChannelListPageState extends State { } }, paginationParams: PaginationParams(limit: 20), + onItemTap: (message) {}, ) : ChannelListView( onStartChatPressed: () { From d5e8ee20713f4d0fba7f78ba969489af443da28b Mon Sep 17 00:00:00 2001 From: xsahil03x Date: Fri, 27 Nov 2020 14:08:41 +0530 Subject: [PATCH 0516/1140] close keyboard on listView scroll Signed-off-by: xsahil03x --- example/lib/main.dart | 62 +++++++++++++++++++++++-------------------- 1 file changed, 33 insertions(+), 29 deletions(-) diff --git a/example/lib/main.dart b/example/lib/main.dart index 5804ecb2..3ba3e93c 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -128,38 +128,42 @@ class _ChannelListPageState extends State { Expanded( child: AnimatedSwitcher( duration: const Duration(milliseconds: 350), - child: _isSearchActive - ? MessageSearchListView( - messageQuery: _channelQuery, - filters: { - 'members': { - r'$in': [user.id] - } - }, - paginationParams: PaginationParams(limit: 20), - onItemTap: (message) {}, - ) - : ChannelListView( - onStartChatPressed: () { - Navigator.pushNamed(context, Routes.NEW_CHAT); - }, - swipeToAction: true, - filter: { - 'members': { - r'$in': [user.id], + child: GestureDetector( + behavior: HitTestBehavior.opaque, + onPanDown: (_) => FocusScope.of(context).unfocus(), + child: _isSearchActive + ? MessageSearchListView( + messageQuery: _channelQuery, + filters: { + 'members': { + r'$in': [user.id] + } }, - 'draft': { - r'$ne': true, + paginationParams: PaginationParams(limit: 20), + onItemTap: (message) {}, + ) + : ChannelListView( + onStartChatPressed: () { + Navigator.pushNamed(context, Routes.NEW_CHAT); }, - }, - options: { - 'presence': true, - }, - pagination: PaginationParams( - limit: 20, + swipeToAction: true, + filter: { + 'members': { + r'$in': [user.id], + }, + 'draft': { + r'$ne': true, + }, + }, + options: { + 'presence': true, + }, + pagination: PaginationParams( + limit: 20, + ), + channelWidget: ChannelPage(), ), - channelWidget: ChannelPage(), - ), + ), ), ), ], From e20ed0f012d7cc5974af961d5624526e0164b5da Mon Sep 17 00:00:00 2001 From: xsahil03x Date: Fri, 27 Nov 2020 14:09:45 +0530 Subject: [PATCH 0517/1140] dartfmt Signed-off-by: xsahil03x --- lib/src/stream_chat_theme.dart | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/lib/src/stream_chat_theme.dart b/lib/src/stream_chat_theme.dart index 9c24525c..54b096d1 100644 --- a/lib/src/stream_chat_theme.dart +++ b/lib/src/stream_chat_theme.dart @@ -243,10 +243,9 @@ class StreamChatThemeData { ), ), title: TextStyle( - fontSize: 14, - color: isDark ? Colors.white : Colors.black, - fontWeight: FontWeight.bold - ), + fontSize: 14, + color: isDark ? Colors.white : Colors.black, + fontWeight: FontWeight.bold), subtitle: TextStyle( fontSize: 12.5, color: (isDark ? Colors.white : Colors.black).withOpacity(0.5), From 78be96eab06944704c6c5256731a808ecc21bcaa Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Fri, 27 Nov 2020 12:49:17 +0100 Subject: [PATCH 0518/1140] use correct response model --- .gitignore | 3 +- example/lib/main.dart | 6 ++ example/lib/search_text_field.dart | 2 +- example/pubspec.yaml | 2 +- lib/src/channel_bottom_sheet.dart | 9 ++- lib/src/channel_name.dart | 87 ++++++++++++++------------- lib/src/message_search_bloc.dart | 16 ++--- lib/src/message_search_item.dart | 42 ++++++++++--- lib/src/message_search_list_view.dart | 18 +++--- pubspec.yaml | 2 +- 10 files changed, 114 insertions(+), 73 deletions(-) diff --git a/.gitignore b/.gitignore index 3a158cd4..1d3bae26 100644 --- a/.gitignore +++ b/.gitignore @@ -61,4 +61,5 @@ doc/api/ fvm google-services.json -example/ios/dist \ No newline at end of file +example/ios/dist +.vscode/ \ No newline at end of file diff --git a/example/lib/main.dart b/example/lib/main.dart index 3ba3e93c..26590237 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -139,6 +139,12 @@ class _ChannelListPageState extends State { r'$in': [user.id] } }, + sortOptions: [ + SortOption( + 'created_at', + direction: SortOption.ASC, + ), + ], paginationParams: PaginationParams(limit: 20), onItemTap: (message) {}, ) diff --git a/example/lib/search_text_field.dart b/example/lib/search_text_field.dart index f46a48b0..e32bb88b 100644 --- a/example/lib/search_text_field.dart +++ b/example/lib/search_text_field.dart @@ -78,7 +78,7 @@ class SearchTextField extends StatelessWidget { Future.microtask( () => [ controller.clear(), - onChanged(''), + if (onChanged != null) onChanged(''), ], ); } diff --git a/example/pubspec.yaml b/example/pubspec.yaml index e0be8fc9..b66e085b 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -1,6 +1,6 @@ name: example description: A new Flutter project. -version: 1.0.78+80 +version: 1.0.80+82 environment: sdk: ">=2.2.2 <3.0.0" diff --git a/lib/src/channel_bottom_sheet.dart b/lib/src/channel_bottom_sheet.dart index 4272b0f3..48ce8887 100644 --- a/lib/src/channel_bottom_sheet.dart +++ b/lib/src/channel_bottom_sheet.dart @@ -30,10 +30,13 @@ class ChannelBottomSheet extends StatelessWidget { vertical: 2.0, ), child: Center( - child: ChannelName( + child: StreamChannel( + showLoading: false, channel: channel, - textStyle: - StreamChatTheme.of(context).channelPreviewTheme.title, + child: ChannelName( + textStyle: + StreamChatTheme.of(context).channelPreviewTheme.title, + ), ), ), ), diff --git a/lib/src/channel_name.dart b/lib/src/channel_name.dart index 337321ed..bf3eff22 100644 --- a/lib/src/channel_name.dart +++ b/lib/src/channel_name.dart @@ -12,60 +12,65 @@ class ChannelName extends StatelessWidget { /// Instantiate a new ChannelName const ChannelName({ Key key, - this.channel, this.textStyle, }) : super(key: key); - /// The channel to show the name of - final Channel channel; - /// The style of the text displayed final TextStyle textStyle; @override Widget build(BuildContext context) { final client = StreamChat.of(context); - final channel = this.channel ?? StreamChannel.of(context).channel; + final channel = StreamChannel.of(context).channel; + + return StreamBuilder>( + stream: channel.extraDataStream, + initialData: channel.extraData, + builder: (context, snapshot) { + return _buildName(snapshot.data, channel.state.members, client); + }, + ); + } + + Widget _buildName( + Map extraData, + List members, + StreamChatState client, + ) { return LayoutBuilder( builder: (context, constraints) { - return StreamBuilder>( - stream: channel.extraDataStream, - initialData: channel.extraData, - builder: (context, snapshot) { - String title; - if (snapshot.data['name'] == null) { - final otherMembers = channel.state.members - .where((member) => member.userId != client.user.id); - if (otherMembers.isNotEmpty) { - final maxWidth = constraints.maxWidth; - final maxChars = maxWidth / textStyle.fontSize; - int currentChars = 0; - final currentMembers = []; - otherMembers.forEach((element) { - final newLength = currentChars + element.user.name.length; - if (newLength < maxChars) { - currentChars = newLength; - currentMembers.add(element); - } - }); - - final exceedingMembers = - otherMembers.length - currentMembers.length; - title = - '${currentMembers.map((e) => e.user.name).join(', ')} ${exceedingMembers > 0 ? '+ $exceedingMembers' : ''}'; - } else { - title = channel.id; + String title; + if (extraData['name'] == null) { + final otherMembers = + members.where((member) => member.userId != client.user.id); + if (otherMembers.isNotEmpty) { + final maxWidth = constraints.maxWidth; + final maxChars = maxWidth / textStyle.fontSize; + var currentChars = 0; + final currentMembers = []; + otherMembers.forEach((element) { + final newLength = currentChars + element.user.name.length; + if (newLength < maxChars) { + currentChars = newLength; + currentMembers.add(element); } - } else { - title = snapshot.data['name']; - } + }); - return Text( - title, - style: textStyle, - overflow: TextOverflow.ellipsis, - ); - }, + final exceedingMembers = + otherMembers.length - currentMembers.length; + title = + '${currentMembers.map((e) => e.user.name).join(', ')} ${exceedingMembers > 0 ? '+ $exceedingMembers' : ''}'; + } else { + title = 'No title'; + } + } else { + title = extraData['name']; + } + + return Text( + title, + style: textStyle, + overflow: TextOverflow.ellipsis, ); }, ); diff --git a/lib/src/message_search_bloc.dart b/lib/src/message_search_bloc.dart index bff2d68e..0128bb22 100644 --- a/lib/src/message_search_bloc.dart +++ b/lib/src/message_search_bloc.dart @@ -36,12 +36,14 @@ class MessageSearchBloc extends StatefulWidget { class MessageSearchBlocState extends State with AutomaticKeepAliveClientMixin { /// The current messages list - List get messages => _messagesController.value; + List get messageResponses => _messageResponses.value; /// The current messages list as a stream - Stream> get messagesStream => _messagesController.stream; + Stream> get messagesStream => + _messageResponses.stream; - final BehaviorSubject> _messagesController = BehaviorSubject(); + final BehaviorSubject> _messageResponses = + BehaviorSubject(); final BehaviorSubject _queryMessagesLoadingController = BehaviorSubject.seeded(false); @@ -69,7 +71,7 @@ class MessageSearchBlocState extends State pagination.offset == null || pagination.offset == 0; - final oldMessages = List.from(messages ?? []); + final oldMessages = List.from(messageResponses ?? []); final messageResponse = await client.search( filter, @@ -79,10 +81,10 @@ class MessageSearchBlocState extends State ); if (clear) { - _messagesController.add(messageResponse.results); + _messageResponses.add(messageResponse.results); } else { final temp = oldMessages + messageResponse.results; - _messagesController.add(temp); + _messageResponses.add(temp); } _queryMessagesLoadingController.add(false); @@ -99,7 +101,7 @@ class MessageSearchBlocState extends State @override void dispose() { - _messagesController.close(); + _messageResponses.close(); _queryMessagesLoadingController.close(); super.dispose(); } diff --git a/lib/src/message_search_item.dart b/lib/src/message_search_item.dart index a89f2ee0..8857fcb8 100644 --- a/lib/src/message_search_item.dart +++ b/lib/src/message_search_item.dart @@ -13,13 +13,13 @@ class MessageSearchItem extends StatelessWidget { /// Instantiate a new MessageSearchItem const MessageSearchItem({ Key key, - @required this.message, + @required this.getMessageResponse, this.onTap, this.showOnlineStatus = true, }) : super(key: key); /// [Message] displayed - final Message message; + final GetMessageResponse getMessageResponse; /// Function called when tapping this widget final VoidCallback onTap; @@ -29,9 +29,12 @@ class MessageSearchItem extends StatelessWidget { @override Widget build(BuildContext context) { - final data = Message.fromJson(message.extraData['message']); - final user = data.user; - debugPrint(message.toJson().toString()); + final message = getMessageResponse.message; + final channel = getMessageResponse.channel; + final channelName = channel.extraData['name']; + print('channel.extraData: ${channel.extraData}'); + print('channelName: ${channelName}'); + final user = message.user; return ListTile( onTap: onTap, leading: UserAvatar( @@ -42,15 +45,34 @@ class MessageSearchItem extends StatelessWidget { width: 40, ), ), - title: Text( - user.name, - style: StreamChatTheme.of(context).channelPreviewTheme.title, + title: Row( + children: [ + Text( + user.name, + style: StreamChatTheme.of(context).channelPreviewTheme.title, + ), + if (channelName != null) + Text( + ' in ', + style: StreamChatTheme.of(context) + .channelPreviewTheme + .title + .copyWith( + fontWeight: FontWeight.normal, + ), + ), + if (channelName != null) + Text( + channelName, + style: StreamChatTheme.of(context).channelPreviewTheme.title, + ), + ], ), subtitle: Row( children: [ - Expanded(child: _buildSubtitle(context, data)), + Expanded(child: _buildSubtitle(context, message)), SizedBox(width: 16), - _buildDate(context, data), + _buildDate(context, message), ], ), ); diff --git a/lib/src/message_search_list_view.dart b/lib/src/message_search_list_view.dart index d5a282a4..8b346570 100644 --- a/lib/src/message_search_list_view.dart +++ b/lib/src/message_search_list_view.dart @@ -8,10 +8,11 @@ import 'lazy_load_scroll_view.dart'; import 'message_search_bloc.dart'; /// Callback called when tapping on a user -typedef MessageSearchItemTapCallback = void Function(Message); +typedef MessageSearchItemTapCallback = void Function(GetMessageResponse); /// Builder used to create a custom [ListUserItem] from a [User] -typedef MessageSearchItemBuilder = Widget Function(BuildContext, Message); +typedef MessageSearchItemBuilder = Widget Function( + BuildContext, GetMessageResponse); /// /// It shows the list of searched messages. @@ -127,13 +128,14 @@ class _MessageSearchListViewState extends State { ); } - Widget _listItemBuilder(BuildContext context, Message message) { + Widget _listItemBuilder( + BuildContext context, GetMessageResponse getMessageResponse) { if (widget.itemBuilder != null) { - return widget.itemBuilder(context, message); + return widget.itemBuilder(context, getMessageResponse); } return MessageSearchItem( - message: message, - onTap: () => widget.onItemTap(message), + getMessageResponse: getMessageResponse, + onTap: () => widget.onItemTap(getMessageResponse), ); } @@ -165,7 +167,7 @@ class _MessageSearchListViewState extends State { } Widget _buildListView(MessageSearchBlocState messageSearchBloc) { - return StreamBuilder>( + return StreamBuilder>( stream: messageSearchBloc.messagesStream, builder: (context, snapshot) { if (snapshot.hasError) { @@ -276,7 +278,7 @@ class _MessageSearchListViewState extends State { filter: widget.filters, sort: widget.sortOptions, pagination: widget.paginationParams.copyWith( - offset: messageSearchBloc.messages?.length ?? 0, + offset: messageSearchBloc.messageResponses?.length ?? 0, ), query: widget.messageQuery, ), diff --git a/pubspec.yaml b/pubspec.yaml index 5ecb60de..eee90a9c 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -28,7 +28,7 @@ dependencies: file_picker: ^2.0.12 image_picker: ^0.6.7+2 flutter_keyboard_visibility: ^3.3.0 - stream_chat: ^0.2.13+1 + stream_chat: ^0.2.14 mime: ^0.9.6+3 video_compress: ^2.1.1 visibility_detector: ^0.1.5 From 3dd994d207107629aa12eb351fe328ef07ecc4eb Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Fri, 27 Nov 2020 12:54:29 +0100 Subject: [PATCH 0519/1140] fix name --- lib/src/message_search_item.dart | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/lib/src/message_search_item.dart b/lib/src/message_search_item.dart index 8857fcb8..9c7ea891 100644 --- a/lib/src/message_search_item.dart +++ b/lib/src/message_search_item.dart @@ -32,8 +32,6 @@ class MessageSearchItem extends StatelessWidget { final message = getMessageResponse.message; final channel = getMessageResponse.channel; final channelName = channel.extraData['name']; - print('channel.extraData: ${channel.extraData}'); - print('channelName: ${channelName}'); final user = message.user; return ListTile( onTap: onTap, @@ -48,7 +46,7 @@ class MessageSearchItem extends StatelessWidget { title: Row( children: [ Text( - user.name, + user.id == StreamChat.of(context).user.id ? 'You' : user.name, style: StreamChatTheme.of(context).channelPreviewTheme.title, ), if (channelName != null) From fa5b4ebab89742f38c212da362419c13134a6076 Mon Sep 17 00:00:00 2001 From: xsahil03x Date: Fri, 27 Nov 2020 17:32:08 +0530 Subject: [PATCH 0520/1140] minor changes Signed-off-by: xsahil03x --- lib/src/message_search_item.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/src/message_search_item.dart b/lib/src/message_search_item.dart index 9c7ea891..3e786b9a 100644 --- a/lib/src/message_search_item.dart +++ b/lib/src/message_search_item.dart @@ -49,7 +49,7 @@ class MessageSearchItem extends StatelessWidget { user.id == StreamChat.of(context).user.id ? 'You' : user.name, style: StreamChatTheme.of(context).channelPreviewTheme.title, ), - if (channelName != null) + if (channelName != null) ...[ Text( ' in ', style: StreamChatTheme.of(context) @@ -59,11 +59,11 @@ class MessageSearchItem extends StatelessWidget { fontWeight: FontWeight.normal, ), ), - if (channelName != null) Text( channelName, style: StreamChatTheme.of(context).channelPreviewTheme.title, ), + ], ], ), subtitle: Row( From c137ffcc6dfd18d6422108b6bbbef8c6a6b90794 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Fri, 27 Nov 2020 19:03:48 +0530 Subject: [PATCH 0521/1140] Add bottomNavigationBar Signed-off-by: Sahil Kumar --- example/lib/choose_user_page.dart | 6 +- example/lib/group_chat_details_screen.dart | 2 +- example/lib/main.dart | 254 +++++++++++++-------- example/lib/new_chat_screen.dart | 2 +- example/lib/routes/app_routes.dart | 6 +- example/lib/routes/routes.dart | 2 +- lib/stream_chat_flutter.dart | 1 + 7 files changed, 171 insertions(+), 102 deletions(-) diff --git a/example/lib/choose_user_page.dart b/example/lib/choose_user_page.dart index 844a8c77..80b76f92 100644 --- a/example/lib/choose_user_page.dart +++ b/example/lib/choose_user_page.dart @@ -155,11 +155,9 @@ class ChooseUserPage extends StatelessWidget { if (!kIsWeb) { initNotifications(client); } - Navigator.pushNamedAndRemoveUntil( + Navigator.pushReplacementNamed( context, - Routes.CHANNEL_LIST, - ModalRoute.withName(Routes.CHANNEL_LIST), - arguments: client, + Routes.HOME, ); }, leading: UserAvatar( diff --git a/example/lib/group_chat_details_screen.dart b/example/lib/group_chat_details_screen.dart index 88de33a9..d759a82e 100644 --- a/example/lib/group_chat_details_screen.dart +++ b/example/lib/group_chat_details_screen.dart @@ -132,7 +132,7 @@ class _GroupChatDetailsScreenState extends State { Navigator.pushNamedAndRemoveUntil( context, Routes.CHANNEL_PAGE, - ModalRoute.withName(Routes.CHANNEL_LIST), + ModalRoute.withName(Routes.HOME), arguments: channel, ); }, diff --git a/example/lib/main.dart b/example/lib/main.dart index 26590237..fa62878d 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -60,51 +60,53 @@ class MyApp extends StatelessWidget { //TODO change to system once dark theme is implemented themeMode: ThemeMode.light, onGenerateRoute: AppRoutes.generateRoute, - initialRoute: client.state.user == null - ? Routes.CHOOSE_USER - : Routes.CHANNEL_LIST, + initialRoute: + client.state.user == null ? Routes.CHOOSE_USER : Routes.HOME, ), ); } } -class ChannelListPage extends StatefulWidget { +class HomePage extends StatefulWidget { @override - _ChannelListPageState createState() => _ChannelListPageState(); + _HomePageState createState() => _HomePageState(); } -class _ChannelListPageState extends State { - TextEditingController _controller; +class _HomePageState extends State { + int _currentIndex = 0; - String _channelQuery = ''; + bool _isSelected(int index) => _currentIndex == index; - bool _isSearchActive = false; - - Timer _debounce; - - void _channelQueryListener() { - if (_debounce?.isActive ?? false) _debounce.cancel(); - _debounce = Timer(const Duration(milliseconds: 350), () { - if (mounted) { - setState(() { - _channelQuery = _controller.text; - _isSearchActive = _channelQuery.isNotEmpty; - }); - } - }); - } - - @override - void initState() { - super.initState(); - _controller = TextEditingController()..addListener(_channelQueryListener); - } - - @override - void dispose() { - _controller?.removeListener(_channelQueryListener); - _controller?.dispose(); - super.dispose(); + List get _navBarItems { + return [ + BottomNavigationBarItem( + icon: Stack( + overflow: Overflow.visible, + children: [ + StreamSvgIcon.message( + color: _isSelected(0) ? Colors.black : Colors.grey, + ), + Positioned( + top: -3, + right: -16, + child: UnreadIndicator(), + ), + ], + ), + label: 'Chats', + ), + BottomNavigationBarItem( + icon: Stack( + overflow: Overflow.visible, + children: [ + StreamSvgIcon.mentions( + color: _isSelected(1) ? Colors.black : Colors.grey, + ), + ], + ), + label: 'Mentions', + ), + ]; } @override @@ -118,63 +120,22 @@ class _ChannelListPageState extends State { ), drawer: _buildDrawer(context, user), drawerEdgeDragWidth: 50, - body: ChannelsBloc( - child: MessageSearchBloc( - child: Column( - children: [ - SearchTextField( - controller: _controller, - ), - Expanded( - child: AnimatedSwitcher( - duration: const Duration(milliseconds: 350), - child: GestureDetector( - behavior: HitTestBehavior.opaque, - onPanDown: (_) => FocusScope.of(context).unfocus(), - child: _isSearchActive - ? MessageSearchListView( - messageQuery: _channelQuery, - filters: { - 'members': { - r'$in': [user.id] - } - }, - sortOptions: [ - SortOption( - 'created_at', - direction: SortOption.ASC, - ), - ], - paginationParams: PaginationParams(limit: 20), - onItemTap: (message) {}, - ) - : ChannelListView( - onStartChatPressed: () { - Navigator.pushNamed(context, Routes.NEW_CHAT); - }, - swipeToAction: true, - filter: { - 'members': { - r'$in': [user.id], - }, - 'draft': { - r'$ne': true, - }, - }, - options: { - 'presence': true, - }, - pagination: PaginationParams( - limit: 20, - ), - channelWidget: ChannelPage(), - ), - ), - ), - ), - ], - ), - ), + bottomNavigationBar: BottomNavigationBar( + currentIndex: _currentIndex, + items: _navBarItems, + type: BottomNavigationBarType.fixed, + selectedItemColor: Colors.black, + unselectedItemColor: Colors.grey, + onTap: (index) { + setState(() => _currentIndex = index); + }, + ), + body: IndexedStack( + index: _currentIndex, + children: [ + ChannelListPage(), + UserMentionPage(), + ], ), ); } @@ -282,6 +243,115 @@ class _ChannelListPageState extends State { } } +class UserMentionPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Center( + child: Text('On Pause Right Now!'), + ); + } +} + +class ChannelListPage extends StatefulWidget { + @override + _ChannelListPageState createState() => _ChannelListPageState(); +} + +class _ChannelListPageState extends State { + TextEditingController _controller; + + String _channelQuery = ''; + + bool _isSearchActive = false; + + Timer _debounce; + + void _channelQueryListener() { + if (_debounce?.isActive ?? false) _debounce.cancel(); + _debounce = Timer(const Duration(milliseconds: 350), () { + if (mounted) { + setState(() { + _channelQuery = _controller.text; + _isSearchActive = _channelQuery.isNotEmpty; + }); + } + }); + } + + @override + void initState() { + super.initState(); + _controller = TextEditingController()..addListener(_channelQueryListener); + } + + @override + void dispose() { + _controller?.removeListener(_channelQueryListener); + _controller?.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + final user = StreamChat.of(context).user; + return ChannelsBloc( + child: MessageSearchBloc( + child: Column( + children: [ + SearchTextField( + controller: _controller, + ), + Expanded( + child: AnimatedSwitcher( + duration: const Duration(milliseconds: 350), + child: GestureDetector( + behavior: HitTestBehavior.opaque, + onPanDown: (_) => FocusScope.of(context).unfocus(), + child: _isSearchActive + ? MessageSearchListView( + messageQuery: _channelQuery, + filters: { + 'members': { + r'$in': [user.id] + } + }, + sortOptions: [ + SortOption( + 'created_at', + direction: SortOption.ASC, + ), + ], + paginationParams: PaginationParams(limit: 20), + onItemTap: (message) {}, + ) + : ChannelListView( + onStartChatPressed: () { + Navigator.pushNamed(context, Routes.NEW_CHAT); + }, + swipeToAction: true, + filter: { + 'members': { + r'$in': [user.id], + }, + }, + options: { + 'presence': true, + }, + pagination: PaginationParams( + limit: 20, + ), + channelWidget: ChannelPage(), + ), + ), + ), + ), + ], + ), + ), + ); + } +} + class ChannelQuerySearchResultPage extends StatelessWidget { final Stream> searchResultStream; diff --git a/example/lib/new_chat_screen.dart b/example/lib/new_chat_screen.dart index 364c8b7e..5fbfbf07 100644 --- a/example/lib/new_chat_screen.dart +++ b/example/lib/new_chat_screen.dart @@ -338,7 +338,7 @@ class _NewChatScreenState extends State { Navigator.pushNamedAndRemoveUntil( context, Routes.CHANNEL_PAGE, - ModalRoute.withName(Routes.CHANNEL_LIST), + ModalRoute.withName(Routes.HOME), arguments: channel, ); } diff --git a/example/lib/routes/app_routes.dart b/example/lib/routes/app_routes.dart index 19352319..6b0529e1 100644 --- a/example/lib/routes/app_routes.dart +++ b/example/lib/routes/app_routes.dart @@ -13,11 +13,11 @@ class AppRoutes { static Route generateRoute(RouteSettings settings) { final args = settings.arguments; switch (settings.name) { - case Routes.CHANNEL_LIST: + case Routes.HOME: return MaterialPageRoute( - settings: const RouteSettings(name: Routes.CHANNEL_LIST), + settings: const RouteSettings(name: Routes.HOME), builder: (_) { - return ChannelListPage(); + return HomePage(); }); case Routes.CHOOSE_USER: return MaterialPageRoute( diff --git a/example/lib/routes/routes.dart b/example/lib/routes/routes.dart index f4ace9a4..0e0b1e57 100644 --- a/example/lib/routes/routes.dart +++ b/example/lib/routes/routes.dart @@ -1,6 +1,6 @@ /// Define all the route names here class Routes { - static const String CHANNEL_LIST = '/channel_list'; + static const String HOME = '/home'; static const String CHOOSE_USER = '/choose_user'; static const String ADVANCED_OPTIONS = '/advance_options'; static const String CHANNEL_PAGE = '/channel_page'; diff --git a/lib/stream_chat_flutter.dart b/lib/stream_chat_flutter.dart index 35239cbd..1cbe21e4 100644 --- a/lib/stream_chat_flutter.dart +++ b/lib/stream_chat_flutter.dart @@ -41,3 +41,4 @@ export 'src/video_attachment.dart'; export 'src/message_search_bloc.dart'; export 'src/message_search_item.dart'; export 'src/message_search_list_view.dart'; +export 'src/unread_indicator.dart'; From 1c2f916070dab4c3e24d4f938dfdc46acb43d094 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Fri, 27 Nov 2020 15:08:29 +0100 Subject: [PATCH 0522/1140] fix heic pics --- example/ios/Podfile.lock | 10 ++----- example/pubspec.yaml | 2 +- lib/src/media_list_view.dart | 14 +++++++-- lib/src/message_input.dart | 57 +++++++++++++----------------------- pubspec.yaml | 1 - 5 files changed, 35 insertions(+), 49 deletions(-) diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock index 707e9fcb..7552423f 100644 --- a/example/ios/Podfile.lock +++ b/example/ios/Podfile.lock @@ -38,7 +38,7 @@ PODS: - Firebase/Messaging (6.33.0): - Firebase/CoreOnly - FirebaseMessaging (~> 4.7.0) - - firebase_core (0.5.2): + - firebase_core (0.5.2-1): - Firebase/CoreOnly (~> 6.33.0) - Flutter - firebase_messaging (7.0.3): @@ -115,8 +115,6 @@ PODS: - nanopb/encode (1.30906.0) - path_provider (0.0.1): - Flutter - - "permission_handler (5.0.1+1)": - - Flutter - photo_manager (0.0.1): - Flutter - PromisesObjC (1.2.11) @@ -172,7 +170,6 @@ DEPENDENCIES: - flutter_secure_storage (from `.symlinks/plugins/flutter_secure_storage/ios`) - image_picker (from `.symlinks/plugins/image_picker/ios`) - path_provider (from `.symlinks/plugins/path_provider/ios`) - - permission_handler (from `.symlinks/plugins/permission_handler/ios`) - photo_manager (from `.symlinks/plugins/photo_manager/ios`) - shared_preferences (from `.symlinks/plugins/shared_preferences/ios`) - sqflite (from `.symlinks/plugins/sqflite/ios`) @@ -228,8 +225,6 @@ EXTERNAL SOURCES: :path: ".symlinks/plugins/image_picker/ios" path_provider: :path: ".symlinks/plugins/path_provider/ios" - permission_handler: - :path: ".symlinks/plugins/permission_handler/ios" photo_manager: :path: ".symlinks/plugins/photo_manager/ios" shared_preferences: @@ -252,7 +247,7 @@ SPEC CHECKSUMS: DKPhotoGallery: fdfad5125a9fdda9cc57df834d49df790dbb4179 file_picker: 3e6c3790de664ccf9b882732d9db5eaf6b8d4eb1 Firebase: 8db6f2d1b2c5e2984efba4949a145875a8f65fe5 - firebase_core: 350ba329d1641211bc6183a3236893cafdacfea7 + firebase_core: 7423d688a1c6f2f2d859d64ae26991be39989781 firebase_messaging: 0aea2cd5885b65e19ede58ee3507f485c992cc75 FirebaseCore: d889d9e12535b7f36ac8bfbf1713a0836a3012cd FirebaseCoreDiagnostics: 770ac5958e1372ce67959ae4b4f31d8e127c3ac1 @@ -271,7 +266,6 @@ SPEC CHECKSUMS: image_picker: 9c3312491f862b28d21ecd8fdf0ee14e601b3f09 nanopb: 59317e09cf1f1a0af72f12af412d54edf52603fc path_provider: abfe2b5c733d04e238b0d8691db0cfd63a27a93c - permission_handler: eac8e15b4a1a3fba55b761d19f3f4e6b005d15b6 photo_manager: f7c619c2cc8c2adb8d85c63363babac477de9c67 PromisesObjC: 8c196f5a328c2cba3e74624585467a557dcb482f Protobuf: 3dac39b34a08151c6d949560efe3f86134a3f748 diff --git a/example/pubspec.yaml b/example/pubspec.yaml index b66e085b..3291c980 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -1,6 +1,6 @@ name: example description: A new Flutter project. -version: 1.0.80+82 +version: 1.0.82+84 environment: sdk: ">=2.2.2 <3.0.0" diff --git a/lib/src/media_list_view.dart b/lib/src/media_list_view.dart index 80686d62..d95c2300 100644 --- a/lib/src/media_list_view.dart +++ b/lib/src/media_list_view.dart @@ -37,7 +37,6 @@ class _MediaListViewState extends State { gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: 3, ), - cacheExtent: 1000, itemBuilder: ( context, position, @@ -88,7 +87,7 @@ class _MediaListViewState extends State { ), ), ), - if (media.type == AssetType.video) + if (media.type == AssetType.video) ...[ Positioned( left: 8, bottom: 10, @@ -97,6 +96,17 @@ class _MediaListViewState extends State { package: 'stream_chat_flutter', ), ), + Positioned( + right: 4, + bottom: 10, + child: Text( + '${media.videoDuration.inMinutes}:${media.videoDuration.inSeconds.toString().padLeft(2, '0')}', + style: TextStyle( + color: Colors.white, + ), + ), + ), + ] ], ), onTap: () { diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 8def16da..d3522a91 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -11,7 +11,6 @@ import 'package:flutter_svg/flutter_svg.dart'; import 'package:http_parser/http_parser.dart' as httpParser; import 'package:image_picker/image_picker.dart'; import 'package:mime/mime.dart'; -import 'package:permission_handler/permission_handler.dart'; import 'package:photo_manager/photo_manager.dart'; import 'package:stream_chat/stream_chat.dart'; import 'package:stream_chat_flutter/src/compress_video_service.dart'; @@ -22,6 +21,7 @@ import 'package:stream_chat_flutter/src/stream_svg_icon.dart'; import 'package:stream_chat_flutter/src/user_avatar.dart'; import 'package:substring_highlight/substring_highlight.dart'; import 'package:video_compress/video_compress.dart'; +import 'package:photo_manager/photo_manager.dart'; import '../stream_chat_flutter.dart'; import 'stream_channel.dart'; @@ -772,10 +772,8 @@ class MessageInputState extends State { Widget _buildPickerSection() { switch (_filePickerIndex) { case 0: - return FutureBuilder( - future: Platform.isAndroid - ? Permission.storage.status - : Permission.photos.status, + return FutureBuilder( + future: PhotoManager.requestPermission(), builder: (context, snapshot) { if (!snapshot.hasData) { return Center( @@ -783,10 +781,10 @@ class MessageInputState extends State { ); } - if (snapshot.data.isGranted) { + if (snapshot.data) { return MediaListView( selectedIds: _attachments.map((e) => e.id).toList(), - onSelect: (media) { + onSelect: (media) async { if (!_attachments .any((element) => element.id == media.id)) { _addAttachment(media); @@ -802,22 +800,7 @@ class MessageInputState extends State { return InkWell( onTap: () async { - var status = await (Platform.isAndroid - ? Permission.storage.status - : Permission.photos.status); - if (status.isPermanentlyDenied || status.isDenied) { - if (await openAppSettings()) { - setState(() {}); - } - } else { - status = await (Platform.isAndroid - ? Permission.storage - : Permission.photos) - .request(); - if (status.isGranted) { - setState(() {}); - } - } + PhotoManager.openSetting(); }, child: Container( color: Color(0xFFF2F2F2), @@ -858,7 +841,7 @@ class MessageInputState extends State { setState(() { _attachments.add(attachment); }); - final mediaFile = await medium.file; + final mediaFile = await medium.originFile; var file = PlatformFile( path: mediaFile.path, @@ -1326,7 +1309,10 @@ class MessageInputState extends State { future: VideoCompress.getFileThumbnail(attachment.file.path), builder: (context, snapshot) { if (!snapshot.hasData) { - return Offstage(); + return Image.asset( + 'images/placeholder.png', + package: 'stream_chat_flutter', + ); } return Image.file( @@ -1405,15 +1391,6 @@ class MessageInputState extends State { _filePickerSize = _kMinMediaPickerSize; }); } else { - final status = await (Platform.isAndroid - ? Permission.storage.status - : Permission.photos.status); - if (status.isUndetermined) { - await (Platform.isAndroid - ? Permission.storage - : Permission.photos) - .request(); - } showAttachmentModal(); } }, @@ -1646,14 +1623,20 @@ class MessageInputState extends State { Future _uploadImage(PlatformFile file, Channel channel) async { final filename = file.name ?? file.path?.split('/')?.last; + httpParser.MediaType mimeType; + if (filename != null) { + if (filename.toLowerCase().endsWith('heic')) { + mimeType = httpParser.MediaType.parse('image/heic'); + } else { + mimeType = httpParser.MediaType.parse(lookupMimeType(filename)); + } + } final bytes = file.bytes; final res = await channel.sendImage( MultipartFile.fromBytes( bytes, filename: filename, - contentType: filename != null - ? httpParser.MediaType.parse(lookupMimeType(filename)) - : null, + contentType: mimeType, ), ); return res.file; diff --git a/pubspec.yaml b/pubspec.yaml index eee90a9c..75195a30 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -39,7 +39,6 @@ dependencies: carousel_slider: ^2.2.1 clipboard: ^0.1.2+8 photo_manager: ^0.5.8 - permission_handler: ^5.0.1+1 transparent_image: ^1.0.0 ezanimation: ^0.4.1 synchronized: ^2.2.0+2 From 9fb2dd5f3f310f441e9b42133650b339280012c7 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Fri, 27 Nov 2020 16:06:46 +0100 Subject: [PATCH 0523/1140] fix video duration --- lib/src/media_list_view.dart | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/lib/src/media_list_view.dart b/lib/src/media_list_view.dart index d95c2300..507238da 100644 --- a/lib/src/media_list_view.dart +++ b/lib/src/media_list_view.dart @@ -6,6 +6,17 @@ import 'package:stream_chat_flutter/src/lazy_load_scroll_view.dart'; import 'package:stream_chat_flutter/src/stream_svg_icon.dart'; import 'dart:ui' as ui; +extension on Duration { + String format() { + final s = '$this'.split('.')[0].padLeft(8, '0'); + if (s.startsWith('00:')) { + return s.replaceFirst('00:', ''); + } + + return s; + } +} + class MediaListView extends StatefulWidget { final List selectedIds; final void Function(AssetEntity media) onSelect; @@ -100,7 +111,7 @@ class _MediaListViewState extends State { right: 4, bottom: 10, child: Text( - '${media.videoDuration.inMinutes}:${media.videoDuration.inSeconds.toString().padLeft(2, '0')}', + media.videoDuration.format(), style: TextStyle( color: Colors.white, ), From c4647761fe351ecca5018887669782f985b64554 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Fri, 27 Nov 2020 16:30:27 +0100 Subject: [PATCH 0524/1140] fix channelinfo --- lib/src/channel_info.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/channel_info.dart b/lib/src/channel_info.dart index 208fa588..eda58f43 100644 --- a/lib/src/channel_info.dart +++ b/lib/src/channel_info.dart @@ -80,7 +80,7 @@ class ChannelInfo extends StatelessWidget { } if (!showTypingIndicator) { - return alternativeWidget; + return alternativeWidget ?? Offstage(); } return TypingIndicator( From 3d1ea5d5881e4768385ef973bf73a5f0f0586aa3 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Mon, 30 Nov 2020 14:23:57 +0530 Subject: [PATCH 0525/1140] feat: Switched to svgicon --- lib/src/image_actions_modal.dart | 44 ++++++++++++------- lib/src/image_footer.dart | 37 ++++++---------- lib/src/image_header.dart | 9 ++-- lib/src/stream_svg_icon.dart | 72 ++++++++++++++++++++++++++++++++ lib/svgs/Icon_menu_point_v.svg | 5 +++ lib/svgs/Icon_save.svg | 4 ++ lib/svgs/Icon_send_message.svg | 3 ++ 7 files changed, 129 insertions(+), 45 deletions(-) create mode 100644 lib/svgs/Icon_menu_point_v.svg create mode 100644 lib/svgs/Icon_save.svg create mode 100644 lib/svgs/Icon_send_message.svg diff --git a/lib/src/image_actions_modal.dart b/lib/src/image_actions_modal.dart index 19f27055..7e50a4f7 100644 --- a/lib/src/image_actions_modal.dart +++ b/lib/src/image_actions_modal.dart @@ -83,8 +83,7 @@ class ImageActionsModal extends StatelessWidget { ], ), IconButton( - icon: Icon( - StreamIcons.close, + icon: StreamSvgIcon.close( size: 24.0, color: Colors.white, ), @@ -111,17 +110,31 @@ class ImageActionsModal extends StatelessWidget { children: ListTile.divideTiles( context: context, tiles: [ - _buildButton(context, 'Reply', - StreamIcons.curve_line_down_left, () {}), - _buildButton(context, 'Show in Chat', StreamIcons.eye, - () { + _buildButton( + context, + 'Reply', + StreamSvgIcon.Icon_curve_line_left_up( + size: 24.0, + color: Colors.black.withOpacity(0.5), + ), + () {}), + _buildButton( + context, + 'Show in Chat', + StreamSvgIcon.eye( + size: 24.0, + color: Colors.black, + ), () { Navigator.pop(context); Navigator.pop(context); }), _buildButton( context, 'Save ${urls[currentIndex].type == 'video' ? 'Video' : 'Image'}', - StreamIcons.save_1, () async { + StreamSvgIcon.Icon_save( + size: 24.0, + color: Colors.black.withOpacity(0.5), + ), () async { var url = urls[currentIndex].imageUrl ?? urls[currentIndex].assetUrl ?? urls[currentIndex].thumbUrl; @@ -135,8 +148,13 @@ class ImageActionsModal extends StatelessWidget { } }), if (StreamChat.of(context).user.id == message.user.id) - _buildButton(context, 'Delete', StreamIcons.delete, - () { + _buildButton( + context, + 'Delete', + StreamSvgIcon.delete( + size: 24.0, + color: Colors.black, + ), () { Navigator.pop(context); Navigator.pop(context); StreamChat.of(context).client.deleteMessage( @@ -157,7 +175,7 @@ class ImageActionsModal extends StatelessWidget { } Widget _buildButton( - context, String title, IconData iconData, VoidCallback onTap, + context, String title, StreamSvgIcon icon, VoidCallback onTap, {Color color}) { var titleStyle = TextStyle( fontSize: 14.5, @@ -174,11 +192,7 @@ class ImageActionsModal extends StatelessWidget { style: color == null ? titleStyle : titleStyle.copyWith(color: color), ), - leading: Icon( - iconData, - color: color ?? StreamChatTheme.of(context).primaryIconTheme.color, - size: 24.0, - ), + leading: icon, ), ), ); diff --git a/lib/src/image_footer.dart b/lib/src/image_footer.dart index 8d2bf30f..5461e139 100644 --- a/lib/src/image_footer.dart +++ b/lib/src/image_footer.dart @@ -12,7 +12,6 @@ import 'package:path_provider/path_provider.dart'; import 'package:stream_chat/stream_chat.dart'; import 'package:stream_chat_flutter/src/stream_chat.dart'; import 'package:stream_chat_flutter/src/stream_chat_theme.dart'; -import 'package:stream_chat_flutter/src/stream_icons.dart'; import 'package:stream_chat_flutter/src/user_avatar.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; @@ -81,8 +80,7 @@ class _ImageFooterState extends State { mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ IconButton( - icon: Icon( - StreamIcons.share_1, + icon: StreamSvgIcon.icon_SHARE( size: 24.0, color: Colors.black, ), @@ -111,8 +109,7 @@ class _ImageFooterState extends State { ), ), IconButton( - icon: Icon( - StreamIcons.grid, + icon: StreamSvgIcon.Icon_grid( color: Colors.black, ), onPressed: () { @@ -160,8 +157,7 @@ class _ImageFooterState extends State { Align( alignment: Alignment.centerRight, child: IconButton( - icon: Icon( - StreamIcons.close, + icon: StreamSvgIcon.close( color: Colors.black, ), onPressed: () { @@ -446,13 +442,11 @@ class _ImageFooterState extends State { prefixIconConstraints: BoxConstraints.tight(Size(38.0, 38.0)), prefixIcon: Transform.scale( - scale: 1.2, - alignment: Alignment.center, - child: Icon( - StreamIcons.search, - color: Colors.black, - ), - ), + scale: 1.2, + alignment: Alignment.center, + child: StreamSvgIcon.search( + color: Colors.black, + )), hintText: 'Search', border: OutlineInputBorder( borderRadius: BorderRadius.circular(32.0), @@ -472,8 +466,7 @@ class _ImageFooterState extends State { width: 8.0, ), IconButton( - icon: Icon( - StreamIcons.close_circle, + icon: StreamSvgIcon.close_small( color: Colors.black.withOpacity(0.5), ), onPressed: () { @@ -494,8 +487,7 @@ class _ImageFooterState extends State { Padding( padding: const EdgeInsets.symmetric(horizontal: 6.0), child: IconButton( - icon: Icon( - StreamIcons.search, + icon: StreamSvgIcon.search( color: Colors.black, ), iconSize: 24.0, @@ -520,8 +512,7 @@ class _ImageFooterState extends State { Padding( padding: const EdgeInsets.symmetric(horizontal: 6.0), child: IconButton( - icon: Icon( - StreamIcons.share, + icon: StreamSvgIcon.search( color: Colors.black, ), iconSize: 24.0, @@ -612,8 +603,7 @@ class _ImageFooterState extends State { }, child: Transform.rotate( angle: -pi / 2, - child: Icon( - StreamIcons.send_message, + child: StreamSvgIcon.Icon_send_message( color: StreamChatTheme.of(context).accentColor, ), ), @@ -630,8 +620,7 @@ class _ImageFooterState extends State { child: Center( child: InkWell( onTap: () {}, - child: Icon( - StreamIcons.send_message, + child: StreamSvgIcon.Icon_send_message( color: Colors.grey, ), )), diff --git a/lib/src/image_header.dart b/lib/src/image_header.dart index 512d8b14..62c3f8ec 100644 --- a/lib/src/image_header.dart +++ b/lib/src/image_header.dart @@ -1,7 +1,7 @@ import 'package:flutter/material.dart'; import 'package:stream_chat/stream_chat.dart'; import 'package:stream_chat_flutter/src/stream_chat_theme.dart'; -import 'package:stream_chat_flutter/src/stream_icons.dart'; +import 'package:stream_chat_flutter/src/stream_svg_icon.dart'; import 'image_actions_modal.dart'; import 'stream_channel.dart'; @@ -49,8 +49,7 @@ class ImageHeader extends StatelessWidget implements PreferredSizeWidget { elevation: 1, leading: showBackButton ? IconButton( - icon: Icon( - StreamIcons.close, + icon: StreamSvgIcon.close( color: Colors.black, size: 24.0, ), @@ -61,10 +60,8 @@ class ImageHeader extends StatelessWidget implements PreferredSizeWidget { StreamChatTheme.of(context).channelTheme.channelHeaderTheme.color, actions: [ IconButton( - icon: Icon( - StreamIcons.menu_point_v, + icon: StreamSvgIcon.Icon_menu_point_v( color: Colors.black, - size: 24.0, ), onPressed: () { _showMessageActionModalBottomSheet(context); diff --git a/lib/src/stream_svg_icon.dart b/lib/src/stream_svg_icon.dart index 9a87ce9d..87d21c14 100644 --- a/lib/src/stream_svg_icon.dart +++ b/lib/src/stream_svg_icon.dart @@ -397,4 +397,76 @@ class StreamSvgIcon extends StatelessWidget { height: size, ); } + + factory StreamSvgIcon.Icon_curve_line_left_up({ + double size, + Color color, + }) { + return StreamSvgIcon( + assetName: 'Icon_curve_line_left_up.svg', + color: color, + width: size, + height: size, + ); + } + + factory StreamSvgIcon.icon_SHARE({ + double size, + Color color, + }) { + return StreamSvgIcon( + assetName: 'icon_SHARE.svg', + color: color, + width: size, + height: size, + ); + } + + factory StreamSvgIcon.Icon_grid({ + double size, + Color color, + }) { + return StreamSvgIcon( + assetName: 'Icon_grid.svg', + color: color, + width: size, + height: size, + ); + } + + factory StreamSvgIcon.Icon_send_message({ + double size, + Color color, + }) { + return StreamSvgIcon( + assetName: 'Icon_send_message.svg', + color: color, + width: size, + height: size, + ); + } + + factory StreamSvgIcon.Icon_menu_point_v({ + double size, + Color color, + }) { + return StreamSvgIcon( + assetName: 'Icon_menu_point_v.svg', + color: color, + width: size, + height: size, + ); + } + + factory StreamSvgIcon.Icon_save({ + double size, + Color color, + }) { + return StreamSvgIcon( + assetName: 'Icon_save.svg', + color: color, + width: size, + height: size, + ); + } } diff --git a/lib/svgs/Icon_menu_point_v.svg b/lib/svgs/Icon_menu_point_v.svg new file mode 100644 index 00000000..f7b61163 --- /dev/null +++ b/lib/svgs/Icon_menu_point_v.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/lib/svgs/Icon_save.svg b/lib/svgs/Icon_save.svg new file mode 100644 index 00000000..14bedc6f --- /dev/null +++ b/lib/svgs/Icon_save.svg @@ -0,0 +1,4 @@ + + + + diff --git a/lib/svgs/Icon_send_message.svg b/lib/svgs/Icon_send_message.svg new file mode 100644 index 00000000..0d504a40 --- /dev/null +++ b/lib/svgs/Icon_send_message.svg @@ -0,0 +1,3 @@ + + + From c0d7571fbf9a912eea8d826d91362c3aacc6111f Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Mon, 30 Nov 2020 09:55:23 +0100 Subject: [PATCH 0526/1140] fix choose user navigation --- example/lib/choose_user_page.dart | 3 ++- example/pubspec.yaml | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/example/lib/choose_user_page.dart b/example/lib/choose_user_page.dart index 80b76f92..c728a193 100644 --- a/example/lib/choose_user_page.dart +++ b/example/lib/choose_user_page.dart @@ -155,9 +155,10 @@ class ChooseUserPage extends StatelessWidget { if (!kIsWeb) { initNotifications(client); } - Navigator.pushReplacementNamed( + Navigator.pushNamedAndRemoveUntil( context, Routes.HOME, + ModalRoute.withName(Routes.HOME), ); }, leading: UserAvatar( diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 3291c980..80a852d8 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -1,6 +1,6 @@ name: example description: A new Flutter project. -version: 1.0.82+84 +version: 1.0.83+85 environment: sdk: ">=2.2.2 <3.0.0" From 832e31cbc67be91f92beda3588d191a558199696 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Mon, 30 Nov 2020 15:56:25 +0530 Subject: [PATCH 0527/1140] feat: Switched to UserListView --- lib/src/image_footer.dart | 326 ++++++++++++----------------------- lib/src/stream_svg_icon.dart | 12 ++ 2 files changed, 124 insertions(+), 214 deletions(-) diff --git a/lib/src/image_footer.dart b/lib/src/image_footer.dart index 5461e139..1605206c 100644 --- a/lib/src/image_footer.dart +++ b/lib/src/image_footer.dart @@ -60,7 +60,7 @@ class _ImageFooterState extends State { TextEditingController _searchController = TextEditingController(); TextEditingController _messageController = TextEditingController(); - List _selectedUsers = []; + Set _selectedUsers = {}; bool _loading = false; @override @@ -204,171 +204,93 @@ class _ImageFooterState extends State { showDialog( context: context, builder: (context) { - return StreamChannel( - channel: channel, - child: Scaffold( - backgroundColor: Colors.transparent, - body: StatefulBuilder(builder: (modalContext, modalSetState) { - return Align( - alignment: _userSearchMode - ? Alignment.topCenter - : Alignment.bottomCenter, - child: Material( - color: Colors.transparent, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(16.0), - ), - child: Stack( + return StatefulBuilder(builder: (context, modalSetState) { + return Padding( + padding: const EdgeInsets.only(top: 16.0, left: 8.0, right: 8.0), + child: Material( + borderRadius: BorderRadius.only( + topLeft: Radius.circular(16.0), + topRight: Radius.circular(16.0), + ), + clipBehavior: Clip.antiAlias, + child: Scaffold( + body: UsersBloc( + child: Column( children: [ - ListView( - children: [ - if (!_userSearchMode && - MediaQuery.of(context).viewInsets.bottom == 0.0) - GestureDetector( - child: Container( - height: - MediaQuery.of(modalContext).size.height / 2, - color: Colors.transparent, - ), - onTapUp: (val) { - Navigator.pop(modalContext); + _buildTextInputSection(modalSetState), + Expanded( + child: UserListView( + selectedUsers: _selectedUsers, + onUserTap: (user, _) { + _searchController.clear(); + if (!_selectedUsers.contains(user)) { + modalSetState(() { + _selectedUsers.add(user); + }); + } else { + modalSetState(() { + _selectedUsers.remove(user); + }); + } + }, + crossAxisCount: 3, + pagination: PaginationParams( + limit: 25, + ), + filter: { + if (_searchController.text.isNotEmpty) + 'name': { + r'$autocomplete': _searchController.text, }, + 'id': { + r'$ne': StreamChat.of(context).user.id, + }, + }, + sort: [ + SortOption( + 'name', + direction: 1, ), - Container( - margin: EdgeInsets.symmetric( - horizontal: 8.0, - ), - padding: EdgeInsets.symmetric( - vertical: 4.0, - ), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.only( - topRight: Radius.circular(16.0), - topLeft: Radius.circular(16.0), - )), - child: _buildTextInputSection(modalSetState), - ), - Container( - margin: EdgeInsets.symmetric( - horizontal: 8.0, - ), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.only( - bottomRight: Radius.circular( - _userSearchMode ? 16.0 : 0.0), - bottomLeft: Radius.circular( - _userSearchMode ? 16.0 : 0.0), - ), - ), - child: FutureBuilder( - future: _userQuery, - builder: (context, snapshot) { - if (!snapshot.hasData) { - return Center( - child: CircularProgressIndicator(), - ); - } - - var filteredData = - snapshot.data.users.toList(); - - if (_userSearchMode && - _searchController.text.length > 0) { - filteredData = snapshot.data.users - .where((element) => element.name - .toLowerCase() - .contains(_searchController.text - .toLowerCase())) - .toList(); - } - - return GridView.builder( - shrinkWrap: true, - physics: NeverScrollableScrollPhysics(), - itemBuilder: (context, position) { - var user = filteredData[position]; - var isUserSelected = - _selectedUsers.contains(user); - - return Padding( - padding: const EdgeInsets.all(8.0), - child: Column( - mainAxisSize: MainAxisSize.min, - mainAxisAlignment: - MainAxisAlignment.start, - crossAxisAlignment: - CrossAxisAlignment.center, - children: [ - Stack( - children: [ - CircleAvatar( - maxRadius: 32.0, - child: UserAvatar( - onTap: (user) { - if (isUserSelected) { - _selectedUsers - .remove(user); - } else { - _selectedUsers - .add(user); - } - modalSetState(() {}); - }, - user: user, - constraints: - BoxConstraints.tightFor( - height: isUserSelected - ? 56 - : 64, - width: isUserSelected - ? 56 - : 64, - ), - borderRadius: - BorderRadius.circular( - 32), - ), - ), - ], - ), - Padding( - padding: - const EdgeInsets.all(8.0), - child: Text( - user.name, - style: Theme.of(context) - .textTheme - .subtitle2, - textAlign: TextAlign.center, - maxLines: 2, - ), - ), - ], - ), - ); - }, - itemCount: filteredData.length, - gridDelegate: - SliverGridDelegateWithFixedCrossAxisCount( - crossAxisCount: 4, - childAspectRatio: 0.75, + ], + emptyBuilder: (_) { + return LayoutBuilder( + builder: (context, viewportConstraints) { + return SingleChildScrollView( + physics: AlwaysScrollableScrollPhysics(), + child: ConstrainedBox( + constraints: BoxConstraints( + minHeight: viewportConstraints.maxHeight, ), - ); - }), - ), - ], + child: Center( + child: Column( + children: [ + Padding( + padding: const EdgeInsets.all(24), + child: StreamSvgIcon.search( + size: 96, + color: Colors.grey, + ), + ), + Text( + 'No user matches these keywords...'), + ], + ), + ), + ), + ); + }, + ); + }, + ), ), + if (_selectedUsers.isNotEmpty) + _buildShareTextInputSection(modalSetState), if (!_userSearchMode && _selectedUsers.isEmpty) Align( alignment: Alignment.bottomCenter, child: Container( color: Colors.white, height: 48.0, - margin: EdgeInsets.symmetric( - horizontal: 8.0, - ), child: Material( child: InkWell( onTap: () async { @@ -392,7 +314,7 @@ class _ImageFooterState extends State { child: Text( 'Save to Photos', style: TextStyle( - color: StreamChatTheme.of(modalContext) + color: StreamChatTheme.of(context) .accentColor, fontWeight: FontWeight.bold, ), @@ -403,15 +325,13 @@ class _ImageFooterState extends State { ), ), ), - if (!_userSearchMode && _selectedUsers.isNotEmpty) - _buildShareTextInputSection(modalSetState), ], ), ), - ); - }), - ), - ); + ), + ), + ); + }); }, ); } @@ -440,13 +360,14 @@ class _ImageFooterState extends State { decoration: InputDecoration( isDense: true, prefixIconConstraints: - BoxConstraints.tight(Size(38.0, 38.0)), - prefixIcon: Transform.scale( - scale: 1.2, - alignment: Alignment.center, - child: StreamSvgIcon.search( - color: Colors.black, - )), + BoxConstraints.tight(Size(36.0, 44.0)), + prefixIcon: Padding( + padding: const EdgeInsets.symmetric( + vertical: 2.0, horizontal: 6.0), + child: StreamSvgIcon.search( + color: Colors.black, + ), + ), hintText: 'Search', border: OutlineInputBorder( borderRadius: BorderRadius.circular(32.0), @@ -512,10 +433,9 @@ class _ImageFooterState extends State { Padding( padding: const EdgeInsets.symmetric(horizontal: 6.0), child: IconButton( - icon: StreamSvgIcon.search( + icon: StreamSvgIcon.share_arrow( color: Colors.black, ), - iconSize: 24.0, onPressed: () async { var url = widget.urls[widget.currentPage].imageUrl ?? widget.urls[widget.currentPage].assetUrl ?? @@ -580,54 +500,32 @@ class _ImageFooterState extends State { ), ), ), - AnimatedCrossFade( - crossFadeState: _messageController.text.isNotEmpty - ? CrossFadeState.showFirst - : CrossFadeState.showSecond, - firstChild: IconTheme( - data: StreamChatTheme.of(context) - .channelTheme - .messageInputButtonIconTheme, - child: Center( - child: Padding( - padding: const EdgeInsets.all(8.0), - child: InkWell( - onTap: () async { - modalSetState(() { - _loading = true; - }); - await sendMessage(); - modalSetState(() { - _loading = false; - }); - }, - child: Transform.rotate( - angle: -pi / 2, - child: StreamSvgIcon.Icon_send_message( - color: StreamChatTheme.of(context).accentColor, - ), + IconTheme( + data: StreamChatTheme.of(context) + .channelTheme + .messageInputButtonIconTheme, + child: Center( + child: Padding( + padding: const EdgeInsets.all(8.0), + child: InkWell( + onTap: () async { + modalSetState(() { + _loading = true; + }); + await sendMessage(); + modalSetState(() { + _loading = false; + }); + }, + child: Transform.rotate( + angle: -pi / 2, + child: StreamSvgIcon.Icon_send_message( + color: StreamChatTheme.of(context).accentColor, ), ), ), ), ), - secondChild: IconTheme( - data: StreamChatTheme.of(context) - .channelTheme - .messageInputButtonIconTheme, - child: Padding( - padding: const EdgeInsets.all(8.0), - child: Center( - child: InkWell( - onTap: () {}, - child: StreamSvgIcon.Icon_send_message( - color: Colors.grey, - ), - )), - ), - ), - duration: Duration(milliseconds: 300), - alignment: Alignment.center, ), ], ), diff --git a/lib/src/stream_svg_icon.dart b/lib/src/stream_svg_icon.dart index 87d21c14..e5ef7ec9 100644 --- a/lib/src/stream_svg_icon.dart +++ b/lib/src/stream_svg_icon.dart @@ -469,4 +469,16 @@ class StreamSvgIcon extends StatelessWidget { height: size, ); } + + factory StreamSvgIcon.share_arrow({ + double size, + Color color, + }) { + return StreamSvgIcon( + assetName: 'share_arrow.svg', + color: color, + width: size, + height: size, + ); + } } From aed495e80f0b80bf3104e596d12f66cc14e88411 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Mon, 30 Nov 2020 12:26:54 +0100 Subject: [PATCH 0528/1140] update notification --- example/lib/main.dart | 1 + example/lib/notifications_service.dart | 3 ++- example/pubspec.yaml | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/example/lib/main.dart b/example/lib/main.dart index fa62878d..ff983fef 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -28,6 +28,7 @@ void main() async { showLocalNotification: (!kIsWeb && Platform.isAndroid) ? showLocalNotification : null, persistenceEnabled: true, + backgroundKeepAlive: Duration(seconds: 3), ); if (userId != null) { diff --git a/example/lib/notifications_service.dart b/example/lib/notifications_service.dart index c5b77c0e..83f5047a 100644 --- a/example/lib/notifications_service.dart +++ b/example/lib/notifications_service.dart @@ -33,7 +33,8 @@ void showLocalNotification(Message message, ChannelModel channel) async { } Future backgroundHandler(Map notification) async { - final messageId = notification['data']['message_id']; + print('new notification ${notification}'); + final messageId = notification['data']['id']; final notificationData = await NotificationService.getAndStoreMessage(messageId); diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 80a852d8..5b025b4d 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -1,6 +1,6 @@ name: example description: A new Flutter project. -version: 1.0.83+85 +version: 1.0.84+86 environment: sdk: ">=2.2.2 <3.0.0" From 11bee325a7fedd27e337980a942a5356422d912d Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Mon, 30 Nov 2020 12:27:20 +0100 Subject: [PATCH 0529/1140] remove debug code --- example/lib/main.dart | 1 - example/pubspec.yaml | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/example/lib/main.dart b/example/lib/main.dart index ff983fef..fa62878d 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -28,7 +28,6 @@ void main() async { showLocalNotification: (!kIsWeb && Platform.isAndroid) ? showLocalNotification : null, persistenceEnabled: true, - backgroundKeepAlive: Duration(seconds: 3), ); if (userId != null) { diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 5b025b4d..e84b2303 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -1,6 +1,6 @@ name: example description: A new Flutter project. -version: 1.0.84+86 +version: 1.0.85+87 environment: sdk: ">=2.2.2 <3.0.0" From 058ecc9a0d659e582d55b0a1c9796e89cf106913 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Mon, 30 Nov 2020 19:20:15 +0530 Subject: [PATCH 0530/1140] fixes --- lib/src/full_screen_media.dart | 14 ++++- lib/src/image_footer.dart | 101 ++++++++++++++++++--------------- 2 files changed, 67 insertions(+), 48 deletions(-) diff --git a/lib/src/full_screen_media.dart b/lib/src/full_screen_media.dart index 88f8d2b9..fed1b9a7 100644 --- a/lib/src/full_screen_media.dart +++ b/lib/src/full_screen_media.dart @@ -63,6 +63,10 @@ class _FullScreenMediaState extends State @override Widget build(BuildContext context) { + var videoAttachments = widget.mediaAttachments + .where((element) => element.type == 'video') + .toList(); + return Scaffold( resizeToAvoidBottomInset: false, body: Stack( @@ -113,7 +117,10 @@ class _FullScreenMediaState extends State ); } else if (widget.mediaAttachments[position].type == 'video') { - if (!videoPackages[position].initialised) { + var controllerPackage = videoPackages[videoAttachments + .indexOf(widget.mediaAttachments[position])]; + + if (!controllerPackage.initialised) { return Center( child: CircularProgressIndicator(), ); @@ -130,7 +137,7 @@ class _FullScreenMediaState extends State } }, child: Chewie( - controller: videoPackages[position].chewieController, + controller: controllerPackage.chewieController, ), ); } @@ -160,8 +167,9 @@ class _FullScreenMediaState extends State ImageFooter( currentPage: _currentPage, totalPages: widget.mediaAttachments.length, - urls: widget.mediaAttachments, + mediaAttachments: widget.mediaAttachments, message: widget.message, + videoPackages: videoPackages, ), ], ), diff --git a/lib/src/image_footer.dart b/lib/src/image_footer.dart index 1605206c..a4651cf7 100644 --- a/lib/src/image_footer.dart +++ b/lib/src/image_footer.dart @@ -3,6 +3,7 @@ import 'dart:math'; import 'dart:typed_data'; import 'package:cached_network_image/cached_network_image.dart'; +import 'package:chewie/chewie.dart'; import 'package:esys_flutter_share/esys_flutter_share.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; @@ -12,7 +13,6 @@ import 'package:path_provider/path_provider.dart'; import 'package:stream_chat/stream_chat.dart'; import 'package:stream_chat_flutter/src/stream_chat.dart'; import 'package:stream_chat_flutter/src/stream_chat_theme.dart'; -import 'package:stream_chat_flutter/src/user_avatar.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; import 'stream_channel.dart'; @@ -31,9 +31,11 @@ class ImageFooter extends StatefulWidget { final int currentPage; final int totalPages; - final List urls; + final List mediaAttachments; final Message message; + final List videoPackages; + /// Creates a channel header ImageFooter({ Key key, @@ -42,8 +44,9 @@ class ImageFooter extends StatefulWidget { this.onImageTap, this.currentPage = 0, this.totalPages = 0, - this.urls, + this.mediaAttachments, this.message, + this.videoPackages, }) : preferredSize = Size.fromHeight(kToolbarHeight), super(key: key); @@ -55,7 +58,6 @@ class ImageFooter extends StatefulWidget { } class _ImageFooterState extends State { - Future _userQuery; bool _userSearchMode = false; TextEditingController _searchController = TextEditingController(); TextEditingController _messageController = TextEditingController(); @@ -63,12 +65,6 @@ class _ImageFooterState extends State { Set _selectedUsers = {}; bool _loading = false; - @override - void initState() { - super.initState(); - _userQuery = _queryUsers(context); - } - @override Widget build(BuildContext context) { return SafeArea( @@ -123,6 +119,10 @@ class _ImageFooterState extends State { } Widget _buildPhotosModal(context) { + var videoAttachments = widget.mediaAttachments + .where((element) => element.type == 'video') + .toList(); + showModalBottomSheet( context: context, shape: RoundedRectangleBorder( @@ -174,20 +174,33 @@ class _ImageFooterState extends State { shrinkWrap: true, physics: NeverScrollableScrollPhysics(), itemBuilder: (context, position) { - return Padding( - padding: const EdgeInsets.all(1.0), - child: AspectRatio( - child: CachedNetworkImage( - imageUrl: widget.urls[position].imageUrl ?? - widget.urls[position].assetUrl ?? - widget.urls[position].thumbUrl, - fit: BoxFit.cover, + if (widget.mediaAttachments[position].type == 'video') { + var controllerPackage = widget.videoPackages[ + videoAttachments + .indexOf(widget.mediaAttachments[position])]; + + return FittedBox( + child: Chewie( + controller: controllerPackage.chewieController, ), - aspectRatio: 1.0, - ), - ); + ); + } else { + return Padding( + padding: const EdgeInsets.all(1.0), + child: AspectRatio( + child: CachedNetworkImage( + imageUrl: + widget.mediaAttachments[position].imageUrl ?? + widget.mediaAttachments[position].assetUrl ?? + widget.mediaAttachments[position].thumbUrl, + fit: BoxFit.cover, + ), + aspectRatio: 1.0, + ), + ); + } }, - itemCount: widget.urls.length, + itemCount: widget.mediaAttachments.length, gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: 3), ), @@ -206,7 +219,12 @@ class _ImageFooterState extends State { builder: (context) { return StatefulBuilder(builder: (context, modalSetState) { return Padding( - padding: const EdgeInsets.only(top: 16.0, left: 8.0, right: 8.0), + padding: EdgeInsets.only( + top: _userSearchMode + ? 16.0 + : MediaQuery.of(context).size.height / 2, + left: 8.0, + right: 8.0), child: Material( borderRadius: BorderRadius.only( topLeft: Radius.circular(16.0), @@ -233,7 +251,7 @@ class _ImageFooterState extends State { }); } }, - crossAxisCount: 3, + crossAxisCount: 4, pagination: PaginationParams( limit: 25, ), @@ -295,12 +313,18 @@ class _ImageFooterState extends State { child: InkWell( onTap: () async { var url = widget - .urls[widget.currentPage].imageUrl ?? + .mediaAttachments[widget.currentPage] + .imageUrl ?? widget - .urls[widget.currentPage].assetUrl ?? - widget.urls[widget.currentPage].thumbUrl; + .mediaAttachments[widget.currentPage] + .assetUrl ?? + widget + .mediaAttachments[widget.currentPage] + .thumbUrl; - if (widget.urls[widget.currentPage].type == + if (widget + .mediaAttachments[widget.currentPage] + .type == 'video') { await _saveVideo(url); Navigator.pop(context); @@ -437,9 +461,10 @@ class _ImageFooterState extends State { color: Colors.black, ), onPressed: () async { - var url = widget.urls[widget.currentPage].imageUrl ?? - widget.urls[widget.currentPage].assetUrl ?? - widget.urls[widget.currentPage].thumbUrl; + var url = + widget.mediaAttachments[widget.currentPage].imageUrl ?? + widget.mediaAttachments[widget.currentPage].assetUrl ?? + widget.mediaAttachments[widget.currentPage].thumbUrl; var type = url?.split('?')?.first?.split('.')?.last ?? 'jpg'; var request = await HttpClient().getUrl(Uri.parse(url)); var response = await request.close(); @@ -533,20 +558,6 @@ class _ImageFooterState extends State { ); } - Future _queryUsers(context) { - return StreamChat.of(context).client.queryUsers( - pagination: PaginationParams( - limit: 25, - ), - sort: [ - SortOption( - 'name', - direction: SortOption.ASC, - ), - ], - ); - } - /// Sends the current message Future sendMessage() async { var text = _messageController.text.trim(); From 6e72e8d03eeb1b04f7b2f1a2393169a49dacb344 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Mon, 30 Nov 2020 15:41:25 +0100 Subject: [PATCH 0531/1140] fix mimetype of .heic pics when picked from files --- example/ios/Flutter/.last_build_id | 2 +- example/pubspec.yaml | 2 +- lib/src/message_input.dart | 25 ++++++++++++++++--------- 3 files changed, 18 insertions(+), 11 deletions(-) diff --git a/example/ios/Flutter/.last_build_id b/example/ios/Flutter/.last_build_id index 20c7c514..3c74be76 100644 --- a/example/ios/Flutter/.last_build_id +++ b/example/ios/Flutter/.last_build_id @@ -1 +1 @@ -c3e639ccf9b069e37a7d1345194e6b99 \ No newline at end of file +be54eb19d957de3aac70eae5513f67ef \ No newline at end of file diff --git a/example/pubspec.yaml b/example/pubspec.yaml index e84b2303..5e7cc348 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -1,6 +1,6 @@ name: example description: A new Flutter project. -version: 1.0.85+87 +version: 1.0.86+88 environment: sdk: ">=2.2.2 <3.0.0" diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index d3522a91..9bcddf05 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -1623,14 +1623,7 @@ class MessageInputState extends State { Future _uploadImage(PlatformFile file, Channel channel) async { final filename = file.name ?? file.path?.split('/')?.last; - httpParser.MediaType mimeType; - if (filename != null) { - if (filename.toLowerCase().endsWith('heic')) { - mimeType = httpParser.MediaType.parse('image/heic'); - } else { - mimeType = httpParser.MediaType.parse(lookupMimeType(filename)); - } - } + final mimeType = _getMimeType(filename); final bytes = file.bytes; final res = await channel.sendImage( MultipartFile.fromBytes( @@ -1642,14 +1635,28 @@ class MessageInputState extends State { return res.file; } + httpParser.MediaType _getMimeType(String filename) { + httpParser.MediaType mimeType; + if (filename != null) { + if (filename.toLowerCase().endsWith('heic')) { + mimeType = httpParser.MediaType.parse('image/heic'); + } else { + mimeType = httpParser.MediaType.parse(lookupMimeType(filename)); + } + } + + return mimeType; + } + Future _uploadFile(PlatformFile file, Channel channel) async { final filename = file.name ?? file.path?.split('/')?.last; + final mimeType = _getMimeType(filename); final bytes = file.bytes; final res = await channel.sendFile( MultipartFile.fromBytes( bytes, filename: filename, - contentType: httpParser.MediaType.parse(lookupMimeType(filename)), + contentType: mimeType, ), ); return res.file; From 37ad5d72be89dc6860f7a4ae5b609f798e749476 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Mon, 30 Nov 2020 20:30:32 +0530 Subject: [PATCH 0532/1140] fixes --- lib/src/full_screen_media.dart | 1 - lib/src/image_footer.dart | 7 +++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/lib/src/full_screen_media.dart b/lib/src/full_screen_media.dart index fed1b9a7..a0c4a03f 100644 --- a/lib/src/full_screen_media.dart +++ b/lib/src/full_screen_media.dart @@ -82,7 +82,6 @@ class _FullScreenMediaState extends State }); }, itemBuilder: (context, position) { - print(widget.mediaAttachments[position].type); if (widget.mediaAttachments[position].type == 'image' || widget.mediaAttachments[position].type == 'giphy') { return PhotoView( diff --git a/lib/src/image_footer.dart b/lib/src/image_footer.dart index a4651cf7..dcc5c5d8 100644 --- a/lib/src/image_footer.dart +++ b/lib/src/image_footer.dart @@ -465,7 +465,10 @@ class _ImageFooterState extends State { widget.mediaAttachments[widget.currentPage].imageUrl ?? widget.mediaAttachments[widget.currentPage].assetUrl ?? widget.mediaAttachments[widget.currentPage].thumbUrl; - var type = url?.split('?')?.first?.split('.')?.last ?? 'jpg'; + var type = + widget.mediaAttachments[widget.currentPage].type == 'image' + ? 'jpg' + : url?.split('?')?.first?.split('.')?.last ?? 'jpg'; var request = await HttpClient().getUrl(Uri.parse(url)); var response = await request.close(); var bytes = await consolidateHttpClientResponseBytes(response); @@ -583,7 +586,7 @@ class _ImageFooterState extends State { message = (Message()).copyWith( text: text, - attachments: attachments, + attachments: [attachments[widget.currentPage]], mentionedUsers: [], showInChannel: false, ); From 48738c84c5b8411f2f55b65cf7aaa74a6e9b478b Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Mon, 30 Nov 2020 17:17:35 +0100 Subject: [PATCH 0533/1140] fix compressed video upload --- lib/src/message_input.dart | 38 ++++++++++++++++++++++---------------- 1 file changed, 22 insertions(+), 16 deletions(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 9bcddf05..777ef1b3 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -1549,8 +1549,23 @@ class MessageInputState extends State { return; } + final channel = StreamChannel.of(context).channel; + final attachment = _SendingAttachment( + file: file, + attachment: Attachment( + localUri: file.path != null ? Uri.parse(file.path) : null, + type: attachmentType, + ), + ); + + setState(() { + _attachments.add(attachment); + }); + + final mimeType = _getMimeType(file.name); + if (file.size > _kMaxAttachmentSize) { - if (attachmentType == 'video') { + if (attachmentType == 'video' || mimeType?.type == 'video') { final mediaInfo = await CompressVideoService.compressVideo(file.path); file = PlatformFile( name: mediaInfo.title, @@ -1566,22 +1581,13 @@ class MessageInputState extends State { ), ), ); + setState(() { + _attachments.remove(attachment); + }); + return; } } - final channel = StreamChannel.of(context).channel; - final attachment = _SendingAttachment( - file: file, - attachment: Attachment( - localUri: file.path != null ? Uri.parse(file.path) : null, - type: attachmentType, - ), - ); - - setState(() { - _attachments.add(attachment); - }); - final url = await _uploadAttachment(file, fileType, channel); if (fileType == DefaultAttachmentTypes.image) { @@ -1622,7 +1628,7 @@ class MessageInputState extends State { } Future _uploadImage(PlatformFile file, Channel channel) async { - final filename = file.name ?? file.path?.split('/')?.last; + final filename = file.path?.split('/')?.last; final mimeType = _getMimeType(filename); final bytes = file.bytes; final res = await channel.sendImage( @@ -1649,7 +1655,7 @@ class MessageInputState extends State { } Future _uploadFile(PlatformFile file, Channel channel) async { - final filename = file.name ?? file.path?.split('/')?.last; + final filename = file.path?.split('/')?.last; final mimeType = _getMimeType(filename); final bytes = file.bytes; final res = await channel.sendFile( From 46dcf6a629c8d3e9d595b189dd2e13c6bf5a667f Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Mon, 30 Nov 2020 18:07:11 +0100 Subject: [PATCH 0534/1140] fix compression video --- lib/src/message_input.dart | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 777ef1b3..6714e812 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -869,7 +869,7 @@ class MessageInputState extends State { } file = PlatformFile( name: file.name, - size: mediaInfo.filesize, + size: (mediaInfo.filesize / 1024).ceil(), bytes: await mediaInfo.file.readAsBytes(), path: mediaInfo.path, ); @@ -1294,6 +1294,12 @@ class MessageInputState extends State { ? Image.memory( attachment.file.bytes, fit: BoxFit.cover, + errorBuilder: (context, _, __) { + return Image.asset( + 'images/placeholder.png', + package: 'stream_chat_flutter', + ); + }, ) : Image.network( attachment.attachment.imageUrl, @@ -1520,6 +1526,7 @@ class MessageInputState extends State { } final bytes = await pickedFile.readAsBytes(); file = PlatformFile( + size: (bytes.length / 1024).ceil(), path: pickedFile.path, bytes: bytes, ); @@ -1549,6 +1556,12 @@ class MessageInputState extends State { return; } + final mimeType = _getMimeType(file.name); + + if (mimeType.type == 'video' || mimeType.type == 'image') { + attachmentType = mimeType.type; + } + final channel = StreamChannel.of(context).channel; final attachment = _SendingAttachment( file: file, @@ -1562,17 +1575,18 @@ class MessageInputState extends State { _attachments.add(attachment); }); - final mimeType = _getMimeType(file.name); - if (file.size > _kMaxAttachmentSize) { - if (attachmentType == 'video' || mimeType?.type == 'video') { + if (attachmentType == 'video') { final mediaInfo = await CompressVideoService.compressVideo(file.path); file = PlatformFile( name: mediaInfo.title, - size: mediaInfo.filesize, + size: (mediaInfo.filesize / 1024).ceil(), bytes: await mediaInfo.file.readAsBytes(), path: mediaInfo.path, ); + setState(() { + attachment.file = file; + }); } else { Scaffold.of(context).showSnackBar( SnackBar( From 7f0c8fe25a54ca0d000ad2841c53f105e8de6970 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Mon, 30 Nov 2020 18:10:55 +0100 Subject: [PATCH 0535/1140] fix mimetype --- lib/src/message_input.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 6714e812..27f9f7bd 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -1556,7 +1556,7 @@ class MessageInputState extends State { return; } - final mimeType = _getMimeType(file.name); + final mimeType = _getMimeType(file.path.split('/').last); if (mimeType.type == 'video' || mimeType.type == 'image') { attachmentType = mimeType.type; From 27ef529c25e49406d4b0bcb63d1a6adf41cbbdab Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Tue, 1 Dec 2020 10:34:21 +0100 Subject: [PATCH 0536/1140] simplify send message --- lib/src/image_footer.dart | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/lib/src/image_footer.dart b/lib/src/image_footer.dart index dcc5c5d8..3a223de2 100644 --- a/lib/src/image_footer.dart +++ b/lib/src/image_footer.dart @@ -212,8 +212,6 @@ class _ImageFooterState extends State { } Widget _buildShareModal(context) { - final channel = StreamChannel.of(context).channel; - showDialog( context: context, builder: (context) { @@ -581,19 +579,14 @@ class _ImageFooterState extends State { await c.create(); - Future sendingFuture; - Message message; - - message = (Message()).copyWith( + final message = Message( text: text, attachments: [attachments[widget.currentPage]], mentionedUsers: [], showInChannel: false, ); - sendingFuture = c.sendMessage(message); - - await sendingFuture; + await c.sendMessage(message); } _selectedUsers.clear(); From 267793bd47015098e0b366bd6454852d753914fb Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Tue, 1 Dec 2020 10:35:44 +0100 Subject: [PATCH 0537/1140] remove useless params --- lib/src/image_footer.dart | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/src/image_footer.dart b/lib/src/image_footer.dart index 3a223de2..a24288e1 100644 --- a/lib/src/image_footer.dart +++ b/lib/src/image_footer.dart @@ -582,8 +582,6 @@ class _ImageFooterState extends State { final message = Message( text: text, attachments: [attachments[widget.currentPage]], - mentionedUsers: [], - showInChannel: false, ); await c.sendMessage(message); From 9659008ae868d9880067af81ce80c0a525e4d3f4 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Tue, 1 Dec 2020 11:14:21 +0100 Subject: [PATCH 0538/1140] remove close button if search is not active --- example/ios/Flutter/.last_build_id | 2 +- example/lib/main.dart | 1 + example/pubspec.yaml | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/example/ios/Flutter/.last_build_id b/example/ios/Flutter/.last_build_id index 3c74be76..20c7c514 100644 --- a/example/ios/Flutter/.last_build_id +++ b/example/ios/Flutter/.last_build_id @@ -1 +1 @@ -be54eb19d957de3aac70eae5513f67ef \ No newline at end of file +c3e639ccf9b069e37a7d1345194e6b99 \ No newline at end of file diff --git a/example/lib/main.dart b/example/lib/main.dart index fa62878d..4b529e23 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -300,6 +300,7 @@ class _ChannelListPageState extends State { children: [ SearchTextField( controller: _controller, + showCloseButton: _isSearchActive, ), Expanded( child: AnimatedSwitcher( diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 5e7cc348..6ae2ab54 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -1,6 +1,6 @@ name: example description: A new Flutter project. -version: 1.0.86+88 +version: 1.0.87+89 environment: sdk: ">=2.2.2 <3.0.0" From 1e8200a86a6a941254a8c5f7f17531d87ca8ea61 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Tue, 1 Dec 2020 15:17:10 +0100 Subject: [PATCH 0539/1140] fix deleted message borderradius --- lib/src/deleted_message.dart | 63 ++++++++++++++++++++++-------------- lib/src/message_widget.dart | 1 + 2 files changed, 39 insertions(+), 25 deletions(-) diff --git a/lib/src/deleted_message.dart b/lib/src/deleted_message.dart index 673d79c8..9181d985 100644 --- a/lib/src/deleted_message.dart +++ b/lib/src/deleted_message.dart @@ -1,6 +1,7 @@ +import 'dart:math'; + import 'package:flutter/material.dart'; import 'package:stream_chat_flutter/src/stream_chat_theme.dart'; -import 'package:stream_chat_flutter/src/stream_svg_icon.dart'; class DeletedMessage extends StatelessWidget { const DeletedMessage({ @@ -9,6 +10,7 @@ class DeletedMessage extends StatelessWidget { this.borderRadiusGeometry, this.shape, this.borderSide, + this.reverse = false, }) : super(key: key); /// The theme of the message @@ -23,33 +25,44 @@ class DeletedMessage extends StatelessWidget { /// The borderside of the message text final BorderSide borderSide; + /// If true the widget will be mirrored + final bool reverse; + @override Widget build(BuildContext context) { - return Material( - color: messageTheme.messageBackgroundColor, - shape: shape ?? - RoundedRectangleBorder( - borderRadius: borderRadiusGeometry ?? BorderRadius.zero, - side: borderSide ?? - BorderSide( - color: Theme.of(context).brightness == Brightness.dark - ? Colors.white.withAlpha(24) - : Colors.black.withAlpha(24), - ), + return Transform( + transform: Matrix4.rotationY(reverse ? pi : 0), + alignment: Alignment.center, + child: Material( + color: messageTheme.messageBackgroundColor, + shape: shape ?? + RoundedRectangleBorder( + borderRadius: borderRadiusGeometry ?? BorderRadius.zero, + side: borderSide ?? + BorderSide( + color: Theme.of(context).brightness == Brightness.dark + ? Colors.white.withAlpha(24) + : Colors.black.withAlpha(24), + ), + ), + child: Padding( + padding: const EdgeInsets.symmetric( + vertical: 8.0, + horizontal: 16, ), - child: Padding( - padding: const EdgeInsets.symmetric( - vertical: 8.0, - horizontal: 16, - ), - child: Text( - 'Message deleted', - style: messageTheme.messageText.copyWith( - fontStyle: FontStyle.italic, - color: (Theme.of(context).brightness == Brightness.dark - ? Colors.white - : Colors.black) - .withOpacity(.5), + child: Transform( + transform: Matrix4.rotationY(reverse ? pi : 0), + alignment: Alignment.center, + child: Text( + 'Message deleted', + style: messageTheme.messageText.copyWith( + fontStyle: FontStyle.italic, + color: (Theme.of(context).brightness == Brightness.dark + ? Colors.white + : Colors.black) + .withOpacity(.5), + ), + ), ), ), ), diff --git a/lib/src/message_widget.dart b/lib/src/message_widget.dart index 45f3c62e..88a93d6f 100644 --- a/lib/src/message_widget.dart +++ b/lib/src/message_widget.dart @@ -286,6 +286,7 @@ class _MessageWidgetState extends State { transform: Matrix4.rotationY( widget.reverse ? pi : 0), child: DeletedMessage( + reverse: widget.reverse, borderRadiusGeometry: widget.borderRadiusGeometry, borderSide: widget.borderSide, From ac0fc427aeaea0b7f0a0c46ab11d3002e8e1fff4 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Tue, 1 Dec 2020 15:18:48 +0100 Subject: [PATCH 0540/1140] fix messageinput send icon --- lib/src/message_input.dart | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 27f9f7bd..1dbc45df 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -1719,17 +1719,17 @@ class MessageInputState extends State { if (_commandEnabled) { return 'Icon_search.svg'; } else { - return 'Icon_circle_up.svg'; + return 'Icon_circle_right.svg'; } } String _getSendIcon() { if (widget.editMessage != null) { - return 'Icon_circle_right.svg'; + return 'Icon_circle_up.svg'; } else if (_commandEnabled) { return 'Icon_search.svg'; } else { - return 'Icon_circle_right.svg'; + return 'Icon_circle_up.svg'; } } From 9cb2ad884f24425be87048fc3bd50fb0504bb1dd Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Wed, 2 Dec 2020 17:13:48 +0530 Subject: [PATCH 0541/1140] fix: Added debounce logic --- lib/src/image_footer.dart | 42 ++++++++++++++++++++++++++++++++++----- 1 file changed, 37 insertions(+), 5 deletions(-) diff --git a/lib/src/image_footer.dart b/lib/src/image_footer.dart index dcc5c5d8..c6df304a 100644 --- a/lib/src/image_footer.dart +++ b/lib/src/image_footer.dart @@ -1,3 +1,4 @@ +import 'dart:async'; import 'dart:io'; import 'dart:math'; import 'dart:typed_data'; @@ -59,12 +60,45 @@ class ImageFooter extends StatefulWidget { class _ImageFooterState extends State { bool _userSearchMode = false; - TextEditingController _searchController = TextEditingController(); + TextEditingController _searchController; TextEditingController _messageController = TextEditingController(); + String _userNameQuery; + bool _isSearchActive = false; + Set _selectedUsers = {}; bool _loading = false; + Timer _debounce; + + Function modalSetStateCallback; + + void _userNameListener() { + if (_debounce?.isActive ?? false) _debounce.cancel(); + _debounce = Timer(const Duration(milliseconds: 350), () { + if (mounted && modalSetStateCallback != null) { + modalSetStateCallback(() { + _userNameQuery = _searchController.text; + _isSearchActive = _userNameQuery.isNotEmpty; + }); + } + }); + } + + @override + void initState() { + super.initState(); + _searchController = TextEditingController()..addListener(_userNameListener); + } + + @override + void dispose() { + _searchController?.clear(); + _searchController?.removeListener(_userNameListener); + _searchController?.dispose(); + super.dispose(); + } + @override Widget build(BuildContext context) { return SafeArea( @@ -218,6 +252,7 @@ class _ImageFooterState extends State { context: context, builder: (context) { return StatefulBuilder(builder: (context, modalSetState) { + modalSetStateCallback = modalSetState; return Padding( padding: EdgeInsets.only( top: _userSearchMode @@ -258,7 +293,7 @@ class _ImageFooterState extends State { filter: { if (_searchController.text.isNotEmpty) 'name': { - r'$autocomplete': _searchController.text, + r'$autocomplete': _userNameQuery, }, 'id': { r'$ne': StreamChat.of(context).user.id, @@ -376,9 +411,6 @@ class _ImageFooterState extends State { Expanded( child: TextField( controller: _searchController, - onChanged: (val) { - modalSetState(() {}); - }, cursorColor: Colors.black, autofocus: true, decoration: InputDecoration( From 06b2929c37c256dea3e907c3e7e7c7a3bec72d09 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Wed, 2 Dec 2020 13:19:31 +0100 Subject: [PATCH 0542/1140] wip --- example/lib/advanced_options_page.dart | 8 +- example/lib/chips_input_text_field.dart | 17 ++-- example/lib/choose_user_page.dart | 36 +++++--- example/lib/main.dart | 3 + example/lib/new_chat_screen.dart | 36 ++++---- example/lib/new_group_chat_screen.dart | 9 +- example/lib/search_text_field.dart | 9 +- example/pubspec.yaml | 2 +- lib/src/channel_list_header.dart | 9 +- lib/src/channel_list_view.dart | 28 +++--- lib/src/channel_preview.dart | 3 + lib/src/message_list_view.dart | 8 +- lib/src/message_search_item.dart | 2 - lib/src/stream_chat_theme.dart | 118 +++++++++++++++++++----- lib/src/user_item.dart | 10 +- lib/src/user_list_view.dart | 2 +- 16 files changed, 203 insertions(+), 97 deletions(-) diff --git a/example/lib/advanced_options_page.dart b/example/lib/advanced_options_page.dart index e07afefd..6c922e3d 100644 --- a/example/lib/advanced_options_page.dart +++ b/example/lib/advanced_options_page.dart @@ -39,11 +39,13 @@ class _AdvancedOptionsPageState extends State { backgroundColor: StreamChatTheme.of(context).primaryColor, elevation: 1, centerTitle: true, + brightness: Theme.of(context).brightness, title: Text( 'Advanced Options', - style: Theme.of(context).textTheme.subtitle1.copyWith( - fontWeight: FontWeight.bold, - ), + style: StreamChatTheme.of(context) + .textTheme + .headlineBold + .copyWith(color: Colors.black), ), leading: IconButton( icon: StreamSvgIcon.left( diff --git a/example/lib/chips_input_text_field.dart b/example/lib/chips_input_text_field.dart index 2ef308f8..efa3b10e 100644 --- a/example/lib/chips_input_text_field.dart +++ b/example/lib/chips_input_text_field.dart @@ -78,10 +78,10 @@ class ChipInputTextFieldState extends State> { padding: const EdgeInsets.symmetric(vertical: 4.0), child: Text( 'TO:', - style: TextStyle( - fontSize: 12, - color: Colors.black.withOpacity(0.5), - ), + style: StreamChatTheme.of(context) + .textTheme + .footnote + .copyWith(color: Colors.black.withOpacity(.5)), ), ), SizedBox(width: 12), @@ -111,10 +111,11 @@ class ChipInputTextFieldState extends State> { disabledBorder: InputBorder.none, contentPadding: const EdgeInsets.only(top: 4.0), hintText: widget.hint, - hintStyle: TextStyle( - color: Colors.black.withOpacity(0.5), - fontSize: 14, - ), + hintStyle: StreamChatTheme.of(context) + .textTheme + .body + .copyWith( + color: Colors.black.withOpacity(.5)), ), ), ], diff --git a/example/lib/choose_user_page.dart b/example/lib/choose_user_page.dart index c728a193..9c732145 100644 --- a/example/lib/choose_user_page.dart +++ b/example/lib/choose_user_page.dart @@ -80,19 +80,12 @@ class ChooseUserPage extends StatelessWidget { padding: const EdgeInsets.only(bottom: 13.0), child: Text( 'Welcome to Stream Chat', - style: TextStyle( - fontSize: 22, - color: Colors.black, - fontWeight: FontWeight.bold, - ), + style: StreamChatTheme.of(context).textTheme.title, ), ), Text( 'Select a user to try the Flutter SDK:', - style: TextStyle( - fontSize: 14.5, - color: Colors.black, - ), + style: StreamChatTheme.of(context).textTheme.body, ), Expanded( child: Padding( @@ -169,9 +162,18 @@ class ChooseUserPage extends StatelessWidget { ), title: Text( user.name, - style: TextStyle(fontWeight: FontWeight.bold), + style: + StreamChatTheme.of(context).textTheme.bodyBold, + ), + subtitle: Text( + 'Stream test account', + style: StreamChatTheme.of(context) + .textTheme + .footnote + .copyWith( + color: Color(0xff7A7A7A), + ), ), - subtitle: Text('Stream test account'), trailing: SvgPicture.asset( 'assets/icon_arrow_right.svg', height: 24, @@ -192,9 +194,17 @@ class ChooseUserPage extends StatelessWidget { ), title: Text( 'Advanced Options', - style: TextStyle(fontWeight: FontWeight.bold), + style: StreamChatTheme.of(context).textTheme.bodyBold, + ), + subtitle: Text( + 'Custom settings', + style: StreamChatTheme.of(context) + .textTheme + .footnote + .copyWith( + color: Color(0xff7A7A7A), + ), ), - subtitle: Text('Custom settings'), trailing: SvgPicture.asset( 'assets/icon_arrow_right.svg', height: 24, diff --git a/example/lib/main.dart b/example/lib/main.dart index 4b529e23..8749a2cf 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -123,6 +123,9 @@ class _HomePageState extends State { bottomNavigationBar: BottomNavigationBar( currentIndex: _currentIndex, items: _navBarItems, + selectedLabelStyle: StreamChatTheme.of(context).textTheme.footnoteBold, + unselectedLabelStyle: + StreamChatTheme.of(context).textTheme.footnoteBold, type: BottomNavigationBarType.fixed, selectedItemColor: Colors.black, unselectedItemColor: Colors.grey, diff --git a/example/lib/new_chat_screen.dart b/example/lib/new_chat_screen.dart index 5fbfbf07..5caa4c6f 100644 --- a/example/lib/new_chat_screen.dart +++ b/example/lib/new_chat_screen.dart @@ -113,10 +113,10 @@ class _NewChatScreenState extends State { leading: const StreamBackButton(), title: Text( 'New Chat', - style: TextStyle( - color: Colors.black, - fontSize: 16, - ), + style: StreamChatTheme.of(context) + .textTheme + .headlineBold + .copyWith(color: Colors.black), ), centerTitle: true, ), @@ -203,10 +203,7 @@ class _NewChatScreenState extends State { SizedBox(width: 8), Text( 'Create a Group', - style: TextStyle( - fontWeight: FontWeight.bold, - fontSize: 16, - ), + style: StreamChatTheme.of(context).textTheme.bodyBold, ), ], ), @@ -233,13 +230,13 @@ class _NewChatScreenState extends State { horizontal: 8, ), child: Text( - _isSearchActive - ? "Matches for \"$_userNameQuery\"" - : 'On the platform', - style: TextStyle( - color: Colors.black.withOpacity(0.5), - ), - ), + _isSearchActive + ? "Matches for \"$_userNameQuery\"" + : 'On the platform', + style: StreamChatTheme.of(context) + .textTheme + .footnote + .copyWith(color: Colors.black.withOpacity(.5))), ), ), Expanded( @@ -299,7 +296,14 @@ class _NewChatScreenState extends State { ), ), Text( - 'No user matches these keywords...'), + 'No user matches these keywords...', + style: StreamChatTheme.of(context) + .textTheme + .footnote + .copyWith( + color: Colors.black + .withOpacity(.5)), + ), ], ), ), diff --git a/example/lib/new_group_chat_screen.dart b/example/lib/new_group_chat_screen.dart index ff77e44d..ba477a73 100644 --- a/example/lib/new_group_chat_screen.dart +++ b/example/lib/new_group_chat_screen.dart @@ -261,7 +261,14 @@ class _NewGroupChatScreenState extends State { color: Colors.grey, ), ), - Text('No user matches these keywords...'), + Text( + 'No user matches these keywords...', + style: StreamChatTheme.of(context) + .textTheme + .footnote + .copyWith( + color: Colors.black.withOpacity(.5)), + ), ], ), ), diff --git a/example/lib/search_text_field.dart b/example/lib/search_text_field.dart index e32bb88b..00859b59 100644 --- a/example/lib/search_text_field.dart +++ b/example/lib/search_text_field.dart @@ -40,6 +40,7 @@ class SearchTextField extends StatelessWidget { controller: controller, onChanged: onChanged, decoration: InputDecoration( + prefixText: ' ', prefixIconConstraints: BoxConstraints.tight(Size(40, 24)), prefixIcon: Padding( padding: const EdgeInsets.only( @@ -52,10 +53,10 @@ class SearchTextField extends StatelessWidget { ), ), hintText: hintText, - hintStyle: TextStyle( - color: Colors.black.withOpacity(0.5), - fontSize: 14, - ), + hintStyle: StreamChatTheme.of(context) + .textTheme + .body + .copyWith(color: Colors.black.withOpacity(.5)), contentPadding: const EdgeInsets.all(0), border: OutlineInputBorder( borderSide: BorderSide.none, diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 6ae2ab54..c5bfa14f 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -1,6 +1,6 @@ name: example description: A new Flutter project. -version: 1.0.87+89 +version: 1.0.88+90 environment: sdk: ">=2.2.2 <3.0.0" diff --git a/lib/src/channel_list_header.dart b/lib/src/channel_list_header.dart index 0a01733b..41b283f5 100644 --- a/lib/src/channel_list_header.dart +++ b/lib/src/channel_list_header.dart @@ -144,13 +144,8 @@ class ChannelListHeader extends StatelessWidget implements PreferredSizeWidget { Widget _buildConnectedTitleState(BuildContext context) => Text( 'Stream Chat', - style: StreamChatTheme.of(context) - .channelTheme - .channelHeaderTheme - .title - .copyWith( - fontSize: 16, - fontWeight: FontWeight.bold, + style: StreamChatTheme.of(context).textTheme.headlineBold.copyWith( + color: Colors.black, ), ); diff --git a/lib/src/channel_list_view.dart b/lib/src/channel_list_view.dart index 1a431672..8301f339 100644 --- a/lib/src/channel_list_view.dart +++ b/lib/src/channel_list_view.dart @@ -210,9 +210,9 @@ class _ChannelListViewState extends State padding: const EdgeInsets.all(8.0), child: Text( 'Let’s start chatting!', - style: TextStyle( - fontSize: 16, - ), + style: StreamChatTheme.of(context) + .textTheme + .headline, ), ), Padding( @@ -223,10 +223,12 @@ class _ChannelListViewState extends State child: Text( 'How about sending your first message to a friend?', textAlign: TextAlign.center, - style: TextStyle( - fontSize: 14, - color: Color(0xff7A7A7A), - ), + style: StreamChatTheme.of(context) + .textTheme + .body + .copyWith( + color: Color(0xff7A7A7A), + ), ), ), ], @@ -242,11 +244,13 @@ class _ChannelListViewState extends State onPressed: widget.onStartChatPressed, child: Text( 'Start a chat', - style: TextStyle( - color: - StreamChatTheme.of(context).accentColor, - fontWeight: FontWeight.bold, - ), + style: StreamChatTheme.of(context) + .textTheme + .bodyBold + .copyWith( + color: StreamChatTheme.of(context) + .accentColor, + ), ), ), ), diff --git a/lib/src/channel_preview.dart b/lib/src/channel_preview.dart index 26f68812..fb0a95c7 100644 --- a/lib/src/channel_preview.dart +++ b/lib/src/channel_preview.dart @@ -49,6 +49,9 @@ class ChannelPreview extends StatelessWidget { return Opacity( opacity: snapshot.data ? 0.5 : 1, child: ListTile( + contentPadding: const EdgeInsets.symmetric( + horizontal: 8, + ), onTap: () { if (onTap != null) { onTap(channel); diff --git a/lib/src/message_list_view.dart b/lib/src/message_list_view.dart index 3feda8ce..8a4ac9c3 100644 --- a/lib/src/message_list_view.dart +++ b/lib/src/message_list_view.dart @@ -195,10 +195,10 @@ class _MessageListViewState extends State { return Center( child: Text( 'No chats here yet...', - style: TextStyle( - fontSize: 12, - color: Colors.black.withOpacity(.5), - ), + style: StreamChatTheme.of(context) + .textTheme + .footnote + .copyWith(color: Colors.black.withOpacity(.5)), ), ); } diff --git a/lib/src/message_search_item.dart b/lib/src/message_search_item.dart index 3e786b9a..0fba5d45 100644 --- a/lib/src/message_search_item.dart +++ b/lib/src/message_search_item.dart @@ -126,8 +126,6 @@ class MessageSearchItem extends StatelessWidget { maxLines: 1, overflow: TextOverflow.ellipsis, style: StreamChatTheme.of(context).channelPreviewTheme.subtitle.copyWith( - color: - StreamChatTheme.of(context).channelPreviewTheme.subtitle.color, fontStyle: (message.isSystem || message.isDeleted) ? FontStyle.italic : FontStyle.normal, diff --git a/lib/src/stream_chat_theme.dart b/lib/src/stream_chat_theme.dart index 54b096d1..3693f3d8 100644 --- a/lib/src/stream_chat_theme.dart +++ b/lib/src/stream_chat_theme.dart @@ -42,6 +42,9 @@ class StreamChatTheme extends InheritedWidget { /// Theme data class StreamChatThemeData { + /// The text themes used in the widgets + final TextTheme textTheme; + /// Primary color of the chat widgets final Color primaryColor; @@ -80,6 +83,7 @@ class StreamChatThemeData { /// Create a theme from scratch StreamChatThemeData({ + this.textTheme, this.primaryColor, this.secondaryColor, this.accentColor, @@ -131,6 +135,7 @@ class StreamChatThemeData { /// Creates a copy of [StreamChatThemeData] with specified attributes overridden. StreamChatThemeData copyWith({ + TextTheme textTheme, Color primaryColor, Color secondaryColor, Color accentColor, @@ -145,6 +150,16 @@ class StreamChatThemeData { List reactionIcons, }) => StreamChatThemeData( + textTheme: this.textTheme?.copyWith( + title: textTheme?.title, + body: textTheme?.body, + bodyBold: textTheme?.bodyBold, + captionBold: textTheme?.captionBold, + footnote: textTheme?.footnote, + footnoteBold: textTheme?.footnoteBold, + headline: textTheme?.headline, + headlineBold: textTheme?.headlineBold, + ), primaryColor: primaryColor ?? this.primaryColor, secondaryColor: secondaryColor ?? this.secondaryColor, primaryIconTheme: primaryIconTheme ?? this.primaryIconTheme, @@ -152,17 +167,12 @@ class StreamChatThemeData { defaultChannelImage: defaultChannelImage ?? this.defaultChannelImage, defaultUserImage: defaultUserImage ?? this.defaultUserImage, backgroundColor: backgroundColor ?? this.backgroundColor, - channelPreviewTheme: channelPreviewTheme?.copyWith( - title: - channelPreviewTheme.title ?? this.channelPreviewTheme.title, - subtitle: channelPreviewTheme.subtitle ?? - this.channelPreviewTheme.subtitle, - lastMessageAt: channelPreviewTheme.lastMessageAt ?? - this.channelPreviewTheme.lastMessageAt, - avatarTheme: channelPreviewTheme.avatarTheme ?? - this.channelPreviewTheme.avatarTheme, - ) ?? - this.channelPreviewTheme, + channelPreviewTheme: this.channelPreviewTheme?.copyWith( + title: channelPreviewTheme.title, + subtitle: channelPreviewTheme.subtitle, + lastMessageAt: channelPreviewTheme.lastMessageAt, + avatarTheme: channelPreviewTheme.avatarTheme, + ), channelTheme: channelTheme?.copyWith( channelHeaderTheme: channelTheme.channelHeaderTheme ?? this.channelTheme.channelHeaderTheme, @@ -218,7 +228,9 @@ class StreamChatThemeData { static StreamChatThemeData getDefaultTheme(ThemeData theme) { final accentColor = Color(0xff006cff); final isDark = theme.brightness == Brightness.dark; + final textTheme = TextTheme(); return StreamChatThemeData( + textTheme: textTheme, secondaryColor: Color(0xffEAEAEA), accentColor: accentColor, primaryColor: isDark ? Colors.black : Colors.white, @@ -242,19 +254,12 @@ class StreamChatThemeData { width: 40, ), ), - title: TextStyle( - fontSize: 14, - color: isDark ? Colors.white : Colors.black, - fontWeight: FontWeight.bold), - subtitle: TextStyle( - fontSize: 12.5, - color: (isDark ? Colors.white : Colors.black).withOpacity(0.5), + title: textTheme.bodyBold, + subtitle: textTheme.footnote.copyWith( + color: Color(0xff7A7A7A), ), - lastMessageAt: TextStyle( - fontSize: 11, - color: isDark - ? Colors.white.withOpacity(.5) - : Colors.black.withOpacity(.5), + lastMessageAt: textTheme.footnote.copyWith( + color: Colors.black.withOpacity(.5), ), ), channelTheme: ChannelTheme( @@ -375,6 +380,73 @@ class StreamChatThemeData { } } +class TextTheme { + final TextStyle title; + final TextStyle headlineBold; + final TextStyle headline; + final TextStyle bodyBold; + final TextStyle body; + final TextStyle footnoteBold; + final TextStyle footnote; + final TextStyle captionBold; + + TextTheme({ + this.title = const TextStyle( + fontSize: 22, + fontWeight: FontWeight.bold, + ), + this.headlineBold = const TextStyle( + fontSize: 16, + fontWeight: FontWeight.bold, + ), + this.headline = const TextStyle( + fontSize: 16, + fontWeight: FontWeight.w500, + ), + this.bodyBold = const TextStyle( + fontSize: 14, + fontWeight: FontWeight.bold, + ), + this.body = const TextStyle( + fontSize: 14, + fontWeight: FontWeight.w500, + ), + this.footnoteBold = const TextStyle( + fontSize: 12, + fontWeight: FontWeight.w500, + ), + this.footnote = const TextStyle( + fontSize: 12, + ), + this.captionBold = const TextStyle( + fontSize: 10, + fontWeight: FontWeight.bold, + ), + }); + + TextTheme copyWith({ + TextStyle body, + TextStyle title, + TextStyle headlineBold, + TextStyle headline, + TextStyle bodyBold, + TextStyle footnoteBold, + TextStyle footnote, + TextStyle captionBold, + }) { + return TextTheme( + body: body ?? this.body, + title: title ?? this.title, + headlineBold: headlineBold ?? this.headlineBold, + headline: headline ?? this.headline, + bodyBold: bodyBold ?? this.bodyBold, + footnoteBold: footnoteBold ?? this.footnoteBold, + footnote: footnote ?? this.footnote, + captionBold: captionBold ?? this.captionBold, + ); + } +} + /// Channel theme data class ChannelTheme { /// Theme of the [ChannelHeader] widget diff --git a/lib/src/user_item.dart b/lib/src/user_item.dart index f12e3e61..5a394865 100644 --- a/lib/src/user_item.dart +++ b/lib/src/user_item.dart @@ -83,13 +83,19 @@ class UserItem extends StatelessWidget { : null, title: Text( user.name, - style: TextStyle(fontWeight: FontWeight.bold), + style: StreamChatTheme.of(context).textTheme.bodyBold, ), subtitle: showLastOnline ? _buildLastActive(context) : null, ); } Widget _buildLastActive(context) { - return Text('Last online ${Jiffy(user.lastActive).fromNow()}'); + return Text( + 'Last online ${Jiffy(user.lastActive).fromNow()}', + style: StreamChatTheme.of(context) + .textTheme + .footnote + .copyWith(color: Colors.black.withOpacity(.5)), + ); } } diff --git a/lib/src/user_list_view.dart b/lib/src/user_list_view.dart index b57e2d55..e05bd49f 100644 --- a/lib/src/user_list_view.dart +++ b/lib/src/user_list_view.dart @@ -361,7 +361,7 @@ class _UserListViewState extends State header, style: TextStyle( fontWeight: FontWeight.bold, - fontSize: 12, + fontSize: 14.5, color: Colors.black.withOpacity(0.3)), ), ), From 4eadc49e474b795dbfb666f78215e833cdb12a1a Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Wed, 2 Dec 2020 14:41:08 +0100 Subject: [PATCH 0543/1140] fix button color and watch channel --- .gitignore | 3 ++- lib/src/image_actions_modal.dart | 29 ++++++++++++++++------------- lib/src/image_footer.dart | 2 +- 3 files changed, 19 insertions(+), 15 deletions(-) diff --git a/.gitignore b/.gitignore index 3a158cd4..1d3bae26 100644 --- a/.gitignore +++ b/.gitignore @@ -61,4 +61,5 @@ doc/api/ fvm google-services.json -example/ios/dist \ No newline at end of file +example/ios/dist +.vscode/ \ No newline at end of file diff --git a/lib/src/image_actions_modal.dart b/lib/src/image_actions_modal.dart index 7e50a4f7..fc81635c 100644 --- a/lib/src/image_actions_modal.dart +++ b/lib/src/image_actions_modal.dart @@ -149,19 +149,22 @@ class ImageActionsModal extends StatelessWidget { }), if (StreamChat.of(context).user.id == message.user.id) _buildButton( - context, - 'Delete', - StreamSvgIcon.delete( - size: 24.0, - color: Colors.black, - ), () { - Navigator.pop(context); - Navigator.pop(context); - StreamChat.of(context).client.deleteMessage( - message, - StreamChannel.of(context).channel.cid, - ); - }, color: Colors.red), + context, + 'Delete', + StreamSvgIcon.delete( + size: 24.0, + color: Color(0xffFF3742), + ), + () { + Navigator.pop(context); + Navigator.pop(context); + StreamChat.of(context).client.deleteMessage( + message, + StreamChannel.of(context).channel.cid, + ); + }, + color: Color(0xffFF3742), + ), ], ).toList(), ), diff --git a/lib/src/image_footer.dart b/lib/src/image_footer.dart index 9455d8f3..09a32e78 100644 --- a/lib/src/image_footer.dart +++ b/lib/src/image_footer.dart @@ -609,7 +609,7 @@ class _ImageFooterState extends State { ], }); - await c.create(); + await c.watch(); final message = Message( text: text, From 390062f1c20879183578be66a59a7f6ce5521cdb Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Wed, 2 Dec 2020 19:30:24 +0530 Subject: [PATCH 0544/1140] feat: 2 way pagination Signed-off-by: Sahil Kumar --- example/lib/main.dart | 230 +++++++++++++++-------------- example/lib/routes/app_routes.dart | 8 +- lib/src/message_list_view.dart | 19 ++- lib/src/stream_channel.dart | 98 +++++++++--- pubspec.yaml | 5 +- 5 files changed, 219 insertions(+), 141 deletions(-) diff --git a/example/lib/main.dart b/example/lib/main.dart index 4b529e23..f1667139 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -294,130 +294,136 @@ class _ChannelListPageState extends State { @override Widget build(BuildContext context) { final user = StreamChat.of(context).user; - return ChannelsBloc( - child: MessageSearchBloc( - child: Column( - children: [ - SearchTextField( - controller: _controller, - showCloseButton: _isSearchActive, - ), - Expanded( - child: AnimatedSwitcher( - duration: const Duration(milliseconds: 350), - child: GestureDetector( - behavior: HitTestBehavior.opaque, - onPanDown: (_) => FocusScope.of(context).unfocus(), - child: _isSearchActive - ? MessageSearchListView( - messageQuery: _channelQuery, - filters: { - 'members': { - r'$in': [user.id] - } - }, - sortOptions: [ - SortOption( - 'created_at', - direction: SortOption.ASC, - ), - ], - paginationParams: PaginationParams(limit: 20), - onItemTap: (message) {}, - ) - : ChannelListView( - onStartChatPressed: () { - Navigator.pushNamed(context, Routes.NEW_CHAT); - }, - swipeToAction: true, - filter: { - 'members': { - r'$in': [user.id], + return WillPopScope( + onWillPop: () async { + if (_isSearchActive) { + _controller.clear(); + setState(() => _isSearchActive = false); + return false; + } + return true; + }, + child: ChannelsBloc( + child: MessageSearchBloc( + child: Column( + children: [ + SearchTextField( + controller: _controller, + showCloseButton: _isSearchActive, + ), + Expanded( + child: AnimatedSwitcher( + duration: const Duration(milliseconds: 350), + child: GestureDetector( + behavior: HitTestBehavior.opaque, + onPanDown: (_) => FocusScope.of(context).unfocus(), + child: _isSearchActive + ? MessageSearchListView( + messageQuery: _channelQuery, + filters: { + 'members': { + r'$in': [user.id] + } }, - }, - options: { - 'presence': true, - }, - pagination: PaginationParams( - limit: 20, + sortOptions: [ + SortOption( + 'created_at', + direction: SortOption.ASC, + ), + ], + paginationParams: PaginationParams(limit: 20), + onItemTap: (messageResponse) async { + final client = StreamChat.of(context).client; + final message = messageResponse.message; + final channel = Channel.fromState( + client, + ChannelState( + channel: messageResponse.channel, + messages: [message], + ), + ); + await Future.wait([ + channel.query( + messagesPagination: PaginationParams( + lessThan: message.id, + limit: 25, + ), + preferOffline: true, + ), + channel.query( + messagesPagination: PaginationParams( + greaterThan: message.id, + limit: 25, + ), + preferOffline: true, + ), + ]); + final messages = channel.state.messages; + final totalMessages = messages.length; + final messageIndex = messages + .indexWhere((e) => e.id == message.id); + final initialIndex = totalMessages - messageIndex; + final bool isFirstMessage = messageIndex == 0; + Navigator.pushNamed( + context, + Routes.CHANNEL_PAGE, + arguments: ChannelPageArgs( + channel: channel, + initialScrollIndex: initialIndex, + initialAlignment: isFirstMessage ? 0 : 0.5, + ), + ); + }, + ) + : ChannelListView( + onStartChatPressed: () { + Navigator.pushNamed(context, Routes.NEW_CHAT); + }, + swipeToAction: true, + filter: { + 'members': { + r'$in': [user.id], + }, + }, + options: { + 'presence': true, + }, + pagination: PaginationParams( + limit: 20, + ), + channelWidget: ChannelPage(), ), - channelWidget: ChannelPage(), - ), + ), ), ), - ), - ], + ], + ), ), ), ); } } -class ChannelQuerySearchResultPage extends StatelessWidget { - final Stream> searchResultStream; +class ChannelPageArgs { + final Channel channel; + final int initialScrollIndex; + final double initialAlignment; - const ChannelQuerySearchResultPage({ - Key key, - @required this.searchResultStream, - }) : super(key: key); - - @override - Widget build(BuildContext context) { - return StreamBuilder>( - initialData: const [], - stream: searchResultStream, - builder: (context, snapshot) { - final result = snapshot.data; - return Column( - children: [ - if (result.isNotEmpty) - Container( - width: double.maxFinite, - decoration: BoxDecoration( - gradient: LinearGradient( - begin: Alignment.centerLeft, - end: Alignment.centerRight, - colors: [ - Colors.black.withOpacity(0.02), - Colors.white.withOpacity(0.05), - ], - stops: [0, 1], - ), - ), - child: Padding( - padding: const EdgeInsets.symmetric( - vertical: 8, - horizontal: 8, - ), - child: Text( - '${result.length} results', - style: TextStyle( - color: Colors.black.withOpacity(0.5), - ), - ), - ), - ), - Expanded( - child: ListView.builder( - itemCount: result.length, - itemBuilder: (context, index) { - return ListTile( - leading: UserAvatar(), - title: Text(result[index].toJson().toString()), - ); - }, - ), - ), - ], - ); - }, - ); - } + const ChannelPageArgs({ + this.channel, + this.initialScrollIndex = 0, + this.initialAlignment = 0, + }); } class ChannelPage extends StatelessWidget { + final int initialScrollIndex; + final double initialAlignment; + const ChannelPage({ Key key, + this.initialScrollIndex = 0, + this.initialAlignment = 0, }) : super(key: key); @override @@ -433,6 +439,8 @@ class ChannelPage extends StatelessWidget { child: Stack( children: [ MessageListView( + initialScrollIndex: initialScrollIndex, + initialAlignment: initialAlignment, threadBuilder: (_, parentMessage) { return ThreadPage( parent: parentMessage, @@ -467,10 +475,14 @@ class ChannelPage extends StatelessWidget { class ThreadPage extends StatelessWidget { final Message parent; + final int initialScrollIndex; + final double initialAlignment; ThreadPage({ Key key, this.parent, + this.initialScrollIndex = 0, + this.initialAlignment = 0, }) : super(key: key); @override @@ -484,6 +496,8 @@ class ThreadPage extends StatelessWidget { Expanded( child: MessageListView( parentMessage: parent, + initialScrollIndex: initialScrollIndex, + initialAlignment: initialAlignment, ), ), if (parent.type != 'deleted') diff --git a/example/lib/routes/app_routes.dart b/example/lib/routes/app_routes.dart index 6b0529e1..8ee907b8 100644 --- a/example/lib/routes/app_routes.dart +++ b/example/lib/routes/app_routes.dart @@ -34,9 +34,13 @@ class AppRoutes { return MaterialPageRoute( settings: const RouteSettings(name: Routes.CHANNEL_PAGE), builder: (_) { + final arg = args as ChannelPageArgs; return StreamChannel( - channel: args as Channel, - child: ChannelPage(), + channel: arg.channel, + child: ChannelPage( + initialScrollIndex: arg.initialScrollIndex, + initialAlignment: arg.initialAlignment, + ), ); }); case Routes.NEW_CHAT: diff --git a/lib/src/message_list_view.dart b/lib/src/message_list_view.dart index 3feda8ce..f9e40bf7 100644 --- a/lib/src/message_list_view.dart +++ b/lib/src/message_list_view.dart @@ -480,8 +480,8 @@ class _MessageListViewState extends State { } else { streamChannel.getReplies(widget.parentMessage.id); } + _topWasVisible = !topIsVisible; } - _topWasVisible = topIsVisible; }, ); } @@ -515,14 +515,21 @@ class _MessageListViewState extends State { key: ValueKey('BOTTOM-MESSAGE'), onVisibilityChanged: (visibility) { final isVisible = visibility.visibleBounds != Rect.zero; - if (isVisible && - !_bottomWasVisible && - streamChannel.channel.config?.readEvents == true) { - if (streamChannel.channel.state.unreadCount > 0) { + if (isVisible && !_bottomWasVisible) { + if (widget.parentMessage == null) { + streamChannel.queryMessages(direction: QueryDirection.bottom); + } else { + streamChannel.getReplies( + widget.parentMessage.id, + direction: QueryDirection.bottom, + ); + } + if (streamChannel.channel.config?.readEvents == true && + streamChannel.channel.state.unreadCount > 0) { streamChannel.channel.markRead(); } + _bottomWasVisible = !isVisible; } - _bottomWasVisible = isVisible; if (mounted) { setState(() { _showScrollToBottom = !isVisible; diff --git a/lib/src/stream_channel.dart b/lib/src/stream_channel.dart index 6fafa070..5dbfd103 100644 --- a/lib/src/stream_channel.dart +++ b/lib/src/stream_channel.dart @@ -4,6 +4,8 @@ import 'package:flutter/material.dart'; import 'package:rxdart/rxdart.dart'; import 'package:stream_chat/stream_chat.dart'; +enum QueryDirection { top, bottom } + /// Widget used to provide information about the channel to the widget tree /// /// Use [StreamChannel.of] to get the current [StreamChannelState] instance. @@ -52,34 +54,57 @@ class StreamChannelState extends State { /// The stream notifying the state of queryMessage call Stream get queryMessage => _queryMessageController.stream; - bool _paginationEnded = false; + bool _topPaginationEnded = false; + bool _bottomPaginationEnded = false; /// Calls [channel.query] updating [queryMessage] stream - void queryMessages() { - if (_queryMessageController.value == true || _paginationEnded) { + void queryMessages({QueryDirection direction = QueryDirection.top}) { + if (_queryMessageController.value == true || + (_topPaginationEnded && _bottomPaginationEnded)) { return; } _queryMessageController.add(true); - String firstId; - if (channel.state.messages.isNotEmpty) { - firstId = channel.state.messages.first.id; - } + String id; + PaginationParams params; - final messageLimit = 50; + final messageLimit = 25; + + if (channel.state.messages.isNotEmpty) { + switch (direction) { + case QueryDirection.top: + id = channel.state.messages.first.id; + params = PaginationParams( + lessThan: id, + limit: messageLimit, + ); + break; + case QueryDirection.bottom: + id = channel.state.messages.last.id; + params = PaginationParams( + greaterThan: id, + limit: messageLimit, + ); + break; + } + } widget.channel .query( - messagesPagination: PaginationParams( - lessThan: firstId, - limit: messageLimit, - ), + messagesPagination: params, preferOffline: true, ) .then((res) { if (res.messages.isEmpty || res.messages.length < messageLimit) { - _paginationEnded = true; + switch (direction) { + case QueryDirection.top: + _topPaginationEnded = true; + break; + case QueryDirection.bottom: + _bottomPaginationEnded = true; + break; + } } _queryMessageController.add(false); }).catchError((e, stack) { @@ -90,35 +115,60 @@ class StreamChannelState extends State { } /// Calls [channel.getReplies] updating [queryMessage] stream - Future getReplies(String parentId) async { - if (_queryMessageController.value == true || _paginationEnded) { + Future getReplies( + String parentId, { + QueryDirection direction = QueryDirection.top, + }) async { + if (_queryMessageController.value == true || + (_topPaginationEnded && _bottomPaginationEnded)) { return; } _queryMessageController.add(true); - String firstId; + String id; + PaginationParams params; + + final messageLimit = 50; + if (widget.channel.state.threads.containsKey(parentId)) { final thread = widget.channel.state.threads[parentId]; - if (thread != null && thread.isNotEmpty) { - firstId = thread?.first?.id; + switch (direction) { + case QueryDirection.top: + id = thread?.first?.id; + params = PaginationParams( + lessThan: id, + limit: messageLimit, + ); + break; + case QueryDirection.bottom: + id = thread?.last?.id; + params = PaginationParams( + greaterThan: id, + limit: messageLimit, + ); + break; + } } } - final messageLimit = 50; return widget.channel .getReplies( parentId, - PaginationParams( - lessThan: firstId, - limit: messageLimit, - ), + params, preferOffline: true, ) .then((res) { if (res.messages.isEmpty || res.messages.length < messageLimit) { - _paginationEnded = true; + switch (direction) { + case QueryDirection.top: + _topPaginationEnded = true; + break; + case QueryDirection.bottom: + _bottomPaginationEnded = true; + break; + } } _queryMessageController.add(false); }).catchError((e, stack) { diff --git a/pubspec.yaml b/pubspec.yaml index 75195a30..1d2a299e 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -28,7 +28,10 @@ dependencies: file_picker: ^2.0.12 image_picker: ^0.6.7+2 flutter_keyboard_visibility: ^3.3.0 - stream_chat: ^0.2.14 + stream_chat: + git: + url: https://github.com/GetStream/stream-chat-dart + ref: two-way-pagination mime: ^0.9.6+3 video_compress: ^2.1.1 visibility_detector: ^0.1.5 From 546fdaf4874658697f13df4f1e5bd91c706ce39b Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Wed, 2 Dec 2020 19:30:55 +0530 Subject: [PATCH 0545/1140] [LazyLoadScrollView] : Add support of onStartOfPage Signed-off-by: Sahil Kumar --- lib/src/lazy_load_scroll_view.dart | 49 ++++++++++++++++++++---------- 1 file changed, 33 insertions(+), 16 deletions(-) diff --git a/lib/src/lazy_load_scroll_view.dart b/lib/src/lazy_load_scroll_view.dart index e83fc777..5ca13d07 100644 --- a/lib/src/lazy_load_scroll_view.dart +++ b/lib/src/lazy_load_scroll_view.dart @@ -1,18 +1,18 @@ import 'package:flutter/widgets.dart'; -enum LoadingStatus { LOADING, STABLE } +enum _LoadingStatus { LOADING, STABLE } -/// Signature for EndOfPageListeners -typedef EndOfPageListenerCallback = void Function(); - -/// A widget that wraps a [Widget] and will trigger [onEndOfPage] when it -/// reaches the bottom of the list +/// A widget that wraps a [Widget] and will trigger [onEndOfPage]/[onStartOfPage] when it +/// reaches the bottom/start of the list class LazyLoadScrollView extends StatefulWidget { /// The [Widget] that this widget watches for changes on final Widget child; + /// Called when the [child] reaches the start of the list + final VoidCallback onStartOfPage; + /// Called when the [child] reaches the end of the list - final EndOfPageListenerCallback onEndOfPage; + final VoidCallback onEndOfPage; /// The offset to take into account when triggering [onEndOfPage] in pixels final int scrollOffset; @@ -20,14 +20,15 @@ class LazyLoadScrollView extends StatefulWidget { /// Used to determine if loading of new data has finished. You should use set this if you aren't using a FutureBuilder or StreamBuilder final bool isLoading; + /// Initiates a LazyLoadScrollView widget LazyLoadScrollView({ Key key, @required this.child, - @required this.onEndOfPage, + this.onStartOfPage, + this.onEndOfPage, this.isLoading = false, this.scrollOffset = 100, - }) : assert(onEndOfPage != null), - assert(child != null), + }) : assert(child != null), super(key: key); @override @@ -35,13 +36,13 @@ class LazyLoadScrollView extends StatefulWidget { } class _LazyLoadScrollViewState extends State { - LoadingStatus _loadMoreStatus = LoadingStatus.STABLE; + _LoadingStatus _loadMoreStatus = _LoadingStatus.STABLE; @override void didUpdateWidget(LazyLoadScrollView oldWidget) { super.didUpdateWidget(oldWidget); if (!widget.isLoading) { - _loadMoreStatus = LoadingStatus.STABLE; + _loadMoreStatus = _LoadingStatus.STABLE; } } @@ -59,21 +60,37 @@ class _LazyLoadScrollViewState extends State { notification.metrics.maxScrollExtent - notification.metrics.pixels <= widget.scrollOffset) { if (_loadMoreStatus != null && - _loadMoreStatus == LoadingStatus.STABLE) { - _loadMoreStatus = LoadingStatus.LOADING; + _loadMoreStatus == _LoadingStatus.STABLE) { + _loadMoreStatus = _LoadingStatus.LOADING; widget.onEndOfPage(); } } + if (notification.metrics.minScrollExtent < notification.metrics.pixels && + notification.metrics.pixels - notification.metrics.minScrollExtent <= + widget.scrollOffset) { + if (_loadMoreStatus != null && + _loadMoreStatus == _LoadingStatus.STABLE) { + _loadMoreStatus = _LoadingStatus.LOADING; + widget.onStartOfPage(); + } + } return true; } if (notification is OverscrollNotification) { if (notification.overscroll > 0) { if (_loadMoreStatus != null && - _loadMoreStatus == LoadingStatus.STABLE) { - _loadMoreStatus = LoadingStatus.LOADING; + _loadMoreStatus == _LoadingStatus.STABLE) { + _loadMoreStatus = _LoadingStatus.LOADING; widget.onEndOfPage(); } } + if (notification.overscroll < 0) { + if (_loadMoreStatus != null && + _loadMoreStatus == _LoadingStatus.STABLE) { + _loadMoreStatus = _LoadingStatus.LOADING; + widget.onStartOfPage(); + } + } return true; } return false; From c99d908e69af62fb3f86a773cde5efdc3069bbc6 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Wed, 2 Dec 2020 20:09:17 +0530 Subject: [PATCH 0546/1140] feat: Added pageview animation when picture modal clicked --- lib/src/full_screen_media.dart | 8 +++++++ lib/src/image_footer.dart | 38 ++++++++++++++++++++++------------ 2 files changed, 33 insertions(+), 13 deletions(-) diff --git a/lib/src/full_screen_media.dart b/lib/src/full_screen_media.dart index a0c4a03f..0857531a 100644 --- a/lib/src/full_screen_media.dart +++ b/lib/src/full_screen_media.dart @@ -169,6 +169,14 @@ class _FullScreenMediaState extends State mediaAttachments: widget.mediaAttachments, message: widget.message, videoPackages: videoPackages, + mediaSelectedCallBack: (val) { + setState(() { + _currentPage = val; + _pageController.animateToPage(val, + duration: Duration(milliseconds: 300), + curve: Curves.easeInOut); + }); + }, ), ], ), diff --git a/lib/src/image_footer.dart b/lib/src/image_footer.dart index 9455d8f3..51bb9009 100644 --- a/lib/src/image_footer.dart +++ b/lib/src/image_footer.dart @@ -36,6 +36,7 @@ class ImageFooter extends StatefulWidget { final Message message; final List videoPackages; + final ValueChanged mediaSelectedCallBack; /// Creates a channel header ImageFooter({ @@ -48,6 +49,7 @@ class ImageFooter extends StatefulWidget { this.mediaAttachments, this.message, this.videoPackages, + this.mediaSelectedCallBack, }) : preferredSize = Size.fromHeight(kToolbarHeight), super(key: key); @@ -213,23 +215,33 @@ class _ImageFooterState extends State { videoAttachments .indexOf(widget.mediaAttachments[position])]; - return FittedBox( - child: Chewie( - controller: controllerPackage.chewieController, + return InkWell( + onTap: () { + widget.mediaSelectedCallBack(position); + }, + child: FittedBox( + child: Chewie( + controller: controllerPackage.chewieController, + ), ), ); } else { - return Padding( - padding: const EdgeInsets.all(1.0), - child: AspectRatio( - child: CachedNetworkImage( - imageUrl: - widget.mediaAttachments[position].imageUrl ?? - widget.mediaAttachments[position].assetUrl ?? - widget.mediaAttachments[position].thumbUrl, - fit: BoxFit.cover, + return InkWell( + onTap: () { + widget.mediaSelectedCallBack(position); + }, + child: Padding( + padding: const EdgeInsets.all(1.0), + child: AspectRatio( + child: CachedNetworkImage( + imageUrl: widget + .mediaAttachments[position].imageUrl ?? + widget.mediaAttachments[position].assetUrl ?? + widget.mediaAttachments[position].thumbUrl, + fit: BoxFit.cover, + ), + aspectRatio: 1.0, ), - aspectRatio: 1.0, ), ); } From fc171ccdea90cd4ef3a56f14c75c67a157ed17d9 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Wed, 2 Dec 2020 16:38:32 +0100 Subject: [PATCH 0547/1140] fix video controls --- example/ios/Podfile.lock | 16 ++++++++++++++-- example/ios/Runner.xcodeproj/project.pbxproj | 4 ++++ example/pubspec.yaml | 2 +- lib/src/full_screen_media.dart | 10 ++++++++-- 4 files changed, 27 insertions(+), 5 deletions(-) diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock index 707e9fcb..223bab2b 100644 --- a/example/ios/Podfile.lock +++ b/example/ios/Podfile.lock @@ -30,6 +30,8 @@ PODS: - DKPhotoGallery/Resource (0.0.17): - SDWebImage - SwiftyGif + - esys_flutter_share (0.0.1): + - Flutter - file_picker (0.0.1): - DKImagePickerController/PhotoGallery - Flutter @@ -38,7 +40,7 @@ PODS: - Firebase/Messaging (6.33.0): - Firebase/CoreOnly - FirebaseMessaging (~> 4.7.0) - - firebase_core (0.5.2): + - firebase_core (0.5.2-1): - Firebase/CoreOnly (~> 6.33.0) - Flutter - firebase_messaging (7.0.3): @@ -106,6 +108,8 @@ PODS: - GoogleUtilities/Logger - GoogleUtilities/UserDefaults (6.7.2): - GoogleUtilities/Logger + - image_gallery_saver (1.5.0): + - Flutter - image_picker (0.0.1): - Flutter - nanopb (1.30906.0): @@ -161,6 +165,7 @@ PODS: - Flutter DEPENDENCIES: + - esys_flutter_share (from `.symlinks/plugins/esys_flutter_share/ios`) - file_picker (from `.symlinks/plugins/file_picker/ios`) - firebase_core (from `.symlinks/plugins/firebase_core/ios`) - firebase_messaging (from `.symlinks/plugins/firebase_messaging/ios`) @@ -170,6 +175,7 @@ DEPENDENCIES: - flutter_keyboard_visibility (from `.symlinks/plugins/flutter_keyboard_visibility/ios`) - flutter_local_notifications (from `.symlinks/plugins/flutter_local_notifications/ios`) - flutter_secure_storage (from `.symlinks/plugins/flutter_secure_storage/ios`) + - image_gallery_saver (from `.symlinks/plugins/image_gallery_saver/ios`) - image_picker (from `.symlinks/plugins/image_picker/ios`) - path_provider (from `.symlinks/plugins/path_provider/ios`) - permission_handler (from `.symlinks/plugins/permission_handler/ios`) @@ -206,6 +212,8 @@ SPEC REPOS: - SwiftyGif EXTERNAL SOURCES: + esys_flutter_share: + :path: ".symlinks/plugins/esys_flutter_share/ios" file_picker: :path: ".symlinks/plugins/file_picker/ios" firebase_core: @@ -224,6 +232,8 @@ EXTERNAL SOURCES: :path: ".symlinks/plugins/flutter_local_notifications/ios" flutter_secure_storage: :path: ".symlinks/plugins/flutter_secure_storage/ios" + image_gallery_saver: + :path: ".symlinks/plugins/image_gallery_saver/ios" image_picker: :path: ".symlinks/plugins/image_picker/ios" path_provider: @@ -250,9 +260,10 @@ EXTERNAL SOURCES: SPEC CHECKSUMS: DKImagePickerController: b5eb7f7a388e4643264105d648d01f727110fc3d DKPhotoGallery: fdfad5125a9fdda9cc57df834d49df790dbb4179 + esys_flutter_share: 403498dab005b36ce1f8d7aff377e81f0621b0b4 file_picker: 3e6c3790de664ccf9b882732d9db5eaf6b8d4eb1 Firebase: 8db6f2d1b2c5e2984efba4949a145875a8f65fe5 - firebase_core: 350ba329d1641211bc6183a3236893cafdacfea7 + firebase_core: 7423d688a1c6f2f2d859d64ae26991be39989781 firebase_messaging: 0aea2cd5885b65e19ede58ee3507f485c992cc75 FirebaseCore: d889d9e12535b7f36ac8bfbf1713a0836a3012cd FirebaseCoreDiagnostics: 770ac5958e1372ce67959ae4b4f31d8e127c3ac1 @@ -268,6 +279,7 @@ SPEC CHECKSUMS: FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a GoogleDataTransport: f56af7caa4ed338dc8e138a5d7c5973e66440833 GoogleUtilities: 7f2f5a07f888cdb145101d6042bc4422f57e70b3 + image_gallery_saver: 259eab68fb271cfd57d599904f7acdc7832e7ef2 image_picker: 9c3312491f862b28d21ecd8fdf0ee14e601b3f09 nanopb: 59317e09cf1f1a0af72f12af412d54edf52603fc path_provider: abfe2b5c733d04e238b0d8691db0cfd63a27a93c diff --git a/example/ios/Runner.xcodeproj/project.pbxproj b/example/ios/Runner.xcodeproj/project.pbxproj index 1a50ae5b..1e7527eb 100644 --- a/example/ios/Runner.xcodeproj/project.pbxproj +++ b/example/ios/Runner.xcodeproj/project.pbxproj @@ -320,12 +320,14 @@ "${BUILT_PRODUCTS_DIR}/Protobuf/Protobuf.framework", "${BUILT_PRODUCTS_DIR}/SDWebImage/SDWebImage.framework", "${BUILT_PRODUCTS_DIR}/SwiftyGif/SwiftyGif.framework", + "${BUILT_PRODUCTS_DIR}/esys_flutter_share/esys_flutter_share.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}/flutter_secure_storage/flutter_secure_storage.framework", + "${BUILT_PRODUCTS_DIR}/image_gallery_saver/image_gallery_saver.framework", "${BUILT_PRODUCTS_DIR}/image_picker/image_picker.framework", "${BUILT_PRODUCTS_DIR}/nanopb/nanopb.framework", "${BUILT_PRODUCTS_DIR}/path_provider/path_provider.framework", @@ -352,12 +354,14 @@ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Protobuf.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SDWebImage.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SwiftyGif.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/esys_flutter_share.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}/flutter_secure_storage.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/image_gallery_saver.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/image_picker.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/nanopb.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/path_provider.framework", diff --git a/example/pubspec.yaml b/example/pubspec.yaml index e0be8fc9..f5beccb2 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -1,6 +1,6 @@ name: example description: A new Flutter project. -version: 1.0.78+80 +version: 1.0.79+81 environment: sdk: ">=2.2.2 <3.0.0" diff --git a/lib/src/full_screen_media.dart b/lib/src/full_screen_media.dart index 0857531a..7e3f3d7d 100644 --- a/lib/src/full_screen_media.dart +++ b/lib/src/full_screen_media.dart @@ -135,8 +135,13 @@ class _FullScreenMediaState extends State _controller.forward(); } }, - child: Chewie( - controller: controllerPackage.chewieController, + child: Padding( + padding: const EdgeInsets.symmetric( + vertical: 50.0, + ), + child: Chewie( + controller: controllerPackage.chewieController, + ), ), ); } @@ -175,6 +180,7 @@ class _FullScreenMediaState extends State _pageController.animateToPage(val, duration: Duration(milliseconds: 300), curve: Curves.easeInOut); + Navigator.pop(context); }); }, ), From e29b8fe9f1cc27dc13eed2a61166da90becb9734 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Wed, 2 Dec 2020 16:46:05 +0100 Subject: [PATCH 0548/1140] fix video boxfit --- lib/src/video_attachment.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/video_attachment.dart b/lib/src/video_attachment.dart index 782b81cb..21ede87a 100644 --- a/lib/src/video_attachment.dart +++ b/lib/src/video_attachment.dart @@ -110,7 +110,7 @@ class _VideoAttachmentState extends State { children: [ Expanded( child: FittedBox( - fit: BoxFit.cover, + fit: BoxFit.none, child: Stack( children: [ Chewie( From c145ed0971ba7d759a4a08fa3300fa752eadb9c9 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Wed, 2 Dec 2020 17:16:11 +0100 Subject: [PATCH 0549/1140] add onLongPress on channel when using custom channel builder --- lib/src/channel_list_view.dart | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/src/channel_list_view.dart b/lib/src/channel_list_view.dart index 1a431672..03284c6d 100644 --- a/lib/src/channel_list_view.dart +++ b/lib/src/channel_list_view.dart @@ -481,6 +481,11 @@ class _ChannelListViewState extends State onTap: () { onTap(channel, widget.channelWidget); }, + onLongPress: widget.onChannelLongPress != null + ? () { + widget.onChannelLongPress(channel); + } + : null, ), ), ), From 759fe5510ee96c089b596bb5ed70710f9b1999dd Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Thu, 3 Dec 2020 14:28:35 +0530 Subject: [PATCH 0550/1140] [MessageSearchListView] : Minor improvements. Signed-off-by: Sahil Kumar --- lib/src/message_search_list_view.dart | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/lib/src/message_search_list_view.dart b/lib/src/message_search_list_view.dart index 8b346570..087ae839 100644 --- a/lib/src/message_search_list_view.dart +++ b/lib/src/message_search_list_view.dart @@ -14,6 +14,10 @@ typedef MessageSearchItemTapCallback = void Function(GetMessageResponse); typedef MessageSearchItemBuilder = Widget Function( BuildContext, GetMessageResponse); +/// Builder used when [MessageSearchListView] is empty +typedef EmptyMessageSearchBuilder = Widget Function( + BuildContext context, String searchQuery); + /// /// It shows the list of searched messages. /// @@ -85,7 +89,7 @@ class MessageSearchListView extends StatefulWidget { final MessageSearchItemTapCallback onItemTap; /// The builder used when the channel list is empty. - final WidgetBuilder emptyBuilder; + final EmptyMessageSearchBuilder emptyBuilder; /// The builder that will be used in case of error final Widget Function(Error error) errorBuilder; @@ -250,11 +254,10 @@ class _MessageSearchListViewState extends State { final items = snapshot.data; - if (items.isEmpty && widget.emptyBuilder != null) { - return widget.emptyBuilder(context); - } - - if (items.isEmpty && widget.emptyBuilder == null) { + if (items.isEmpty) { + if (widget.emptyBuilder != null) { + return widget.emptyBuilder(context, widget.messageQuery); + } return LayoutBuilder( builder: (context, viewportConstraints) { return SingleChildScrollView( From 4373888ae63fb2d7168b7fd895980d6b1f2b5b4a Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Thu, 3 Dec 2020 10:49:41 +0100 Subject: [PATCH 0551/1140] jump scrollview on new messages --- lib/src/message_list_view.dart | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/lib/src/message_list_view.dart b/lib/src/message_list_view.dart index f9e40bf7..803ce456 100644 --- a/lib/src/message_list_view.dart +++ b/lib/src/message_list_view.dart @@ -164,6 +164,7 @@ class _MessageListViewState extends State { Function _onThreadTap; bool _showScrollToBottom = false; ItemPositionsListener _itemPositionListener; + int messageListLength; @override Widget build(BuildContext context) { @@ -203,6 +204,22 @@ class _MessageListViewState extends State { ); } + final newMessagesListLength = messages.length; + + if (_itemPositionListener.itemPositions.value?.isNotEmpty == true && + messageListLength != null) { + final first = _itemPositionListener.itemPositions.value.first; + final diff = newMessagesListLength - messageListLength; + if (diff > 0) { + _scrollController.jumpTo( + index: first.index + diff, + alignment: first.itemLeadingEdge, + ); + } + } + + messageListLength = newMessagesListLength; + return Stack( alignment: Alignment.center, children: [ From f367e6b7a8e6273c2bfa8e6652c2c34b106dc825 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Thu, 3 Dec 2020 15:46:58 +0530 Subject: [PATCH 0552/1140] minor changes Signed-off-by: Sahil Kumar --- lib/src/message_list_view.dart | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/src/message_list_view.dart b/lib/src/message_list_view.dart index 803ce456..88e33ddc 100644 --- a/lib/src/message_list_view.dart +++ b/lib/src/message_list_view.dart @@ -164,7 +164,7 @@ class _MessageListViewState extends State { Function _onThreadTap; bool _showScrollToBottom = false; ItemPositionsListener _itemPositionListener; - int messageListLength; + int _messageListLength; @override Widget build(BuildContext context) { @@ -207,9 +207,9 @@ class _MessageListViewState extends State { final newMessagesListLength = messages.length; if (_itemPositionListener.itemPositions.value?.isNotEmpty == true && - messageListLength != null) { + _messageListLength != null) { final first = _itemPositionListener.itemPositions.value.first; - final diff = newMessagesListLength - messageListLength; + final diff = newMessagesListLength - _messageListLength; if (diff > 0) { _scrollController.jumpTo( index: first.index + diff, @@ -218,7 +218,7 @@ class _MessageListViewState extends State { } } - messageListLength = newMessagesListLength; + _messageListLength = newMessagesListLength; return Stack( alignment: Alignment.center, From 895497290c74ccdb97c1e5a9735d1151c6e9ed0b Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Tue, 1 Dec 2020 15:26:54 +0530 Subject: [PATCH 0553/1140] feat: Added file icons, added new file attachment and bg --- lib/src/file_attachment.dart | 96 +++++++++++++- lib/src/message_input.dart | 12 ++ lib/src/message_widget.dart | 55 ++++++-- lib/src/stream_svg_icon.dart | 240 +++++++++++++++++++++++++++++++++++ 4 files changed, 387 insertions(+), 16 deletions(-) diff --git a/lib/src/file_attachment.dart b/lib/src/file_attachment.dart index 05318862..ebbf57f6 100644 --- a/lib/src/file_attachment.dart +++ b/lib/src/file_attachment.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:stream_chat/stream_chat.dart'; +import 'package:stream_chat_flutter/src/stream_svg_icon.dart'; import 'package:stream_chat_flutter/src/utils.dart'; class FileAttachment extends StatelessWidget { @@ -17,16 +18,103 @@ class FileAttachment extends StatelessWidget { return Material( child: InkWell( onTap: () { - launchURL(context, attachment.assetUrl); + //launchURL(context, attachment.assetUrl); }, child: Container( width: size?.width ?? 100, - height: size?.height ?? 100, - child: Center( - child: Icon(Icons.attach_file), + decoration: BoxDecoration( + color: Colors.white, + ), + child: ListTile( + dense: true, + leading: Container( + child: _getFileTypeImage(attachment.extraData['mime_type']), + height: 40.0, + width: 33.33, + ), + title: Text( + attachment?.title ?? 'File', + style: TextStyle( + fontWeight: FontWeight.bold, + ), + maxLines: 3, + ), + subtitle: Text( + '${attachment.extraData['file_size'] ?? 'N/A'} bytes', + style: TextStyle( + color: Colors.black.withOpacity(0.5), + ), + ), + trailing: IconButton( + icon: StreamSvgIcon.cloud_download( + color: Colors.black, + ), + onPressed: () { + launchURL(context, attachment.assetUrl); + }, + ), ), ), ), ); } + + StreamSvgIcon _getFileTypeImage(String type) { + switch (type) { + case '7z': + return StreamSvgIcon.filetype_7z(); + break; + case 'csv': + return StreamSvgIcon.filetype_csv(); + break; + case 'doc': + return StreamSvgIcon.filetype_doc(); + break; + case 'docx': + return StreamSvgIcon.filetype_docx(); + break; + case 'html': + return StreamSvgIcon.filetype_html(); + break; + case 'md': + return StreamSvgIcon.filetype_md(); + break; + case 'odt': + return StreamSvgIcon.filetype_odt(); + break; + case 'pdf': + return StreamSvgIcon.filetype_pdf(); + break; + case 'ppt': + return StreamSvgIcon.filetype_ppt(); + break; + case 'pptx': + return StreamSvgIcon.filetype_pptx(); + break; + case 'rar': + return StreamSvgIcon.filetype_rar(); + break; + case 'rtf': + return StreamSvgIcon.filetype_rtf(); + break; + case 'tar': + return StreamSvgIcon.filetype_tar(); + break; + case 'txt': + return StreamSvgIcon.filetype_txt(); + break; + case 'xls': + return StreamSvgIcon.filetype_xls(); + break; + case 'xlsx': + return StreamSvgIcon.filetype_xlsx(); + break; + case 'zip': + return StreamSvgIcon.filetype_zip(); + break; + default: + return StreamSvgIcon.filetype_Generic(); + break; + } + } } diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 1dbc45df..c2d3d7e6 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -1562,12 +1562,24 @@ class MessageInputState extends State { attachmentType = mimeType.type; } + Map extraDataMap = {}; + + if (mimeType?.subtype != null) { + extraDataMap['mime_type'] = mimeType.subtype.toLowerCase(); + } + + if (file.size != null) { + extraDataMap['file_size'] = file.size; + } + final channel = StreamChannel.of(context).channel; final attachment = _SendingAttachment( file: file, attachment: Attachment( localUri: file.path != null ? Uri.parse(file.path) : null, type: attachmentType, + extraData: extraDataMap.isNotEmpty ? extraDataMap : null, + title: file.name ?? 'File', ), ); diff --git a/lib/src/message_widget.dart b/lib/src/message_widget.dart index 64dab4ac..3e83ac0d 100644 --- a/lib/src/message_widget.dart +++ b/lib/src/message_widget.dart @@ -223,6 +223,8 @@ class _MessageWidgetState extends State { widget.message.attachments?.any((element) => element.type == 'giphy') == true; + var user = StreamChat.of(context).user; + return Portal( child: Padding( padding: widget.padding ?? EdgeInsets.all(8), @@ -295,18 +297,47 @@ class _MessageWidgetState extends State { messageTheme: widget.messageTheme, ), ) - : Column( - crossAxisAlignment: - CrossAxisAlignment.start, - mainAxisSize: MainAxisSize.min, - children: [ - ..._parseAttachments(context), - if (widget.message.text - .trim() - .isNotEmpty && - !isGiphy) - _buildTextBubble(context), - ], + : Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.only( + topLeft: Radius.circular(8.0), + topRight: Radius.circular(8.0), + bottomRight: Radius.circular(8.0), + ), + border: Border.fromBorderSide( + BorderSide( + color: Color(0xFFE6E6E6), + )), + color: widget.message.attachments + .where((element) => + element.type == 'file') + .isEmpty + ? Colors.transparent + : (user.id == + widget.message.user.id + ? Color(0xFFE6E6E6) + : Colors.white), + ), + padding: EdgeInsets.all(widget + .message.attachments + .where((element) => + element.type == 'file') + .isEmpty + ? 0.0 + : 2.0), + child: Column( + crossAxisAlignment: + CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + ..._parseAttachments(context), + if (widget.message.text + .trim() + .isNotEmpty && + !isGiphy) + _buildTextBubble(context), + ], + ), ), ), if (widget.showReactionPickerIndicator) diff --git a/lib/src/stream_svg_icon.dart b/lib/src/stream_svg_icon.dart index e5ef7ec9..42fed46e 100644 --- a/lib/src/stream_svg_icon.dart +++ b/lib/src/stream_svg_icon.dart @@ -338,6 +338,30 @@ class StreamSvgIcon extends StatelessWidget { ); } + factory StreamSvgIcon.download({ + double size, + Color color, + }) { + return StreamSvgIcon( + assetName: 'Icon_download.svg', + color: color, + width: size, + height: size, + ); + } + + factory StreamSvgIcon.cloud_download({ + double size, + Color color, + }) { + return StreamSvgIcon( + assetName: 'Icon_cloud_download.svg', + color: color, + width: size, + height: size, + ); + } + factory StreamSvgIcon.copy({ double size, Color color, @@ -481,4 +505,220 @@ class StreamSvgIcon extends StatelessWidget { height: size, ); } + + factory StreamSvgIcon.filetype_7z({ + double size, + Color color, + }) { + return StreamSvgIcon( + assetName: 'filetype_7z.svg', + color: color, + width: size, + height: size, + ); + } + + factory StreamSvgIcon.filetype_csv({ + double size, + Color color, + }) { + return StreamSvgIcon( + assetName: 'filetype_CSV.svg', + color: color, + width: size, + height: size, + ); + } + + factory StreamSvgIcon.filetype_doc({ + double size, + Color color, + }) { + return StreamSvgIcon( + assetName: 'filetype_DOC.svg', + color: color, + width: size, + height: size, + ); + } + + factory StreamSvgIcon.filetype_docx({ + double size, + Color color, + }) { + return StreamSvgIcon( + assetName: 'filetype_DOCX.svg', + color: color, + width: size, + height: size, + ); + } + + factory StreamSvgIcon.filetype_Generic({ + double size, + Color color, + }) { + return StreamSvgIcon( + assetName: 'filetype_Generic.svg', + color: color, + width: size, + height: size, + ); + } + + factory StreamSvgIcon.filetype_html({ + double size, + Color color, + }) { + return StreamSvgIcon( + assetName: 'filetype_html.svg', + color: color, + width: size, + height: size, + ); + } + + factory StreamSvgIcon.filetype_md({ + double size, + Color color, + }) { + return StreamSvgIcon( + assetName: 'filetype_MD.svg', + color: color, + width: size, + height: size, + ); + } + + factory StreamSvgIcon.filetype_odt({ + double size, + Color color, + }) { + return StreamSvgIcon( + assetName: 'filetype_ODT.svg', + color: color, + width: size, + height: size, + ); + } + + factory StreamSvgIcon.filetype_pdf({ + double size, + Color color, + }) { + return StreamSvgIcon( + assetName: 'filetype_PDF.svg', + color: color, + width: size, + height: size, + ); + } + + factory StreamSvgIcon.filetype_ppt({ + double size, + Color color, + }) { + return StreamSvgIcon( + assetName: 'filetype_PPT.svg', + color: color, + width: size, + height: size, + ); + } + + factory StreamSvgIcon.filetype_pptx({ + double size, + Color color, + }) { + return StreamSvgIcon( + assetName: 'filetype_PPTX.svg', + color: color, + width: size, + height: size, + ); + } + + factory StreamSvgIcon.filetype_rar({ + double size, + Color color, + }) { + return StreamSvgIcon( + assetName: 'filetype_RAR.svg', + color: color, + width: size, + height: size, + ); + } + + factory StreamSvgIcon.filetype_rtf({ + double size, + Color color, + }) { + return StreamSvgIcon( + assetName: 'filetype_RTF.svg', + color: color, + width: size, + height: size, + ); + } + + factory StreamSvgIcon.filetype_tar({ + double size, + Color color, + }) { + return StreamSvgIcon( + assetName: 'filetype_TAR.svg', + color: color, + width: size, + height: size, + ); + } + + factory StreamSvgIcon.filetype_txt({ + double size, + Color color, + }) { + return StreamSvgIcon( + assetName: 'filetype_TXT.svg', + color: color, + width: size, + height: size, + ); + } + + factory StreamSvgIcon.filetype_xls({ + double size, + Color color, + }) { + return StreamSvgIcon( + assetName: 'filetype_XLS.svg', + color: color, + width: size, + height: size, + ); + } + + factory StreamSvgIcon.filetype_xlsx({ + double size, + Color color, + }) { + return StreamSvgIcon( + assetName: 'filetype_XLSX.svg', + color: color, + width: size, + height: size, + ); + } + + factory StreamSvgIcon.filetype_zip({ + double size, + Color color, + }) { + return StreamSvgIcon( + assetName: 'filetype_ZIP.svg', + color: color, + width: size, + height: size, + ); + } } From 922208224d6f571f861f9e78fcec82d3a0e1860a Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Tue, 1 Dec 2020 16:19:02 +0530 Subject: [PATCH 0554/1140] feat: Added file attachment to pick attachment section --- lib/src/file_attachment.dart | 24 ++++++--- lib/src/message_input.dart | 94 +++++++++++++++++++++++------------- lib/src/message_widget.dart | 56 ++++++++++++--------- 3 files changed, 109 insertions(+), 65 deletions(-) diff --git a/lib/src/file_attachment.dart b/lib/src/file_attachment.dart index ebbf57f6..fd6f152a 100644 --- a/lib/src/file_attachment.dart +++ b/lib/src/file_attachment.dart @@ -6,11 +6,13 @@ import 'package:stream_chat_flutter/src/utils.dart'; class FileAttachment extends StatelessWidget { final Attachment attachment; final Size size; + final Widget trailing; const FileAttachment({ Key key, @required this.attachment, this.size, + this.trailing, }) : super(key: key); @override @@ -22,8 +24,13 @@ class FileAttachment extends StatelessWidget { }, child: Container( width: size?.width ?? 100, + margin: trailing != null ? EdgeInsets.only(top: 4.0) : null, decoration: BoxDecoration( color: Colors.white, + borderRadius: trailing != null ? BorderRadius.circular(16.0) : null, + border: trailing != null + ? Border.fromBorderSide(BorderSide(color: Color(0xFFE6E6E6))) + : null, ), child: ListTile( dense: true, @@ -45,14 +52,15 @@ class FileAttachment extends StatelessWidget { color: Colors.black.withOpacity(0.5), ), ), - trailing: IconButton( - icon: StreamSvgIcon.cloud_download( - color: Colors.black, - ), - onPressed: () { - launchURL(context, attachment.assetUrl); - }, - ), + trailing: trailing ?? + IconButton( + icon: StreamSvgIcon.cloud_download( + color: Colors.black, + ), + onPressed: () { + launchURL(context, attachment.assetUrl); + }, + ), ), ), ), diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index c2d3d7e6..4119be7d 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -1201,44 +1201,72 @@ class MessageInputState extends State { Widget _buildAttachments() { return _attachments.isEmpty ? Container() - : LimitedBox( - maxHeight: 104.0, - child: ListView( - scrollDirection: Axis.horizontal, - children: _attachments + : Column( + children: [ + ..._attachments + .where((e) => e.attachment.type == 'file') .map( - (attachment) => Padding( - padding: const EdgeInsets.all(8.0), - child: ClipRRect( - borderRadius: BorderRadius.circular(10), - child: Stack( - children: [ - AspectRatio( - aspectRatio: 1.0, - child: Container( - height: 104, - width: 104, - child: _buildAttachment(attachment), - ), - ), - _buildRemoveButton(attachment), - attachment.uploaded - ? SizedBox() - : Positioned.fill( - child: Center( - child: Padding( - padding: const EdgeInsets.all(16.0), - child: CircularProgressIndicator(), - ), - ), - ), - ], - ), + (e) => FileAttachment( + attachment: e.attachment, + size: Size( + MediaQuery.of(context).size.width * 0.6, + MediaQuery.of(context).size.height * 0.3, + ), + trailing: IconButton( + icon: StreamSvgIcon.close_small(), + onPressed: () { + setState(() { + _attachments.remove(e); + }); + }, ), ), ) .toList(), - ), + if (_attachments.any((e) => e.attachment.type != 'file')) + LimitedBox( + maxHeight: 104.0, + child: ListView( + scrollDirection: Axis.horizontal, + children: _attachments + .where((e) => e.attachment.type != 'file') + .map( + (attachment) => Padding( + padding: const EdgeInsets.all(8.0), + child: ClipRRect( + borderRadius: BorderRadius.circular(10), + child: Stack( + children: [ + AspectRatio( + aspectRatio: 1.0, + child: Container( + height: 104, + width: 104, + child: _buildAttachment(attachment), + ), + ), + _buildRemoveButton(attachment), + attachment.uploaded + ? SizedBox() + : Positioned.fill( + child: Center( + child: Padding( + padding: + const EdgeInsets.all(16.0), + child: + CircularProgressIndicator(), + ), + ), + ), + ], + ), + ), + ), + ) + .toList(), + ), + ), + ], ); } diff --git a/lib/src/message_widget.dart b/lib/src/message_widget.dart index 3e83ac0d..6a35648d 100644 --- a/lib/src/message_widget.dart +++ b/lib/src/message_widget.dart @@ -225,6 +225,9 @@ class _MessageWidgetState extends State { var user = StreamChat.of(context).user; + bool hasFiles = + widget.message.attachments.any((element) => element.type == 'file'); + return Portal( child: Padding( padding: widget.padding ?? EdgeInsets.all(8), @@ -298,33 +301,38 @@ class _MessageWidgetState extends State { ), ) : Container( - decoration: BoxDecoration( - borderRadius: BorderRadius.only( - topLeft: Radius.circular(8.0), - topRight: Radius.circular(8.0), - bottomRight: Radius.circular(8.0), - ), - border: Border.fromBorderSide( - BorderSide( - color: Color(0xFFE6E6E6), - )), - color: widget.message.attachments - .where((element) => - element.type == 'file') - .isEmpty - ? Colors.transparent - : (user.id == - widget.message.user.id - ? Color(0xFFE6E6E6) - : Colors.white), - ), - padding: EdgeInsets.all(widget - .message.attachments + decoration: widget.message.attachments .where((element) => element.type == 'file') .isEmpty - ? 0.0 - : 2.0), + ? null + : BoxDecoration( + borderRadius: + BorderRadius.only( + topLeft: + Radius.circular(8.0), + topRight: + Radius.circular(8.0), + bottomRight: + Radius.circular(8.0), + ), + border: hasFiles + ? Border.fromBorderSide( + BorderSide( + color: + Color(0xFFE6E6E6), + )) + : null, + color: hasFiles + ? (user.id == + widget.message + .user.id + ? Color(0xFFE6E6E6) + : Colors.white) + : Colors.transparent, + ), + padding: EdgeInsets.all( + hasFiles ? 2.0 : 0.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, From a846048ef171457a5b3e2b7250b18e18feb12aea Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Tue, 1 Dec 2020 20:41:11 +0530 Subject: [PATCH 0555/1140] fix: Fixed multiple file upload --- lib/src/message_input.dart | 49 ++++++++++++++++++++++---------------- 1 file changed, 29 insertions(+), 20 deletions(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 4119be7d..489ba558 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -1203,26 +1203,35 @@ class MessageInputState extends State { ? Container() : Column( children: [ - ..._attachments - .where((e) => e.attachment.type == 'file') - .map( - (e) => FileAttachment( - attachment: e.attachment, - size: Size( - MediaQuery.of(context).size.width * 0.6, - MediaQuery.of(context).size.height * 0.3, - ), - trailing: IconButton( - icon: StreamSvgIcon.close_small(), - onPressed: () { - setState(() { - _attachments.remove(e); - }); - }, - ), - ), - ) - .toList(), + LimitedBox( + maxHeight: 73.0, + child: ListView( + scrollDirection: Axis.horizontal, + children: _attachments + .where((e) => e.attachment.type == 'file') + .map( + (e) => Padding( + padding: const EdgeInsets.symmetric(horizontal: 4.0), + child: FileAttachment( + attachment: e.attachment, + size: Size( + MediaQuery.of(context).size.width * 0.55, + MediaQuery.of(context).size.height * 0.3, + ), + trailing: IconButton( + icon: StreamSvgIcon.close_small(), + onPressed: () { + setState(() { + _attachments.remove(e); + }); + }, + ), + ), + ), + ) + .toList(), + ), + ), if (_attachments.any((e) => e.attachment.type != 'file')) LimitedBox( maxHeight: 104.0, From 9918a4bfde4ddb27079a5ce70323a6a0c480ad6c Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Wed, 2 Dec 2020 16:37:08 +0530 Subject: [PATCH 0556/1140] fix: Added boolean for picking one thing at a time -_- --- lib/src/message_input.dart | 84 +++++++++++++++++++++++--------------- 1 file changed, 51 insertions(+), 33 deletions(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 489ba558..bb9c8ec4 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -108,6 +108,7 @@ class MessageInput extends StatefulWidget { this.actionsLocation = ActionsLocation.left, this.attachmentThumbnailBuilders, this.focusNode, + this.enableFileAndImageAttachment = false, }) : super(key: key); /// Message to edit @@ -156,6 +157,9 @@ class MessageInput extends StatefulWidget { /// The focus node associated to the TextField final FocusNode focusNode; + /// Enables adding both file+images at the same time + final bool enableFileAndImageAttachment; + @override MessageInputState createState() => MessageInputState(); @@ -787,7 +791,14 @@ class MessageInputState extends State { onSelect: (media) async { if (!_attachments .any((element) => element.id == media.id)) { - _addAttachment(media); + if (widget.enableFileAndImageAttachment) { + _addAttachment(media); + } else { + if (!_attachments.any( + (element) => element.attachment?.type == 'file')) { + _addAttachment(media); + } + } } else { setState(() { _attachments @@ -850,7 +861,7 @@ class MessageInputState extends State { ); if (file.size > _kMaxAttachmentSize) { - if (medium.type == AssetType.video) { + if (medium?.type == AssetType.video) { final mediaInfo = await CompressVideoService.compressVideo(file.path); if (mediaInfo.filesize / (1024 * 1024) > _kMaxAttachmentSize) { @@ -1203,42 +1214,44 @@ class MessageInputState extends State { ? Container() : Column( children: [ - LimitedBox( - maxHeight: 73.0, - child: ListView( - scrollDirection: Axis.horizontal, - children: _attachments - .where((e) => e.attachment.type == 'file') - .map( - (e) => Padding( - padding: const EdgeInsets.symmetric(horizontal: 4.0), - child: FileAttachment( - attachment: e.attachment, - size: Size( - MediaQuery.of(context).size.width * 0.55, - MediaQuery.of(context).size.height * 0.3, - ), - trailing: IconButton( - icon: StreamSvgIcon.close_small(), - onPressed: () { - setState(() { - _attachments.remove(e); - }); - }, + if (_attachments.any((e) => e.attachment?.type == 'file')) + LimitedBox( + maxHeight: 73.0, + child: ListView( + scrollDirection: Axis.horizontal, + children: _attachments + .where((e) => e.attachment?.type == 'file') + .map( + (e) => Padding( + padding: + const EdgeInsets.symmetric(horizontal: 4.0), + child: FileAttachment( + attachment: e.attachment, + size: Size( + MediaQuery.of(context).size.width * 0.55, + MediaQuery.of(context).size.height * 0.3, + ), + trailing: IconButton( + icon: StreamSvgIcon.close_small(), + onPressed: () { + setState(() { + _attachments.remove(e); + }); + }, + ), ), ), - ), - ) - .toList(), + ) + .toList(), + ), ), - ), - if (_attachments.any((e) => e.attachment.type != 'file')) + if (_attachments.any((e) => e.attachment?.type != 'file')) LimitedBox( maxHeight: 104.0, child: ListView( scrollDirection: Axis.horizontal, children: _attachments - .where((e) => e.attachment.type != 'file') + .where((e) => e.attachment?.type != 'file') .map( (attachment) => Padding( padding: const EdgeInsets.all(8.0), @@ -1312,9 +1325,9 @@ class MessageInputState extends State { Widget _buildAttachment(_SendingAttachment attachment) { if (widget.attachmentThumbnailBuilders - ?.containsKey(attachment.attachment.type) == + ?.containsKey(attachment.attachment?.type) == true) { - return widget.attachmentThumbnailBuilders[attachment.attachment.type]( + return widget.attachmentThumbnailBuilders[attachment.attachment?.type]( context, attachment, ); @@ -1324,7 +1337,7 @@ class MessageInputState extends State { return SizedBox(); } - switch (attachment.attachment.type) { + switch (attachment.attachment?.type) { case 'image': case 'giphy': return attachment.file != null @@ -1568,6 +1581,11 @@ class MessageInputState extends State { bytes: bytes, ); } else { + if (_attachments.any((element) => element.attachment.type != 'file') && + !widget.enableFileAndImageAttachment) { + return; + } + FileType type; if (fileType == DefaultAttachmentTypes.image) { type = FileType.image; From 3d92d5fc32403eb01d300ac940a25b8f5da59ec6 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Wed, 2 Dec 2020 15:11:04 +0100 Subject: [PATCH 0557/1140] ui fix --- lib/src/file_attachment.dart | 75 +++++++++++++++++------------------- lib/src/message_widget.dart | 62 ++++++++++++++--------------- 2 files changed, 63 insertions(+), 74 deletions(-) diff --git a/lib/src/file_attachment.dart b/lib/src/file_attachment.dart index fd6f152a..168e7989 100644 --- a/lib/src/file_attachment.dart +++ b/lib/src/file_attachment.dart @@ -18,50 +18,45 @@ class FileAttachment extends StatelessWidget { @override Widget build(BuildContext context) { return Material( - child: InkWell( - onTap: () { - //launchURL(context, attachment.assetUrl); - }, - child: Container( - width: size?.width ?? 100, - margin: trailing != null ? EdgeInsets.only(top: 4.0) : null, - decoration: BoxDecoration( - color: Colors.white, - borderRadius: trailing != null ? BorderRadius.circular(16.0) : null, - border: trailing != null - ? Border.fromBorderSide(BorderSide(color: Color(0xFFE6E6E6))) - : null, + child: Container( + width: size?.width ?? 100, + margin: trailing != null ? EdgeInsets.only(top: 4.0) : null, + decoration: BoxDecoration( + color: Colors.white, + borderRadius: trailing != null ? BorderRadius.circular(16.0) : null, + border: trailing != null + ? Border.fromBorderSide(BorderSide(color: Color(0xFFE6E6E6))) + : null, + ), + child: ListTile( + dense: true, + leading: Container( + child: _getFileTypeImage(attachment.extraData['mime_type']), + height: 40.0, + width: 33.33, ), - child: ListTile( - dense: true, - leading: Container( - child: _getFileTypeImage(attachment.extraData['mime_type']), - height: 40.0, - width: 33.33, + title: Text( + attachment?.title ?? 'File', + style: TextStyle( + fontWeight: FontWeight.bold, ), - title: Text( - attachment?.title ?? 'File', - style: TextStyle( - fontWeight: FontWeight.bold, - ), - maxLines: 3, + maxLines: 3, + ), + subtitle: Text( + '${attachment.extraData['file_size'] ?? 'N/A'} bytes', + style: TextStyle( + color: Colors.black.withOpacity(0.5), ), - subtitle: Text( - '${attachment.extraData['file_size'] ?? 'N/A'} bytes', - style: TextStyle( - color: Colors.black.withOpacity(0.5), - ), - ), - trailing: trailing ?? - IconButton( - icon: StreamSvgIcon.cloud_download( - color: Colors.black, - ), - onPressed: () { - launchURL(context, attachment.assetUrl); - }, + ), + trailing: trailing ?? + IconButton( + icon: StreamSvgIcon.cloud_download( + color: Colors.black, ), - ), + onPressed: () { + launchURL(context, attachment.assetUrl); + }, + ), ), ), ); diff --git a/lib/src/message_widget.dart b/lib/src/message_widget.dart index 6a35648d..7c007735 100644 --- a/lib/src/message_widget.dart +++ b/lib/src/message_widget.dart @@ -668,46 +668,40 @@ class _MessageWidgetState extends State { []; } - Padding wrapAttachmentWidget( + Widget wrapAttachmentWidget( BuildContext context, Widget attachmentWidget, { Attachment attachment, }) { final attachmentShape = widget.attachmentShape ?? widget.shape ?? _getDefaultShape(context); - return Padding( - padding: EdgeInsets.only( - bottom: 4, - ), - child: GestureDetector( - onTap: () => retryMessage(context), - onLongPress: () => onLongPress(context), - child: Material( - color: attachment?.type == 'giphy' - ? Colors.white - : _getBackgroundColor(), - clipBehavior: Clip.hardEdge, - shape: attachmentShape, - child: Padding( - padding: widget.attachmentPadding, - child: Material( - clipBehavior: Clip.hardEdge, - shape: attachmentShape, - type: MaterialType.transparency, - child: Transform( - transform: Matrix4.rotationY(widget.reverse ? pi : 0), - alignment: Alignment.center, - child: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.end, - children: [ - getFailedMessageWidget( - context, - padding: const EdgeInsets.all(8.0), - ), - attachmentWidget, - ], - ), + return GestureDetector( + onTap: () => retryMessage(context), + onLongPress: () => onLongPress(context), + child: Material( + color: + attachment?.type == 'giphy' ? Colors.white : _getBackgroundColor(), + clipBehavior: Clip.hardEdge, + shape: attachmentShape, + child: Padding( + padding: widget.attachmentPadding, + child: Material( + clipBehavior: Clip.hardEdge, + shape: attachmentShape, + type: MaterialType.transparency, + child: Transform( + transform: Matrix4.rotationY(widget.reverse ? pi : 0), + alignment: Alignment.center, + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.end, + children: [ + getFailedMessageWidget( + context, + padding: const EdgeInsets.all(8.0), + ), + attachmentWidget, + ], ), ), ), From d26833aa72c374f2e9adf184a0d80cadf76ccf72 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Wed, 2 Dec 2020 15:25:33 +0100 Subject: [PATCH 0558/1140] fi borderradius --- lib/src/message_widget.dart | 113 ++++++++++++++++++++++-------------- 1 file changed, 68 insertions(+), 45 deletions(-) diff --git a/lib/src/message_widget.dart b/lib/src/message_widget.dart index 7c007735..e1644c84 100644 --- a/lib/src/message_widget.dart +++ b/lib/src/message_widget.dart @@ -300,51 +300,74 @@ class _MessageWidgetState extends State { messageTheme: widget.messageTheme, ), ) - : Container( - decoration: widget.message.attachments - .where((element) => - element.type == 'file') - .isEmpty - ? null - : BoxDecoration( - borderRadius: - BorderRadius.only( - topLeft: - Radius.circular(8.0), - topRight: - Radius.circular(8.0), - bottomRight: - Radius.circular(8.0), - ), - border: hasFiles - ? Border.fromBorderSide( - BorderSide( - color: - Color(0xFFE6E6E6), - )) - : null, - color: hasFiles - ? (user.id == - widget.message - .user.id - ? Color(0xFFE6E6E6) - : Colors.white) - : Colors.transparent, - ), - padding: EdgeInsets.all( - hasFiles ? 2.0 : 0.0), - child: Column( - crossAxisAlignment: - CrossAxisAlignment.start, - mainAxisSize: MainAxisSize.min, - children: [ - ..._parseAttachments(context), - if (widget.message.text - .trim() - .isNotEmpty && - !isGiphy) - _buildTextBubble(context), - ], + : Material( + shape: widget.shape ?? + RoundedRectangleBorder( + side: !hasFiles + ? BorderSide.none + : widget.borderSide ?? + BorderSide( + color: Theme.of(context) + .brightness == + Brightness + .dark + ? Colors.white + .withAlpha(24) + : Colors.black + .withAlpha( + 24), + ), + borderRadius: widget + .borderRadiusGeometry ?? + BorderRadius.zero, + ), + color: _getBackgroundColor(), + // decoration: widget.message.attachments + // .where((element) => + // element.type == 'file') + // .isEmpty + // ? null + // : BoxDecoration( + // borderRadius: + // BorderRadius.only( + // topLeft: + // Radius.circular(8.0), + // topRight: + // Radius.circular(8.0), + // bottomRight: + // Radius.circular(8.0), + // ), + // border: hasFiles + // ? Border.fromBorderSide( + // BorderSide( + // color: + // Color(0xFFE6E6E6), + // )) + // : null, + // color: hasFiles + // ? (user.id == + // widget.message + // .user.id + // ? Color(0xFFE6E6E6) + // : Colors.white) + // : Colors.transparent, + // ), + child: Padding( + padding: EdgeInsets.all( + hasFiles ? 2.0 : 0.0), + child: Column( + crossAxisAlignment: + CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + ..._parseAttachments(context), + if (widget.message.text + .trim() + .isNotEmpty && + !isGiphy) + _buildTextBubble(context), + ], + ), ), ), ), From aff59fd603398edb5e5eef7e9a0a1d5229862a50 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Wed, 2 Dec 2020 15:29:13 +0100 Subject: [PATCH 0559/1140] fix message text align --- 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 e1644c84..a510da28 100644 --- a/lib/src/message_widget.dart +++ b/lib/src/message_widget.dart @@ -357,7 +357,7 @@ class _MessageWidgetState extends State { hasFiles ? 2.0 : 0.0), child: Column( crossAxisAlignment: - CrossAxisAlignment.start, + CrossAxisAlignment.end, mainAxisSize: MainAxisSize.min, children: [ ..._parseAttachments(context), From e1c1e053b364b8d654e6ba652d5199be125d4904 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Wed, 2 Dec 2020 15:42:16 +0100 Subject: [PATCH 0560/1140] remove comment --- lib/src/message_widget.dart | 30 ------------------------------ 1 file changed, 30 deletions(-) diff --git a/lib/src/message_widget.dart b/lib/src/message_widget.dart index a510da28..deeaa921 100644 --- a/lib/src/message_widget.dart +++ b/lib/src/message_widget.dart @@ -322,36 +322,6 @@ class _MessageWidgetState extends State { BorderRadius.zero, ), color: _getBackgroundColor(), - // decoration: widget.message.attachments - // .where((element) => - // element.type == 'file') - // .isEmpty - // ? null - // : BoxDecoration( - // borderRadius: - // BorderRadius.only( - // topLeft: - // Radius.circular(8.0), - // topRight: - // Radius.circular(8.0), - // bottomRight: - // Radius.circular(8.0), - // ), - // border: hasFiles - // ? Border.fromBorderSide( - // BorderSide( - // color: - // Color(0xFFE6E6E6), - // )) - // : null, - // color: hasFiles - // ? (user.id == - // widget.message - // .user.id - // ? Color(0xFFE6E6E6) - // : Colors.white) - // : Colors.transparent, - // ), child: Padding( padding: EdgeInsets.all( hasFiles ? 2.0 : 0.0), From c4c0f97f3416487386206f888aedffdbc3d39f05 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Thu, 3 Dec 2020 14:12:39 +0530 Subject: [PATCH 0561/1140] feat: Icons are now disabled according to file type chosen --- lib/src/message_input.dart | 122 +++++++++++++++++++++---------------- 1 file changed, 70 insertions(+), 52 deletions(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index bb9c8ec4..04c9b3d1 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -108,7 +108,6 @@ class MessageInput extends StatefulWidget { this.actionsLocation = ActionsLocation.left, this.attachmentThumbnailBuilders, this.focusNode, - this.enableFileAndImageAttachment = false, }) : super(key: key); /// Message to edit @@ -157,9 +156,6 @@ class MessageInput extends StatefulWidget { /// The focus node associated to the TextField final FocusNode focusNode; - /// Enables adding both file+images at the same time - final bool enableFileAndImageAttachment; - @override MessageInputState createState() => MessageInputState(); @@ -662,6 +658,34 @@ class MessageInputState extends State { } Widget _buildFilePickerSection() { + var _attachmentContainsFile = + _attachments.any((element) => element.attachment.type == 'file'); + + Color _getIconColor(int index) { + switch (index) { + case 0: + return _attachmentContainsFile && _attachments.isNotEmpty + ? Colors.black.withOpacity(0.2) + : Colors.black.withOpacity(0.5); + break; + case 1: + return !_attachmentContainsFile && _attachments.isNotEmpty + ? Colors.black.withOpacity(0.2) + : Colors.black.withOpacity(0.5); + break; + case 2: + return _attachmentContainsFile && _attachments.isNotEmpty + ? Colors.black.withOpacity(0.2) + : Colors.black.withOpacity(0.5); + break; + case 3: + return _attachmentContainsFile && _attachments.isNotEmpty + ? Colors.black.withOpacity(0.2) + : Colors.black.withOpacity(0.5); + break; + } + } + return AnimatedContainer( duration: _animateContainer ? Duration(milliseconds: 300) : Duration.zero, height: _openFilePickerSection ? _filePickerSize : 0, @@ -675,49 +699,49 @@ class MessageInputState extends State { IconButton( iconSize: 24, icon: StreamSvgIcon.pictures( - color: _filePickerIndex == 0 - ? StreamChatTheme.of(context).accentColor - : Colors.black.withOpacity(0.5), + color: _getIconColor(0), ), - onPressed: () { - setState(() { - _filePickerIndex = 0; - }); - }, + onPressed: _attachmentContainsFile && _attachments.isNotEmpty + ? null + : () { + setState(() { + _filePickerIndex = 0; + }); + }, ), IconButton( iconSize: 32, icon: StreamSvgIcon.files( - color: _filePickerIndex == 1 - ? StreamChatTheme.of(context).accentColor - : Colors.black.withOpacity(0.5), + color: _getIconColor(1), ), - onPressed: () { - pickFile(DefaultAttachmentTypes.file, false); - }, + onPressed: !_attachmentContainsFile && _attachments.isNotEmpty + ? null + : () { + pickFile(DefaultAttachmentTypes.file, false); + }, ), IconButton( iconSize: 24, icon: StreamSvgIcon.camera( - color: _filePickerIndex == 2 - ? StreamChatTheme.of(context).accentColor - : Colors.black.withOpacity(0.5), + color: _getIconColor(2), ), - onPressed: () { - pickFile(DefaultAttachmentTypes.image, true); - }, + onPressed: _attachmentContainsFile && _attachments.isNotEmpty + ? null + : () { + pickFile(DefaultAttachmentTypes.image, true); + }, ), IconButton( padding: const EdgeInsets.all(0), iconSize: 24, icon: StreamSvgIcon.record( - color: _filePickerIndex == 3 - ? StreamChatTheme.of(context).accentColor - : Colors.black.withOpacity(0.5), + color: _getIconColor(3), ), - onPressed: () { - pickFile(DefaultAttachmentTypes.video, true); - }, + onPressed: _attachmentContainsFile && _attachments.isNotEmpty + ? null + : () { + pickFile(DefaultAttachmentTypes.video, true); + }, ), ], ), @@ -774,6 +798,9 @@ class MessageInputState extends State { } Widget _buildPickerSection() { + var _attachmentContainsFile = + _attachments.any((element) => element.attachment.type == 'file'); + switch (_filePickerIndex) { case 0: return FutureBuilder( @@ -786,26 +813,22 @@ class MessageInputState extends State { } if (snapshot.data) { - return MediaListView( - selectedIds: _attachments.map((e) => e.id).toList(), - onSelect: (media) async { - if (!_attachments - .any((element) => element.id == media.id)) { - if (widget.enableFileAndImageAttachment) { + return IgnorePointer( + ignoring: _attachmentContainsFile, + child: MediaListView( + selectedIds: _attachments.map((e) => e.id).toList(), + onSelect: (media) async { + if (!_attachments + .any((element) => element.id == media.id)) { _addAttachment(media); } else { - if (!_attachments.any( - (element) => element.attachment?.type == 'file')) { - _addAttachment(media); - } + setState(() { + _attachments + .removeWhere((element) => element.id == media.id); + }); } - } else { - setState(() { - _attachments - .removeWhere((element) => element.id == media.id); - }); - } - }, + }, + ), ); } @@ -1581,11 +1604,6 @@ class MessageInputState extends State { bytes: bytes, ); } else { - if (_attachments.any((element) => element.attachment.type != 'file') && - !widget.enableFileAndImageAttachment) { - return; - } - FileType type; if (fileType == DefaultAttachmentTypes.image) { type = FileType.image; From dffad3d6bca6b94454f5af37083d9c32e5b383f4 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Thu, 3 Dec 2020 14:54:58 +0530 Subject: [PATCH 0562/1140] fix: fixed sizes of file attachment --- lib/src/file_attachment.dart | 107 ++++++++++++++++++++++++++--------- lib/src/message_input.dart | 24 +++++--- 2 files changed, 98 insertions(+), 33 deletions(-) diff --git a/lib/src/file_attachment.dart b/lib/src/file_attachment.dart index 168e7989..fff13bbe 100644 --- a/lib/src/file_attachment.dart +++ b/lib/src/file_attachment.dart @@ -20,6 +20,7 @@ class FileAttachment extends StatelessWidget { return Material( child: Container( width: size?.width ?? 100, + height: 56.0, margin: trailing != null ? EdgeInsets.only(top: 4.0) : null, decoration: BoxDecoration( color: Colors.white, @@ -28,36 +29,90 @@ class FileAttachment extends StatelessWidget { ? Border.fromBorderSide(BorderSide(color: Color(0xFFE6E6E6))) : null, ), - child: ListTile( - dense: true, - leading: Container( - child: _getFileTypeImage(attachment.extraData['mime_type']), - height: 40.0, - width: 33.33, - ), - title: Text( - attachment?.title ?? 'File', - style: TextStyle( - fontWeight: FontWeight.bold, + child: Row( + children: [ + Container( + child: _getFileTypeImage(attachment.extraData['mime_type']), + height: 40.0, + width: 33.33, + margin: EdgeInsets.all(8.0), ), - maxLines: 3, - ), - subtitle: Text( - '${attachment.extraData['file_size'] ?? 'N/A'} bytes', - style: TextStyle( - color: Colors.black.withOpacity(0.5), + SizedBox( + width: 6.0, ), - ), - trailing: trailing ?? - IconButton( - icon: StreamSvgIcon.cloud_download( - color: Colors.black, - ), - onPressed: () { - launchURL(context, attachment.assetUrl); - }, + Expanded( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + attachment?.title ?? 'File', + style: TextStyle( + fontWeight: FontWeight.bold, + fontSize: 14.0, + ), + maxLines: 1, + overflow: TextOverflow.ellipsis, + ), + SizedBox( + height: 3.0, + ), + Text( + '${attachment.extraData['file_size'] ?? 'N/A'} bytes', + style: TextStyle( + color: Colors.black.withOpacity(0.5), + fontSize: 14.0, + ), + ), + ], ), + ), + Column( + children: [ + trailing ?? + IconButton( + icon: StreamSvgIcon.cloud_download( + color: Colors.black, + ), + onPressed: () { + launchURL(context, attachment.assetUrl); + }, + ), + ], + ), + ], ), + + // ListTile( + // dense: true, + // leading: Container( + // child: _getFileTypeImage(attachment.extraData['mime_type']), + // height: 40.0, + // width: 33.33, + // ), + // title: Text( + // attachment?.title ?? 'File', + // style: TextStyle( + // fontWeight: FontWeight.bold, + // ), + // maxLines: 3, + // ), + // subtitle: Text( + // '${attachment.extraData['file_size'] ?? 'N/A'} bytes', + // style: TextStyle( + // color: Colors.black.withOpacity(0.5), + // ), + // ), + // trailing: trailing ?? + // IconButton( + // icon: StreamSvgIcon.cloud_download( + // color: Colors.black, + // ), + // onPressed: () { + // launchURL(context, attachment.assetUrl); + // }, + // ), + // ), ), ); } diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 04c9b3d1..3ebcef21 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -1254,13 +1254,23 @@ class MessageInputState extends State { MediaQuery.of(context).size.width * 0.55, MediaQuery.of(context).size.height * 0.3, ), - trailing: IconButton( - icon: StreamSvgIcon.close_small(), - onPressed: () { - setState(() { - _attachments.remove(e); - }); - }, + trailing: Padding( + padding: const EdgeInsets.all(8.0), + child: InkWell( + child: CircleAvatar( + backgroundColor: + Colors.black.withOpacity(0.2), + maxRadius: 12.0, + child: StreamSvgIcon.close( + color: Colors.white, + ), + ), + onTap: () { + setState(() { + _attachments.remove(e); + }); + }, + ), ), ), ), From 38687f59efedf88a6dca225ad85594636dd6871f Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Thu, 3 Dec 2020 11:32:59 +0100 Subject: [PATCH 0563/1140] add cliprrect to file section of messageinput --- lib/src/message_input.dart | 46 +++++++++++++++++++++----------------- 1 file changed, 25 insertions(+), 21 deletions(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 3ebcef21..1469e574 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -1247,29 +1247,33 @@ class MessageInputState extends State { .map( (e) => Padding( padding: - const EdgeInsets.symmetric(horizontal: 4.0), - child: FileAttachment( - attachment: e.attachment, - size: Size( - MediaQuery.of(context).size.width * 0.55, - MediaQuery.of(context).size.height * 0.3, - ), - trailing: Padding( - padding: const EdgeInsets.all(8.0), - child: InkWell( - child: CircleAvatar( - backgroundColor: - Colors.black.withOpacity(0.2), - maxRadius: 12.0, - child: StreamSvgIcon.close( - color: Colors.white, + const EdgeInsets.symmetric(horizontal: 8.0), + child: ClipRRect( + borderRadius: BorderRadius.circular(10), + clipBehavior: Clip.antiAlias, + child: FileAttachment( + attachment: e.attachment, + size: Size( + MediaQuery.of(context).size.width * 0.55, + MediaQuery.of(context).size.height * 0.3, + ), + trailing: Padding( + padding: const EdgeInsets.all(8.0), + child: InkWell( + child: CircleAvatar( + backgroundColor: + Colors.black.withOpacity(0.2), + maxRadius: 12.0, + child: StreamSvgIcon.close( + color: Colors.white, + ), ), + onTap: () { + setState(() { + _attachments.remove(e); + }); + }, ), - onTap: () { - setState(() { - _attachments.remove(e); - }); - }, ), ), ), From e1c02de32039262116779d43d1dcc32dce913d28 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Thu, 3 Dec 2020 11:37:40 +0100 Subject: [PATCH 0564/1140] fix mention debounce --- lib/src/message_input.dart | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 1469e574..580a4f17 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -1087,7 +1087,7 @@ class MessageInputState extends State { offset: rejoin.length, ), ); - + _debounce.cancel(); _mentionsOverlay?.remove(); _mentionsOverlay = null; }, @@ -1294,6 +1294,7 @@ class MessageInputState extends State { padding: const EdgeInsets.all(8.0), child: ClipRRect( borderRadius: BorderRadius.circular(10), + clipBehavior: Clip.antiAlias, child: Stack( children: [ AspectRatio( From d81d6804201b98aad232841eb656e125c465123e Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Thu, 3 Dec 2020 11:55:14 +0100 Subject: [PATCH 0565/1140] fix borderradius --- lib/src/message_list_view.dart | 7 +++++- lib/src/message_widget.dart | 39 ++++++++++++---------------------- 2 files changed, 19 insertions(+), 27 deletions(-) diff --git a/lib/src/message_list_view.dart b/lib/src/message_list_view.dart index 3feda8ce..430e0b85 100644 --- a/lib/src/message_list_view.dart +++ b/lib/src/message_list_view.dart @@ -617,7 +617,12 @@ class _MessageListViewState extends State { showDeleteMessage: isMyMessage, borderSide: isMyMessage ? BorderSide.none : null, onThreadTap: _onThreadTap, - attachmentBorderRadiusGeometry: BorderRadius.circular(16), + attachmentBorderRadiusGeometry: BorderRadius.only( + topLeft: Radius.circular(16), + bottomLeft: Radius.circular(!isNextUser ? 0 : 16), + topRight: Radius.circular(16), + bottomRight: Radius.circular(16), + ), attachmentPadding: const EdgeInsets.all(2), borderRadiusGeometry: BorderRadius.only( topLeft: Radius.circular(16), diff --git a/lib/src/message_widget.dart b/lib/src/message_widget.dart index deeaa921..1ba4db87 100644 --- a/lib/src/message_widget.dart +++ b/lib/src/message_widget.dart @@ -301,22 +301,19 @@ class _MessageWidgetState extends State { ), ) : Material( + clipBehavior: Clip.antiAlias, shape: widget.shape ?? RoundedRectangleBorder( - side: !hasFiles - ? BorderSide.none - : widget.borderSide ?? - BorderSide( - color: Theme.of(context) - .brightness == - Brightness - .dark - ? Colors.white - .withAlpha(24) - : Colors.black - .withAlpha( - 24), - ), + side: widget.borderSide ?? + BorderSide( + color: Theme.of(context) + .brightness == + Brightness.dark + ? Colors.white + .withAlpha(24) + : Colors.black + .withAlpha(24), + ), borderRadius: widget .borderRadiusGeometry ?? BorderRadius.zero, @@ -327,7 +324,7 @@ class _MessageWidgetState extends State { hasFiles ? 2.0 : 0.0), child: Column( crossAxisAlignment: - CrossAxisAlignment.end, + CrossAxisAlignment.start, mainAxisSize: MainAxisSize.min, children: [ ..._parseAttachments(context), @@ -828,17 +825,7 @@ class _MessageWidgetState extends State { BuildContext context, Widget child, }) { - return Material( - shape: widget.shape ?? - RoundedRectangleBorder( - side: widget.borderSide ?? - BorderSide( - color: Theme.of(context).brightness == Brightness.dark - ? Colors.white.withAlpha(24) - : Colors.black.withAlpha(24), - ), - borderRadius: widget.borderRadiusGeometry ?? BorderRadius.zero, - ), + return Container( color: _getBackgroundColor(), child: child, ); From a551ab445b36a582a4c3e004e93b4b90fc25ac37 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Thu, 3 Dec 2020 12:08:20 +0100 Subject: [PATCH 0566/1140] fix emoji only messages --- lib/src/message_widget.dart | 52 ++++++++++++++++--------------------- 1 file changed, 23 insertions(+), 29 deletions(-) diff --git a/lib/src/message_widget.dart b/lib/src/message_widget.dart index 1ba4db87..94d9afd3 100644 --- a/lib/src/message_widget.dart +++ b/lib/src/message_widget.dart @@ -223,9 +223,10 @@ class _MessageWidgetState extends State { widget.message.attachments?.any((element) => element.type == 'giphy') == true; - var user = StreamChat.of(context).user; + final isOnlyEmoji = + widget.message.text.characters.every((c) => Emoji.byChar(c) != null); - bool hasFiles = + final hasFiles = widget.message.attachments.any((element) => element.type == 'file'); return Portal( @@ -304,16 +305,20 @@ class _MessageWidgetState extends State { clipBehavior: Clip.antiAlias, shape: widget.shape ?? RoundedRectangleBorder( - side: widget.borderSide ?? - BorderSide( - color: Theme.of(context) - .brightness == - Brightness.dark - ? Colors.white - .withAlpha(24) - : Colors.black - .withAlpha(24), - ), + side: isOnlyEmoji + ? BorderSide.none + : widget.borderSide ?? + BorderSide( + color: Theme.of(context) + .brightness == + Brightness + .dark + ? Colors.white + .withAlpha(24) + : Colors.black + .withAlpha( + 24), + ), borderRadius: widget .borderRadiusGeometry ?? BorderRadius.zero, @@ -821,16 +826,6 @@ class _MessageWidgetState extends State { return SizedBox(); } - Widget _wrapTextInBubble({ - BuildContext context, - Widget child, - }) { - return Container( - color: _getBackgroundColor(), - child: child, - ); - } - Widget _buildTextBubble(BuildContext context) { final isOnlyEmoji = widget.message.text.characters.every((c) => Emoji.byChar(c) != null); @@ -871,13 +866,6 @@ class _MessageWidgetState extends State { ], ), ); - - if (!isOnlyEmoji) { - child = _wrapTextInBubble( - context: context, - child: child, - ); - } return GestureDetector( onTap: () => retryMessage(context), onLongPress: () => onLongPress(context), @@ -886,6 +874,9 @@ class _MessageWidgetState extends State { } Color _getBackgroundColor() { + final isOnlyEmoji = + widget.message.text.characters.every((c) => Emoji.byChar(c) != null); + if ((widget.message.status == MessageSendingStatus.FAILED || widget.message.status == MessageSendingStatus.FAILED_UPDATE || widget.message.status == MessageSendingStatus.FAILED_DELETE)) { @@ -898,6 +889,9 @@ class _MessageWidgetState extends State { return Color(0xFFE9F2FF); } + if (isOnlyEmoji) { + return Colors.transparent; + } return widget.messageTheme.messageBackgroundColor; } From 71b494c977af8fa56804f9f5144b7fd9b1441654 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Thu, 3 Dec 2020 12:14:35 +0100 Subject: [PATCH 0567/1140] fix messageinput exception --- lib/src/message_input.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 580a4f17..4e30afe1 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -659,7 +659,7 @@ class MessageInputState extends State { Widget _buildFilePickerSection() { var _attachmentContainsFile = - _attachments.any((element) => element.attachment.type == 'file'); + _attachments.any((element) => element?.attachment?.type == 'file'); Color _getIconColor(int index) { switch (index) { @@ -924,7 +924,7 @@ class MessageInputState extends State { ..file = file ..attachment = Attachment( localUri: file.path != null ? Uri.parse(file.path) : null, - type: medium.type == AssetType.image ? 'image' : 'video', + type: medium?.type == AssetType.image ? 'image' : 'video', ); }); From f052ac96ac3fdec2049464bc6c07c76fbf089e2a Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Thu, 3 Dec 2020 12:36:43 +0100 Subject: [PATCH 0568/1140] fix tests --- lib/src/message_widget.dart | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/src/message_widget.dart b/lib/src/message_widget.dart index 94d9afd3..e5fe146f 100644 --- a/lib/src/message_widget.dart +++ b/lib/src/message_widget.dart @@ -227,7 +227,8 @@ class _MessageWidgetState extends State { widget.message.text.characters.every((c) => Emoji.byChar(c) != null); final hasFiles = - widget.message.attachments.any((element) => element.type == 'file'); + widget.message.attachments?.any((element) => element.type == 'file') == + true; return Portal( child: Padding( From 5cd9653c34093087f891e1c8729136d61ef1e679 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Thu, 3 Dec 2020 17:28:38 +0530 Subject: [PATCH 0569/1140] [MessageListView] : Use notification listener to implement pagination. Signed-off-by: Sahil Kumar --- lib/src/lazy_load_scroll_view.dart | 2 +- lib/src/message_list_view.dart | 230 ++++++++++++++--------------- 2 files changed, 114 insertions(+), 118 deletions(-) diff --git a/lib/src/lazy_load_scroll_view.dart b/lib/src/lazy_load_scroll_view.dart index 5ca13d07..5cfeea61 100644 --- a/lib/src/lazy_load_scroll_view.dart +++ b/lib/src/lazy_load_scroll_view.dart @@ -15,7 +15,7 @@ class LazyLoadScrollView extends StatefulWidget { final VoidCallback onEndOfPage; /// The offset to take into account when triggering [onEndOfPage] in pixels - final int scrollOffset; + final double scrollOffset; /// Used to determine if loading of new data has finished. You should use set this if you aren't using a FutureBuilder or StreamBuilder final bool isLoading; diff --git a/lib/src/message_list_view.dart b/lib/src/message_list_view.dart index 88e33ddc..cbe09a6f 100644 --- a/lib/src/message_list_view.dart +++ b/lib/src/message_list_view.dart @@ -5,6 +5,7 @@ import 'package:flutter/material.dart'; import 'package:jiffy/jiffy.dart'; import 'package:scrollable_positioned_list/scrollable_positioned_list.dart'; import 'package:stream_chat/stream_chat.dart'; +import 'package:stream_chat_flutter/src/lazy_load_scroll_view.dart'; import 'package:stream_chat_flutter/src/message_widget.dart'; import 'package:stream_chat_flutter/src/stream_svg_icon.dart'; import 'package:stream_chat_flutter/src/system_message.dart'; @@ -160,7 +161,6 @@ class MessageListView extends StatefulWidget { class _MessageListViewState extends State { ItemScrollController _scrollController; bool _bottomWasVisible = false; - bool _topWasVisible = false; Function _onThreadTap; bool _showScrollToBottom = false; ItemPositionsListener _itemPositionListener; @@ -223,110 +223,121 @@ class _MessageListViewState extends State { return Stack( alignment: Alignment.center, children: [ - ScrollablePositionedList.builder( - itemPositionsListener: _itemPositionListener, - addAutomaticKeepAlives: true, - key: Key('messageListView'), - initialScrollIndex: widget.initialScrollIndex, - initialAlignment: widget.initialAlignment, - physics: widget.scrollPhysics, - itemScrollController: _scrollController, - reverse: true, - itemCount: messages.length + - 1 + - (widget.parentMessage != null ? 1 : 0), - itemBuilder: (context, i) { - if (i == messages.length + 1) { - if (widget.parentMessageBuilder != null) { - return widget.parentMessageBuilder( + LazyLoadScrollView( + onStartOfPage: () => _paginateData( + streamChannel, + QueryDirection.bottom, + ), + onEndOfPage: () => _paginateData( + streamChannel, + QueryDirection.top, + ), + child: ScrollablePositionedList.builder( + itemPositionsListener: _itemPositionListener, + addAutomaticKeepAlives: true, + key: Key('messageListView'), + initialScrollIndex: widget.initialScrollIndex, + initialAlignment: widget.initialAlignment, + physics: widget.scrollPhysics, + itemScrollController: _scrollController, + reverse: true, + itemCount: messages.length + + 1 + + (widget.parentMessage != null ? 1 : 0), + itemBuilder: (context, i) { + if (i == messages.length + 1) { + if (widget.parentMessageBuilder != null) { + return widget.parentMessageBuilder( + context, + widget.parentMessage, + ); + } else { + return Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + buildParentMessage(widget.parentMessage), + Padding( + padding: + const EdgeInsets.symmetric(horizontal: 32), + child: Container( + padding: const EdgeInsets.all(8), + child: Text( + 'Start of thread', + textAlign: TextAlign.center, + ), + color: + Theme.of(context).accentColor.withAlpha(50), + ), + ), + ], + ); + } + } + + if (i == messages.length) { + return _buildLoadingIndicator(streamChannel); + } + final message = messages[i]; + final nextMessage = i > 0 ? messages[i - 1] : null; + + Widget messageWidget; + + if (i == 0) { + messageWidget = _buildBottomMessage( context, - widget.parentMessage, + message, + messages, + streamChannel, + ); + } else if (i == messages.length - 1) { + messageWidget = _buildTopMessage( + context, + message, + messages, + streamChannel, ); } else { + if (widget.messageBuilder != null) { + messageWidget = Builder( + key: ValueKey('MESSAGE-${message.id}'), + builder: (_) => widget.messageBuilder( + context, + MessageDetails( + context, + message, + messages, + i, + ), + messages), + ); + } else { + messageWidget = buildMessage(message, messages, i); + } + } + + if (nextMessage != null && + !Jiffy(message.createdAt.toLocal()).isSame( + nextMessage.createdAt.toLocal(), Units.DAY)) { return Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ - buildParentMessage(widget.parentMessage), + messageWidget, Padding( - padding: const EdgeInsets.symmetric(horizontal: 32), - child: Container( - padding: const EdgeInsets.all(8), - child: Text( - 'Start of thread', - textAlign: TextAlign.center, - ), - color: - Theme.of(context).accentColor.withAlpha(50), - ), + padding: const EdgeInsets.symmetric(vertical: 12.0), + child: widget.dateDividerBuilder != null + ? widget.dateDividerBuilder( + nextMessage.createdAt.toLocal()) + : DateDivider( + dateTime: nextMessage.createdAt.toLocal(), + ), ), ], ); } - } - if (i == messages.length) { - return _buildLoadingIndicator(streamChannel); - } - final message = messages[i]; - final nextMessage = i > 0 ? messages[i - 1] : null; - - Widget messageWidget; - - if (i == 0) { - messageWidget = _buildBottomMessage( - context, - message, - messages, - streamChannel, - ); - } else if (i == messages.length - 1) { - messageWidget = _buildTopMessage( - context, - message, - messages, - streamChannel, - ); - } else { - if (widget.messageBuilder != null) { - messageWidget = Builder( - key: ValueKey('MESSAGE-${message.id}'), - builder: (_) => widget.messageBuilder( - context, - MessageDetails( - context, - message, - messages, - i, - ), - messages), - ); - } else { - 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; - }, + return messageWidget; + }, + ), ), if (widget.showScrollToBottom && _showScrollToBottom) _buildScrollToBottom(), @@ -365,6 +376,14 @@ class _MessageListViewState extends State { }); } + void _paginateData(StreamChannelState channel, QueryDirection direction) { + if (widget.parentMessage == null) { + channel.queryMessages(direction: direction); + } else { + channel.getReplies(widget.parentMessage.id, direction: direction); + } + } + ItemPosition _getTopElement(Iterable values) { return values .where((ItemPosition position) => position.itemLeadingEdge < 0.9) @@ -485,22 +504,7 @@ class _MessageListViewState extends State { } else { messageWidget = buildMessage(message, messages, messages.length - 1); } - - return VisibilityDetector( - key: ValueKey('TOP-MESSAGE'), - child: messageWidget, - onVisibilityChanged: (visibility) { - final topIsVisible = visibility.visibleBounds != Rect.zero; - if (topIsVisible && !_topWasVisible) { - if (widget.parentMessage == null) { - streamChannel.queryMessages(); - } else { - streamChannel.getReplies(widget.parentMessage.id); - } - _topWasVisible = !topIsVisible; - } - }, - ); + return messageWidget; } Widget _buildBottomMessage( @@ -533,14 +537,6 @@ class _MessageListViewState extends State { onVisibilityChanged: (visibility) { final isVisible = visibility.visibleBounds != Rect.zero; if (isVisible && !_bottomWasVisible) { - if (widget.parentMessage == null) { - streamChannel.queryMessages(direction: QueryDirection.bottom); - } else { - streamChannel.getReplies( - widget.parentMessage.id, - direction: QueryDirection.bottom, - ); - } if (streamChannel.channel.config?.readEvents == true && streamChannel.channel.state.unreadCount > 0) { streamChannel.channel.markRead(); From 4f49664a41dee66b440bc66bea16f6fffa900d10 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Thu, 3 Dec 2020 14:38:25 +0100 Subject: [PATCH 0570/1140] use boxfit.cover --- lib/src/image_footer.dart | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/src/image_footer.dart b/lib/src/image_footer.dart index 7c39fb4c..3c37a66a 100644 --- a/lib/src/image_footer.dart +++ b/lib/src/image_footer.dart @@ -220,6 +220,7 @@ class _ImageFooterState extends State { widget.mediaSelectedCallBack(position); }, child: FittedBox( + fit: BoxFit.cover, child: Chewie( controller: controllerPackage.chewieController, ), From b05df980748010f8b0103059ff79b5e9afb099e5 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Fri, 4 Dec 2020 11:06:00 +0100 Subject: [PATCH 0571/1140] update default users and app --- example/lib/choose_user_page.dart | 12 ++++++------ example/pubspec.yaml | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/example/lib/choose_user_page.dart b/example/lib/choose_user_page.dart index c728a193..a64013b9 100644 --- a/example/lib/choose_user_page.dart +++ b/example/lib/choose_user_page.dart @@ -13,41 +13,41 @@ import 'routes/routes.dart'; const kStreamApiKey = 'STREAM_API_KEY'; const kStreamUserId = 'STREAM_USER_ID'; const kStreamToken = 'STREAM_TOKEN'; -const kDefaultStreamApiKey = 's2dxdhpxd94g'; +const kDefaultStreamApiKey = 'uj7qrdbfrzvg'; class ChooseUserPage extends StatelessWidget { @override Widget build(BuildContext context) { final users = { - 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoidmlzaGFsIn0._JHWzo92fpTWZMZriJHXqOng6ShYVmWrdaIaPwEPKBg': + 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoidmlzaGFsIn0.lCz-idDgaZ-xszjnuB_hTfeIOhTFmJtTB2fEjhwrcCI': User( id: 'vishal', extraData: { 'name': 'Vishal', }, ), - 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoic3VwZXItYmFuZC05In0.0L6lGoeLwkz0aZRUcpZKsvaXtNEDHBcezVTZ0oPq40A': + 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoic3VwZXItYmFuZC05In0.1AvvK2TvEsfcxAlfOK2iUMFACucnk6N-Q8f5bbfnjCM': User( id: 'super-band-9', extraData: { 'name': 'John Doe', }, ), - 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoic2FsdmF0b3JlIn0.GMEKyEhONmFnqtkf1TR1A3oUOSIWhjfQv5RpI906dAM': + 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoic2FsdmF0b3JlIn0.uQ-pz8e1_C-Df2rIFpkkvWf7g4M0aW2Zkr7pHVhmU1Y': User( id: 'salvatore', extraData: { 'name': 'Salvatore', }, ), - 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoidG9tbWFzbyJ9.GTalMeZHaBdpIM5w-KWrVIDSy-ODkHTRkf1GZbWAveM': + 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoidG9tbWFzbyJ9.feLvMytd5_3-eETKrRdwtO3jcA0HxD8woFUbFU7gQCg': User( id: 'tommaso', extraData: { 'name': 'Tommaso', }, ), - 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoiamFhcCJ9.xpGE2lu4OoYS7-2yy6PbF0gJnxOaxeGO4EU6xo4EdMU': + 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoiamFhcCJ9.VLkLs6KH-jRRkPvhYMa4_lqN0R6WiK7JhJVmYvxcKz0': User( id: 'jaap', extraData: { diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 6ae2ab54..c5bfa14f 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -1,6 +1,6 @@ name: example description: A new Flutter project. -version: 1.0.87+89 +version: 1.0.88+90 environment: sdk: ">=2.2.2 <3.0.0" From 16ed0c5bb46541877d624298e82ae176a1947ffc Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Fri, 4 Dec 2020 16:29:43 +0530 Subject: [PATCH 0572/1140] feat: Added chat info page --- lib/src/channel_header.dart | 23 ++- lib/src/chat_info_screen.dart | 319 +++++++++++++++++++++++++++++++++ lib/src/stream_svg_icon.dart | 36 ++++ lib/svgs/Icon_group.svg | 3 + lib/svgs/Icon_notification.svg | 6 + 5 files changed, 386 insertions(+), 1 deletion(-) create mode 100644 lib/src/chat_info_screen.dart create mode 100644 lib/svgs/Icon_group.svg create mode 100644 lib/svgs/Icon_notification.svg diff --git a/lib/src/channel_header.dart b/lib/src/channel_header.dart index ebaaf20f..09833ad3 100644 --- a/lib/src/channel_header.dart +++ b/lib/src/channel_header.dart @@ -5,8 +5,10 @@ import 'package:stream_chat_flutter/src/channel_info.dart'; import 'package:stream_chat_flutter/src/channel_name.dart'; import 'package:stream_chat_flutter/src/stream_chat_theme.dart'; +import '../stream_chat_flutter.dart'; import './channel_name.dart'; import 'channel_image.dart'; +import 'chat_info_screen.dart'; import 'stream_channel.dart'; /// ![screenshot](https://raw.githubusercontent.com/GetStream/stream-chat-flutter/master/screenshots/channel_header.png) @@ -97,7 +99,26 @@ class ChannelHeader extends StatelessWidget implements PreferredSizeWidget { padding: const EdgeInsets.only(right: 10.0), child: Center( child: ChannelImage( - onTap: onImageTap, + onTap: onImageTap ?? + () { + var currentUser = StreamChat.of(context).user; + var otherUser = channel.state.members.firstWhere( + (element) => element.user.id != currentUser.id); + + if (channel.memberCount == 2) { + if (otherUser != null) { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => StreamChannel( + channel: channel, + child: ChatInfoScreen( + user: otherUser.user, + ), + ))); + } + } + }, ), ), ), diff --git a/lib/src/chat_info_screen.dart b/lib/src/chat_info_screen.dart new file mode 100644 index 00000000..18efdc1b --- /dev/null +++ b/lib/src/chat_info_screen.dart @@ -0,0 +1,319 @@ +import 'package:emojis/emojis.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +import '../stream_chat_flutter.dart'; + +/// Detail screen for a 1:1 chat correspondence +class ChatInfoScreen extends StatefulWidget { + /// User in consideration + final User user; + + const ChatInfoScreen({Key key, this.user}) : super(key: key); + + @override + _ChatInfoScreenState createState() => _ChatInfoScreenState(); +} + +class _ChatInfoScreenState extends State { + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: Color(0xFFe6e6e6), + body: ListView( + children: [ + _buildUserHeader(), + SizedBox( + height: 8.0, + ), + _buildOptionListTiles(), + SizedBox( + height: 8.0, + ), + _buildDeleteListTile(), + ], + ), + ); + } + + Widget _buildUserHeader() { + return Material( + color: Colors.white, + child: SafeArea( + child: Stack( + children: [ + Column( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Padding( + padding: const EdgeInsets.all(16.0), + child: UserAvatar( + user: widget.user, + constraints: BoxConstraints( + maxWidth: 72.0, + maxHeight: 72.0, + ), + borderRadius: BorderRadius.circular(36.0), + ), + ), + SizedBox(height: 15.0), + Text( + widget.user.name, + style: TextStyle(fontSize: 16.0, fontWeight: FontWeight.bold), + ), + SizedBox(height: 7.0), + Text('Online for 5 minutes'), + SizedBox(height: 15.0), + _OptionListTile( + title: '@user', + trailing: Text(widget.user.name), + onTap: () {}, + ), + ], + ), + Positioned( + top: 21, + left: 16, + child: InkWell( + child: StreamSvgIcon.left(), + onTap: () { + Navigator.of(context).pop(); + }, + ), + ), + ], + ), + ), + ); + } + + Widget _buildOptionListTiles() { + var channel = StreamChannel.of(context); + + return Column( + children: [ + _OptionListTile( + title: 'Notifications', + leading: StreamSvgIcon.Icon_notification( + size: 24.0, + color: Colors.black.withOpacity(0.5), + ), + trailing: CupertinoSwitch( + value: true, + onChanged: (val) {}, + ), + onTap: () {}, + ), + StreamBuilder( + stream: StreamChannel.of(context).channel.isMutedStream, + builder: (context, snapshot) { + return _OptionListTile( + title: 'Mute user', + leading: StreamSvgIcon.mute( + size: 23.0, + color: Colors.black.withOpacity(0.5), + ), + trailing: snapshot.data == null + ? CircularProgressIndicator() + : CupertinoSwitch( + value: snapshot.data, + onChanged: (val) { + if (snapshot.data) { + channel.channel.unmute(); + } else { + channel.channel.mute(); + } + }, + ), + onTap: () {}, + ); + }), + _OptionListTile( + title: 'Block User', + leading: StreamSvgIcon.Icon_user_delete( + size: 24.0, + color: Colors.black.withOpacity(0.5), + ), + trailing: CupertinoSwitch( + value: true, + onChanged: (val) {}, + ), + onTap: () {}, + ), + _OptionListTile( + title: '615 Photos & Videos', + leading: StreamSvgIcon.pictures( + size: 24.0, + color: Colors.black.withOpacity(0.5), + ), + trailing: StreamSvgIcon.right(), + onTap: () {}, + ), + _OptionListTile( + title: '8 Files', + leading: StreamSvgIcon.files( + size: 24.0, + color: Colors.black.withOpacity(0.5), + ), + trailing: StreamSvgIcon.right(), + onTap: () {}, + ), + _OptionListTile( + title: '2 Shared groups', + leading: StreamSvgIcon.Icon_group( + size: 24.0, + color: Colors.black.withOpacity(0.5), + ), + trailing: StreamSvgIcon.right(), + onTap: () {}, + ), + ], + ); + } + + Widget _buildDeleteListTile() { + return _OptionListTile( + title: 'Delete', + leading: StreamSvgIcon.delete( + color: Colors.red, + size: 20.0, + ), + onTap: () { + _showDeleteDialog(); + }, + titleColor: Colors.red, + ); + } + + void _showDeleteDialog() { + var channel = StreamChannel.of(context).channel; + + showModalBottomSheet( + backgroundColor: Colors.white, + context: context, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.only( + topLeft: Radius.circular(16.0), + topRight: Radius.circular(16.0), + )), + builder: (context) { + return Column( + mainAxisSize: MainAxisSize.min, + children: [ + SizedBox( + height: 26.0, + ), + StreamSvgIcon.delete( + color: Colors.red, + ), + SizedBox( + height: 26.0, + ), + Text( + 'Delete Conversation', + style: TextStyle(fontWeight: FontWeight.bold, fontSize: 16.0), + ), + SizedBox( + height: 7.0, + ), + Text('Are you sure you want to delete this conversation?'), + SizedBox( + height: 36.0, + ), + Container( + color: Color(0xffe6e6e6), + height: 1.0, + ), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + FlatButton( + child: Text( + 'CANCEL', + style: TextStyle( + color: Colors.black.withOpacity(0.5), + fontWeight: FontWeight.w400), + ), + onPressed: () { + Navigator.of(context).pop(); + }, + ), + FlatButton( + child: Text( + 'DELETE', + style: TextStyle( + color: Colors.red, fontWeight: FontWeight.w400), + ), + onPressed: () { + channel.delete().then((value) { + Navigator.pop(context); + Navigator.pop(context); + Navigator.pop(context); + }); + }, + ), + ], + ), + ], + ); + }); + } +} + +class _OptionListTile extends StatelessWidget { + final String title; + final StreamSvgIcon leading; + final Widget trailing; + final VoidCallback onTap; + final Color titleColor; + + _OptionListTile({ + this.title, + this.leading, + this.trailing, + this.onTap, + this.titleColor, + }); + + @override + Widget build(BuildContext context) { + return Column( + children: [ + Container( + color: Color(0xffe6e6e6), + height: 2.0, + ), + Material( + color: Colors.white, + child: InkWell( + onTap: onTap, + child: Row( + children: [ + if (leading != null) + Padding( + padding: const EdgeInsets.all(22.0), + child: leading, + ), + if (leading == null) + SizedBox( + width: 16.0, + ), + Expanded( + child: Text( + title, + style: + TextStyle(fontWeight: FontWeight.w600, color: titleColor), + )), + if (trailing != null) + Padding( + padding: const EdgeInsets.all(16.0), + child: trailing, + ), + ], + ), + ), + ), + ], + ); + } +} diff --git a/lib/src/stream_svg_icon.dart b/lib/src/stream_svg_icon.dart index 42fed46e..98ce0f8e 100644 --- a/lib/src/stream_svg_icon.dart +++ b/lib/src/stream_svg_icon.dart @@ -721,4 +721,40 @@ class StreamSvgIcon extends StatelessWidget { height: size, ); } + + factory StreamSvgIcon.Icon_group({ + double size, + Color color, + }) { + return StreamSvgIcon( + assetName: 'Icon_group.svg', + color: color, + width: size, + height: size, + ); + } + + factory StreamSvgIcon.Icon_notification({ + double size, + Color color, + }) { + return StreamSvgIcon( + assetName: 'Icon_notification.svg', + color: color, + width: size, + height: size, + ); + } + + factory StreamSvgIcon.Icon_user_delete({ + double size, + Color color, + }) { + return StreamSvgIcon( + assetName: 'Icon_user_delete.svg', + color: color, + width: size, + height: size, + ); + } } diff --git a/lib/svgs/Icon_group.svg b/lib/svgs/Icon_group.svg new file mode 100644 index 00000000..6db40129 --- /dev/null +++ b/lib/svgs/Icon_group.svg @@ -0,0 +1,3 @@ + + + diff --git a/lib/svgs/Icon_notification.svg b/lib/svgs/Icon_notification.svg new file mode 100644 index 00000000..213f33c0 --- /dev/null +++ b/lib/svgs/Icon_notification.svg @@ -0,0 +1,6 @@ + + + + + + From 44cd3754fb51fa93c859a15f1ef48e74e1e7d294 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Fri, 4 Dec 2020 15:23:25 +0100 Subject: [PATCH 0573/1140] fix giphy badge --- lib/src/giphy_attachment.dart | 31 ++++++++++++++----------------- 1 file changed, 14 insertions(+), 17 deletions(-) diff --git a/lib/src/giphy_attachment.dart b/lib/src/giphy_attachment.dart index 6ab38c83..90e5929e 100644 --- a/lib/src/giphy_attachment.dart +++ b/lib/src/giphy_attachment.dart @@ -103,33 +103,30 @@ class GiphyAttachment extends StatelessWidget { ), ), Positioned( - left: 0, - top: 0, - child: Container( - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.only( - bottomRight: Radius.circular(16.0), - )), + bottom: 16, + left: 16, + child: Material( + color: Colors.black.withOpacity(.5), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12), + ), child: Padding( - padding: const EdgeInsets.only( - left: 8.0, - right: 8.0, - top: 8.0, - bottom: 4.0, + padding: const EdgeInsets.symmetric( + horizontal: 8.0, + vertical: 4.0, ), child: Row( children: [ StreamSvgIcon.lightning( - color: StreamChatTheme.of(context).accentColor, - size: 16.0, + color: Colors.white, + size: 16, ), Text( 'GIPHY', style: TextStyle( - color: StreamChatTheme.of(context).accentColor, + color: Colors.white, fontWeight: FontWeight.bold, - fontSize: 11.0, + fontSize: 11, ), ), ], From 5365082e4a10ebb69a90872a85fa93f8227a91c8 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Fri, 4 Dec 2020 15:42:26 +0100 Subject: [PATCH 0574/1140] fix giphy background --- lib/src/message_widget.dart | 35 ++++++++++++++++------------------- 1 file changed, 16 insertions(+), 19 deletions(-) diff --git a/lib/src/message_widget.dart b/lib/src/message_widget.dart index e5fe146f..f761f756 100644 --- a/lib/src/message_widget.dart +++ b/lib/src/message_widget.dart @@ -186,9 +186,7 @@ class MessageWidget extends StatefulWidget { 'giphy': (context, message, attachment) { return GiphyAttachment( attachment: attachment, - messageTheme: messageTheme.copyWith( - messageBackgroundColor: Colors.white, - ), + messageTheme: messageTheme, message: message, size: Size( MediaQuery.of(context).size.width * 0.8, @@ -219,13 +217,6 @@ class _MessageWidgetState extends State { ? widget.messageTheme.avatarTheme.constraints.maxWidth + 16.0 : 6.0; - final isGiphy = - widget.message.attachments?.any((element) => element.type == 'giphy') == - true; - - final isOnlyEmoji = - widget.message.text.characters.every((c) => Emoji.byChar(c) != null); - final hasFiles = widget.message.attachments?.any((element) => element.type == 'file') == true; @@ -484,6 +475,10 @@ class _MessageWidgetState extends State { ); } + bool get isGiphy => + widget.message.attachments?.any((element) => element.type == 'giphy') == + true; + Widget _buildReadIndicator() { var padding = 0.0; return Stack( @@ -675,9 +670,8 @@ class _MessageWidgetState extends State { onTap: () => retryMessage(context), onLongPress: () => onLongPress(context), child: Material( - color: - attachment?.type == 'giphy' ? Colors.white : _getBackgroundColor(), - clipBehavior: Clip.hardEdge, + color: _getBackgroundColor(), + clipBehavior: Clip.antiAlias, shape: attachmentShape, child: Padding( padding: widget.attachmentPadding, @@ -828,9 +822,6 @@ class _MessageWidgetState extends State { } Widget _buildTextBubble(BuildContext context) { - final isOnlyEmoji = - widget.message.text.characters.every((c) => Emoji.byChar(c) != null); - Widget child = Transform( transform: Matrix4.rotationY(widget.reverse ? pi : 0), alignment: Alignment.center, @@ -874,10 +865,11 @@ class _MessageWidgetState extends State { ); } - Color _getBackgroundColor() { - final isOnlyEmoji = - widget.message.text.characters.every((c) => Emoji.byChar(c) != null); + bool get isOnlyEmoji => + widget.message.text.characters.isNotEmpty && + widget.message.text.characters.every((c) => Emoji.byChar(c) != null); + Color _getBackgroundColor() { if ((widget.message.status == MessageSendingStatus.FAILED || widget.message.status == MessageSendingStatus.FAILED_UPDATE || widget.message.status == MessageSendingStatus.FAILED_DELETE)) { @@ -893,6 +885,11 @@ class _MessageWidgetState extends State { if (isOnlyEmoji) { return Colors.transparent; } + + if (isGiphy) { + return Colors.transparent; + } + return widget.messageTheme.messageBackgroundColor; } From e80a30dca45a5aeb7f704b87682d417811688dc1 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Fri, 4 Dec 2020 16:08:46 +0100 Subject: [PATCH 0575/1140] fix giphy borderradius --- lib/src/giphy_attachment.dart | 44 ++++++++++++++++++++--------------- 1 file changed, 25 insertions(+), 19 deletions(-) diff --git a/lib/src/giphy_attachment.dart b/lib/src/giphy_attachment.dart index 90e5929e..3e29b2f1 100644 --- a/lib/src/giphy_attachment.dart +++ b/lib/src/giphy_attachment.dart @@ -79,26 +79,32 @@ class GiphyAttachment extends StatelessWidget { ); })); }, - child: CachedNetworkImage( - height: size?.height, - width: size?.width, - placeholder: (_, __) { - return Container( - width: size?.width, - height: size?.height, - child: Center( - child: CircularProgressIndicator(), - ), - ); - }, - imageUrl: attachment.thumbUrl ?? - attachment.imageUrl ?? - attachment.assetUrl, - errorWidget: (context, url, error) => AttachmentError( - attachment: attachment, - size: size, + child: ClipRRect( + borderRadius: BorderRadius.only( + topLeft: Radius.circular(8), + topRight: Radius.circular(8), + ), + child: CachedNetworkImage( + height: size?.height, + width: size?.width, + placeholder: (_, __) { + return Container( + width: size?.width, + height: size?.height, + child: Center( + child: CircularProgressIndicator(), + ), + ); + }, + imageUrl: attachment.thumbUrl ?? + attachment.imageUrl ?? + attachment.assetUrl, + errorWidget: (context, url, error) => AttachmentError( + attachment: attachment, + size: size, + ), + fit: BoxFit.cover, ), - fit: BoxFit.cover, ), ), ), From 75262dbd4995a28e37940dfa8ed4ef6b223f5c50 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Mon, 7 Dec 2020 20:30:54 +0530 Subject: [PATCH 0576/1140] feat: Added shared groups, removed notifications, fixed listtile --- lib/src/chat_info_screen.dart | 185 +++++++++++++++++++++++++--------- 1 file changed, 138 insertions(+), 47 deletions(-) diff --git a/lib/src/chat_info_screen.dart b/lib/src/chat_info_screen.dart index 18efdc1b..8310d1b9 100644 --- a/lib/src/chat_info_screen.dart +++ b/lib/src/chat_info_screen.dart @@ -92,18 +92,18 @@ class _ChatInfoScreenState extends State { return Column( children: [ - _OptionListTile( - title: 'Notifications', - leading: StreamSvgIcon.Icon_notification( - size: 24.0, - color: Colors.black.withOpacity(0.5), - ), - trailing: CupertinoSwitch( - value: true, - onChanged: (val) {}, - ), - onTap: () {}, - ), + // _OptionListTile( + // title: 'Notifications', + // leading: StreamSvgIcon.Icon_notification( + // size: 24.0, + // color: Colors.black.withOpacity(0.5), + // ), + // trailing: CupertinoSwitch( + // value: true, + // onChanged: (val) {}, + // ), + // onTap: () {}, + // ), StreamBuilder( stream: StreamChannel.of(context).channel.isMutedStream, builder: (context, snapshot) { @@ -143,7 +143,7 @@ class _ChatInfoScreenState extends State { _OptionListTile( title: '615 Photos & Videos', leading: StreamSvgIcon.pictures( - size: 24.0, + size: 32.0, color: Colors.black.withOpacity(0.5), ), trailing: StreamSvgIcon.right(), @@ -152,21 +152,36 @@ class _ChatInfoScreenState extends State { _OptionListTile( title: '8 Files', leading: StreamSvgIcon.files( - size: 24.0, - color: Colors.black.withOpacity(0.5), - ), - trailing: StreamSvgIcon.right(), - onTap: () {}, - ), - _OptionListTile( - title: '2 Shared groups', - leading: StreamSvgIcon.Icon_group( - size: 24.0, + size: 32.0, color: Colors.black.withOpacity(0.5), ), trailing: StreamSvgIcon.right(), onTap: () {}, ), + StreamBuilder>( + stream: StreamChat.of(context).client.queryChannels( + filter: { + 'members': [StreamChat.of(context).user.id, widget.user.id], + }, + ), + builder: (context, snapshot) { + return _OptionListTile( + title: + '${snapshot.data == null ? '0' : snapshot.data.length} Shared groups', + leading: StreamSvgIcon.Icon_group( + size: 24.0, + color: Colors.black.withOpacity(0.5), + ), + trailing: StreamSvgIcon.right(), + onTap: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => _SharedGroupsScreen( + StreamChat.of(context).user, widget.user))); + }, + ); + }), ], ); } @@ -285,31 +300,34 @@ class _OptionListTile extends StatelessWidget { ), Material( color: Colors.white, - child: InkWell( - onTap: onTap, - child: Row( - children: [ - if (leading != null) - Padding( - padding: const EdgeInsets.all(22.0), - child: leading, + child: Container( + height: 56.0, + child: InkWell( + onTap: onTap, + child: Row( + children: [ + if (leading != null) + Expanded( + child: Center(child: leading), + ), + if (leading == null) + SizedBox( + width: 16.0, + ), + Expanded( + flex: 4, + child: Text( + title, + style: TextStyle( + fontWeight: FontWeight.w600, color: titleColor), + )), + Expanded( + child: Center( + child: trailing ?? Container(), + ), ), - if (leading == null) - SizedBox( - width: 16.0, - ), - Expanded( - child: Text( - title, - style: - TextStyle(fontWeight: FontWeight.w600, color: titleColor), - )), - if (trailing != null) - Padding( - padding: const EdgeInsets.all(16.0), - child: trailing, - ), - ], + ], + ), ), ), ), @@ -317,3 +335,76 @@ class _OptionListTile extends StatelessWidget { ); } } + +class _SharedGroupsScreen extends StatefulWidget { + final User mainUser; + final User otherUser; + + _SharedGroupsScreen(this.mainUser, this.otherUser); + + @override + __SharedGroupsScreenState createState() => __SharedGroupsScreenState(); +} + +class __SharedGroupsScreenState extends State<_SharedGroupsScreen> { + @override + Widget build(BuildContext context) { + var chat = StreamChat.of(context); + + return Scaffold( + backgroundColor: Colors.white, + appBar: AppBar( + brightness: Theme.of(context).brightness, + elevation: 1, + centerTitle: true, + title: Text( + 'Shared Groups', + style: TextStyle(color: Colors.black, fontSize: 16.0), + ), + leading: Center( + child: InkWell( + onTap: () { + Navigator.of(context).pop(); + }, + child: Container( + child: StreamSvgIcon.left( + color: Colors.black, + size: 24.0, + ), + width: 24.0, + height: 24.0, + ), + ), + ), + backgroundColor: StreamChatTheme.of(context).primaryColor, + ), + body: StreamBuilder>( + stream: chat.client.queryChannels( + filter: { + 'members': [widget.mainUser.id, widget.otherUser.id], + }, + ), + builder: (context, snapshot) { + if (snapshot.data == null) { + return Center( + child: CircularProgressIndicator(), + ); + } + + return ListView.builder( + itemCount: snapshot.data.length, + itemBuilder: (context, position) { + return StreamChannel( + channel: snapshot.data[position], + child: ChannelPreview( + channel: snapshot.data[position], + onTap: (val) {}, + ), + ); + }, + ); + }, + ), + ); + } +} From 914a82bb4944359f939575b6069bc51803c05f3d Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Mon, 7 Dec 2020 22:29:40 +0530 Subject: [PATCH 0577/1140] Add Message Reply feature Signed-off-by: Sahil Kumar --- example/lib/main.dart | 36 +++- lib/src/extension.dart | 5 + lib/src/file_attachment.dart | 61 +------ lib/src/message_actions_modal.dart | 39 +++- lib/src/message_input.dart | 200 ++++++++++++++------ lib/src/message_list_view.dart | 100 ++++++---- lib/src/message_reactions_modal.dart | 2 +- lib/src/message_widget.dart | 90 +++++---- lib/src/reply_message_widget.dart | 264 +++++++++++++++++++++++++++ lib/src/stream_svg_icon.dart | 12 ++ lib/src/swipeable.dart | 162 ++++++++++++++++ lib/src/utils.dart | 104 +++++++++++ 12 files changed, 858 insertions(+), 217 deletions(-) create mode 100644 lib/src/extension.dart create mode 100644 lib/src/reply_message_widget.dart create mode 100644 lib/src/swipeable.dart diff --git a/example/lib/main.dart b/example/lib/main.dart index 4b529e23..ab002a62 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -415,10 +415,31 @@ class ChannelQuerySearchResultPage extends StatelessWidget { } } -class ChannelPage extends StatelessWidget { - const ChannelPage({ - Key key, - }) : super(key: key); +class ChannelPage extends StatefulWidget { + @override + _ChannelPageState createState() => _ChannelPageState(); +} + +class _ChannelPageState extends State { + Message _replyMessage; + FocusNode _focusNode; + + @override + void initState() { + super.initState(); + _focusNode = FocusNode(); + } + + @override + void dispose() { + _focusNode.dispose(); + super.dispose(); + } + + void _reply(Message message) { + setState(() => _replyMessage = message); + _focusNode.requestFocus(); + } @override Widget build(BuildContext context) { @@ -433,6 +454,8 @@ class ChannelPage extends StatelessWidget { child: Stack( children: [ MessageListView( + onMessageSwiped: _reply, + onReplyTap: _reply, threadBuilder: (_, parentMessage) { return ThreadPage( parent: parentMessage, @@ -458,7 +481,10 @@ class ChannelPage extends StatelessWidget { ], ), ), - MessageInput(), + MessageInput( + focusNode: _focusNode, + replyMessage: _replyMessage, + ), ], ), ); diff --git a/lib/src/extension.dart b/lib/src/extension.dart new file mode 100644 index 00000000..d0b18fe8 --- /dev/null +++ b/lib/src/extension.dart @@ -0,0 +1,5 @@ +extension StringExtension on String { + String capitalize() { + return "${this[0].toUpperCase()}${this.substring(1)}"; + } +} diff --git a/lib/src/file_attachment.dart b/lib/src/file_attachment.dart index fff13bbe..599b71f6 100644 --- a/lib/src/file_attachment.dart +++ b/lib/src/file_attachment.dart @@ -32,7 +32,7 @@ class FileAttachment extends StatelessWidget { child: Row( children: [ Container( - child: _getFileTypeImage(attachment.extraData['mime_type']), + child: getFileTypeImage(attachment.extraData['mime_type']), height: 40.0, width: 33.33, margin: EdgeInsets.all(8.0), @@ -116,63 +116,4 @@ class FileAttachment extends StatelessWidget { ), ); } - - StreamSvgIcon _getFileTypeImage(String type) { - switch (type) { - case '7z': - return StreamSvgIcon.filetype_7z(); - break; - case 'csv': - return StreamSvgIcon.filetype_csv(); - break; - case 'doc': - return StreamSvgIcon.filetype_doc(); - break; - case 'docx': - return StreamSvgIcon.filetype_docx(); - break; - case 'html': - return StreamSvgIcon.filetype_html(); - break; - case 'md': - return StreamSvgIcon.filetype_md(); - break; - case 'odt': - return StreamSvgIcon.filetype_odt(); - break; - case 'pdf': - return StreamSvgIcon.filetype_pdf(); - break; - case 'ppt': - return StreamSvgIcon.filetype_ppt(); - break; - case 'pptx': - return StreamSvgIcon.filetype_pptx(); - break; - case 'rar': - return StreamSvgIcon.filetype_rar(); - break; - case 'rtf': - return StreamSvgIcon.filetype_rtf(); - break; - case 'tar': - return StreamSvgIcon.filetype_tar(); - break; - case 'txt': - return StreamSvgIcon.filetype_txt(); - break; - case 'xls': - return StreamSvgIcon.filetype_xls(); - break; - case 'xlsx': - return StreamSvgIcon.filetype_xlsx(); - break; - case 'zip': - return StreamSvgIcon.filetype_zip(); - break; - default: - return StreamSvgIcon.filetype_Generic(); - break; - } - } } diff --git a/lib/src/message_actions_modal.dart b/lib/src/message_actions_modal.dart index 1967cd2b..e8966197 100644 --- a/lib/src/message_actions_modal.dart +++ b/lib/src/message_actions_modal.dart @@ -15,7 +15,8 @@ import 'stream_chat_theme.dart'; class MessageActionsModal extends StatelessWidget { final Widget Function(BuildContext, Message) editMessageInputBuilder; - final void Function(Message) onThreadTap; + final void Function(Message) onThreadReplyTap; + final void Function(Message) onReplyTap; final Message message; final MessageTheme messageTheme; final bool showReactions; @@ -23,6 +24,7 @@ class MessageActionsModal extends StatelessWidget { final bool showCopyMessage; final bool showEditMessage; final bool showReply; + final bool showThreadReply; final bool reverse; final ShapeBorder messageShape; final DisplayWidget showUserAvatar; @@ -34,9 +36,11 @@ class MessageActionsModal extends StatelessWidget { this.showReactions = true, this.showDeleteMessage = true, this.showEditMessage = true, - this.onThreadTap, + this.onReplyTap, + this.onThreadReplyTap, this.showCopyMessage = true, this.showReply = true, + this.showThreadReply = true, this.showUserAvatar = DisplayWidget.show, this.editMessageInputBuilder, this.messageShape, @@ -114,6 +118,7 @@ class MessageActionsModal extends StatelessWidget { showReactions: false, showUsername: false, showReplyIndicator: false, + showThreadReplyIndicator: false, showUserAvatar: showUserAvatar, showTimestamp: false, translateUserAvatar: false, @@ -158,6 +163,12 @@ class MessageActionsModal extends StatelessWidget { message.status == null) && message.parentId == null) _buildReplyButton(context), + if (showThreadReply && + (message.status == + MessageSendingStatus.SENT || + message.status == null) && + message.parentId == null) + _buildThreadReplyButton(context), if (showEditMessage) _buildEditMessage(context), if (showDeleteMessage) @@ -181,6 +192,24 @@ 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, + ), + onTap: () { + Navigator.pop(context); + if (onReplyTap != null) { + onReplyTap(message); + } + }, + ); + } + Widget _buildDeleteButton(BuildContext context) { return ListTile( title: Text( @@ -313,7 +342,7 @@ class MessageActionsModal extends StatelessWidget { ); } - Widget _buildReplyButton(BuildContext context) { + Widget _buildThreadReplyButton(BuildContext context) { return ListTile( title: Text( 'Thread reply', @@ -324,8 +353,8 @@ class MessageActionsModal extends StatelessWidget { ), onTap: () { Navigator.pop(context); - if (onThreadTap != null) { - onThreadTap(message); + if (onThreadReplyTap != null) { + onThreadReplyTap(message); } }, ); diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 4e30afe1..18b6d014 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -1,5 +1,6 @@ import 'dart:async'; import 'dart:io'; +import 'dart:math'; import 'package:emojis/emoji.dart'; import 'package:file_picker/file_picker.dart'; @@ -21,9 +22,10 @@ import 'package:stream_chat_flutter/src/stream_svg_icon.dart'; import 'package:stream_chat_flutter/src/user_avatar.dart'; import 'package:substring_highlight/substring_highlight.dart'; import 'package:video_compress/video_compress.dart'; -import 'package:photo_manager/photo_manager.dart'; +import 'extension.dart'; import '../stream_chat_flutter.dart'; +import 'reply_message_widget.dart'; import 'stream_channel.dart'; typedef FileUploader = Future Function(PlatformFile, Channel); @@ -108,6 +110,7 @@ class MessageInput extends StatefulWidget { this.actionsLocation = ActionsLocation.left, this.attachmentThumbnailBuilders, this.focusNode, + this.replyMessage, }) : super(key: key); /// Message to edit @@ -156,6 +159,9 @@ class MessageInput extends StatefulWidget { /// The focus node associated to the TextField final FocusNode focusNode; + /// + final Message replyMessage; + @override MessageInputState createState() => MessageInputState(); @@ -167,7 +173,7 @@ class MessageInput extends StatefulWidget { if (messageInputState == null) { throw Exception( - 'You must have a MessageInput widget as anchestor of your widget tree'); + 'You must have a MessageInput widget as ancestor of your widget tree'); } return messageInputState; @@ -197,9 +203,13 @@ class MessageInputState extends State { /// The editing controller passed to the input TextField TextEditingController textEditingController; + Message _replyMessage; + + bool get _hasReplyMessage => _replyMessage != null; + @override Widget build(BuildContext context) { - return SafeArea( + Widget child = SafeArea( child: GestureDetector( onPanUpdate: (details) { if (details.delta.dy > 0) { @@ -214,8 +224,31 @@ class MessageInputState extends State { child: Column( mainAxisSize: MainAxisSize.min, children: [ + if (_hasReplyMessage) + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Padding( + padding: const EdgeInsets.all(8.0), + child: StreamSvgIcon.reply( + color: Colors.black.withOpacity(0.2), + ), + ), + Text( + 'Reply to Message', + style: TextStyle(fontWeight: FontWeight.bold), + ), + IconButton( + visualDensity: VisualDensity.compact, + icon: StreamSvgIcon.close_small(), + onPressed: () { + setState(() => _replyMessage = null); + }, + ), + ], + ), Padding( - padding: const EdgeInsets.all(8.0), + padding: const EdgeInsets.symmetric(vertical: 8.0), child: _buildTextField(context), ), if (widget.parentMessage != null) @@ -228,6 +261,14 @@ class MessageInputState extends State { ), ), ); + if (widget.editMessage == null) { + child = Material( + color: Colors.white, + elevation: 8, + child: child, + ); + } + return child; } Flex _buildTextField(BuildContext context) { @@ -332,6 +373,9 @@ class MessageInputState extends State { _actionsShrunk = false; }); }, + visualDensity: VisualDensity.compact, + splashRadius: 24, + padding: const EdgeInsets.all(0), icon: StreamSvgIcon.emptyCircleLeft( color: StreamChatTheme.of(context).accentColor, ), @@ -356,12 +400,13 @@ class MessageInputState extends State { decoration: BoxDecoration( borderRadius: BorderRadius.circular(20.0), border: Border.all( - color: Colors.grey, + color: Colors.black.withOpacity(0.16), ), ), child: Column( mainAxisSize: MainAxisSize.min, children: [ + _buildRepyToMessage(), _buildAttachments(), LimitedBox( maxHeight: widget.maxHeight, @@ -436,6 +481,7 @@ class MessageInputState extends State { } Timer _debounce; + void _onChanged(BuildContext context, String s) { if (_debounce?.isActive == true) _debounce.cancel(); _debounce = Timer( @@ -799,7 +845,7 @@ class MessageInputState extends State { Widget _buildPickerSection() { var _attachmentContainsFile = - _attachments.any((element) => element.attachment.type == 'file'); + _attachments.any((element) => element.attachment?.type == 'file'); switch (_filePickerIndex) { case 0: @@ -1232,6 +1278,25 @@ class MessageInputState extends State { _commandsOverlay = null; } + Widget _buildRepyToMessage() { + if (!_hasReplyMessage) { + return Offstage(); + } + final containsUrl = _replyMessage.attachments + ?.any((element) => element.ogScrapeUrl != null) == + true; + return Transform( + transform: Matrix4.rotationY(pi), + alignment: Alignment.center, + child: ReplyMessageWidget( + reverse: true, + showBorder: !containsUrl, + message: _replyMessage, + messageTheme: StreamChatTheme.of(context).otherMessageTheme, + ), + ); + } + Widget _buildAttachments() { return _attachments.isEmpty ? Container() @@ -1437,57 +1502,68 @@ class MessageInputState extends State { } Widget _buildCommandButton() { - return InkWell( - child: Padding( - padding: - const EdgeInsets.only(left: 4.0, right: 8.0, top: 8.0, bottom: 8.0), - child: StreamSvgIcon.lightning( + return Padding( + padding: const EdgeInsets.all(8.0), + child: IconButton( + icon: StreamSvgIcon.lightning( color: Color(0xFF000000).withAlpha(128), ), + padding: const EdgeInsets.all(0), + constraints: BoxConstraints.tightFor( + height: 24, + width: 24, + ), + splashRadius: 24, + onPressed: () { + if (_commandsOverlay == null) { + _commandsOverlay = _buildCommandsOverlayEntry(); + Overlay.of(context).insert(_commandsOverlay); + } else { + _commandsOverlay?.remove(); + _commandsOverlay = null; + } + }, ), - onTap: () { - if (_commandsOverlay == null) { - _commandsOverlay = _buildCommandsOverlayEntry(); - Overlay.of(context).insert(_commandsOverlay); - } else { - _commandsOverlay?.remove(); - _commandsOverlay = null; - } - }, ); } Widget _buildAttachmentButton() { var padding = widget.editMessage == null ? 4.0 : 8.0; return Center( - child: InkWell( - child: Padding( - padding: - EdgeInsets.only(left: 8.0, right: padding, top: 8.0, bottom: 8.0), - child: StreamSvgIcon.attach( + child: Padding( + padding: + EdgeInsets.only(left: 8.0, right: padding, top: 8.0, bottom: 8.0), + child: IconButton( + icon: StreamSvgIcon.attach( color: _openFilePickerSection ? StreamChatTheme.of(context).accentColor : Color(0xFF000000).withAlpha(128), ), - ), - onTap: () async { - _emojiOverlay?.remove(); - _emojiOverlay = null; - _commandsOverlay?.remove(); - _commandsOverlay = null; - _mentionsOverlay?.remove(); - _mentionsOverlay = null; + padding: const EdgeInsets.all(0), + constraints: BoxConstraints.tightFor( + height: 24, + width: 24, + ), + splashRadius: 24, + onPressed: () async { + _emojiOverlay?.remove(); + _emojiOverlay = null; + _commandsOverlay?.remove(); + _commandsOverlay = null; + _mentionsOverlay?.remove(); + _mentionsOverlay = null; - if (_openFilePickerSection) { - setState(() { - _animateContainer = true; - _openFilePickerSection = false; - _filePickerSize = _kMinMediaPickerSize; - }); - } else { - showAttachmentModal(); - } - }, + if (_openFilePickerSection) { + setState(() { + _animateContainer = true; + _openFilePickerSection = false; + _filePickerSize = _kMinMediaPickerSize; + }); + } else { + showAttachmentModal(); + } + }, + ), ), ); } @@ -1786,15 +1862,11 @@ class MessageInputState extends State { return Padding( padding: const EdgeInsets.all(8.0), child: Center( - child: InkWell( - onTap: () { - sendMessage(); - }, child: StreamSvgIcon( assetName: _getIdleSendIcon(), color: Colors.grey, ), - )), + ), ); } @@ -1802,11 +1874,16 @@ class MessageInputState extends State { return Center( child: Padding( padding: const EdgeInsets.all(8.0), - child: InkWell( - onTap: () { - sendMessage(); - }, - child: StreamSvgIcon( + child: IconButton( + onPressed: sendMessage, + visualDensity: VisualDensity.compact, + padding: const EdgeInsets.all(0), + splashRadius: 24, + constraints: BoxConstraints.tightFor( + height: 24, + width: 24, + ), + icon: StreamSvgIcon( assetName: _getSendIcon(), color: StreamChatTheme.of(context).accentColor, ), @@ -1918,6 +1995,8 @@ class MessageInputState extends State { void initState() { super.initState(); + _replyMessage = widget.replyMessage; + _focusNode = widget.focusNode ?? FocusNode(); _emojiNames = Emoji.all().map((e) => e.name); @@ -1970,6 +2049,7 @@ class MessageInputState extends State { } bool _initialized = false; + @override void didChangeDependencies() { if (widget.editMessage != null && !_initialized) { @@ -1978,6 +2058,14 @@ class MessageInputState extends State { } super.didChangeDependencies(); } + + @override + void didUpdateWidget(MessageInput oldWidget) { + super.didUpdateWidget(oldWidget); + if (widget.replyMessage?.id != _replyMessage?.id) { + _replyMessage = widget.replyMessage; + } + } } class _SendingAttachment { @@ -1994,12 +2082,6 @@ class _SendingAttachment { }); } -extension StringExtension on String { - String capitalize() { - return "${this[0].toUpperCase()}${this.substring(1)}"; - } -} - /// Represents a 2-tuple, or pair. class Tuple2 { /// Returns the first item of the tuple diff --git a/lib/src/message_list_view.dart b/lib/src/message_list_view.dart index 430e0b85..2881496e 100644 --- a/lib/src/message_list_view.dart +++ b/lib/src/message_list_view.dart @@ -13,6 +13,7 @@ import 'package:visibility_detector/visibility_detector.dart'; import '../stream_chat_flutter.dart'; import 'date_divider.dart'; import 'stream_channel.dart'; +import 'swipeable.dart'; typedef MessageBuilder = Widget Function( BuildContext, @@ -26,6 +27,9 @@ typedef ParentMessageBuilder = Widget Function( typedef ThreadBuilder = Widget Function(BuildContext context, Message parent); typedef ThreadTapCallback = void Function(Message, Widget); +typedef OnMessageSwiped = void Function(Message); +typedef ReplyTapCallback = void Function(Message); + class MessageDetails { /// True if the message belongs to the current user bool isMyMessage; @@ -106,12 +110,14 @@ class MessageListView extends StatefulWidget { this.parentMessage, this.threadBuilder, this.onThreadTap, + this.onReplyTap, this.dateDividerBuilder, this.scrollPhysics = const AlwaysScrollableScrollPhysics(), this.initialScrollIndex = 0, this.initialAlignment = 0, this.scrollController, this.itemPositionListener, + this.onMessageSwiped, }) : super(key: key); /// Function used to build a custom message widget @@ -153,6 +159,12 @@ class MessageListView extends StatefulWidget { /// The ScrollPhysics used by the ListView final ScrollPhysics scrollPhysics; + /// Called when message item gets swiped + final OnMessageSwiped onMessageSwiped; + + /// + final ReplyTapCallback onReplyTap; + @override _MessageListViewState createState() => _MessageListViewState(); } @@ -273,7 +285,7 @@ class _MessageListViewState extends State { if (widget.messageBuilder != null) { messageWidget = Builder( key: ValueKey('MESSAGE-${message.id}'), - builder: (_) => widget.messageBuilder( + builder: (context) => widget.messageBuilder( context, MessageDetails( context, @@ -540,6 +552,7 @@ class _MessageListViewState extends State { return MessageWidget( showReplyIndicator: false, + showThreadReplyIndicator: false, message: message, reverse: isMyMessage, showUsername: !isMyMessage, @@ -597,47 +610,54 @@ class _MessageListViewState extends State { final allRead = readList.length >= (channel.memberCount ?? 0) - 1; - return MessageWidget( - key: ValueKey('MESSAGE-${message.id}'), - message: message, - reverse: isMyMessage, - showReactions: !message.isDeleted, - padding: EdgeInsets.only( - left: 8.0, - right: 8.0, - bottom: index == 0 ? 30 : (isNextUser ? 5 : 10), + return Swipeable( + onSwipeEnd: () => widget.onMessageSwiped(message), + backgroundIcon: StreamSvgIcon.reply( + color: StreamChatTheme.of(context).accentColor, ), - showUsername: !isMyMessage && !isNextUser, - showSendingIndicator: isMyMessage && - (index == 0 || message.status != MessageSendingStatus.SENT) - ? DisplayWidget.show - : DisplayWidget.hide, - showTimestamp: !isNextUser || readList?.isNotEmpty == true, - showEditMessage: isMyMessage, - showDeleteMessage: isMyMessage, - borderSide: isMyMessage ? BorderSide.none : null, - onThreadTap: _onThreadTap, - attachmentBorderRadiusGeometry: BorderRadius.only( - topLeft: Radius.circular(16), - bottomLeft: Radius.circular(!isNextUser ? 0 : 16), - topRight: Radius.circular(16), - bottomRight: Radius.circular(16), + child: MessageWidget( + key: ValueKey('MESSAGE-${message.id}'), + message: message, + reverse: isMyMessage, + showReactions: !message.isDeleted, + padding: EdgeInsets.only( + left: 8.0, + right: 8.0, + bottom: index == 0 ? 30 : (isNextUser ? 5 : 10), + ), + showUsername: !isMyMessage && !isNextUser, + showSendingIndicator: isMyMessage && + (index == 0 || message.status != MessageSendingStatus.SENT) + ? DisplayWidget.show + : DisplayWidget.hide, + showTimestamp: !isNextUser || readList?.isNotEmpty == true, + showEditMessage: isMyMessage, + showDeleteMessage: isMyMessage, + borderSide: isMyMessage ? BorderSide.none : null, + 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), + ), + attachmentPadding: const EdgeInsets.all(2), + borderRadiusGeometry: BorderRadius.only( + topLeft: Radius.circular(16), + bottomLeft: Radius.circular(!isNextUser ? 0 : 16), + topRight: Radius.circular(16), + bottomRight: Radius.circular(16), + ), + showUserAvatar: isMyMessage + ? DisplayWidget.gone + : (isNextUser ? DisplayWidget.hide : DisplayWidget.show), + messageTheme: isMyMessage + ? StreamChatTheme.of(context).ownMessageTheme + : StreamChatTheme.of(context).otherMessageTheme, + readList: readList, + allRead: allRead, ), - attachmentPadding: const EdgeInsets.all(2), - borderRadiusGeometry: BorderRadius.only( - topLeft: Radius.circular(16), - bottomLeft: Radius.circular(!isNextUser ? 0 : 16), - topRight: Radius.circular(16), - bottomRight: Radius.circular(16), - ), - showUserAvatar: isMyMessage - ? DisplayWidget.gone - : (isNextUser ? DisplayWidget.hide : DisplayWidget.show), - messageTheme: isMyMessage - ? StreamChatTheme.of(context).ownMessageTheme - : StreamChatTheme.of(context).otherMessageTheme, - readList: readList, - allRead: allRead, ); } diff --git a/lib/src/message_reactions_modal.dart b/lib/src/message_reactions_modal.dart index db5d8710..e5043e62 100644 --- a/lib/src/message_reactions_modal.dart +++ b/lib/src/message_reactions_modal.dart @@ -105,7 +105,7 @@ class MessageReactionsModal extends StatelessWidget { showReactions: false, showUsername: false, showUserAvatar: showUserAvatar, - showReplyIndicator: false, + showThreadReplyIndicator: false, showTimestamp: false, translateUserAvatar: false, showSendingIndicator: DisplayWidget.gone, diff --git a/lib/src/message_widget.dart b/lib/src/message_widget.dart index e5fe146f..27fa4df4 100644 --- a/lib/src/message_widget.dart +++ b/lib/src/message_widget.dart @@ -11,11 +11,13 @@ import 'package:jiffy/jiffy.dart'; import 'package:stream_chat_flutter/src/message_actions_modal.dart'; import 'package:stream_chat_flutter/src/message_reactions_modal.dart'; import 'package:stream_chat_flutter/src/reaction_bubble.dart'; +import 'package:stream_chat_flutter/src/reply_message_widget.dart'; import 'package:stream_chat_flutter/src/url_attachment.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; import 'image_group.dart'; import 'message_text.dart'; +import 'extension.dart'; typedef AttachmentBuilder = Widget Function(BuildContext, Message, Attachment); @@ -46,6 +48,7 @@ class MessageWidget extends StatefulWidget { /// The function called when tapping on replies final void Function(Message) onThreadTap; + final void Function(Message) onReplyTap; final Widget Function(BuildContext, Message) editMessageInputBuilder; final Widget Function(BuildContext, Message) textBuilder; @@ -55,6 +58,9 @@ class MessageWidget extends StatefulWidget { /// The message final Message message; + /// The replyMessage + final Message replyMessage; + /// The message theme final MessageTheme messageTheme; @@ -99,6 +105,9 @@ class MessageWidget extends StatefulWidget { final bool allRead; + /// If true the widget will show the thread reply indicator + final bool showThreadReplyIndicator; + /// If true the widget will show the reply indicator final bool showReplyIndicator; @@ -127,6 +136,7 @@ class MessageWidget extends StatefulWidget { Key key, @required this.message, @required this.messageTheme, + this.replyMessage, this.reverse = false, this.translateUserAvatar = true, this.shape, @@ -140,6 +150,8 @@ class MessageWidget extends StatefulWidget { this.showUserAvatar = DisplayWidget.show, this.showSendingIndicator = DisplayWidget.show, this.showReplyIndicator = true, + this.showThreadReplyIndicator = true, + this.onReplyTap, this.onThreadTap, this.showUsername = true, this.showTimestamp = true, @@ -213,6 +225,8 @@ class MessageWidget extends StatefulWidget { } class _MessageWidgetState extends State { + bool get _hasReplyMessage => widget.replyMessage != null; + @override Widget build(BuildContext context) { var leftPadding = widget.showUserAvatar != DisplayWidget.gone @@ -230,6 +244,9 @@ class _MessageWidgetState extends State { widget.message.attachments?.any((element) => element.type == 'file') == true; + final isMyMessage = + widget.message.user.id == StreamChat.of(context).user.id; + return Portal( child: Padding( padding: widget.padding ?? EdgeInsets.all(8), @@ -306,7 +323,8 @@ class _MessageWidgetState extends State { clipBehavior: Clip.antiAlias, shape: widget.shape ?? RoundedRectangleBorder( - side: isOnlyEmoji + side: isOnlyEmoji && + !_hasReplyMessage ? BorderSide.none : widget.borderSide ?? BorderSide( @@ -333,6 +351,19 @@ class _MessageWidgetState extends State { CrossAxisAlignment.start, mainAxisSize: MainAxisSize.min, children: [ + if (_hasReplyMessage) + ReplyMessageWidget( + message: + widget.replyMessage, + messageTheme: isMyMessage + ? StreamChatTheme.of( + context) + .otherMessageTheme + : StreamChatTheme.of( + context) + .ownMessageTheme, + reverse: widget.reverse, + ), ..._parseAttachments(context), if (widget.message.text .trim() @@ -367,7 +398,7 @@ class _MessageWidgetState extends State { ), ], ), - if (widget.showReplyIndicator && + if (widget.showThreadReplyIndicator && widget.message.replyCount > 0) _buildReplyIndicator(leftPadding), ], @@ -393,7 +424,7 @@ class _MessageWidgetState extends State { var splitList = host.split('.'); var hostName = splitList.length == 3 ? splitList[1] : splitList[0]; var hostDisplayName = urlAttachment.authorName?.capitalize() ?? - _getWebsiteName(hostName.toLowerCase()) ?? + getWebsiteName(hostName.toLowerCase()) ?? hostName.capitalize(); return UrlAttachment( @@ -562,14 +593,16 @@ class _MessageWidgetState extends State { showDeleteMessage: widget.showDeleteMessage, message: widget.message, editMessageInputBuilder: widget.editMessageInputBuilder, - onThreadTap: widget.onThreadTap, + onReplyTap: widget.onReplyTap, + onThreadReplyTap: widget.onThreadTap, showEditMessage: widget.showEditMessage && widget.message.attachments ?.any((element) => element.type == 'giphy') != true, showReactions: widget.showReactions, - showReply: - widget.showReplyIndicator && widget.onThreadTap != null, + showReply: widget.showReplyIndicator, + showThreadReply: + widget.showThreadReplyIndicator && widget.onThreadTap != null, ), ); }); @@ -878,6 +911,10 @@ class _MessageWidgetState extends State { final isOnlyEmoji = widget.message.text.characters.every((c) => Emoji.byChar(c) != null); + if (_hasReplyMessage) { + return widget.messageTheme.messageBackgroundColor; + } + if ((widget.message.status == MessageSendingStatus.FAILED || widget.message.status == MessageSendingStatus.FAILED_UPDATE || widget.message.status == MessageSendingStatus.FAILED_DELETE)) { @@ -918,45 +955,4 @@ class _MessageWidgetState extends State { return; } } - - String _getWebsiteName(String hostName) { - switch (hostName) { - case 'reddit': - return 'Reddit'; - case 'youtube': - return 'Youtube'; - case 'wikipedia': - return 'Wikipedia'; - case 'twitter': - return 'Twitter'; - case 'facebook': - return 'Facebook'; - case 'amazon': - return 'Amazon'; - case 'yelp': - return 'Yelp'; - case 'imdb': - return 'IMDB'; - case 'pinterest': - return 'Pinterest'; - case 'tripadvisor': - return 'TripAdvisor'; - case 'instagram': - return 'Instagram'; - case 'walmart': - return 'Walmart'; - case 'craigslist': - return 'Craigslist'; - case 'ebay': - return 'eBay'; - case 'linkedin': - return 'LinkedIn'; - case 'google': - return 'Google'; - case 'apple': - return 'Apple'; - default: - return null; - } - } } diff --git a/lib/src/reply_message_widget.dart b/lib/src/reply_message_widget.dart new file mode 100644 index 00000000..9ae6f23e --- /dev/null +++ b/lib/src/reply_message_widget.dart @@ -0,0 +1,264 @@ +import 'dart:math'; + +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:emojis/emoji.dart'; +import 'package:flutter/material.dart'; +import 'package:stream_chat/stream_chat.dart'; + +import 'attachment_error.dart'; +import 'image_attachment.dart'; +import 'message_text.dart'; +import 'stream_chat_theme.dart'; +import 'user_avatar.dart'; +import 'utils.dart'; + +/// +class ReplyMessageWidget extends StatelessWidget { + /// The message + final Message message; + + /// The message theme + final MessageTheme messageTheme; + + /// If true the widget will be mirrored + final bool reverse; + + /// If true the message will show a grey border + final bool showBorder; + + /// limit of the text message shown + final int textLimit; + + final Map _attachmentBuilders; + + /// + ReplyMessageWidget({ + Key key, + @required this.message, + @required this.messageTheme, + this.reverse = false, + this.showBorder = false, + this.textLimit = 170, + }) : _attachmentBuilders = { + 'image': (attachment) { + return ImageAttachment( + attachment: attachment, + message: message, + messageTheme: messageTheme, + size: Size(32, 32), + ); + }, + 'video': (attachment) { + final size = Size(32, 32); + if (attachment.thumbUrl != null) { + return Container( + height: size.height, + width: size.width, + decoration: BoxDecoration( + image: DecorationImage( + fit: BoxFit.cover, + image: CachedNetworkImageProvider( + attachment.thumbUrl, + ), + ), + ), + ); + } + return AttachmentError( + attachment: attachment, + size: size, + ); + }, + 'giphy': (attachment) { + final size = Size(32, 32); + return CachedNetworkImage( + height: size?.height, + width: size?.width, + placeholder: (_, __) { + return Container( + width: size?.width, + height: size?.height, + child: Center( + child: CircularProgressIndicator(), + ), + ); + }, + imageUrl: attachment.thumbUrl ?? + attachment.imageUrl ?? + attachment.assetUrl, + errorWidget: (context, url, error) => AttachmentError( + attachment: attachment, + size: size, + ), + fit: BoxFit.cover, + ); + }, + 'file': (attachment) { + return Container( + height: 32, + width: 32, + child: getFileTypeImage(attachment.extraData['mime_type']), + ); + }, + }, + super(key: key); + + bool get _hasAttachments => message.attachments?.isNotEmpty == true; + + bool get _containsScrapeUrl => + message.attachments?.any((element) => element.ogScrapeUrl != null) == + true; + + bool get _containsText => message?.text?.isNotEmpty == true; + + @override + Widget build(BuildContext context) { + return Padding( + padding: const EdgeInsets.only(top: 8, bottom: 6, right: 4, left: 8), + child: Row( + crossAxisAlignment: CrossAxisAlignment.end, + children: [ + Expanded(child: _buildMessage(context)), + SizedBox(width: 4), + _buildUserAvatar(), + ], + ), + ); + } + + Widget _buildMessage(BuildContext context) { + final children = [ + if (_hasAttachments) ...[ + _parseAttachments(context), + SizedBox(width: 8), + ], + Expanded(child: _buildTextMessage()), + ]; + return Container( + constraints: BoxConstraints( + minHeight: 48.0, + ), + decoration: BoxDecoration( + color: _getBackgroundColor(), + border: showBorder ? Border.all(color: Colors.black.withOpacity(0.08)) : null, + borderRadius: BorderRadius.only( + topRight: Radius.circular(12), + topLeft: Radius.circular(12), + bottomLeft: Radius.circular(12), + ), + ), + padding: const EdgeInsets.all(8), + child: Row( + mainAxisAlignment: + reverse ? MainAxisAlignment.end : MainAxisAlignment.start, + children: reverse ? children.reversed.toList() : children, + ), + ); + } + + Widget _buildTextMessage() { + final isOnlyEmoji = + message.text.characters.every((c) => Emoji.byChar(c) != null); + var msg = _hasAttachments && !_containsText + ? message.copyWith(text: message.attachments.last?.title ?? 'File') + : message; + if (msg.text.length > textLimit) { + msg = msg.copyWith(text: '${msg.text.substring(0, textLimit - 3)}...'); + } + return Transform( + transform: Matrix4.rotationY(reverse ? pi : 0), + alignment: Alignment.center, + child: MessageText( + message: msg, + messageTheme: isOnlyEmoji && _containsText + ? messageTheme.copyWith( + messageText: messageTheme.messageText.copyWith( + fontSize: 24, + )) + : messageTheme, + ), + ); + } + + Widget _buildUrlAttachment(Attachment attachment) { + final size = Size(32, 32); + if (attachment.thumbUrl != null) { + return Container( + height: size.height, + width: size.width, + decoration: BoxDecoration( + image: DecorationImage( + fit: BoxFit.cover, + image: CachedNetworkImageProvider( + attachment.imageUrl, + ), + ), + ), + ); + } + return AttachmentError( + attachment: attachment, + size: size, + ); + } + + Widget _parseAttachments(BuildContext context) { + Widget child; + Attachment attachment; + if (_containsScrapeUrl) { + attachment = message.attachments.firstWhere( + (element) => element.ogScrapeUrl != null, + ); + child = _buildUrlAttachment(attachment); + } else { + attachment = message.attachments.last; + final attachmentBuilder = _attachmentBuilders[attachment.type]; + if (attachmentBuilder == null) { + child = Offstage(); + } + child = attachmentBuilder(attachment); + } + return Material( + clipBehavior: Clip.hardEdge, + color: Colors.transparent, + shape: attachment.type == 'file' ? null : _getDefaultShape(context), + child: child, + ); + } + + ShapeBorder _getDefaultShape(BuildContext context) { + return RoundedRectangleBorder( + side: BorderSide( + color: Theme.of(context).brightness == Brightness.dark + ? Colors.white.withAlpha(24) + : Colors.black.withAlpha(24), + ), + borderRadius: BorderRadius.circular(8), + ); + } + + Widget _buildUserAvatar() { + return Transform( + transform: Matrix4.rotationY(reverse ? pi : 0), + alignment: Alignment.center, + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 4.0), + child: UserAvatar( + user: message.user, + constraints: BoxConstraints.tightFor( + height: 24, + width: 24, + ), + showOnlineStatus: false, + ), + ), + ); + } + + Color _getBackgroundColor() { + if (_containsScrapeUrl) { + return Color(0xFFE9F2FF); + } + return messageTheme.messageBackgroundColor; + } +} diff --git a/lib/src/stream_svg_icon.dart b/lib/src/stream_svg_icon.dart index 42fed46e..607f7208 100644 --- a/lib/src/stream_svg_icon.dart +++ b/lib/src/stream_svg_icon.dart @@ -326,6 +326,18 @@ class StreamSvgIcon extends StatelessWidget { ); } + factory StreamSvgIcon.reply({ + double size, + Color color, + }) { + return StreamSvgIcon( + assetName: 'Icon_curve_line_left_up_big.svg', + color: color, + width: size, + height: size, + ); + } + factory StreamSvgIcon.edit({ double size, Color color, diff --git a/lib/src/swipeable.dart b/lib/src/swipeable.dart new file mode 100644 index 00000000..bdaf6993 --- /dev/null +++ b/lib/src/swipeable.dart @@ -0,0 +1,162 @@ +import 'dart:math' as math; + +import 'package:flutter/material.dart'; + +/// +class Swipeable extends StatefulWidget { + final Widget child; + final Widget backgroundIcon; + final VoidCallback onSwipeStart; + final VoidCallback onSwipeCancel; + final VoidCallback onSwipeEnd; + final double threshold; + + /// + const Swipeable({ + @required this.child, + @required this.backgroundIcon, + this.onSwipeStart, + this.onSwipeCancel, + this.onSwipeEnd, + this.threshold = 82.0, + }); + + @override + State createState() => _SwipeableState(); +} + +class _SwipeableState extends State with TickerProviderStateMixin { + double _dragExtent = 0.0; + AnimationController _moveController; + AnimationController _iconMoveController; + Animation _moveAnimation; + Animation _iconTransitionAnimation; + Animation _iconFadeAnimation; + bool _pastThreshold = false; + + final _animationDuration = const Duration(milliseconds: 200); + + @override + void initState() { + super.initState(); + _moveController = + AnimationController(duration: _animationDuration, vsync: this); + _iconMoveController = + AnimationController(duration: _animationDuration, vsync: this); + _moveAnimation = Tween(begin: Offset.zero, end: Offset(1.0, 0.0)) + .animate(_moveController); + _iconTransitionAnimation = + Tween(begin: Offset(-0.1, 0.0), end: Offset(0.4, 0.0)) + .animate(_moveController); + _iconFadeAnimation = + Tween(begin: 0.7, end: 1.0).animate(_iconMoveController); + + final controllerValue = 0.0; + _moveController.animateTo(controllerValue); + _iconMoveController.animateTo(controllerValue); + } + + @override + void dispose() { + _moveController.dispose(); + _iconMoveController.dispose(); + super.dispose(); + } + + void _handleDragStart(DragStartDetails details) { + if (widget.onSwipeStart != null) { + widget.onSwipeStart(); + } + } + + void _handleDragUpdate(DragUpdateDetails details) { + print(_moveAnimation.value.dx); + + final delta = details.primaryDelta; + if (delta.isNegative) return; + + _dragExtent += delta; + + var movePastThresholdPixels = widget.threshold; + var newPos = _dragExtent.abs() / context.size.width; + + if (_dragExtent.abs() > movePastThresholdPixels) { + // how many "thresholds" past the threshold we are. 1 = the threshold 2 + // = two thresholds. + var n = _dragExtent.abs() / movePastThresholdPixels; + + // Take the number of thresholds past the threshold, and reduce this + // number + var reducedThreshold = math.pow(n, 0.3); + + var adjustedPixelPos = movePastThresholdPixels * reducedThreshold; + newPos = adjustedPixelPos / context.size.width; + + if (_dragExtent > 0 && !_pastThreshold) { + _iconMoveController.value = 1; + _pastThreshold = true; + } + } else { + // Send a cancel event if the user has swiped back underneath the + // threshold + if (_pastThreshold && widget.onSwipeCancel != null) { + widget.onSwipeCancel(); + } + _pastThreshold = false; + } + if (!_pastThreshold || newPos < _moveController.value) { + _iconMoveController.value = newPos; + } + _moveController.value = newPos; + } + + void _handleDragEnd(DragEndDetails details) { + _moveController.animateTo(0.0, duration: _animationDuration); + _iconMoveController.animateTo(0.0, duration: _animationDuration); + _dragExtent = 0.0; + if (_pastThreshold && widget.onSwipeEnd != null) { + widget.onSwipeEnd(); + } + } + + @override + Widget build(BuildContext context) { + return GestureDetector( + onHorizontalDragStart: _handleDragStart, + onHorizontalDragUpdate: _handleDragUpdate, + onHorizontalDragEnd: _handleDragEnd, + behavior: HitTestBehavior.opaque, + child: Stack( + alignment: Alignment.center, + fit: StackFit.passthrough, + children: [ + SlideTransition( + position: _iconTransitionAnimation, + child: Row( + children: [ + FadeTransition( + opacity: _iconFadeAnimation, + child: Container( + margin: const EdgeInsets.all(8), + padding: const EdgeInsets.all(4), + decoration: BoxDecoration( + shape: BoxShape.circle, + border: Border.all( + color: Colors.black.withOpacity(0.08), + ), + ), + child: widget.backgroundIcon, + ), + ), + ], + ), + ), + SlideTransition( + position: _moveAnimation, + child: widget.child, + ), + ], + ), + ); + } +} diff --git a/lib/src/utils.dart b/lib/src/utils.dart index 20e3ce1f..aad972a4 100644 --- a/lib/src/utils.dart +++ b/lib/src/utils.dart @@ -2,6 +2,8 @@ import 'package:flutter/material.dart'; import 'package:stream_chat/stream_chat.dart'; import 'package:url_launcher/url_launcher.dart'; +import 'stream_svg_icon.dart'; + Future launchURL(BuildContext context, String url) async { if (await canLaunch(url)) { await launch(url); @@ -47,3 +49,105 @@ Future showConfirmationDialog( /// Get random png with initials String getRandomPicUrl(User user) => 'https://getstream.io/random_png/?id=${user.id}&name=${user.name}'; + +/// Get websiteName from [hostName] +String getWebsiteName(String hostName) { + switch (hostName) { + case 'reddit': + return 'Reddit'; + case 'youtube': + return 'Youtube'; + case 'wikipedia': + return 'Wikipedia'; + case 'twitter': + return 'Twitter'; + case 'facebook': + return 'Facebook'; + case 'amazon': + return 'Amazon'; + case 'yelp': + return 'Yelp'; + case 'imdb': + return 'IMDB'; + case 'pinterest': + return 'Pinterest'; + case 'tripadvisor': + return 'TripAdvisor'; + case 'instagram': + return 'Instagram'; + case 'walmart': + return 'Walmart'; + case 'craigslist': + return 'Craigslist'; + case 'ebay': + return 'eBay'; + case 'linkedin': + return 'LinkedIn'; + case 'google': + return 'Google'; + case 'apple': + return 'Apple'; + default: + return null; + } +} + +/// +StreamSvgIcon getFileTypeImage(String type) { + switch (type) { + case '7z': + return StreamSvgIcon.filetype_7z(); + break; + case 'csv': + return StreamSvgIcon.filetype_csv(); + break; + case 'doc': + return StreamSvgIcon.filetype_doc(); + break; + case 'docx': + return StreamSvgIcon.filetype_docx(); + break; + case 'html': + return StreamSvgIcon.filetype_html(); + break; + case 'md': + return StreamSvgIcon.filetype_md(); + break; + case 'odt': + return StreamSvgIcon.filetype_odt(); + break; + case 'pdf': + return StreamSvgIcon.filetype_pdf(); + break; + case 'ppt': + return StreamSvgIcon.filetype_ppt(); + break; + case 'pptx': + return StreamSvgIcon.filetype_pptx(); + break; + case 'rar': + return StreamSvgIcon.filetype_rar(); + break; + case 'rtf': + return StreamSvgIcon.filetype_rtf(); + break; + case 'tar': + return StreamSvgIcon.filetype_tar(); + break; + case 'txt': + return StreamSvgIcon.filetype_txt(); + break; + case 'xls': + return StreamSvgIcon.filetype_xls(); + break; + case 'xlsx': + return StreamSvgIcon.filetype_xlsx(); + break; + case 'zip': + return StreamSvgIcon.filetype_zip(); + break; + default: + return StreamSvgIcon.filetype_Generic(); + break; + } +} From 8223f4833005833bcba7f0465cef81fe543bf4f2 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Mon, 7 Dec 2020 22:45:59 +0530 Subject: [PATCH 0578/1140] flutter format Signed-off-by: Sahil Kumar --- lib/src/reply_message_widget.dart | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/src/reply_message_widget.dart b/lib/src/reply_message_widget.dart index 9ae6f23e..9a56c601 100644 --- a/lib/src/reply_message_widget.dart +++ b/lib/src/reply_message_widget.dart @@ -140,7 +140,9 @@ class ReplyMessageWidget extends StatelessWidget { ), decoration: BoxDecoration( color: _getBackgroundColor(), - border: showBorder ? Border.all(color: Colors.black.withOpacity(0.08)) : null, + border: showBorder + ? Border.all(color: Colors.black.withOpacity(0.08)) + : null, borderRadius: BorderRadius.only( topRight: Radius.circular(12), topLeft: Radius.circular(12), From e78bdc60278f96407d89b2c009363a8793e76648 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Tue, 8 Dec 2020 11:52:11 +0530 Subject: [PATCH 0579/1140] fix test Signed-off-by: Sahil Kumar --- test/src/message_action_modal_test.dart | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/src/message_action_modal_test.dart b/test/src/message_action_modal_test.dart index 5b0c1678..0dcd8d87 100644 --- a/test/src/message_action_modal_test.dart +++ b/test/src/message_action_modal_test.dart @@ -71,6 +71,7 @@ void main() { showCopyMessage: false, showDeleteMessage: false, showReply: false, + showThreadReply: false, message: Message( text: 'test', user: User( @@ -87,6 +88,7 @@ void main() { await tester.pump(Duration(milliseconds: 1000)); expect(find.byKey(Key('MessageWidget')), findsOneWidget); + expect(find.text('Reply'), findsNothing); expect(find.text('Thread reply'), findsNothing); expect(find.text('Edit message'), findsNothing); expect(find.text('Delete message'), findsNothing); From c133002118a126774758bfaa145ca94d1eae4627 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Tue, 8 Dec 2020 17:01:29 +0530 Subject: [PATCH 0580/1140] [Swipeable] Allow widget to swipe backward Signed-off-by: Sahil Kumar --- lib/src/swipeable.dart | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/lib/src/swipeable.dart b/lib/src/swipeable.dart index bdaf6993..d56a8e24 100644 --- a/lib/src/swipeable.dart +++ b/lib/src/swipeable.dart @@ -70,13 +70,11 @@ class _SwipeableState extends State with TickerProviderStateMixin { } void _handleDragUpdate(DragUpdateDetails details) { - print(_moveAnimation.value.dx); - final delta = details.primaryDelta; - if (delta.isNegative) return; - _dragExtent += delta; + if (_dragExtent.isNegative) return; + var movePastThresholdPixels = widget.threshold; var newPos = _dragExtent.abs() / context.size.width; From 4c3cb91318056b2129935df4c1980081053092bc Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Tue, 8 Dec 2020 17:02:58 +0530 Subject: [PATCH 0581/1140] [Reply Message Widget] Remove default message text. Signed-off-by: Sahil Kumar --- lib/src/reply_message_widget.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/reply_message_widget.dart b/lib/src/reply_message_widget.dart index 9a56c601..d09903cf 100644 --- a/lib/src/reply_message_widget.dart +++ b/lib/src/reply_message_widget.dart @@ -162,7 +162,7 @@ class ReplyMessageWidget extends StatelessWidget { final isOnlyEmoji = message.text.characters.every((c) => Emoji.byChar(c) != null); var msg = _hasAttachments && !_containsText - ? message.copyWith(text: message.attachments.last?.title ?? 'File') + ? message.copyWith(text: message.attachments.last?.title ?? '') : message; if (msg.text.length > textLimit) { msg = msg.copyWith(text: '${msg.text.substring(0, textLimit - 3)}...'); From 54061c8d509bd50271d0875612b0de32e6c95694 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Tue, 8 Dec 2020 17:12:33 +0530 Subject: [PATCH 0582/1140] [MessageInput] Remove reply message widget when sendMessage is called. Signed-off-by: Sahil Kumar --- lib/src/message_input.dart | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 18b6d014..7aaa8f5f 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -1925,6 +1925,7 @@ class MessageInputState extends State { textEditingController.clear(); _attachments.clear(); + _replyMessage = null; setState(() { _messageIsPresent = false; From 3394126adfbb1df2d441cfd9cdac2058b16b738b Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Tue, 8 Dec 2020 17:21:20 +0530 Subject: [PATCH 0583/1140] fix: Fixed message input --- lib/src/message_input.dart | 47 ++++++++++++++++++++++++++++---------- 1 file changed, 35 insertions(+), 12 deletions(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 4e30afe1..1d220eaf 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -354,7 +354,7 @@ class MessageInputState extends State { child: Container( clipBehavior: Clip.antiAlias, decoration: BoxDecoration( - borderRadius: BorderRadius.circular(20.0), + borderRadius: BorderRadius.circular(24.0), border: Border.all( color: Colors.grey, ), @@ -404,26 +404,45 @@ class MessageInputState extends State { child: Chip( backgroundColor: StreamChatTheme.of(context).accentColor, - label: Text( - _chosenCommand?.name ?? "", - style: TextStyle(color: Colors.white), - ), - avatar: StreamSvgIcon.lightning( - color: Colors.white, + padding: EdgeInsets.zero, + labelPadding: + EdgeInsets.symmetric(horizontal: 9.0), + label: Row( + mainAxisSize: MainAxisSize.min, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + StreamSvgIcon.lightning( + color: Colors.white, + size: 16.0, + ), + Text( + _chosenCommand?.name?.toUpperCase() ?? "", + style: TextStyle( + color: Colors.white, fontSize: 12.0), + ), + ], ), ), ) : null, suffixIcon: _commandEnabled - ? IconButton( - icon: Icon(Icons.cancel_outlined), - onPressed: () { + ? InkWell( + child: Padding( + padding: + const EdgeInsets.symmetric(horizontal: 8.0), + child: StreamSvgIcon.close_small(), + ), + onTap: () { setState(() { _commandEnabled = false; }); }, ) : null, + suffixIconConstraints: BoxConstraints( + maxHeight: 24.0, + maxWidth: 40.0, + ), ), textCapitalization: TextCapitalization.sentences, ), @@ -1784,7 +1803,7 @@ class MessageInputState extends State { Widget _buildIdleSendButton(BuildContext context) { return Padding( - padding: const EdgeInsets.all(8.0), + padding: const EdgeInsets.all(8.0) + EdgeInsets.only(bottom: 3.0), child: Center( child: InkWell( onTap: () { @@ -1793,6 +1812,8 @@ class MessageInputState extends State { child: StreamSvgIcon( assetName: _getIdleSendIcon(), color: Colors.grey, + height: 24.0, + width: 24.0, ), )), ); @@ -1801,7 +1822,7 @@ class MessageInputState extends State { Widget _buildSendButton(BuildContext context) { return Center( child: Padding( - padding: const EdgeInsets.all(8.0), + padding: const EdgeInsets.all(8.0) + EdgeInsets.only(bottom: 3.0), child: InkWell( onTap: () { sendMessage(); @@ -1809,6 +1830,8 @@ class MessageInputState extends State { child: StreamSvgIcon( assetName: _getSendIcon(), color: StreamChatTheme.of(context).accentColor, + height: 24.0, + width: 24.0, ), ), ), From 08c7b281983082c4adec0caf12c13a331166c0a4 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Tue, 8 Dec 2020 17:36:21 +0530 Subject: [PATCH 0584/1140] fix: Fixed command picker --- lib/src/message_input.dart | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 1d220eaf..2eb5b706 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -1461,16 +1461,31 @@ class MessageInputState extends State { padding: const EdgeInsets.only(left: 4.0, right: 8.0, top: 8.0, bottom: 8.0), child: StreamSvgIcon.lightning( - color: Color(0xFF000000).withAlpha(128), + color: _commandsOverlay != null + ? StreamChatTheme.of(context).accentColor + : Color(0xFF000000).withAlpha(128), ), ), - onTap: () { + onTap: () async { + if (_openFilePickerSection) { + setState(() { + _animateContainer = false; + _openFilePickerSection = false; + _filePickerSize = _kMinMediaPickerSize; + }); + await Future.delayed(Duration(milliseconds: 300)); + } + if (_commandsOverlay == null) { - _commandsOverlay = _buildCommandsOverlayEntry(); - Overlay.of(context).insert(_commandsOverlay); + setState(() { + _commandsOverlay = _buildCommandsOverlayEntry(); + Overlay.of(context).insert(_commandsOverlay); + }); } else { - _commandsOverlay?.remove(); - _commandsOverlay = null; + setState(() { + _commandsOverlay?.remove(); + _commandsOverlay = null; + }); } }, ); From b9a1f813ac1affc12c90cbd68f7f295b54b4deff Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Tue, 8 Dec 2020 19:25:04 +0530 Subject: [PATCH 0585/1140] fix: Fixed file title --- lib/src/message_input.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 2eb5b706..43bfec97 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -1701,7 +1701,7 @@ class MessageInputState extends State { localUri: file.path != null ? Uri.parse(file.path) : null, type: attachmentType, extraData: extraDataMap.isNotEmpty ? extraDataMap : null, - title: file.name ?? 'File', + title: mimeType.type == 'file' ? file.name : null, ), ); From c6a97751316bdebcc05f1a6c19535a3aa0315c8d Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Tue, 8 Dec 2020 20:00:30 +0530 Subject: [PATCH 0586/1140] feat: Added dummy pages for files and media --- lib/src/chat_info_screen.dart | 78 ++++++++++++++++++++++++++++++++++- 1 file changed, 76 insertions(+), 2 deletions(-) diff --git a/lib/src/chat_info_screen.dart b/lib/src/chat_info_screen.dart index 8310d1b9..92ee4446 100644 --- a/lib/src/chat_info_screen.dart +++ b/lib/src/chat_info_screen.dart @@ -147,7 +147,10 @@ class _ChatInfoScreenState extends State { color: Colors.black.withOpacity(0.5), ), trailing: StreamSvgIcon.right(), - onTap: () {}, + onTap: () { + Navigator.push(context, + MaterialPageRoute(builder: (context) => _MediaDisplayScreen())); + }, ), _OptionListTile( title: '8 Files', @@ -156,7 +159,10 @@ class _ChatInfoScreenState extends State { color: Colors.black.withOpacity(0.5), ), trailing: StreamSvgIcon.right(), - onTap: () {}, + onTap: () { + Navigator.push(context, + MaterialPageRoute(builder: (context) => _FileDisplayScreen())); + }, ), StreamBuilder>( stream: StreamChat.of(context).client.queryChannels( @@ -408,3 +414,71 @@ class __SharedGroupsScreenState extends State<_SharedGroupsScreen> { ); } } + +class _MediaDisplayScreen extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: Colors.white, + appBar: AppBar( + brightness: Theme.of(context).brightness, + elevation: 1, + centerTitle: true, + title: Text( + 'Photos & Videos', + style: TextStyle(color: Colors.black, fontSize: 16.0), + ), + leading: Center( + child: InkWell( + onTap: () { + Navigator.of(context).pop(); + }, + child: Container( + child: StreamSvgIcon.left( + color: Colors.black, + size: 24.0, + ), + width: 24.0, + height: 24.0, + ), + ), + ), + backgroundColor: StreamChatTheme.of(context).primaryColor, + ), + ); + } +} + +class _FileDisplayScreen extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: Colors.white, + appBar: AppBar( + brightness: Theme.of(context).brightness, + elevation: 1, + centerTitle: true, + title: Text( + 'Files', + style: TextStyle(color: Colors.black, fontSize: 16.0), + ), + leading: Center( + child: InkWell( + onTap: () { + Navigator.of(context).pop(); + }, + child: Container( + child: StreamSvgIcon.left( + color: Colors.black, + size: 24.0, + ), + width: 24.0, + height: 24.0, + ), + ), + ), + backgroundColor: StreamChatTheme.of(context).primaryColor, + ), + ); + } +} From bec480dad7bcd1a7dcecce02af448cbf2d080499 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Wed, 9 Dec 2020 12:29:29 +0530 Subject: [PATCH 0587/1140] [Swipeable] Remove extra margin Signed-off-by: Sahil Kumar --- lib/src/swipeable.dart | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/src/swipeable.dart b/lib/src/swipeable.dart index d56a8e24..c2279e63 100644 --- a/lib/src/swipeable.dart +++ b/lib/src/swipeable.dart @@ -135,7 +135,6 @@ class _SwipeableState extends State with TickerProviderStateMixin { FadeTransition( opacity: _iconFadeAnimation, child: Container( - margin: const EdgeInsets.all(8), padding: const EdgeInsets.all(4), decoration: BoxDecoration( shape: BoxShape.circle, From 5cef917e511538342e855e0d22d1a4d2f4d79077 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Wed, 9 Dec 2020 13:35:28 +0530 Subject: [PATCH 0588/1140] feat: Added implementation for last seen --- lib/src/chat_info_screen.dart | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/lib/src/chat_info_screen.dart b/lib/src/chat_info_screen.dart index 92ee4446..9ef80c9e 100644 --- a/lib/src/chat_info_screen.dart +++ b/lib/src/chat_info_screen.dart @@ -1,6 +1,7 @@ import 'package:emojis/emojis.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; +import 'package:jiffy/jiffy.dart'; import '../stream_chat_flutter.dart'; @@ -62,7 +63,7 @@ class _ChatInfoScreenState extends State { style: TextStyle(fontSize: 16.0, fontWeight: FontWeight.bold), ), SizedBox(height: 7.0), - Text('Online for 5 minutes'), + _buildConnectedTitleState(), SizedBox(height: 15.0), _OptionListTile( title: '@user', @@ -279,6 +280,31 @@ class _ChatInfoScreenState extends State { ); }); } + + Widget _buildConnectedTitleState() { + var alternativeWidget; + + final otherMember = widget.user; + + if (otherMember != null) { + if (otherMember.online) { + alternativeWidget = Text( + 'Online', + style: StreamChatTheme.of(context) + .channelTheme + .channelHeaderTheme + .lastMessageAt, + ); + } else { + alternativeWidget = Text( + 'Last seen ${Jiffy(otherMember.lastActive).fromNow()}', + //style: textStyle, + ); + } + } + + return alternativeWidget; + } } class _OptionListTile extends StatelessWidget { From ae73eb95c60c6f27e81c9ba4ae21c5d52a1c53a4 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Wed, 9 Dec 2020 13:50:03 +0530 Subject: [PATCH 0589/1140] [ReplyMessageWidget] remove expanded width Signed-off-by: Sahil Kumar --- lib/src/message_input.dart | 1 + lib/src/reply_message_widget.dart | 6 ++++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 7aaa8f5f..d1a670f9 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -405,6 +405,7 @@ class MessageInputState extends State { ), child: Column( mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, children: [ _buildRepyToMessage(), _buildAttachments(), diff --git a/lib/src/reply_message_widget.dart b/lib/src/reply_message_widget.dart index d09903cf..7fdae3f2 100644 --- a/lib/src/reply_message_widget.dart +++ b/lib/src/reply_message_widget.dart @@ -117,8 +117,9 @@ class ReplyMessageWidget extends StatelessWidget { padding: const EdgeInsets.only(top: 8, bottom: 6, right: 4, left: 8), child: Row( crossAxisAlignment: CrossAxisAlignment.end, + mainAxisSize: MainAxisSize.min, children: [ - Expanded(child: _buildMessage(context)), + Flexible(child: _buildMessage(context)), SizedBox(width: 4), _buildUserAvatar(), ], @@ -132,7 +133,7 @@ class ReplyMessageWidget extends StatelessWidget { _parseAttachments(context), SizedBox(width: 8), ], - Expanded(child: _buildTextMessage()), + Flexible(child: _buildTextMessage()), ]; return Container( constraints: BoxConstraints( @@ -151,6 +152,7 @@ class ReplyMessageWidget extends StatelessWidget { ), padding: const EdgeInsets.all(8), child: Row( + mainAxisSize: MainAxisSize.min, mainAxisAlignment: reverse ? MainAxisAlignment.end : MainAxisAlignment.start, children: reverse ? children.reversed.toList() : children, From fe541892d9ee8dacbd42818544ba301c5629cba4 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Wed, 9 Dec 2020 12:03:01 +0100 Subject: [PATCH 0590/1140] fix .type on null bug --- lib/src/message_input.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 43bfec97..96439be9 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -818,7 +818,7 @@ class MessageInputState extends State { Widget _buildPickerSection() { var _attachmentContainsFile = - _attachments.any((element) => element.attachment.type == 'file'); + _attachments.any((element) => element.attachment?.type == 'file'); switch (_filePickerIndex) { case 0: From 09fcbad9003546510797af9dd7494ae948fead7c Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Wed, 9 Dec 2020 16:35:07 +0530 Subject: [PATCH 0591/1140] [ReplyMessageWidget] fix video attachment thumbnail Signed-off-by: Sahil Kumar --- lib/src/message_widget.dart | 5 +- lib/src/reply_message_widget.dart | 191 +++++++++++++++++++----------- 2 files changed, 123 insertions(+), 73 deletions(-) diff --git a/lib/src/message_widget.dart b/lib/src/message_widget.dart index c0968cce..ff0d1c7c 100644 --- a/lib/src/message_widget.dart +++ b/lib/src/message_widget.dart @@ -892,8 +892,9 @@ class _MessageWidgetState extends State { ), ), if (widget.message.attachments - ?.any((element) => element.ogScrapeUrl != null) == - true) + ?.any((element) => element.ogScrapeUrl != null) == + true && + !_hasReplyMessage) _buildUrlAttachment(), ], ), diff --git a/lib/src/reply_message_widget.dart b/lib/src/reply_message_widget.dart index 7fdae3f2..56f3112f 100644 --- a/lib/src/reply_message_widget.dart +++ b/lib/src/reply_message_widget.dart @@ -4,6 +4,7 @@ import 'package:cached_network_image/cached_network_image.dart'; import 'package:emojis/emoji.dart'; import 'package:flutter/material.dart'; import 'package:stream_chat/stream_chat.dart'; +import 'package:video_player/video_player.dart'; import 'attachment_error.dart'; import 'image_attachment.dart'; @@ -12,6 +13,55 @@ import 'stream_chat_theme.dart'; import 'user_avatar.dart'; import 'utils.dart'; +typedef ReplyMessageAttachmentThumbnailBuilder = Widget Function( + BuildContext, + Attachment, +); + +class _VideoAttachmentThumbnail extends StatefulWidget { + final Size size; + final Attachment attachment; + + const _VideoAttachmentThumbnail({ + Key key, + @required this.attachment, + this.size = const Size(32, 32), + }) : super(key: key); + + @override + _VideoAttachmentThumbnailState createState() => + _VideoAttachmentThumbnailState(); +} + +class _VideoAttachmentThumbnailState extends State<_VideoAttachmentThumbnail> { + VideoPlayerController _controller; + + @override + void initState() { + super.initState(); + _controller = VideoPlayerController.network(widget.attachment.assetUrl) + ..initialize().then((_) { + setState(() {}); //when your thumbnail will show. + }); + } + + @override + void dispose() { + super.dispose(); + _controller.dispose(); + } + + @override + Widget build(BuildContext context) { + return Container( + height: widget.size.height, + width: widget.size.width, + child: _controller.value.initialized + ? VideoPlayer(_controller) + : CircularProgressIndicator()); + } +} + /// class ReplyMessageWidget extends StatelessWidget { /// The message @@ -29,7 +79,9 @@ class ReplyMessageWidget extends StatelessWidget { /// limit of the text message shown final int textLimit; - final Map _attachmentBuilders; + /// Map that defines a thumbnail builder for an attachment type + final Map + attachmentThumbnailBuilders; /// ReplyMessageWidget({ @@ -39,69 +91,8 @@ class ReplyMessageWidget extends StatelessWidget { this.reverse = false, this.showBorder = false, this.textLimit = 170, - }) : _attachmentBuilders = { - 'image': (attachment) { - return ImageAttachment( - attachment: attachment, - message: message, - messageTheme: messageTheme, - size: Size(32, 32), - ); - }, - 'video': (attachment) { - final size = Size(32, 32); - if (attachment.thumbUrl != null) { - return Container( - height: size.height, - width: size.width, - decoration: BoxDecoration( - image: DecorationImage( - fit: BoxFit.cover, - image: CachedNetworkImageProvider( - attachment.thumbUrl, - ), - ), - ), - ); - } - return AttachmentError( - attachment: attachment, - size: size, - ); - }, - 'giphy': (attachment) { - final size = Size(32, 32); - return CachedNetworkImage( - height: size?.height, - width: size?.width, - placeholder: (_, __) { - return Container( - width: size?.width, - height: size?.height, - child: Center( - child: CircularProgressIndicator(), - ), - ); - }, - imageUrl: attachment.thumbUrl ?? - attachment.imageUrl ?? - attachment.assetUrl, - errorWidget: (context, url, error) => AttachmentError( - attachment: attachment, - size: size, - ), - fit: BoxFit.cover, - ); - }, - 'file': (attachment) { - return Container( - height: 32, - width: 32, - child: getFileTypeImage(attachment.extraData['mime_type']), - ); - }, - }, - super(key: key); + this.attachmentThumbnailBuilders, + }) : super(key: key); bool get _hasAttachments => message.attachments?.isNotEmpty == true; @@ -215,18 +206,26 @@ class ReplyMessageWidget extends StatelessWidget { ); child = _buildUrlAttachment(attachment); } else { + ReplyMessageAttachmentThumbnailBuilder attachmentBuilder; attachment = message.attachments.last; - final attachmentBuilder = _attachmentBuilders[attachment.type]; + if (attachmentThumbnailBuilders?.containsKey(attachment?.type) == true) { + attachmentBuilder = attachmentThumbnailBuilders[attachment?.type]; + } + attachmentBuilder = _defaultAttachmentBuilder[attachment?.type]; if (attachmentBuilder == null) { child = Offstage(); } - child = attachmentBuilder(attachment); + child = attachmentBuilder(context, attachment); } - return Material( - clipBehavior: Clip.hardEdge, - color: Colors.transparent, - shape: attachment.type == 'file' ? null : _getDefaultShape(context), - child: child, + return Transform( + transform: Matrix4.rotationY(reverse ? pi : 0), + alignment: Alignment.center, + child: Material( + clipBehavior: Clip.hardEdge, + color: Colors.transparent, + shape: attachment.type == 'file' ? null : _getDefaultShape(context), + child: child, + ), ); } @@ -259,6 +258,56 @@ class ReplyMessageWidget extends StatelessWidget { ); } + Map + get _defaultAttachmentBuilder { + return { + 'image': (_, attachment) { + return ImageAttachment( + attachment: attachment, + message: message, + messageTheme: messageTheme, + size: Size(32, 32), + ); + }, + 'video': (_, attachment) { + return _VideoAttachmentThumbnail( + key: ValueKey(attachment.assetUrl), + attachment: attachment, + ); + }, + 'giphy': (_, attachment) { + final size = Size(32, 32); + return CachedNetworkImage( + height: size?.height, + width: size?.width, + placeholder: (_, __) { + return Container( + width: size?.width, + height: size?.height, + child: Center( + child: CircularProgressIndicator(), + ), + ); + }, + imageUrl: + attachment.thumbUrl ?? attachment.imageUrl ?? attachment.assetUrl, + errorWidget: (context, url, error) => AttachmentError( + attachment: attachment, + size: size, + ), + fit: BoxFit.cover, + ); + }, + 'file': (_, attachment) { + return Container( + height: 32, + width: 32, + child: getFileTypeImage(attachment.extraData['mime_type']), + ); + }, + }; + } + Color _getBackgroundColor() { if (_containsScrapeUrl) { return Color(0xFFE9F2FF); From aa09fd380ef08eebe48986dd920121e9fb8e856f Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Wed, 9 Dec 2020 16:56:26 +0530 Subject: [PATCH 0592/1140] fix: UI fixes --- lib/src/chat_info_screen.dart | 95 +++++++++++++++++++++++++++++++---- 1 file changed, 84 insertions(+), 11 deletions(-) diff --git a/lib/src/chat_info_screen.dart b/lib/src/chat_info_screen.dart index 9ef80c9e..cbda9d9b 100644 --- a/lib/src/chat_info_screen.dart +++ b/lib/src/chat_info_screen.dart @@ -67,7 +67,11 @@ class _ChatInfoScreenState extends State { SizedBox(height: 15.0), _OptionListTile( title: '@user', - trailing: Text(widget.user.name), + trailing: Text( + widget.user.name, + style: TextStyle( + color: Colors.black.withOpacity(0.5), fontSize: 16.0), + ), onTap: () {}, ), ], @@ -198,7 +202,7 @@ class _ChatInfoScreenState extends State { title: 'Delete', leading: StreamSvgIcon.delete( color: Colors.red, - size: 20.0, + size: 24.0, ), onTap: () { _showDeleteDialog(); @@ -290,15 +294,12 @@ class _ChatInfoScreenState extends State { if (otherMember.online) { alternativeWidget = Text( 'Online', - style: StreamChatTheme.of(context) - .channelTheme - .channelHeaderTheme - .lastMessageAt, + style: TextStyle(color: Colors.black.withOpacity(0.5)), ); } else { alternativeWidget = Text( 'Last seen ${Jiffy(otherMember.lastActive).fromNow()}', - //style: textStyle, + style: TextStyle(color: Colors.black.withOpacity(0.5)), ); } } @@ -428,10 +429,7 @@ class __SharedGroupsScreenState extends State<_SharedGroupsScreen> { itemBuilder: (context, position) { return StreamChannel( channel: snapshot.data[position], - child: ChannelPreview( - channel: snapshot.data[position], - onTap: (val) {}, - ), + child: _buildListTile(snapshot.data[position]), ); }, ); @@ -439,6 +437,81 @@ class __SharedGroupsScreenState extends State<_SharedGroupsScreen> { ), ); } + + Widget _buildListTile(Channel channel) { + var extraData = channel.extraData; + var members = channel.state.members; + + var textStyle = TextStyle(fontSize: 14.0, fontWeight: FontWeight.bold); + + return Container( + height: 64.0, + child: LayoutBuilder(builder: (context, constraints) { + String title; + if (extraData['name'] == null) { + final otherMembers = members.where( + (member) => member.userId != StreamChat.of(context).user.id); + if (otherMembers.isNotEmpty) { + final maxWidth = constraints.maxWidth; + final maxChars = maxWidth / textStyle.fontSize; + var currentChars = 0; + final currentMembers = []; + otherMembers.forEach((element) { + final newLength = currentChars + element.user.name.length; + if (newLength < maxChars) { + currentChars = newLength; + currentMembers.add(element); + } + }); + + final exceedingMembers = + otherMembers.length - currentMembers.length; + title = + '${currentMembers.map((e) => e.user.name).join(', ')} ${exceedingMembers > 0 ? '+ $exceedingMembers' : ''}'; + } else { + title = 'No title'; + } + } else { + title = extraData['name']; + } + + return Column( + children: [ + Expanded( + child: Row( + children: [ + Padding( + padding: const EdgeInsets.all(8.0), + child: ChannelImage( + channel: channel, + constraints: + BoxConstraints(maxWidth: 40.0, maxHeight: 40.0), + ), + ), + Expanded( + child: Text( + title, + style: textStyle, + )), + Padding( + padding: const EdgeInsets.all(8.0), + child: Text( + '${channel.memberCount} members', + style: TextStyle(color: Colors.black.withOpacity(0.5)), + ), + ) + ], + ), + ), + Container( + height: 1.0, + color: Color(0xffe6e6e6), + ), + ], + ); + }), + ); + } } class _MediaDisplayScreen extends StatelessWidget { From a3e2eec345457679a981ffb4c496447f17b35fdc Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Wed, 9 Dec 2020 17:09:19 +0530 Subject: [PATCH 0593/1140] [MessageWidget] Fix widget gesture detector Signed-off-by: Sahil Kumar --- lib/src/message_widget.dart | 165 ++++++++++++++++++------------------ 1 file changed, 81 insertions(+), 84 deletions(-) diff --git a/lib/src/message_widget.dart b/lib/src/message_widget.dart index ff0d1c7c..2ab87fbd 100644 --- a/lib/src/message_widget.dart +++ b/lib/src/message_widget.dart @@ -317,58 +317,64 @@ class _MessageWidgetState extends State { messageTheme: widget.messageTheme, ), ) - : Material( - clipBehavior: Clip.antiAlias, - shape: widget.shape ?? - RoundedRectangleBorder( - side: isOnlyEmoji && - !_hasReplyMessage - ? BorderSide.none - : widget.borderSide ?? - BorderSide( - color: Theme.of(context) - .brightness == - Brightness - .dark - ? Colors.white - .withAlpha(24) - : Colors.black - .withAlpha( - 24), - ), - borderRadius: widget - .borderRadiusGeometry ?? - BorderRadius.zero, + : GestureDetector( + onTap: () => retryMessage(context), + onLongPress: () => + onLongPress(context), + child: Material( + clipBehavior: Clip.antiAlias, + shape: widget.shape ?? + RoundedRectangleBorder( + side: isOnlyEmoji && + !_hasReplyMessage + ? BorderSide.none + : widget.borderSide ?? + BorderSide( + color: Theme.of(context) + .brightness == + Brightness + .dark + ? Colors.white + .withAlpha( + 24) + : Colors.black + .withAlpha( + 24), + ), + borderRadius: widget + .borderRadiusGeometry ?? + BorderRadius.zero, + ), + color: _getBackgroundColor(), + child: Padding( + padding: EdgeInsets.all( + hasFiles ? 2.0 : 0.0), + child: Column( + crossAxisAlignment: + CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + if (_hasReplyMessage) + ReplyMessageWidget( + message: + widget.replyMessage, + messageTheme: isMyMessage + ? StreamChatTheme.of( + context) + .otherMessageTheme + : StreamChatTheme.of( + context) + .ownMessageTheme, + reverse: widget.reverse, + ), + ..._parseAttachments(context), + if (widget.message.text + .trim() + .isNotEmpty && + !isGiphy) + _buildTextBubble(context), + ], ), - color: _getBackgroundColor(), - child: Padding( - padding: EdgeInsets.all( - hasFiles ? 2.0 : 0.0), - child: Column( - crossAxisAlignment: - CrossAxisAlignment.start, - mainAxisSize: MainAxisSize.min, - children: [ - if (_hasReplyMessage) - ReplyMessageWidget( - message: - widget.replyMessage, - messageTheme: isMyMessage - ? StreamChatTheme.of( - context) - .otherMessageTheme - : StreamChatTheme.of( - context) - .ownMessageTheme, - reverse: widget.reverse, - ), - ..._parseAttachments(context), - if (widget.message.text - .trim() - .isNotEmpty && - !isGiphy) - _buildTextBubble(context), - ], ), ), ), @@ -706,33 +712,29 @@ class _MessageWidgetState extends State { }) { final attachmentShape = widget.attachmentShape ?? widget.shape ?? _getDefaultShape(context); - return GestureDetector( - onTap: () => retryMessage(context), - onLongPress: () => onLongPress(context), - child: Material( - color: _getBackgroundColor(), - clipBehavior: Clip.antiAlias, - shape: attachmentShape, - child: Padding( - padding: widget.attachmentPadding, - child: Material( - clipBehavior: Clip.hardEdge, - shape: attachmentShape, - type: MaterialType.transparency, - child: Transform( - transform: Matrix4.rotationY(widget.reverse ? pi : 0), - alignment: Alignment.center, - child: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.end, - children: [ - getFailedMessageWidget( - context, - padding: const EdgeInsets.all(8.0), - ), - attachmentWidget, - ], - ), + return Material( + color: _getBackgroundColor(), + clipBehavior: Clip.antiAlias, + shape: attachmentShape, + child: Padding( + padding: widget.attachmentPadding, + child: Material( + clipBehavior: Clip.hardEdge, + shape: attachmentShape, + type: MaterialType.transparency, + child: Transform( + transform: Matrix4.rotationY(widget.reverse ? pi : 0), + alignment: Alignment.center, + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.end, + children: [ + getFailedMessageWidget( + context, + padding: const EdgeInsets.all(8.0), + ), + attachmentWidget, + ], ), ), ), @@ -862,7 +864,7 @@ class _MessageWidgetState extends State { } Widget _buildTextBubble(BuildContext context) { - Widget child = Transform( + return Transform( transform: Matrix4.rotationY(widget.reverse ? pi : 0), alignment: Alignment.center, child: Column( @@ -899,11 +901,6 @@ class _MessageWidgetState extends State { ], ), ); - return GestureDetector( - onTap: () => retryMessage(context), - onLongPress: () => onLongPress(context), - child: child, - ); } bool get isOnlyEmoji => From 9f56730409cb49063518a239019adbeae2df5c54 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Wed, 9 Dec 2020 17:13:59 +0530 Subject: [PATCH 0594/1140] fix: UI fixes --- lib/src/chat_info_screen.dart | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/lib/src/chat_info_screen.dart b/lib/src/chat_info_screen.dart index cbda9d9b..c961b0e0 100644 --- a/lib/src/chat_info_screen.dart +++ b/lib/src/chat_info_screen.dart @@ -55,6 +55,7 @@ class _ChatInfoScreenState extends State { maxHeight: 72.0, ), borderRadius: BorderRadius.circular(36.0), + showOnlineStatus: false, ), ), SizedBox(height: 15.0), @@ -304,7 +305,28 @@ class _ChatInfoScreenState extends State { } } - return alternativeWidget; + return Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + if (widget.user.online) + Material( + type: MaterialType.circle, + child: Container( + padding: const EdgeInsets.symmetric(horizontal: 8.0), + constraints: BoxConstraints.tightFor( + width: 28, + height: 12, + ), + child: Material( + shape: CircleBorder(), + color: Color(0xff20E070), + ), + ), + color: Colors.white, + ), + alternativeWidget, + ], + ); } } From 839582d72b4b905a77d2a3570bc39322ead00869 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Wed, 9 Dec 2020 17:16:48 +0530 Subject: [PATCH 0595/1140] fix: UI fixes --- lib/src/chat_info_screen.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/chat_info_screen.dart b/lib/src/chat_info_screen.dart index c961b0e0..aad1cd05 100644 --- a/lib/src/chat_info_screen.dart +++ b/lib/src/chat_info_screen.dart @@ -58,7 +58,7 @@ class _ChatInfoScreenState extends State { showOnlineStatus: false, ), ), - SizedBox(height: 15.0), + //SizedBox(height: 4.0), Text( widget.user.name, style: TextStyle(fontSize: 16.0, fontWeight: FontWeight.bold), From ca6a90c97f3ada6d9bdcdf24cb6fe57d05a37436 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Wed, 9 Dec 2020 17:47:24 +0530 Subject: [PATCH 0596/1140] fix: Fixed colors of message attachments --- lib/src/message_input.dart | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 96439be9..b19211ba 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -683,14 +683,10 @@ class MessageInputState extends State { Color _getIconColor(int index) { switch (index) { case 0: - return _attachmentContainsFile && _attachments.isNotEmpty - ? Colors.black.withOpacity(0.2) - : Colors.black.withOpacity(0.5); + return _attachments.isEmpty ? StreamChatTheme.of(context).accentColor : (!_attachmentContainsFile ? StreamChatTheme.of(context).accentColor : Colors.black.withOpacity(0.2)); break; case 1: - return !_attachmentContainsFile && _attachments.isNotEmpty - ? Colors.black.withOpacity(0.2) - : Colors.black.withOpacity(0.5); + return _attachmentContainsFile ? StreamChatTheme.of(context).accentColor : (_attachments.isEmpty ? Colors.black.withOpacity(0.5) : Colors.black.withOpacity(0.2)); break; case 2: return _attachmentContainsFile && _attachments.isNotEmpty From 79b1401700a3d5cd2ec1090f46d3b34f1e4c93ae Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Wed, 9 Dec 2020 17:54:13 +0530 Subject: [PATCH 0597/1140] fix: Fixed padding --- lib/src/chat_info_screen.dart | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/lib/src/chat_info_screen.dart b/lib/src/chat_info_screen.dart index aad1cd05..3881e4a3 100644 --- a/lib/src/chat_info_screen.dart +++ b/lib/src/chat_info_screen.dart @@ -68,10 +68,13 @@ class _ChatInfoScreenState extends State { SizedBox(height: 15.0), _OptionListTile( title: '@user', - trailing: Text( - widget.user.name, - style: TextStyle( - color: Colors.black.withOpacity(0.5), fontSize: 16.0), + trailing: Padding( + padding: const EdgeInsets.symmetric(horizontal: 8.0), + child: Text( + widget.user.name, + style: TextStyle( + color: Colors.black.withOpacity(0.5), fontSize: 16.0), + ), ), onTap: () {}, ), From 39a2eeea32407f72074271d80dccfc6c06bc36c0 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Thu, 10 Dec 2020 13:40:01 +0530 Subject: [PATCH 0598/1140] fix: File fix --- lib/src/message_input.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index b19211ba..e21ab4b1 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -1697,7 +1697,7 @@ class MessageInputState extends State { localUri: file.path != null ? Uri.parse(file.path) : null, type: attachmentType, extraData: extraDataMap.isNotEmpty ? extraDataMap : null, - title: mimeType.type == 'file' ? file.name : null, + title: file.name, ), ); From 328bc4d1bcf02b56c63706f7e19991cc424849db Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Thu, 10 Dec 2020 14:42:58 +0530 Subject: [PATCH 0599/1140] fix: Removed block button --- lib/src/chat_info_screen.dart | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/lib/src/chat_info_screen.dart b/lib/src/chat_info_screen.dart index 3881e4a3..434b0021 100644 --- a/lib/src/chat_info_screen.dart +++ b/lib/src/chat_info_screen.dart @@ -137,18 +137,24 @@ class _ChatInfoScreenState extends State { onTap: () {}, ); }), - _OptionListTile( - title: 'Block User', - leading: StreamSvgIcon.Icon_user_delete( - size: 24.0, - color: Colors.black.withOpacity(0.5), - ), - trailing: CupertinoSwitch( - value: true, - onChanged: (val) {}, - ), - onTap: () {}, - ), + // _OptionListTile( + // title: 'Block User', + // leading: StreamSvgIcon.Icon_user_delete( + // size: 24.0, + // color: Colors.black.withOpacity(0.5), + // ), + // trailing: CupertinoSwitch( + // value: widget.user.banned, + // onChanged: (val) { + // if (widget.user.banned) { + // channel.channel.shadowBan(widget.user.id, {}); + // } else { + // channel.channel.unbanUser(widget.user.id); + // } + // }, + // ), + // onTap: () {}, + // ), _OptionListTile( title: '615 Photos & Videos', leading: StreamSvgIcon.pictures( From e0e98299cae1fa51b1b88d4fb54d7e6f7d945643 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Thu, 10 Dec 2020 15:06:32 +0530 Subject: [PATCH 0600/1140] fix: Filter and alignment fix --- lib/src/chat_info_screen.dart | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/lib/src/chat_info_screen.dart b/lib/src/chat_info_screen.dart index 434b0021..e56e812c 100644 --- a/lib/src/chat_info_screen.dart +++ b/lib/src/chat_info_screen.dart @@ -182,7 +182,18 @@ class _ChatInfoScreenState extends State { StreamBuilder>( stream: StreamChat.of(context).client.queryChannels( filter: { - 'members': [StreamChat.of(context).user.id, widget.user.id], + r'$and': [ + { + 'members': { + r'$in': [widget.user.id], + }, + }, + { + 'members': { + r'$in': [StreamChat.of(context).user.id], + }, + } + ], }, ), builder: (context, snapshot) { @@ -386,8 +397,13 @@ class _OptionListTile extends StatelessWidget { fontWeight: FontWeight.w600, color: titleColor), )), Expanded( - child: Center( - child: trailing ?? Container(), + flex: 2, + child: Padding( + padding: const EdgeInsets.only(right: 16.0), + child: Align( + alignment: Alignment.centerRight, + child: trailing ?? Container(), + ), ), ), ], From d97f7ecebffe821fce9edca057ad1ec368a21378 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Thu, 10 Dec 2020 15:18:14 +0530 Subject: [PATCH 0601/1140] fix: Filter and alignment fix --- lib/src/chat_info_screen.dart | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/lib/src/chat_info_screen.dart b/lib/src/chat_info_screen.dart index e56e812c..f9ee70cd 100644 --- a/lib/src/chat_info_screen.dart +++ b/lib/src/chat_info_screen.dart @@ -461,7 +461,18 @@ class __SharedGroupsScreenState extends State<_SharedGroupsScreen> { body: StreamBuilder>( stream: chat.client.queryChannels( filter: { - 'members': [widget.mainUser.id, widget.otherUser.id], + r'$and': [ + { + 'members': { + r'$in': [widget.otherUser.id], + }, + }, + { + 'members': { + r'$in': [widget.mainUser.id], + }, + } + ], }, ), builder: (context, snapshot) { From df2d82231502f32551612c81ef095a447ac7c71e Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Thu, 10 Dec 2020 11:42:01 +0100 Subject: [PATCH 0602/1140] add ontap to channelpreview --- lib/src/channel_header.dart | 29 ++++++++++++++++------------- lib/src/channel_preview.dart | 25 ++++++++++++++++++++++++- 2 files changed, 40 insertions(+), 14 deletions(-) diff --git a/lib/src/channel_header.dart b/lib/src/channel_header.dart index 09833ad3..96ed9769 100644 --- a/lib/src/channel_header.dart +++ b/lib/src/channel_header.dart @@ -101,21 +101,24 @@ class ChannelHeader extends StatelessWidget implements PreferredSizeWidget { child: ChannelImage( onTap: onImageTap ?? () { - var currentUser = StreamChat.of(context).user; - var otherUser = channel.state.members.firstWhere( - (element) => element.user.id != currentUser.id); - - if (channel.memberCount == 2) { + if (channel.memberCount == 2 && channel.isDistinct) { + final currentUser = StreamChat.of(context).user; + final otherUser = channel.state.members.firstWhere( + (element) => element.user.id != currentUser.id, + orElse: () => null, + ); if (otherUser != null) { Navigator.push( - context, - MaterialPageRoute( - builder: (context) => StreamChannel( - channel: channel, - child: ChatInfoScreen( - user: otherUser.user, - ), - ))); + context, + MaterialPageRoute( + builder: (context) => StreamChannel( + channel: channel, + child: ChatInfoScreen( + user: otherUser.user, + ), + ), + ), + ); } } }, diff --git a/lib/src/channel_preview.dart b/lib/src/channel_preview.dart index 26f68812..5f58e254 100644 --- a/lib/src/channel_preview.dart +++ b/lib/src/channel_preview.dart @@ -7,6 +7,7 @@ import 'package:stream_chat_flutter/src/stream_svg_icon.dart'; import '../stream_chat_flutter.dart'; import 'channel_name.dart'; import 'channel_unread_indicator.dart'; +import 'chat_info_screen.dart'; /// ![screenshot](https://raw.githubusercontent.com/GetStream/stream-chat-flutter/master/screenshots/channel_preview.png) /// ![screenshot](https://raw.githubusercontent.com/GetStream/stream-chat-flutter/master/screenshots/channel_preview_paint.png) @@ -60,7 +61,29 @@ class ChannelPreview extends StatelessWidget { } }, leading: ChannelImage( - onTap: onImageTap, + onTap: onImageTap ?? + () { + if (channel.memberCount == 2 && channel.isDistinct) { + final currentUser = StreamChat.of(context).user; + final otherUser = channel.state.members.firstWhere( + (element) => element.user.id != currentUser.id, + orElse: () => null, + ); + if (otherUser != null) { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => StreamChannel( + channel: channel, + child: ChatInfoScreen( + user: otherUser.user, + ), + ), + ), + ); + } + } + }, ), title: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, From b85ed04170019289b8d1aa06bc4ddcde5ec12935 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Thu, 10 Dec 2020 12:29:51 +0100 Subject: [PATCH 0603/1140] update 1:1 chatinfo ui --- lib/src/chat_info_screen.dart | 56 +++++++++++------------------------ 1 file changed, 18 insertions(+), 38 deletions(-) diff --git a/lib/src/chat_info_screen.dart b/lib/src/chat_info_screen.dart index f9ee70cd..0ba300ee 100644 --- a/lib/src/chat_info_screen.dart +++ b/lib/src/chat_info_screen.dart @@ -67,7 +67,7 @@ class _ChatInfoScreenState extends State { _buildConnectedTitleState(), SizedBox(height: 15.0), _OptionListTile( - title: '@user', + title: '@${widget.user.id}', trailing: Padding( padding: const EdgeInsets.symmetric(horizontal: 8.0), child: Text( @@ -156,7 +156,7 @@ class _ChatInfoScreenState extends State { // onTap: () {}, // ), _OptionListTile( - title: '615 Photos & Videos', + title: 'Photos & Videos', leading: StreamSvgIcon.pictures( size: 32.0, color: Colors.black.withOpacity(0.5), @@ -168,7 +168,7 @@ class _ChatInfoScreenState extends State { }, ), _OptionListTile( - title: '8 Files', + title: 'Files', leading: StreamSvgIcon.files( size: 32.0, color: Colors.black.withOpacity(0.5), @@ -179,41 +179,21 @@ class _ChatInfoScreenState extends State { MaterialPageRoute(builder: (context) => _FileDisplayScreen())); }, ), - StreamBuilder>( - stream: StreamChat.of(context).client.queryChannels( - filter: { - r'$and': [ - { - 'members': { - r'$in': [widget.user.id], - }, - }, - { - 'members': { - r'$in': [StreamChat.of(context).user.id], - }, - } - ], - }, - ), - builder: (context, snapshot) { - return _OptionListTile( - title: - '${snapshot.data == null ? '0' : snapshot.data.length} Shared groups', - leading: StreamSvgIcon.Icon_group( - size: 24.0, - color: Colors.black.withOpacity(0.5), - ), - trailing: StreamSvgIcon.right(), - onTap: () { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => _SharedGroupsScreen( - StreamChat.of(context).user, widget.user))); - }, - ); - }), + _OptionListTile( + title: 'Shared groups', + leading: StreamSvgIcon.Icon_group( + size: 24.0, + color: Colors.black.withOpacity(0.5), + ), + trailing: StreamSvgIcon.right(), + onTap: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => _SharedGroupsScreen( + StreamChat.of(context).user, widget.user))); + }, + ), ], ); } From 0534488b9480c9ff3503b7d6bc83cdc61c8d0c2b Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Thu, 10 Dec 2020 14:42:15 +0100 Subject: [PATCH 0604/1140] fix delete conversation logic --- lib/src/channel_bottom_sheet.dart | 72 +++++++++++------------ lib/src/channel_header.dart | 8 ++- lib/src/channel_list_view.dart | 55 +++++++----------- lib/src/chat_info_screen.dart | 97 ++++++++----------------------- lib/src/utils.dart | 93 +++++++++++++++++++++-------- 5 files changed, 158 insertions(+), 167 deletions(-) diff --git a/lib/src/channel_bottom_sheet.dart b/lib/src/channel_bottom_sheet.dart index 48ce8887..2d16bf6d 100644 --- a/lib/src/channel_bottom_sheet.dart +++ b/lib/src/channel_bottom_sheet.dart @@ -69,40 +69,26 @@ class ChannelBottomSheet extends StatelessWidget { ), ), Divider(), - StreamBuilder( - stream: channel.isMutedStream, - initialData: channel.isMuted, - builder: (context, snapshot) { - return ListTile( - leading: StreamSvgIcon.mute( - size: 22, - color: StreamChatTheme.of(context).primaryIconTheme.color, - ), - title: Text('Mute ${channel.isGroup ? 'group' : 'user'}'), - trailing: Switch( - onChanged: (bool muted) async { - if (muted) { - await channel.mute(); - } else { - await channel.unmute(); - } - }, - value: snapshot.data, - ), - ); - }), - Divider(), if (channel.isGroup && !channel.isDistinct) ListTile( leading: StreamSvgIcon.userRemove( - size: 22, - color: Colors.black, + size: 24, + color: Color(0xff7A7A7A), + ), + title: Text( + 'Leave Group', + style: TextStyle(fontWeight: FontWeight.bold), ), - title: Text('Leave Group'), onTap: () async { final confirm = await showConfirmationDialog( context, - 'Do you want to leave the group?', + title: 'Leave Group', + okText: 'LEAVE', + question: 'Are you sure you want to leave this group?', + cancelText: 'CANCEL', + icon: StreamSvgIcon.userRemove( + color: Colors.red, + ), ); if (confirm == true) { await channel @@ -111,11 +97,17 @@ class ChannelBottomSheet extends StatelessWidget { } }, ), - if (!channel.isGroup && !channel.isDistinct) + if ([ + 'admin', + 'owner', + ].contains(channel.state.members + .firstWhere((m) => m.userId == channel.client.state.user.id, + orElse: () => null) + ?.role)) ListTile( - leading: Icon( - Icons.delete_outline, + leading: StreamSvgIcon.delete( color: Color(0xFFFF3742), + size: 24, ), title: Text( 'Delete chat', @@ -124,14 +116,22 @@ class ChannelBottomSheet extends StatelessWidget { ), ), onTap: () async { - final confirm = await showConfirmationDialog( + final res = await showConfirmationDialog( context, - 'Do you want to delete the chat?', + title: 'Delete Conversation', + okText: 'DELETE', + question: + 'Are you sure you want to delete this conversation?', + cancelText: 'CANCEL', + icon: StreamSvgIcon.delete( + color: Colors.red, + ), ); - if (confirm == true) { - await channel - .removeMembers([StreamChat.of(context).user.id]); - Navigator.pop(context); + var channel = StreamChannel.of(context).channel; + if (res == true) { + await channel.delete().then((value) { + Navigator.pop(context); + }); } }, ), diff --git a/lib/src/channel_header.dart b/lib/src/channel_header.dart index 96ed9769..65f63cc4 100644 --- a/lib/src/channel_header.dart +++ b/lib/src/channel_header.dart @@ -100,7 +100,7 @@ class ChannelHeader extends StatelessWidget implements PreferredSizeWidget { child: Center( child: ChannelImage( onTap: onImageTap ?? - () { + () async { if (channel.memberCount == 2 && channel.isDistinct) { final currentUser = StreamChat.of(context).user; final otherUser = channel.state.members.firstWhere( @@ -108,7 +108,7 @@ class ChannelHeader extends StatelessWidget implements PreferredSizeWidget { orElse: () => null, ); if (otherUser != null) { - Navigator.push( + final pop = await Navigator.push( context, MaterialPageRoute( builder: (context) => StreamChannel( @@ -119,6 +119,10 @@ class ChannelHeader extends StatelessWidget implements PreferredSizeWidget { ), ), ); + + if (pop == true) { + Navigator.pop(context); + } } } }, diff --git a/lib/src/channel_list_view.dart b/lib/src/channel_list_view.dart index 03284c6d..5dbc9f90 100644 --- a/lib/src/channel_list_view.dart +++ b/lib/src/channel_list_view.dart @@ -524,44 +524,33 @@ class _ChannelListViewState extends State ); }, ), - IconSlideAction( - color: backgroundColor, - iconWidget: StreamSvgIcon.mute(), - onTap: () async { - if (!channel.isMuted) { - await channel.mute(); - } else { - await channel.unmute(); - } - }, - ), - if (channel.isGroup && !channel.isDistinct) + if ([ + 'admin', + 'owner', + ].contains(channel.state.members + .firstWhere( + (m) => m.userId == channel.client.state.user.id, + orElse: () => null) + ?.role)) IconSlideAction( color: backgroundColor, - iconWidget: StreamSvgIcon.userRemove(), + iconWidget: StreamSvgIcon.delete( + color: Color(0xFFFF3742), + ), onTap: () async { - final confirm = await showConfirmationDialog( + final res = await showConfirmationDialog( context, - 'Do you want to leave the group?', + title: 'Delete Conversation', + okText: 'DELETE', + question: + 'Are you sure you want to delete this conversation?', + cancelText: 'CANCEL', + icon: StreamSvgIcon.delete( + color: Color(0xFFFF3742), + ), ); - if (confirm == true) { - await channel - .removeMembers([StreamChat.of(context).user.id]); - } - }, - ), - if (!channel.isGroup && !channel.isDistinct) - IconSlideAction( - color: backgroundColor, - icon: Icons.delete_outline, - onTap: () async { - final confirm = await showConfirmationDialog( - context, - 'Do you want to delete the chat?', - ); - if (confirm == true) { - await channel - .removeMembers([StreamChat.of(context).user.id]); + if (res == true) { + await channel.delete(); } }, ), diff --git a/lib/src/chat_info_screen.dart b/lib/src/chat_info_screen.dart index 0ba300ee..0ec62c36 100644 --- a/lib/src/chat_info_screen.dart +++ b/lib/src/chat_info_screen.dart @@ -19,6 +19,7 @@ class ChatInfoScreen extends StatefulWidget { class _ChatInfoScreenState extends State { @override Widget build(BuildContext context) { + final channel = StreamChannel.of(context).channel; return Scaffold( backgroundColor: Color(0xFFe6e6e6), body: ListView( @@ -31,7 +32,14 @@ class _ChatInfoScreenState extends State { SizedBox( height: 8.0, ), - _buildDeleteListTile(), + if ([ + 'admin', + 'owner', + ].contains(channel.state.members + .firstWhere((m) => m.userId == channel.client.state.user.id, + orElse: () => null) + ?.role)) + _buildDeleteListTile(), ], ), ); @@ -212,78 +220,23 @@ class _ChatInfoScreenState extends State { ); } - void _showDeleteDialog() { + void _showDeleteDialog() async { + final res = await showConfirmationDialog( + context, + title: 'Delete Conversation', + okText: 'DELETE', + question: 'Are you sure you want to delete this conversation?', + cancelText: 'CANCEL', + icon: StreamSvgIcon.delete( + color: Colors.red, + ), + ); var channel = StreamChannel.of(context).channel; - - showModalBottomSheet( - backgroundColor: Colors.white, - context: context, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.only( - topLeft: Radius.circular(16.0), - topRight: Radius.circular(16.0), - )), - builder: (context) { - return Column( - mainAxisSize: MainAxisSize.min, - children: [ - SizedBox( - height: 26.0, - ), - StreamSvgIcon.delete( - color: Colors.red, - ), - SizedBox( - height: 26.0, - ), - Text( - 'Delete Conversation', - style: TextStyle(fontWeight: FontWeight.bold, fontSize: 16.0), - ), - SizedBox( - height: 7.0, - ), - Text('Are you sure you want to delete this conversation?'), - SizedBox( - height: 36.0, - ), - Container( - color: Color(0xffe6e6e6), - height: 1.0, - ), - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - FlatButton( - child: Text( - 'CANCEL', - style: TextStyle( - color: Colors.black.withOpacity(0.5), - fontWeight: FontWeight.w400), - ), - onPressed: () { - Navigator.of(context).pop(); - }, - ), - FlatButton( - child: Text( - 'DELETE', - style: TextStyle( - color: Colors.red, fontWeight: FontWeight.w400), - ), - onPressed: () { - channel.delete().then((value) { - Navigator.pop(context); - Navigator.pop(context); - Navigator.pop(context); - }); - }, - ), - ], - ), - ], - ); - }); + if (res == true) { + await channel.delete().then((value) { + Navigator.pop(context); + }); + } } Widget _buildConnectedTitleState() { diff --git a/lib/src/utils.dart b/lib/src/utils.dart index 20e3ce1f..74b1da64 100644 --- a/lib/src/utils.dart +++ b/lib/src/utils.dart @@ -2,6 +2,8 @@ import 'package:flutter/material.dart'; import 'package:stream_chat/stream_chat.dart'; import 'package:url_launcher/url_launcher.dart'; +import '../stream_chat_flutter.dart'; + Future launchURL(BuildContext context, String url) async { if (await canLaunch(url)) { await launch(url); @@ -15,33 +17,76 @@ Future launchURL(BuildContext context, String url) async { } Future showConfirmationDialog( - BuildContext context, + BuildContext context, { + String title, + Widget icon, String question, -) { - return showDialog( - context: context, - builder: (context) { - return AlertDialog( - title: Text(question), - actions: [ - FlatButton( - child: Text('Ok'), - onPressed: () => Navigator.pop( - context, - true, + String okText, + String cancelText, +}) { + return showModalBottomSheet( + backgroundColor: Colors.white, + context: context, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.only( + topLeft: Radius.circular(16.0), + topRight: Radius.circular(16.0), + )), + builder: (context) { + return Column( + mainAxisSize: MainAxisSize.min, + children: [ + SizedBox( + height: 26.0, ), - ), - FlatButton( - child: Text('Cancel'), - onPressed: () => Navigator.pop( - context, - false, + if (icon != null) icon, + SizedBox( + height: 26.0, ), - ), - ], - ); - }, - ); + Text( + title, + style: TextStyle(fontWeight: FontWeight.bold, fontSize: 16.0), + ), + SizedBox( + height: 7.0, + ), + Text(question), + SizedBox( + height: 36.0, + ), + Container( + color: Color(0xffe6e6e6), + height: 1.0, + ), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + FlatButton( + child: Text( + cancelText, + style: TextStyle( + color: Colors.black.withOpacity(0.5), + fontWeight: FontWeight.w400), + ), + onPressed: () { + Navigator.of(context).pop(); + }, + ), + FlatButton( + child: Text( + okText, + style: TextStyle( + color: Colors.red, fontWeight: FontWeight.w400), + ), + onPressed: () { + Navigator.pop(context, true); + }, + ), + ], + ), + ], + ); + }); } /// Get random png with initials From 54cb49eac198142eec3d239f480e768f4264c47b Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Thu, 10 Dec 2020 19:52:32 +0530 Subject: [PATCH 0605/1140] feat: Added file previews --- lib/src/file_attachment.dart | 46 +++++++++++++++++++++++++++++++++--- lib/src/media_utils.dart | 17 +++++++++++++ lib/src/message_input.dart | 26 +++++++++++++++----- 3 files changed, 80 insertions(+), 9 deletions(-) create mode 100644 lib/src/media_utils.dart diff --git a/lib/src/file_attachment.dart b/lib/src/file_attachment.dart index fff13bbe..cef966c5 100644 --- a/lib/src/file_attachment.dart +++ b/lib/src/file_attachment.dart @@ -1,18 +1,28 @@ +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:file_picker/file_picker.dart'; import 'package:flutter/material.dart'; import 'package:stream_chat/stream_chat.dart'; +import 'package:stream_chat_flutter/src/stream_chat_theme.dart'; import 'package:stream_chat_flutter/src/stream_svg_icon.dart'; import 'package:stream_chat_flutter/src/utils.dart'; +import 'media_utils.dart'; + +enum FileAttachmentType { local, online } class FileAttachment extends StatelessWidget { final Attachment attachment; final Size size; final Widget trailing; + final FileAttachmentType attachmentType; + final PlatformFile file; const FileAttachment({ Key key, @required this.attachment, this.size, this.trailing, + this.attachmentType = FileAttachmentType.online, + this.file, }) : super(key: key); @override @@ -32,7 +42,7 @@ class FileAttachment extends StatelessWidget { child: Row( children: [ Container( - child: _getFileTypeImage(attachment.extraData['mime_type']), + child: _getFileTypeImage(), height: 40.0, width: 33.33, margin: EdgeInsets.all(8.0), @@ -117,8 +127,38 @@ class FileAttachment extends StatelessWidget { ); } - StreamSvgIcon _getFileTypeImage(String type) { - switch (type) { + Widget _getFileTypeImage() { + if ((MediaUtils.getMimeType(attachment.title).type == 'image')) { + switch (attachmentType) { + case FileAttachmentType.local: + return Image.memory( + file.bytes, + fit: BoxFit.cover, + ); + break; + case FileAttachmentType.online: + return CachedNetworkImage( + imageUrl: attachment.imageUrl ?? + attachment.assetUrl ?? + attachment.thumbUrl, + fit: BoxFit.cover, + progressIndicatorBuilder: (context, _, progress) { + return Center( + child: Container( + width: 20.0, + height: 20.0, + child: CircularProgressIndicator( + backgroundColor: StreamChatTheme.of(context).accentColor, + ), + ), + ); + }, + ); + break; + } + } + + switch (attachment.extraData['mime_type']) { case '7z': return StreamSvgIcon.filetype_7z(); break; diff --git a/lib/src/media_utils.dart b/lib/src/media_utils.dart new file mode 100644 index 00000000..e91a47d6 --- /dev/null +++ b/lib/src/media_utils.dart @@ -0,0 +1,17 @@ +import 'package:http_parser/http_parser.dart' as httpParser; +import 'package:mime/mime.dart'; + +class MediaUtils { + static httpParser.MediaType getMimeType(String filename) { + httpParser.MediaType mimeType; + if (filename != null) { + if (filename.toLowerCase().endsWith('heic')) { + mimeType = httpParser.MediaType.parse('image/heic'); + } else { + mimeType = httpParser.MediaType.parse(lookupMimeType(filename)); + } + } + + return mimeType; + } +} diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index e21ab4b1..870c1ed9 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -683,10 +683,18 @@ class MessageInputState extends State { Color _getIconColor(int index) { switch (index) { case 0: - return _attachments.isEmpty ? StreamChatTheme.of(context).accentColor : (!_attachmentContainsFile ? StreamChatTheme.of(context).accentColor : Colors.black.withOpacity(0.2)); + return _attachments.isEmpty + ? StreamChatTheme.of(context).accentColor + : (!_attachmentContainsFile + ? StreamChatTheme.of(context).accentColor + : Colors.black.withOpacity(0.2)); break; case 1: - return _attachmentContainsFile ? StreamChatTheme.of(context).accentColor : (_attachments.isEmpty ? Colors.black.withOpacity(0.5) : Colors.black.withOpacity(0.2)); + return _attachmentContainsFile + ? StreamChatTheme.of(context).accentColor + : (_attachments.isEmpty + ? Colors.black.withOpacity(0.5) + : Colors.black.withOpacity(0.2)); break; case 2: return _attachmentContainsFile && _attachments.isNotEmpty @@ -1268,6 +1276,8 @@ class MessageInputState extends State { clipBehavior: Clip.antiAlias, child: FileAttachment( attachment: e.attachment, + attachmentType: FileAttachmentType.local, + file: e.file, size: Size( MediaQuery.of(context).size.width * 0.55, MediaQuery.of(context).size.height * 0.3, @@ -1676,12 +1686,16 @@ class MessageInputState extends State { final mimeType = _getMimeType(file.path.split('/').last); - if (mimeType.type == 'video' || mimeType.type == 'image') { - attachmentType = mimeType.type; - } - Map extraDataMap = {}; + if (camera) { + if (mimeType.type == 'video' || mimeType.type == 'image') { + attachmentType = mimeType.type; + } + } else { + attachmentType = 'file'; + } + if (mimeType?.subtype != null) { extraDataMap['mime_type'] = mimeType.subtype.toLowerCase(); } From 5302b16115e7af9d272a3f3605c65468e5b67152 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Fri, 11 Dec 2020 13:04:12 +0530 Subject: [PATCH 0606/1140] fix: keyboard fix --- lib/src/message_input.dart | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 870c1ed9..dd9e2718 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -326,14 +326,17 @@ class MessageInputState extends State { return AnimatedCrossFade( crossFadeState: _actionsShrunk ? CrossFadeState.showFirst : CrossFadeState.showSecond, - firstChild: IconButton( - onPressed: () { + firstChild: InkWell( + onTap: () { setState(() { _actionsShrunk = false; }); }, - icon: StreamSvgIcon.emptyCircleLeft( - color: StreamChatTheme.of(context).accentColor, + child: Padding( + padding: const EdgeInsets.all(8.0) + EdgeInsets.only(bottom: 3.0), + child: StreamSvgIcon.emptyCircleLeft( + color: StreamChatTheme.of(context).accentColor, + ), ), ), secondChild: Row( From bcdc034a2d7f9f1e9c3de93d3cc1e435bf75c2cd Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Fri, 11 Dec 2020 09:40:33 +0100 Subject: [PATCH 0607/1140] fix medialistview null bug --- lib/src/media_list_view.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/media_list_view.dart b/lib/src/media_list_view.dart index 507238da..5f52e9b5 100644 --- a/lib/src/media_list_view.dart +++ b/lib/src/media_list_view.dart @@ -180,7 +180,7 @@ class MediaThumbnailProvider extends ImageProvider { MediaThumbnailProvider key, DecoderCallback decode) async { assert(key == this); final bytes = await media.thumbData; - if (bytes.isEmpty) return null; + if (bytes?.isNotEmpty != true) return null; return await decode(bytes); } From 9fd79a3e00055e4b3671e4a55fa94cfe56aac36c Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Fri, 11 Dec 2020 10:15:07 +0100 Subject: [PATCH 0608/1140] fix urlattachment title --- lib/src/url_attachment.dart | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/src/url_attachment.dart b/lib/src/url_attachment.dart index d735ad67..ad314455 100644 --- a/lib/src/url_attachment.dart +++ b/lib/src/url_attachment.dart @@ -78,8 +78,9 @@ class UrlAttachment extends StatelessWidget { children: [ if (urlAttachment.title != null) Text( - urlAttachment.title, + urlAttachment.title.trim(), maxLines: 1, + overflow: TextOverflow.ellipsis, style: TextStyle( fontWeight: FontWeight.w700, fontSize: 12.0, From 4b122a7e5460f16ee671fad205caa505c135e533 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Fri, 11 Dec 2020 17:01:00 +0530 Subject: [PATCH 0609/1140] feat: Added new picker implementation --- lib/src/message_input.dart | 47 +++++++++++++++++++++++++------------- 1 file changed, 31 insertions(+), 16 deletions(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index dd9e2718..b6a74f11 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -839,22 +839,37 @@ class MessageInputState extends State { } if (snapshot.data) { - return IgnorePointer( - ignoring: _attachmentContainsFile, - child: MediaListView( - selectedIds: _attachments.map((e) => e.id).toList(), - onSelect: (media) async { - if (!_attachments - .any((element) => element.id == media.id)) { - _addAttachment(media); - } else { - setState(() { - _attachments - .removeWhere((element) => element.id == media.id); - }); - } - }, - ), + if (_attachmentContainsFile) { + return Container( + color: Color(0xfff2f2f2), + child: InkWell( + onTap: () { + pickFile(DefaultAttachmentTypes.file); + }, + child: Text( + 'Add more files', + style: TextStyle( + color: StreamChatTheme.of(context).accentColor, + fontWeight: FontWeight.bold, + ), + ), + ), + alignment: Alignment.center, + ); + } + return MediaListView( + selectedIds: _attachments.map((e) => e.id).toList(), + onSelect: (media) async { + if (!_attachments + .any((element) => element.id == media.id)) { + _addAttachment(media); + } else { + setState(() { + _attachments + .removeWhere((element) => element.id == media.id); + }); + } + }, ); } From edeb38a2553dac733d48135c919ad2e3cbfd86bb Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Fri, 11 Dec 2020 17:10:12 +0530 Subject: [PATCH 0610/1140] fix: Fixed file clip bug --- lib/src/message_input.dart | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index b6a74f11..befed883 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -362,6 +362,7 @@ class MessageInputState extends State { color: Colors.grey, ), ), + padding: EdgeInsets.all(6.0), child: Column( mainAxisSize: MainAxisSize.min, children: [ From 102e6ce4d09dcc1485c9274a32b5a1a6a226db7c Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Fri, 11 Dec 2020 17:11:19 +0530 Subject: [PATCH 0611/1140] fix: Fixed file clip bug --- lib/src/message_input.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index befed883..e60c6187 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -362,7 +362,7 @@ class MessageInputState extends State { color: Colors.grey, ), ), - padding: EdgeInsets.all(6.0), + padding: _attachments.isEmpty ? null : EdgeInsets.all(6.0), child: Column( mainAxisSize: MainAxisSize.min, children: [ From 18781201e37d28d09fcdce0c24bd8569a1ab53fc Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Fri, 11 Dec 2020 18:18:35 +0530 Subject: [PATCH 0612/1140] feat: Added video thumbnails and playback for attachments --- lib/src/file_attachment.dart | 101 +++++++++++++++++++++++++++++------ 1 file changed, 85 insertions(+), 16 deletions(-) diff --git a/lib/src/file_attachment.dart b/lib/src/file_attachment.dart index cef966c5..95e628f0 100644 --- a/lib/src/file_attachment.dart +++ b/lib/src/file_attachment.dart @@ -1,3 +1,5 @@ +import 'dart:io'; + import 'package:cached_network_image/cached_network_image.dart'; import 'package:file_picker/file_picker.dart'; import 'package:flutter/material.dart'; @@ -5,11 +7,13 @@ import 'package:stream_chat/stream_chat.dart'; import 'package:stream_chat_flutter/src/stream_chat_theme.dart'; import 'package:stream_chat_flutter/src/stream_svg_icon.dart'; import 'package:stream_chat_flutter/src/utils.dart'; +import 'package:video_compress/video_compress.dart'; +import 'package:video_player/video_player.dart'; import 'media_utils.dart'; enum FileAttachmentType { local, online } -class FileAttachment extends StatelessWidget { +class FileAttachment extends StatefulWidget { final Attachment attachment; final Size size; final Widget trailing; @@ -25,17 +29,44 @@ class FileAttachment extends StatelessWidget { this.file, }) : super(key: key); + @override + _FileAttachmentState createState() => _FileAttachmentState(); +} + +class _FileAttachmentState extends State { + VideoPlayerController _controller; + Future _initializeVideoPlayerFuture; + + @override + void initState() { + super.initState(); + if (MediaUtils.getMimeType(widget.attachment.title).type == 'video') { + if (widget.attachmentType == FileAttachmentType.online) { + _controller = VideoPlayerController.network( + widget.attachment.assetUrl, + ); + } else { + _controller = VideoPlayerController.file( + File.fromRawPath(widget.file.bytes), + ); + } + + _initializeVideoPlayerFuture = _controller.initialize(); + } + } + @override Widget build(BuildContext context) { return Material( child: Container( - width: size?.width ?? 100, + width: widget.size?.width ?? 100, height: 56.0, - margin: trailing != null ? EdgeInsets.only(top: 4.0) : null, + margin: widget.trailing != null ? EdgeInsets.only(top: 4.0) : null, decoration: BoxDecoration( color: Colors.white, - borderRadius: trailing != null ? BorderRadius.circular(16.0) : null, - border: trailing != null + borderRadius: + widget.trailing != null ? BorderRadius.circular(16.0) : null, + border: widget.trailing != null ? Border.fromBorderSide(BorderSide(color: Color(0xFFE6E6E6))) : null, ), @@ -56,7 +87,7 @@ class FileAttachment extends StatelessWidget { crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( - attachment?.title ?? 'File', + widget.attachment?.title ?? 'File', style: TextStyle( fontWeight: FontWeight.bold, fontSize: 14.0, @@ -68,7 +99,7 @@ class FileAttachment extends StatelessWidget { height: 3.0, ), Text( - '${attachment.extraData['file_size'] ?? 'N/A'} bytes', + '${widget.attachment.extraData['file_size'] ?? 'N/A'} bytes', style: TextStyle( color: Colors.black.withOpacity(0.5), fontSize: 14.0, @@ -79,13 +110,13 @@ class FileAttachment extends StatelessWidget { ), Column( children: [ - trailing ?? + widget.trailing ?? IconButton( icon: StreamSvgIcon.cloud_download( color: Colors.black, ), onPressed: () { - launchURL(context, attachment.assetUrl); + launchURL(context, widget.attachment.assetUrl); }, ), ], @@ -128,19 +159,19 @@ class FileAttachment extends StatelessWidget { } Widget _getFileTypeImage() { - if ((MediaUtils.getMimeType(attachment.title).type == 'image')) { - switch (attachmentType) { + if ((MediaUtils.getMimeType(widget.attachment.title).type == 'image')) { + switch (widget.attachmentType) { case FileAttachmentType.local: return Image.memory( - file.bytes, + widget.file.bytes, fit: BoxFit.cover, ); break; case FileAttachmentType.online: return CachedNetworkImage( - imageUrl: attachment.imageUrl ?? - attachment.assetUrl ?? - attachment.thumbUrl, + imageUrl: widget.attachment.imageUrl ?? + widget.attachment.assetUrl ?? + widget.attachment.thumbUrl, fit: BoxFit.cover, progressIndicatorBuilder: (context, _, progress) { return Center( @@ -158,7 +189,45 @@ class FileAttachment extends StatelessWidget { } } - switch (attachment.extraData['mime_type']) { + if ((MediaUtils.getMimeType(widget.attachment.title).type == 'video')) { + switch (widget.attachmentType) { + case FileAttachmentType.local: + return FutureBuilder( + future: VideoCompress.getFileThumbnail(widget.file.path), + builder: (context, snapshot) { + if (!snapshot.hasData) { + return Image.asset( + 'images/placeholder.png', + package: 'stream_chat_flutter', + ); + } + + return Image.file( + snapshot.data, + fit: BoxFit.cover, + ); + }, + ); + break; + case FileAttachmentType.online: + return FutureBuilder( + future: _initializeVideoPlayerFuture, + builder: (context, snapshot) { + if (snapshot.connectionState == ConnectionState.done) { + return AspectRatio( + aspectRatio: _controller.value.aspectRatio, + child: VideoPlayer(_controller), + ); + } else { + return Center(child: CircularProgressIndicator()); + } + }, + ); + break; + } + } + + switch (widget.attachment.extraData['mime_type']) { case '7z': return StreamSvgIcon.filetype_7z(); break; From c487ce92d0fd1f458f757e445811c8fd14760c18 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Fri, 11 Dec 2020 19:54:02 +0530 Subject: [PATCH 0613/1140] feat: Added file size in proper format --- lib/src/file_attachment.dart | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/lib/src/file_attachment.dart b/lib/src/file_attachment.dart index 95e628f0..4bba7779 100644 --- a/lib/src/file_attachment.dart +++ b/lib/src/file_attachment.dart @@ -99,7 +99,7 @@ class _FileAttachmentState extends State { height: 3.0, ), Text( - '${widget.attachment.extraData['file_size'] ?? 'N/A'} bytes', + '${_getSizeText(widget.attachment.extraData['file_size'])}', style: TextStyle( color: Colors.black.withOpacity(0.5), fontSize: 14.0, @@ -284,4 +284,18 @@ class _FileAttachmentState extends State { break; } } + + String _getSizeText(int bytes) { + if (bytes == null) { + return 'Size N/A'; + } + + if (bytes <= 1000) { + return '${bytes} bytes'; + } else if (bytes <= 100000) { + return '${(bytes / 1000).toStringAsFixed(2)} KB'; + } else { + return '${(bytes / 1000000).toStringAsFixed(2)} MB'; + } + } } From bdd94693717ca31c660c95845734877630921227 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Fri, 11 Dec 2020 15:09:25 +0100 Subject: [PATCH 0614/1140] use expanded gesturedetector --- lib/src/message_input.dart | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index e60c6187..542f63e7 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -841,12 +841,13 @@ class MessageInputState extends State { if (snapshot.data) { if (_attachmentContainsFile) { - return Container( - color: Color(0xfff2f2f2), - child: InkWell( - onTap: () { - pickFile(DefaultAttachmentTypes.file); - }, + return GestureDetector( + onTap: () { + pickFile(DefaultAttachmentTypes.file); + }, + child: Container( + constraints: BoxConstraints.expand(), + color: Color(0xfff2f2f2), child: Text( 'Add more files', style: TextStyle( @@ -854,8 +855,8 @@ class MessageInputState extends State { fontWeight: FontWeight.bold, ), ), + alignment: Alignment.center, ), - alignment: Alignment.center, ); } return MediaListView( From 255f9c1608a10d6b0e5619fdff70f864f7128f91 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Mon, 14 Dec 2020 10:02:14 +0100 Subject: [PATCH 0615/1140] add enforce_unique: true in send reaction --- lib/src/reaction_picker.dart | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/src/reaction_picker.dart b/lib/src/reaction_picker.dart index ff23b8a3..b019ee79 100644 --- a/lib/src/reaction_picker.dart +++ b/lib/src/reaction_picker.dart @@ -136,7 +136,9 @@ class _ReactionPickerState extends State void sendReaction(BuildContext context, String reactionType) { StreamChannel.of(context) .channel - .sendReaction(widget.message, reactionType); + .sendReaction(widget.message, reactionType, extraData: { + 'enforce_unique': true, + }); pop(); } From 984d3ec104c614d975c0536a61f0d71815b898e8 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Mon, 14 Dec 2020 10:03:54 +0100 Subject: [PATCH 0616/1140] don't show copy message for empty messages --- lib/src/message_widget.dart | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/src/message_widget.dart b/lib/src/message_widget.dart index f761f756..c7c6acdb 100644 --- a/lib/src/message_widget.dart +++ b/lib/src/message_widget.dart @@ -558,6 +558,7 @@ class _MessageWidgetState extends State { message: widget.message, editMessageInputBuilder: widget.editMessageInputBuilder, onThreadTap: widget.onThreadTap, + showCopyMessage: widget.message.text?.trim()?.isNotEmpty == true, showEditMessage: widget.showEditMessage && widget.message.attachments ?.any((element) => element.type == 'giphy') != From faafb21481a92eeb7630343c07cff568a27e54ac Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Mon, 14 Dec 2020 10:35:33 +0100 Subject: [PATCH 0617/1140] trigger ci --- example/lib/main.dart | 2 +- example/pubspec.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/example/lib/main.dart b/example/lib/main.dart index 4b529e23..3fb47b66 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -57,7 +57,7 @@ class MyApp extends StatelessWidget { debugShowCheckedModeBanner: false, theme: ThemeData.light(), darkTheme: ThemeData.dark(), - //TODO change to system once dark theme is implemented + //TODO change to system once dark theme is implemented themeMode: ThemeMode.light, onGenerateRoute: AppRoutes.generateRoute, initialRoute: diff --git a/example/pubspec.yaml b/example/pubspec.yaml index c5bfa14f..5459debc 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -1,6 +1,6 @@ name: example description: A new Flutter project. -version: 1.0.88+90 +version: 1.0.89+91 environment: sdk: ">=2.2.2 <3.0.0" From 2903cae4e84f3742c43f68d6107f9b443325b958 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Mon, 14 Dec 2020 11:47:27 +0100 Subject: [PATCH 0618/1140] trigger ci --- example/pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 5459debc..2e0c0ae3 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -1,6 +1,6 @@ name: example description: A new Flutter project. -version: 1.0.89+91 +version: 1.0.90+93 environment: sdk: ">=2.2.2 <3.0.0" From f2a707bc45e13cf0f546002fb8d33ee179e7a8f5 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Mon, 14 Dec 2020 20:22:48 +0530 Subject: [PATCH 0619/1140] feat: Added group info screen, refactored components, added some functionality --- lib/src/channel_file_display_screen.dart | 36 ++ lib/src/channel_header.dart | 11 + lib/src/channel_media_display_screen.dart | 36 ++ lib/src/channel_preview.dart | 11 + lib/src/chat_info_screen.dart | 161 +------ lib/src/group_info_screen.dart | 502 ++++++++++++++++++++++ lib/src/option_list_tile.dart | 68 +++ 7 files changed, 681 insertions(+), 144 deletions(-) create mode 100644 lib/src/channel_file_display_screen.dart create mode 100644 lib/src/channel_media_display_screen.dart create mode 100644 lib/src/group_info_screen.dart create mode 100644 lib/src/option_list_tile.dart diff --git a/lib/src/channel_file_display_screen.dart b/lib/src/channel_file_display_screen.dart new file mode 100644 index 00000000..d34a4b87 --- /dev/null +++ b/lib/src/channel_file_display_screen.dart @@ -0,0 +1,36 @@ +import 'package:flutter/material.dart'; +import 'package:stream_chat_flutter/stream_chat_flutter.dart'; + +class ChannelFileDisplayScreen extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: Colors.white, + appBar: AppBar( + brightness: Theme.of(context).brightness, + elevation: 1, + centerTitle: true, + title: Text( + 'Files', + style: TextStyle(color: Colors.black, fontSize: 16.0), + ), + leading: Center( + child: InkWell( + onTap: () { + Navigator.of(context).pop(); + }, + child: Container( + child: StreamSvgIcon.left( + color: Colors.black, + size: 24.0, + ), + width: 24.0, + height: 24.0, + ), + ), + ), + backgroundColor: StreamChatTheme.of(context).primaryColor, + ), + ); + } +} diff --git a/lib/src/channel_header.dart b/lib/src/channel_header.dart index 65f63cc4..73e44b35 100644 --- a/lib/src/channel_header.dart +++ b/lib/src/channel_header.dart @@ -9,6 +9,7 @@ import '../stream_chat_flutter.dart'; import './channel_name.dart'; import 'channel_image.dart'; import 'chat_info_screen.dart'; +import 'group_info_screen.dart'; import 'stream_channel.dart'; /// ![screenshot](https://raw.githubusercontent.com/GetStream/stream-chat-flutter/master/screenshots/channel_header.png) @@ -124,6 +125,16 @@ class ChannelHeader extends StatelessWidget implements PreferredSizeWidget { Navigator.pop(context); } } + } else { + await Navigator.push( + context, + MaterialPageRoute( + builder: (context) => StreamChannel( + channel: channel, + child: GroupInfoScreen(), + ), + ), + ); } }, ), diff --git a/lib/src/channel_media_display_screen.dart b/lib/src/channel_media_display_screen.dart new file mode 100644 index 00000000..bcad35e2 --- /dev/null +++ b/lib/src/channel_media_display_screen.dart @@ -0,0 +1,36 @@ +import 'package:flutter/material.dart'; +import 'package:stream_chat_flutter/stream_chat_flutter.dart'; + +class ChannelMediaDisplayScreen extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: Colors.white, + appBar: AppBar( + brightness: Theme.of(context).brightness, + elevation: 1, + centerTitle: true, + title: Text( + 'Photos & Videos', + style: TextStyle(color: Colors.black, fontSize: 16.0), + ), + leading: Center( + child: InkWell( + onTap: () { + Navigator.of(context).pop(); + }, + child: Container( + child: StreamSvgIcon.left( + color: Colors.black, + size: 24.0, + ), + width: 24.0, + height: 24.0, + ), + ), + ), + backgroundColor: StreamChatTheme.of(context).primaryColor, + ), + ); + } +} diff --git a/lib/src/channel_preview.dart b/lib/src/channel_preview.dart index 5f58e254..ff727cfa 100644 --- a/lib/src/channel_preview.dart +++ b/lib/src/channel_preview.dart @@ -2,6 +2,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/widgets.dart'; import 'package:jiffy/jiffy.dart'; import 'package:stream_chat/stream_chat.dart'; +import 'package:stream_chat_flutter/src/group_info_screen.dart'; import 'package:stream_chat_flutter/src/stream_svg_icon.dart'; import '../stream_chat_flutter.dart'; @@ -82,6 +83,16 @@ class ChannelPreview extends StatelessWidget { ), ); } + } else { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => StreamChannel( + channel: channel, + child: GroupInfoScreen(), + ), + ), + ); } }, ), diff --git a/lib/src/chat_info_screen.dart b/lib/src/chat_info_screen.dart index 0ec62c36..436ff675 100644 --- a/lib/src/chat_info_screen.dart +++ b/lib/src/chat_info_screen.dart @@ -4,6 +4,9 @@ import 'package:flutter/material.dart'; import 'package:jiffy/jiffy.dart'; import '../stream_chat_flutter.dart'; +import 'channel_file_display_screen.dart'; +import 'channel_media_display_screen.dart'; +import 'option_list_tile.dart'; /// Detail screen for a 1:1 chat correspondence class ChatInfoScreen extends StatefulWidget { @@ -74,7 +77,7 @@ class _ChatInfoScreenState extends State { SizedBox(height: 7.0), _buildConnectedTitleState(), SizedBox(height: 15.0), - _OptionListTile( + OptionListTile( title: '@${widget.user.id}', trailing: Padding( padding: const EdgeInsets.symmetric(horizontal: 8.0), @@ -124,7 +127,7 @@ class _ChatInfoScreenState extends State { StreamBuilder( stream: StreamChannel.of(context).channel.isMutedStream, builder: (context, snapshot) { - return _OptionListTile( + return OptionListTile( title: 'Mute user', leading: StreamSvgIcon.mute( size: 23.0, @@ -163,7 +166,7 @@ class _ChatInfoScreenState extends State { // ), // onTap: () {}, // ), - _OptionListTile( + OptionListTile( title: 'Photos & Videos', leading: StreamSvgIcon.pictures( size: 32.0, @@ -171,11 +174,13 @@ class _ChatInfoScreenState extends State { ), trailing: StreamSvgIcon.right(), onTap: () { - Navigator.push(context, - MaterialPageRoute(builder: (context) => _MediaDisplayScreen())); + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => ChannelMediaDisplayScreen())); }, ), - _OptionListTile( + OptionListTile( title: 'Files', leading: StreamSvgIcon.files( size: 32.0, @@ -183,11 +188,13 @@ class _ChatInfoScreenState extends State { ), trailing: StreamSvgIcon.right(), onTap: () { - Navigator.push(context, - MaterialPageRoute(builder: (context) => _FileDisplayScreen())); + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => ChannelFileDisplayScreen())); }, ), - _OptionListTile( + OptionListTile( title: 'Shared groups', leading: StreamSvgIcon.Icon_group( size: 24.0, @@ -207,7 +214,7 @@ class _ChatInfoScreenState extends State { } Widget _buildDeleteListTile() { - return _OptionListTile( + return OptionListTile( title: 'Delete', leading: StreamSvgIcon.delete( color: Colors.red, @@ -283,72 +290,6 @@ class _ChatInfoScreenState extends State { } } -class _OptionListTile extends StatelessWidget { - final String title; - final StreamSvgIcon leading; - final Widget trailing; - final VoidCallback onTap; - final Color titleColor; - - _OptionListTile({ - this.title, - this.leading, - this.trailing, - this.onTap, - this.titleColor, - }); - - @override - Widget build(BuildContext context) { - return Column( - children: [ - Container( - color: Color(0xffe6e6e6), - height: 2.0, - ), - Material( - color: Colors.white, - child: Container( - height: 56.0, - child: InkWell( - onTap: onTap, - child: Row( - children: [ - if (leading != null) - Expanded( - child: Center(child: leading), - ), - if (leading == null) - SizedBox( - width: 16.0, - ), - Expanded( - flex: 4, - child: Text( - title, - style: TextStyle( - fontWeight: FontWeight.w600, color: titleColor), - )), - Expanded( - flex: 2, - child: Padding( - padding: const EdgeInsets.only(right: 16.0), - child: Align( - alignment: Alignment.centerRight, - child: trailing ?? Container(), - ), - ), - ), - ], - ), - ), - ), - ), - ], - ); - } -} - class _SharedGroupsScreen extends StatefulWidget { final User mainUser; final User otherUser; @@ -504,71 +445,3 @@ class __SharedGroupsScreenState extends State<_SharedGroupsScreen> { ); } } - -class _MediaDisplayScreen extends StatelessWidget { - @override - Widget build(BuildContext context) { - return Scaffold( - backgroundColor: Colors.white, - appBar: AppBar( - brightness: Theme.of(context).brightness, - elevation: 1, - centerTitle: true, - title: Text( - 'Photos & Videos', - style: TextStyle(color: Colors.black, fontSize: 16.0), - ), - leading: Center( - child: InkWell( - onTap: () { - Navigator.of(context).pop(); - }, - child: Container( - child: StreamSvgIcon.left( - color: Colors.black, - size: 24.0, - ), - width: 24.0, - height: 24.0, - ), - ), - ), - backgroundColor: StreamChatTheme.of(context).primaryColor, - ), - ); - } -} - -class _FileDisplayScreen extends StatelessWidget { - @override - Widget build(BuildContext context) { - return Scaffold( - backgroundColor: Colors.white, - appBar: AppBar( - brightness: Theme.of(context).brightness, - elevation: 1, - centerTitle: true, - title: Text( - 'Files', - style: TextStyle(color: Colors.black, fontSize: 16.0), - ), - leading: Center( - child: InkWell( - onTap: () { - Navigator.of(context).pop(); - }, - child: Container( - child: StreamSvgIcon.left( - color: Colors.black, - size: 24.0, - ), - width: 24.0, - height: 24.0, - ), - ), - ), - backgroundColor: StreamChatTheme.of(context).primaryColor, - ), - ); - } -} diff --git a/lib/src/group_info_screen.dart b/lib/src/group_info_screen.dart new file mode 100644 index 00000000..ceb33dc8 --- /dev/null +++ b/lib/src/group_info_screen.dart @@ -0,0 +1,502 @@ +import 'dart:async'; + +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:jiffy/jiffy.dart'; +import 'package:stream_chat_flutter/src/option_list_tile.dart'; +import 'package:stream_chat_flutter/src/stream_svg_icon.dart'; + +import '../stream_chat_flutter.dart'; +import 'channel_file_display_screen.dart'; +import 'channel_media_display_screen.dart'; + +class GroupInfoScreen extends StatefulWidget { + @override + _GroupInfoScreenState createState() => _GroupInfoScreenState(); +} + +class _GroupInfoScreenState extends State { + Future _memberQueryFuture; + TextEditingController _nameController; + + bool _userSearchMode = false; + TextEditingController _searchController; + bool _loading = false; + String _userNameQuery = ''; + + Timer _debounce; + Function modalSetStateCallback; + + void _userNameListener() { + if (_debounce?.isActive ?? false) _debounce.cancel(); + _debounce = Timer(const Duration(milliseconds: 350), () { + if (mounted && modalSetStateCallback != null) { + modalSetStateCallback(() { + _userNameQuery = _searchController.text; + }); + } + }); + } + + @override + void initState() { + super.initState(); + var channel = StreamChannel.of(context); + + _memberQueryFuture = channel.channel.queryMembers( + filter: {}, + ); + _nameController = TextEditingController.fromValue( + TextEditingValue(text: channel.channel.extraData['name'])); + _searchController = TextEditingController()..addListener(_userNameListener); + } + + @override + Widget build(BuildContext context) { + var channel = StreamChannel.of(context); + + return Scaffold( + backgroundColor: Color(0xffdbdbdb), + appBar: AppBar( + elevation: 1.0, + toolbarHeight: 56.0, + backgroundColor: Colors.white, + leading: InkWell( + onTap: () { + Navigator.pop(context); + }, + child: Padding( + padding: const EdgeInsets.only(left: 12.0), + child: StreamSvgIcon.left(), + ), + ), + leadingWidth: 36.0, + title: Column( + children: [ + // TODO: Add member names instead of Demo (if name = null) + Text( + channel.channel.extraData['name'] ?? 'Demo', + style: TextStyle(color: Colors.black), + ), + SizedBox( + height: 3.0, + ), + FutureBuilder( + future: _memberQueryFuture, + builder: (context, snapshot) { + return Text( + '${channel.channel.memberCount} Members, ${snapshot?.data?.members?.where((e) => e.user.online)?.length ?? 0} Online', + style: TextStyle( + color: Colors.black.withOpacity(0.5), fontSize: 12.0), + ); + }), + ], + ), + centerTitle: true, + actions: [ + StreamNeumorphicButton( + child: InkWell( + onTap: () { + _buildAddUserModal(context); + }, + child: Padding( + padding: const EdgeInsets.all(8.0), + child: StreamSvgIcon.userAdd( + color: StreamChatTheme.of(context).accentColor), + ), + ), + ), + ], + ), + body: ListView( + children: [ + _buildMembers(), + Container( + height: 8.0, + color: Color(0xffdbdbdb), + ), + _buildNameTile(), + _buildOptionListTiles(), + ], + ), + ); + } + + Widget _buildMembers() { + var channel = StreamChannel.of(context); + + return FutureBuilder( + builder: (context, snapshot) { + if (snapshot.data == null) { + return Center( + child: Padding( + padding: const EdgeInsets.all(8.0), + child: CircularProgressIndicator(), + ), + ); + } + + return ListView.builder( + shrinkWrap: true, + physics: NeverScrollableScrollPhysics(), + itemCount: snapshot.data.members.length, + itemBuilder: (context, position) { + return Material( + child: Container( + height: 65.0, + child: Column( + children: [ + Row( + children: [ + Padding( + padding: const EdgeInsets.symmetric( + horizontal: 8.0, vertical: 12.0), + child: UserAvatar( + user: snapshot.data.members[position].user, + constraints: + BoxConstraints(maxHeight: 40.0, maxWidth: 40.0), + ), + ), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + snapshot.data.members[position].user.name, + style: TextStyle(fontWeight: FontWeight.bold), + ), + SizedBox( + height: 1.0, + ), + Text( + _getLastSeen( + snapshot.data.members[position].user), + style: TextStyle( + color: Colors.black.withOpacity(0.5)), + ), + ], + ), + ), + Padding( + padding: const EdgeInsets.all(8.0), + child: Text( + snapshot.data.members[position].user.id == + channel.channel.createdBy.id + ? 'Owner' + : '', + style: + TextStyle(color: Colors.black.withOpacity(0.5)), + ), + ), + ], + ), + Container( + height: 1.0, + color: Color(0xffdbdbdb), + ), + ], + ), + ), + color: Colors.white, + ); + }, + ); + }, + future: _memberQueryFuture, + ); + } + + Widget _buildNameTile() { + return Material( + color: Colors.white, + child: Container( + height: 56.0, + alignment: Alignment.center, + child: Row( + children: [ + Padding( + padding: const EdgeInsets.all(8.0), + child: Text( + 'NAME', + style: TextStyle( + color: Colors.black.withOpacity(0.5), fontSize: 12.0), + ), + ), + SizedBox( + width: 9.0, + ), + Expanded( + child: TextField( + controller: _nameController, + cursorColor: Colors.black, + decoration: InputDecoration.collapsed( + hintText: 'Add a group name', + hintStyle: TextStyle( + fontWeight: FontWeight.bold, + color: Colors.black.withOpacity(0.5), + ), + ), + style: TextStyle( + fontWeight: FontWeight.bold, + ), + ), + ), + ], + ), + ), + ); + } + + Widget _buildOptionListTiles() { + var channel = StreamChannel.of(context); + + return Column( + children: [ + // OptionListTile( + // title: 'Notifications', + // leading: StreamSvgIcon.Icon_notification( + // size: 24.0, + // color: Colors.black.withOpacity(0.5), + // ), + // trailing: CupertinoSwitch( + // value: true, + // onChanged: (val) {}, + // ), + // onTap: () {}, + // ), + StreamBuilder( + stream: StreamChannel.of(context).channel.isMutedStream, + builder: (context, snapshot) { + return OptionListTile( + title: 'Mute group', + leading: StreamSvgIcon.mute( + size: 23.0, + color: Colors.black.withOpacity(0.5), + ), + trailing: snapshot.data == null + ? CircularProgressIndicator() + : CupertinoSwitch( + value: snapshot.data, + onChanged: (val) { + if (snapshot.data) { + channel.channel.unmute(); + } else { + channel.channel.mute(); + } + }, + ), + onTap: () {}, + ); + }), + OptionListTile( + title: 'Photos & Videos', + leading: StreamSvgIcon.pictures( + size: 32.0, + color: Colors.black.withOpacity(0.5), + ), + trailing: StreamSvgIcon.right(), + onTap: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => ChannelMediaDisplayScreen())); + }, + ), + OptionListTile( + title: 'Files', + leading: StreamSvgIcon.files( + size: 32.0, + color: Colors.black.withOpacity(0.5), + ), + trailing: StreamSvgIcon.right(), + onTap: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => ChannelFileDisplayScreen())); + }, + ), + OptionListTile( + title: 'Leave Group', + leading: StreamSvgIcon.userRemove( + size: 24.0, + color: Colors.black.withOpacity(0.5), + ), + trailing: Container( + height: 24.0, + width: 24.0, + ), + onTap: () async { + await channel.channel + .removeMembers([StreamChat.of(context).user.id]); + Navigator.pop(context); + Navigator.pop(context); + }, + ), + ], + ); + } + + void _buildAddUserModal(context) { + var channel = StreamChannel.of(context).channel; + + showDialog( + context: context, + builder: (context) { + return StatefulBuilder(builder: (context, modalSetState) { + modalSetStateCallback = modalSetState; + return Padding( + padding: EdgeInsets.only(top: 16.0, left: 8.0, right: 8.0), + child: Material( + borderRadius: BorderRadius.only( + topLeft: Radius.circular(16.0), + topRight: Radius.circular(16.0), + ), + clipBehavior: Clip.antiAlias, + child: Scaffold( + body: UsersBloc( + child: Column( + children: [ + _buildTextInputSection(modalSetState), + Expanded( + child: UserListView( + selectedUsers: {}, + onUserTap: (user, _) async { + _searchController.clear(); + + await channel.addMembers([user.id]); + Navigator.pop(context); + _memberQueryFuture = channel.queryMembers( + filter: {}, + ); + setState(() {}); + }, + crossAxisCount: 4, + pagination: PaginationParams( + limit: 25, + ), + filter: { + if (_searchController.text.isNotEmpty) + 'name': { + r'$autocomplete': _userNameQuery, + }, + 'id': { + r'$ne': StreamChat.of(context).user.id, + }, + }, + sort: [ + SortOption( + 'name', + direction: 1, + ), + ], + emptyBuilder: (_) { + return LayoutBuilder( + builder: (context, viewportConstraints) { + return SingleChildScrollView( + physics: AlwaysScrollableScrollPhysics(), + child: ConstrainedBox( + constraints: BoxConstraints( + minHeight: viewportConstraints.maxHeight, + ), + child: Center( + child: Column( + children: [ + Padding( + padding: const EdgeInsets.all(24), + child: StreamSvgIcon.search( + size: 96, + color: Colors.grey, + ), + ), + Text( + 'No user matches these keywords...'), + ], + ), + ), + ), + ); + }, + ); + }, + ), + ), + ], + ), + ), + ), + ), + ); + }); + }, + ); + } + + Widget _buildTextInputSection(modalSetState) { + return Column( + children: [ + SizedBox( + height: 16.0, + ), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + SizedBox( + width: 16.0, + ), + Expanded( + child: TextField( + controller: _searchController, + cursorColor: Colors.black, + autofocus: true, + decoration: InputDecoration( + isDense: true, + prefixIconConstraints: BoxConstraints.tight(Size(36.0, 44.0)), + prefixIcon: Padding( + padding: const EdgeInsets.symmetric( + vertical: 2.0, horizontal: 6.0), + child: StreamSvgIcon.search( + color: Colors.black, + ), + ), + hintText: 'Search', + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(32.0), + borderSide: + BorderSide(color: Colors.black.withOpacity(0.08)), + ), + focusedBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(32.0), + borderSide: + BorderSide(color: Colors.black.withOpacity(0.08)), + ), + contentPadding: EdgeInsets.zero, + ), + ), + ), + SizedBox( + width: 8.0, + ), + IconButton( + icon: StreamSvgIcon.close_small( + color: Colors.black.withOpacity(0.5), + ), + onPressed: () { + Navigator.pop(context); + }, + ) + ], + ), + ], + ); + } + + String _getLastSeen(User user) { + if (user.online) { + return 'Online'; + } else { + return 'Last seen ${Jiffy(user.lastActive).fromNow()}'; + } + } +} diff --git a/lib/src/option_list_tile.dart b/lib/src/option_list_tile.dart new file mode 100644 index 00000000..c1f48b71 --- /dev/null +++ b/lib/src/option_list_tile.dart @@ -0,0 +1,68 @@ +import 'package:flutter/material.dart'; +import 'package:stream_chat_flutter/src/stream_svg_icon.dart'; + +class OptionListTile extends StatelessWidget { + final String title; + final StreamSvgIcon leading; + final Widget trailing; + final VoidCallback onTap; + final Color titleColor; + + OptionListTile({ + this.title, + this.leading, + this.trailing, + this.onTap, + this.titleColor, + }); + + @override + Widget build(BuildContext context) { + return Column( + children: [ + Container( + color: Color(0xffe6e6e6), + height: 2.0, + ), + Material( + color: Colors.white, + child: Container( + height: 56.0, + child: InkWell( + onTap: onTap, + child: Row( + children: [ + if (leading != null) + Expanded( + child: Center(child: leading), + ), + if (leading == null) + SizedBox( + width: 16.0, + ), + Expanded( + flex: 4, + child: Text( + title, + style: TextStyle( + fontWeight: FontWeight.w600, color: titleColor), + )), + Expanded( + flex: 2, + child: Padding( + padding: const EdgeInsets.only(right: 16.0), + child: Align( + alignment: Alignment.centerRight, + child: trailing ?? Container(), + ), + ), + ), + ], + ), + ), + ), + ), + ], + ); + } +} From 5e7e5aaac03c0821309565c839d394596cb15bcb Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Tue, 15 Dec 2020 12:18:16 +0100 Subject: [PATCH 0620/1140] fix new chat screen flow --- example/ios/fastlane/report.xml | 22 ++------ example/lib/new_chat_screen.dart | 87 ++++++++++++++++++++------------ example/pubspec.yaml | 2 +- lib/src/message_input.dart | 31 +++++++----- lib/src/message_list_view.dart | 8 +-- lib/src/user_list_view.dart | 2 +- 6 files changed, 85 insertions(+), 67 deletions(-) diff --git a/example/ios/fastlane/report.xml b/example/ios/fastlane/report.xml index d6fdf2d7..17688944 100644 --- a/example/ios/fastlane/report.xml +++ b/example/ios/fastlane/report.xml @@ -5,39 +5,27 @@ - + - + - + - + - - - - - - - - - - - - - + diff --git a/example/lib/new_chat_screen.dart b/example/lib/new_chat_screen.dart index 5fbfbf07..a2ce9ebf 100644 --- a/example/lib/new_chat_screen.dart +++ b/example/lib/new_chat_screen.dart @@ -37,6 +37,8 @@ class _NewChatScreenState extends State { bool _showUserList = true; + bool _channelExisted = false; + void _userNameListener() { if (_debounce?.isActive ?? false) _debounce.cancel(); _debounce = Timer(const Duration(milliseconds: 350), () { @@ -56,11 +58,6 @@ class _NewChatScreenState extends State { _searchFocusNode.addListener(() async { if (_searchFocusNode.hasFocus && !_showUserList) { - if (channel.extraData['draft'] == true) { - await channel.stopWatching(); - channel.dispose(); - channel.client.state.channels.remove(channel.cid); - } setState(() { _showUserList = true; }); @@ -71,19 +68,38 @@ class _NewChatScreenState extends State { if (_messageInputFocusNode.hasFocus && _selectedUsers.isNotEmpty) { final chatState = StreamChat.of(context); - channel = chatState.client.channel( - 'messaging', - extraData: { + final res = await chatState.client.queryChannels( + options: { + 'state': false, + 'watch': false, + }, + filter: { 'members': [ ..._selectedUsers.map((e) => e.id), chatState.user.id, ], - 'draft': true, + 'distinct': true, }, - ); + messageLimit: 0, + paginationParams: PaginationParams( + limit: 1, + ), + ).first; - if (!chatState.client.state.channels.containsKey(channel.cid)) { + final _channelExisted = res.length == 1; + if (_channelExisted) { + channel = res.first; await channel.watch(); + } else { + channel = chatState.client.channel( + 'messaging', + extraData: { + 'members': [ + ..._selectedUsers.map((e) => e.id), + chatState.user.id, + ], + }, + ); } setState(() { @@ -134,6 +150,7 @@ class _NewChatScreenState extends State { return GestureDetector( onTap: () { _chipInputTextFieldState.removeItem(user); + _searchFocusNode.requestFocus(); }, child: Stack( alignment: AlignmentDirectional.centerStart, @@ -311,18 +328,38 @@ class _NewChatScreenState extends State { ), ), ) - : MessageListView(), + : FutureBuilder( + future: channel.initialized, + builder: (context, snapshot) { + if (snapshot.data == true) { + return MessageListView(); + } + + return Center( + child: Text( + 'No chats here yet...', + style: TextStyle( + fontSize: 12, + color: Colors.black.withOpacity(.5), + ), + ), + ); + }, + ), ), MessageInput( focusNode: _messageInputFocusNode, + preMessageSending: (message) async { + await channel.watch(); + return message; + }, onMessageSent: (m) { - if (!m.isEphemeral) { - _updateChannelAndNavigate(context); - } else { - channel.on('message.new').first.then((_) { - _updateChannelAndNavigate(context); - }); - } + Navigator.pushNamedAndRemoveUntil( + context, + Routes.CHANNEL_PAGE, + ModalRoute.withName(Routes.HOME), + arguments: channel, + ); }, ), ], @@ -330,16 +367,4 @@ class _NewChatScreenState extends State { ), ); } - - void _updateChannelAndNavigate(BuildContext context) { - channel.update({ - 'draft': false, - }); - Navigator.pushNamedAndRemoveUntil( - context, - Routes.CHANNEL_PAGE, - ModalRoute.withName(Routes.HOME), - arguments: channel, - ); - } } diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 2e0c0ae3..f9c71355 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -1,6 +1,6 @@ name: example description: A new Flutter project. -version: 1.0.90+93 +version: 1.0.91+94 environment: sdk: ">=2.2.2 <3.0.0" diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 542f63e7..447d49d9 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -343,7 +343,10 @@ class MessageInputState extends State { mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ if (!widget.disableAttachments) _buildAttachmentButton(), - if (widget.editMessage == null) _buildCommandButton(), + if (widget.editMessage == null && + StreamChannel.of(context).channel?.config?.commands?.isNotEmpty == + true) + _buildCommandButton(), ], ), duration: Duration(milliseconds: 300), @@ -543,11 +546,12 @@ class MessageInputState extends State { void _checkCommands(String s, BuildContext context) { if (s.startsWith('/')) { var matchedCommandsList = StreamChannel.of(context) - .channel - .config - .commands - .where((element) => element.name == s.substring(1)) - .toList(); + .channel + .config + ?.commands + ?.where((element) => element.name == s.substring(1)) + ?.toList() ?? + []; if (matchedCommandsList.length == 1) { _chosenCommand = matchedCommandsList[0]; @@ -568,11 +572,12 @@ class MessageInputState extends State { OverlayEntry _buildCommandsOverlayEntry() { final text = textEditingController.text.trimLeft(); final commands = StreamChannel.of(context) - .channel - .config - .commands - .where((c) => c.name.contains(text.replaceFirst('/', ''))) - .toList(); + .channel + .config + ?.commands + ?.where((c) => c.name.contains(text.replaceFirst('/', ''))) + ?.toList() ?? + []; RenderBox renderBox = context.findRenderObject(); final size = renderBox.size; @@ -1927,8 +1932,6 @@ class MessageInputState extends State { _mentionsOverlay?.remove(); _mentionsOverlay = null; - final channel = StreamChannel.of(context).channel; - Future sendingFuture; Message message; if (widget.editMessage != null) { @@ -1953,6 +1956,8 @@ class MessageInputState extends State { message = await widget.preMessageSending(message); } + final channel = StreamChannel.of(context).channel; + if (widget.editMessage == null || widget.editMessage.status == MessageSendingStatus.FAILED) { sendingFuture = channel.sendMessage(message); diff --git a/lib/src/message_list_view.dart b/lib/src/message_list_view.dart index 430e0b85..5eaccc6a 100644 --- a/lib/src/message_list_view.dart +++ b/lib/src/message_list_view.dart @@ -173,15 +173,15 @@ class _MessageListViewState extends State { ? streamChannel.channel.state.threadsStream .where((threads) => threads.containsKey(widget.parentMessage.id)) .map((threads) => threads[widget.parentMessage.id]) - : streamChannel.channel.state.messagesStream; + : streamChannel.channel.state?.messagesStream; return StreamBuilder>( - stream: messagesStream.map((messages) => messages - .where((e) => + stream: messagesStream?.map((messages) => messages + ?.where((e) => !e.isDeleted || (e.isDeleted && e.user.id == streamChannel.channel.client.state.user.id)) - .toList()), + ?.toList()), builder: (context, snapshot) { if (!snapshot.hasData) { return Center( diff --git a/lib/src/user_list_view.dart b/lib/src/user_list_view.dart index b57e2d55..8ea0a72c 100644 --- a/lib/src/user_list_view.dart +++ b/lib/src/user_list_view.dart @@ -190,7 +190,7 @@ class _UserListViewState extends State } final groupedUsers = >{}; for (var e in temp) { - final alphabet = e.name[0]; + final alphabet = e.name[0]?.toUpperCase(); groupedUsers[alphabet] = [...groupedUsers[alphabet] ?? [], e]; } final items = []; From d2a115be6fe9584bd5e7a25cb0e5592088005eb3 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Tue, 15 Dec 2020 19:47:21 +0530 Subject: [PATCH 0621/1140] feat: Added change name, group name, etc --- lib/src/group_info_screen.dart | 85 ++++++++++++++++++++++++++++++++-- 1 file changed, 81 insertions(+), 4 deletions(-) diff --git a/lib/src/group_info_screen.dart b/lib/src/group_info_screen.dart index ceb33dc8..7dd7ceaa 100644 --- a/lib/src/group_info_screen.dart +++ b/lib/src/group_info_screen.dart @@ -27,6 +27,11 @@ class _GroupInfoScreenState extends State { Timer _debounce; Function modalSetStateCallback; + final FocusNode _focusNode = FocusNode(); + + bool namedChanged = false; + String changedName = ''; + void _userNameListener() { if (_debounce?.isActive ?? false) _debounce.cancel(); _debounce = Timer(const Duration(milliseconds: 350), () { @@ -49,6 +54,10 @@ class _GroupInfoScreenState extends State { _nameController = TextEditingController.fromValue( TextEditingValue(text: channel.channel.extraData['name'])); _searchController = TextEditingController()..addListener(_userNameListener); + + _nameController.addListener(() { + setState(() {}); + }); } @override @@ -74,10 +83,19 @@ class _GroupInfoScreenState extends State { title: Column( children: [ // TODO: Add member names instead of Demo (if name = null) - Text( - channel.channel.extraData['name'] ?? 'Demo', - style: TextStyle(color: Colors.black), - ), + FutureBuilder( + future: _memberQueryFuture, + builder: (context, snapshot) { + return Text( + _getChannelName(MediaQuery.of(context).size.width, + members: snapshot.data?.members + ?.map((e) => e.user) + ?.toList()), + style: TextStyle(color: Colors.black), + maxLines: 1, + overflow: TextOverflow.ellipsis, + ); + }), SizedBox( height: 3.0, ), @@ -208,6 +226,9 @@ class _GroupInfoScreenState extends State { } Widget _buildNameTile() { + var channel = StreamChannel.of(context).channel; + var channelName = channel.extraData['name']; + return Material( color: Colors.white, child: Container( @@ -228,6 +249,7 @@ class _GroupInfoScreenState extends State { ), Expanded( child: TextField( + focusNode: _focusNode, controller: _nameController, cursorColor: Colors.black, decoration: InputDecoration.collapsed( @@ -242,6 +264,48 @@ class _GroupInfoScreenState extends State { ), ), ), + if ((channelName == null) || + (channelName != _nameController.text.trim())) + Row( + mainAxisSize: MainAxisSize.min, + children: [ + InkWell( + child: StreamSvgIcon.close_small(), + onTap: () { + setState(() { + _nameController.text = + _getChannelName(MediaQuery.of(context).size.width); + _focusNode.unfocus(); + }); + }, + ), + Padding( + padding: const EdgeInsets.only(right: 16.0, left: 8.0), + child: InkWell( + child: StreamSvgIcon.check( + color: StreamChatTheme.of(context).accentColor, + size: 24.0, + ), + onTap: () { + StreamChannel.of(context).channel.update({ + 'name': _nameController.text.trim(), + }).then((value) { + setState(() { + _focusNode.unfocus(); + namedChanged = true; + changedName = _nameController.text.trim(); + }); + }).catchError((err) { + setState(() { + _nameController.text = channelName; + _focusNode.unfocus(); + }); + }); + }, + ), + ), + ], + ), ], ), ), @@ -492,6 +556,19 @@ class _GroupInfoScreenState extends State { ); } + String _getChannelName(double width, {List members}) { + if (namedChanged) { + return changedName; + } + + if (StreamChannel.of(context).channel.extraData['name'] == null && + members != null) { + return '${members[0].name} & ${members.length - 1} others'; + } + + return StreamChannel.of(context).channel.extraData['name'] ?? ''; + } + String _getLastSeen(User user) { if (user.online) { return 'Online'; From f85cf6bb16ff6d7353d9d463f4f55240429b3af0 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Tue, 15 Dec 2020 20:18:13 +0530 Subject: [PATCH 0622/1140] qa fix for file list --- lib/src/message_input.dart | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 447d49d9..dec2b033 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -1287,10 +1287,11 @@ class MessageInputState extends State { children: [ if (_attachments.any((e) => e.attachment?.type == 'file')) LimitedBox( - maxHeight: 73.0, + maxHeight: 136.0, child: ListView( - scrollDirection: Axis.horizontal, - children: _attachments + reverse: true, + shrinkWrap: true, + children: _attachments.reversed .where((e) => e.attachment?.type == 'file') .map( (e) => Padding( @@ -1304,8 +1305,8 @@ class MessageInputState extends State { attachmentType: FileAttachmentType.local, file: e.file, size: Size( - MediaQuery.of(context).size.width * 0.55, - MediaQuery.of(context).size.height * 0.3, + MediaQuery.of(context).size.width * 0.65, + 56.0, ), trailing: Padding( padding: const EdgeInsets.all(8.0), From 7495acee3ee5d6c9fa3e7589ac3f7f45d518e86b Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Wed, 16 Dec 2020 16:56:09 +0530 Subject: [PATCH 0623/1140] changes Signed-off-by: Sahil Kumar --- example/lib/choose_user_page.dart | 4 +- example/lib/group_chat_details_screen.dart | 2 +- example/lib/main.dart | 47 +-- example/lib/new_chat_screen.dart | 2 +- example/lib/routes/app_routes.dart | 4 +- lib/src/lazy_load_scroll_view.dart | 37 ++- lib/src/message_input.dart | 10 +- lib/src/message_list_view.dart | 359 +++++++++++++-------- lib/src/stream_channel.dart | 351 ++++++++++++-------- lib/src/user_list_view.dart | 4 +- pubspec.yaml | 7 +- 11 files changed, 504 insertions(+), 323 deletions(-) diff --git a/example/lib/choose_user_page.dart b/example/lib/choose_user_page.dart index a64013b9..73b12425 100644 --- a/example/lib/choose_user_page.dart +++ b/example/lib/choose_user_page.dart @@ -13,13 +13,13 @@ import 'routes/routes.dart'; const kStreamApiKey = 'STREAM_API_KEY'; const kStreamUserId = 'STREAM_USER_ID'; const kStreamToken = 'STREAM_TOKEN'; -const kDefaultStreamApiKey = 'uj7qrdbfrzvg'; +const kDefaultStreamApiKey = 's2dxdhpxd94g'; class ChooseUserPage extends StatelessWidget { @override Widget build(BuildContext context) { final users = { - 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoidmlzaGFsIn0.lCz-idDgaZ-xszjnuB_hTfeIOhTFmJtTB2fEjhwrcCI': + 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoidmlzaGFsIn0._JHWzo92fpTWZMZriJHXqOng6ShYVmWrdaIaPwEPKBg': User( id: 'vishal', extraData: { diff --git a/example/lib/group_chat_details_screen.dart b/example/lib/group_chat_details_screen.dart index d759a82e..c6d4331d 100644 --- a/example/lib/group_chat_details_screen.dart +++ b/example/lib/group_chat_details_screen.dart @@ -133,7 +133,7 @@ class _GroupChatDetailsScreenState extends State { context, Routes.CHANNEL_PAGE, ModalRoute.withName(Routes.HOME), - arguments: channel, + arguments: ChannelPageArgs(channel: channel), ); }, ), diff --git a/example/lib/main.dart b/example/lib/main.dart index f1667139..10f6d5b3 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -337,40 +337,14 @@ class _ChannelListPageState extends State { final message = messageResponse.message; final channel = Channel.fromState( client, - ChannelState( - channel: messageResponse.channel, - messages: [message], - ), + ChannelState(channel: messageResponse.channel), ); - await Future.wait([ - channel.query( - messagesPagination: PaginationParams( - lessThan: message.id, - limit: 25, - ), - preferOffline: true, - ), - channel.query( - messagesPagination: PaginationParams( - greaterThan: message.id, - limit: 25, - ), - preferOffline: true, - ), - ]); - final messages = channel.state.messages; - final totalMessages = messages.length; - final messageIndex = messages - .indexWhere((e) => e.id == message.id); - final initialIndex = totalMessages - messageIndex; - final bool isFirstMessage = messageIndex == 0; Navigator.pushNamed( context, Routes.CHANNEL_PAGE, arguments: ChannelPageArgs( channel: channel, - initialScrollIndex: initialIndex, - initialAlignment: isFirstMessage ? 0 : 0.5, + initialMessage: message, ), ); }, @@ -406,24 +380,24 @@ class _ChannelListPageState extends State { class ChannelPageArgs { final Channel channel; - final int initialScrollIndex; - final double initialAlignment; + final Message initialMessage; const ChannelPageArgs({ this.channel, - this.initialScrollIndex = 0, - this.initialAlignment = 0, + this.initialMessage, }); } class ChannelPage extends StatelessWidget { final int initialScrollIndex; final double initialAlignment; + final bool highlightInitialMessage; const ChannelPage({ Key key, - this.initialScrollIndex = 0, - this.initialAlignment = 0, + this.initialScrollIndex, + this.initialAlignment, + this.highlightInitialMessage = false, }) : super(key: key); @override @@ -441,6 +415,7 @@ class ChannelPage extends StatelessWidget { MessageListView( initialScrollIndex: initialScrollIndex, initialAlignment: initialAlignment, + highlightInitialMessage: highlightInitialMessage, threadBuilder: (_, parentMessage) { return ThreadPage( parent: parentMessage, @@ -481,8 +456,8 @@ class ThreadPage extends StatelessWidget { ThreadPage({ Key key, this.parent, - this.initialScrollIndex = 0, - this.initialAlignment = 0, + this.initialScrollIndex, + this.initialAlignment, }) : super(key: key); @override diff --git a/example/lib/new_chat_screen.dart b/example/lib/new_chat_screen.dart index 5fbfbf07..94c7f866 100644 --- a/example/lib/new_chat_screen.dart +++ b/example/lib/new_chat_screen.dart @@ -339,7 +339,7 @@ class _NewChatScreenState extends State { context, Routes.CHANNEL_PAGE, ModalRoute.withName(Routes.HOME), - arguments: channel, + arguments: ChannelPageArgs(channel: channel), ); } } diff --git a/example/lib/routes/app_routes.dart b/example/lib/routes/app_routes.dart index 8ee907b8..8082245f 100644 --- a/example/lib/routes/app_routes.dart +++ b/example/lib/routes/app_routes.dart @@ -37,9 +37,9 @@ class AppRoutes { final arg = args as ChannelPageArgs; return StreamChannel( channel: arg.channel, + initialMessageId: arg.initialMessage?.id, child: ChannelPage( - initialScrollIndex: arg.initialScrollIndex, - initialAlignment: arg.initialAlignment, + highlightInitialMessage: arg.initialMessage != null, ), ); }); diff --git a/lib/src/lazy_load_scroll_view.dart b/lib/src/lazy_load_scroll_view.dart index 5cfeea61..a3c344aa 100644 --- a/lib/src/lazy_load_scroll_view.dart +++ b/lib/src/lazy_load_scroll_view.dart @@ -1,3 +1,4 @@ +import 'package:flutter/foundation.dart'; import 'package:flutter/widgets.dart'; enum _LoadingStatus { LOADING, STABLE } @@ -9,10 +10,10 @@ class LazyLoadScrollView extends StatefulWidget { final Widget child; /// Called when the [child] reaches the start of the list - final VoidCallback onStartOfPage; + final AsyncCallback onStartOfPage; /// Called when the [child] reaches the end of the list - final VoidCallback onEndOfPage; + final AsyncCallback onEndOfPage; /// The offset to take into account when triggering [onEndOfPage] in pixels final double scrollOffset; @@ -38,14 +39,6 @@ class LazyLoadScrollView extends StatefulWidget { class _LazyLoadScrollViewState extends State { _LoadingStatus _loadMoreStatus = _LoadingStatus.STABLE; - @override - void didUpdateWidget(LazyLoadScrollView oldWidget) { - super.didUpdateWidget(oldWidget); - if (!widget.isLoading) { - _loadMoreStatus = _LoadingStatus.STABLE; - } - } - @override Widget build(BuildContext context) { return NotificationListener( @@ -62,7 +55,11 @@ class _LazyLoadScrollViewState extends State { if (_loadMoreStatus != null && _loadMoreStatus == _LoadingStatus.STABLE) { _loadMoreStatus = _LoadingStatus.LOADING; - widget.onEndOfPage(); + if (widget.onEndOfPage != null) { + widget.onEndOfPage().whenComplete(() { + _loadMoreStatus = _LoadingStatus.STABLE; + }); + } } } if (notification.metrics.minScrollExtent < notification.metrics.pixels && @@ -71,7 +68,11 @@ class _LazyLoadScrollViewState extends State { if (_loadMoreStatus != null && _loadMoreStatus == _LoadingStatus.STABLE) { _loadMoreStatus = _LoadingStatus.LOADING; - widget.onStartOfPage(); + if (widget.onStartOfPage != null) { + widget.onStartOfPage().whenComplete(() { + _loadMoreStatus = _LoadingStatus.STABLE; + }); + } } } return true; @@ -81,14 +82,22 @@ class _LazyLoadScrollViewState extends State { if (_loadMoreStatus != null && _loadMoreStatus == _LoadingStatus.STABLE) { _loadMoreStatus = _LoadingStatus.LOADING; - widget.onEndOfPage(); + if (widget.onEndOfPage != null) { + widget.onEndOfPage().whenComplete(() { + _loadMoreStatus = _LoadingStatus.STABLE; + }); + } } } if (notification.overscroll < 0) { if (_loadMoreStatus != null && _loadMoreStatus == _LoadingStatus.STABLE) { _loadMoreStatus = _LoadingStatus.LOADING; - widget.onStartOfPage(); + if (widget.onStartOfPage != null) { + widget.onStartOfPage().whenComplete(() { + _loadMoreStatus = _LoadingStatus.STABLE; + }); + } } } return true; diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 4e30afe1..e38b9af3 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -21,7 +21,6 @@ import 'package:stream_chat_flutter/src/stream_svg_icon.dart'; import 'package:stream_chat_flutter/src/user_avatar.dart'; import 'package:substring_highlight/substring_highlight.dart'; import 'package:video_compress/video_compress.dart'; -import 'package:photo_manager/photo_manager.dart'; import '../stream_chat_flutter.dart'; import 'stream_channel.dart'; @@ -436,6 +435,7 @@ class MessageInputState extends State { } Timer _debounce; + void _onChanged(BuildContext context, String s) { if (_debounce?.isActive == true) _debounce.cancel(); _debounce = Timer( @@ -1859,7 +1859,8 @@ class MessageInputState extends State { _mentionsOverlay?.remove(); _mentionsOverlay = null; - final channel = StreamChannel.of(context).channel; + final streamChannel = StreamChannel.of(context); + final channel = streamChannel.channel; Future sendingFuture; Message message; @@ -1885,6 +1886,10 @@ class MessageInputState extends State { message = await widget.preMessageSending(message); } + if (!channel.state.isUpToDate) { + await streamChannel.reloadChannel(); + } + if (widget.editMessage == null || widget.editMessage.status == MessageSendingStatus.FAILED) { sendingFuture = channel.sendMessage(message); @@ -1970,6 +1975,7 @@ class MessageInputState extends State { } bool _initialized = false; + @override void didChangeDependencies() { if (widget.editMessage != null && !_initialized) { diff --git a/lib/src/message_list_view.dart b/lib/src/message_list_view.dart index 5efdb36a..042e20b9 100644 --- a/lib/src/message_list_view.dart +++ b/lib/src/message_list_view.dart @@ -1,8 +1,10 @@ import 'dart:async'; import 'dart:math'; +import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:jiffy/jiffy.dart'; +import 'package:rxdart/rxdart.dart'; import 'package:scrollable_positioned_list/scrollable_positioned_list.dart'; import 'package:stream_chat/stream_chat.dart'; import 'package:stream_chat_flutter/src/lazy_load_scroll_view.dart'; @@ -109,10 +111,11 @@ class MessageListView extends StatefulWidget { this.onThreadTap, this.dateDividerBuilder, this.scrollPhysics = const AlwaysScrollableScrollPhysics(), - this.initialScrollIndex = 0, - this.initialAlignment = 0, + this.initialScrollIndex, + this.initialAlignment, this.scrollController, this.itemPositionListener, + this.highlightInitialMessage = false, }) : super(key: key); /// Function used to build a custom message widget @@ -154,6 +157,11 @@ class MessageListView extends StatefulWidget { /// The ScrollPhysics used by the ListView final ScrollPhysics scrollPhysics; + /// If true the list will highlight the initialMessage if there is any. + /// + /// Also See [StreamChannel] + final bool highlightInitialMessage; + @override _MessageListViewState createState() => _MessageListViewState(); } @@ -166,6 +174,51 @@ class _MessageListViewState extends State { ItemPositionsListener _itemPositionListener; int _messageListLength; + int get _initialIndex { + if (widget.initialScrollIndex != null) return widget.initialScrollIndex; + final streamChannel = StreamChannel.of(context); + if (streamChannel.initialMessageId != null) { + final messages = streamChannel.channel.state.messages; + final totalMessages = messages.length; + final messageIndex = messages.indexWhere((e) { + return e.id == streamChannel.initialMessageId; + }); + return totalMessages - messageIndex - 1; + } + return 0; + } + + double get _initialAlignment { + if (widget.initialAlignment != null) return widget.initialAlignment; + final streamChannel = StreamChannel.of(context); + if (streamChannel.initialMessageId != null) { + final messages = streamChannel.channel.state.messages; + final messageIndex = messages.indexWhere((e) { + return e.id == streamChannel.initialMessageId; + }); + final isFirstMessage = messageIndex == 0; + return isFirstMessage ? 0 : 0.5; + } + return 0; + } + + bool _isInitialMessage(String id) { + final streamChannel = StreamChannel.of(context); + return streamChannel.initialMessageId == id; + } + + bool get _upToDate => StreamChannel.of(context).channel.state.isUpToDate; + + bool _topPaginationActive = false; + bool _bottomPaginationActive = false; + + bool get _paginationActive => _topPaginationActive || _bottomPaginationActive; + + int initialIndex; + double initialAlignment; + + List messages = []; + @override Widget build(BuildContext context) { final streamChannel = StreamChannel.of(context); @@ -176,6 +229,11 @@ class _MessageListViewState extends State { .map((threads) => threads[widget.parentMessage.id]) : streamChannel.channel.state.messagesStream; + if (!_paginationActive && !_upToDate) { + initialIndex = _initialIndex; + initialAlignment = _initialAlignment; + } + return StreamBuilder>( stream: messagesStream.map((messages) => messages .where((e) => @@ -190,32 +248,40 @@ class _MessageListViewState extends State { ); } - final messages = snapshot.data?.reversed?.toList() ?? []; + final messageList = snapshot.data?.reversed?.toList() ?? []; - if (messages.isEmpty) { - return Center( - child: Text( - 'No chats here yet...', - style: TextStyle( - fontSize: 12, - color: Colors.black.withOpacity(.5), + if (messageList.isEmpty) { + if (_upToDate) { + return Center( + child: Text( + 'No chats here yet...', + style: TextStyle( + fontSize: 12, + color: Colors.black.withOpacity(.5), + ), ), - ), - ); + ); + } + } else { + messages = messageList; } final newMessagesListLength = messages.length; - if (_itemPositionListener.itemPositions.value?.isNotEmpty == true && - _messageListLength != null) { - final first = _itemPositionListener.itemPositions.value.first; - final diff = newMessagesListLength - _messageListLength; - if (diff > 0) { - _scrollController.jumpTo( - index: first.index + diff, - alignment: first.itemLeadingEdge, - ); + if (_bottomPaginationActive) { + if (_itemPositionListener.itemPositions.value?.isNotEmpty == true && + _messageListLength != null) { + final first = _itemPositionListener.itemPositions.value.first; + final diff = newMessagesListLength - _messageListLength; + if (diff > 0) { + initialIndex = first.index + diff; + initialAlignment = first.itemLeadingEdge; + } } + } else if (!_topPaginationActive && _upToDate) { + // Reset the index in-case we send any new message + initialIndex = 0; + initialAlignment = 0; } _messageListLength = newMessagesListLength; @@ -224,28 +290,32 @@ class _MessageListViewState extends State { alignment: Alignment.center, children: [ LazyLoadScrollView( - onStartOfPage: () => _paginateData( - streamChannel, - QueryDirection.bottom, - ), - onEndOfPage: () => _paginateData( - streamChannel, - QueryDirection.top, - ), + onStartOfPage: () async { + if (!_upToDate) { + _topPaginationActive = false; + _bottomPaginationActive = true; + _paginateData(streamChannel, QueryDirection.bottom); + } + }, + onEndOfPage: () async { + _topPaginationActive = true; + _bottomPaginationActive = false; + _paginateData(streamChannel, QueryDirection.top); + }, child: ScrollablePositionedList.builder( + key: ValueKey(initialIndex + initialAlignment), itemPositionsListener: _itemPositionListener, addAutomaticKeepAlives: true, - key: Key('messageListView'), - initialScrollIndex: widget.initialScrollIndex, - initialAlignment: widget.initialAlignment, + initialScrollIndex: initialIndex ?? 0, + initialAlignment: initialAlignment ?? 0, physics: widget.scrollPhysics, itemScrollController: _scrollController, reverse: true, itemCount: messages.length + - 1 + + 2 + (widget.parentMessage != null ? 1 : 0), itemBuilder: (context, i) { - if (i == messages.length + 1) { + if (i == messages.length + 2) { if (widget.parentMessageBuilder != null) { return widget.parentMessageBuilder( context, @@ -273,16 +343,24 @@ class _MessageListViewState extends State { ); } } - - if (i == messages.length) { - return _buildLoadingIndicator(streamChannel); + if (i == messages.length + 1) { + return _buildLoadingIndicator( + streamChannel, + QueryDirection.top, + ); } - final message = messages[i]; - final nextMessage = i > 0 ? messages[i - 1] : null; + if (i == 0) { + return _buildLoadingIndicator( + streamChannel, + QueryDirection.bottom, + ); + } + final message = messages[i - 1]; + final nextMessage = (i - 1) > 0 ? messages[i - 2] : null; Widget messageWidget; - if (i == 0) { + if (i == 1) { messageWidget = _buildBottomMessage( context, message, @@ -339,8 +417,7 @@ class _MessageListViewState extends State { }, ), ), - if (widget.showScrollToBottom && _showScrollToBottom) - _buildScrollToBottom(), + if (widget.showScrollToBottom) _buildScrollToBottom(), Positioned( top: 20.0, child: ValueListenableBuilder>( @@ -380,7 +457,7 @@ class _MessageListViewState extends State { if (widget.parentMessage == null) { channel.queryMessages(direction: direction); } else { - channel.getReplies(widget.parentMessage.id, direction: direction); + channel.getReplies(widget.parentMessage.id); } } @@ -393,91 +470,117 @@ class _MessageListViewState extends State { Widget _buildScrollToBottom() { final streamChannel = StreamChannel.of(context); - return Positioned( - bottom: 8, - right: 8, - width: 40, - height: 40, - child: Stack( - clipBehavior: Clip.none, - children: [ - FloatingActionButton( - backgroundColor: Colors.white, - child: StreamSvgIcon.down( - color: Colors.black, - ), - onPressed: () { - setState(() { - _showScrollToBottom = false; - }); - _scrollController.scrollTo( - index: 0, - duration: Duration(seconds: 1), - curve: Curves.easeInOut, - ); - }, - ), - if (streamChannel.channel.state.members.any((Member e) => - e.userId == streamChannel.channel.client.state.user.id)) - StreamBuilder( - stream: streamChannel.channel.state.unreadCountStream, - initialData: streamChannel.channel.state.unreadCount, - builder: (context, snapshot) { - if (!snapshot.hasData || snapshot.data <= 0) { - return Offstage(); + return StreamBuilder>( + stream: Rx.combineLatest2( + streamChannel.channel.state.isUpToDateStream, + streamChannel.channel.state.unreadCountStream, + (bool isUpToDate, int unreadCount) => Tuple2(isUpToDate, unreadCount), + ), + builder: (_, snapshot) { + if (snapshot.hasError) { + return Offstage(); + } else if (!snapshot.hasData) { + return Offstage(); + } + final isUpToDate = snapshot.data.item1; + final showScrollToBottom = !isUpToDate || _showScrollToBottom; + if (!showScrollToBottom) { + return Offstage(); + } + final unreadCount = snapshot.data.item2; + final showUnreadCount = unreadCount > 0 && + streamChannel.channel.state.members.any( + (e) => e.userId == streamChannel.channel.client.state.user.id); + return Positioned( + bottom: 8, + right: 8, + width: 40, + height: 40, + child: Stack( + clipBehavior: Clip.none, + children: [ + FloatingActionButton( + backgroundColor: Colors.white, + child: StreamSvgIcon.down( + color: Colors.black, + ), + onPressed: () { + if (!_upToDate) { + _bottomPaginationActive = false; + _topPaginationActive = false; + streamChannel.reloadChannel(); + } else { + setState(() => _showScrollToBottom = false); + _scrollController.scrollTo( + index: 0, + duration: Duration(seconds: 1), + curve: Curves.easeInOut, + ); } - return Positioned( - width: 20, - height: 20, - left: 10, - top: -10, - child: CircleAvatar( - child: Padding( - padding: const EdgeInsets.all(3.0), - child: Text( - snapshot.data.toString(), - style: TextStyle( - fontSize: 11, - fontWeight: FontWeight.bold, - ), + }, + ), + if (showUnreadCount) + Positioned( + width: 20, + height: 20, + left: 10, + top: -10, + child: CircleAvatar( + child: Padding( + padding: const EdgeInsets.all(3.0), + child: Text( + snapshot.data.toString(), + style: TextStyle( + fontSize: 11, + fontWeight: FontWeight.bold, ), ), ), - ); - }), - ], - ), + ), + ), + ], + ), + ); + }, ); } - Container _buildLoadingIndicator(StreamChannelState streamChannel) { - return Container( - key: Key('LOADING-INDICATOR'), - height: 50, - width: double.infinity, - child: StreamBuilder( - stream: streamChannel.queryMessage, - initialData: false, - builder: (context, snapshot) { - if (snapshot.hasError) { - return Container( - color: Color(0xffd0021B).withAlpha(26), - child: Center( - child: Text('Error loading messages'), - ), - ); - } - if (!snapshot.data) { - return SizedBox(); - } - return Center( - child: Padding( - padding: const EdgeInsets.all(8.0), - child: CircularProgressIndicator(), + Widget _buildLoadingIndicator( + StreamChannelState streamChannel, + QueryDirection direction, + ) { + final stream = direction == QueryDirection.top + ? streamChannel.queryTopMessages + : streamChannel.queryBottomMessages; + return StreamBuilder( + key: Key('LOADING-INDICATOR'), + stream: stream, + initialData: false, + builder: (context, snapshot) { + if (snapshot.hasError) { + return Container( + color: Color(0xffd0021B).withAlpha(26), + child: Center( + child: Text('Error loading messages'), ), ); - }), - ); + } + if (!snapshot.data) { + if (direction == QueryDirection.top) { + return Container( + height: 50, + width: double.infinity, + ); + } + return Offstage(); + } + return Center( + child: Padding( + padding: const EdgeInsets.all(8.0), + child: const CupertinoActivityIndicator(), + ), + ); + }); } Widget _buildTopMessage( @@ -544,9 +647,7 @@ class _MessageListViewState extends State { _bottomWasVisible = !isVisible; } if (mounted) { - setState(() { - _showScrollToBottom = !isVisible; - }); + setState(() => _showScrollToBottom = !isVisible); } }, child: messageWidget, @@ -602,7 +703,7 @@ class _MessageListViewState extends State { final userId = StreamChat.of(context).user.id; final isMyMessage = message.user.id == userId; final isNextUser = - index - 1 >= 0 && message.user.id == messages[index - 1]?.user?.id; + index - 2 >= 0 && message.user.id == messages[index - 2]?.user?.id; final channel = StreamChannel.of(context).channel; final readList = channel.state?.read @@ -673,24 +774,12 @@ class _MessageListViewState extends State { _messageNewListener = streamChannel.channel.on(EventType.messageNew).listen((event) { - final firstElementInViewport = - _itemPositionListener.itemPositions.value.first; if (event.message.user.id == streamChannel.channel.client.state.user.id) { WidgetsBinding.instance.addPostFrameCallback((_) { _scrollController.jumpTo( index: 0, ); }); - } else { - if (firstElementInViewport.index != 0) { - _scrollController.jumpTo( - index: firstElementInViewport.index + 1, - alignment: firstElementInViewport.itemLeadingEdge, - ); - } - } - if (firstElementInViewport.index == 0) { - streamChannel.channel.markRead(); } }); diff --git a/lib/src/stream_channel.dart b/lib/src/stream_channel.dart index 5dbfd103..0ca87b96 100644 --- a/lib/src/stream_channel.dart +++ b/lib/src/stream_channel.dart @@ -10,19 +10,23 @@ enum QueryDirection { top, bottom } /// /// Use [StreamChannel.of] to get the current [StreamChannelState] instance. class StreamChannel extends StatefulWidget { - StreamChannel({ + const StreamChannel({ Key key, @required this.child, @required this.channel, this.showLoading = true, - }) : super( - key: key, - ); + this.initialMessageId, + }) : assert(child != null), + assert(channel != null), + super(key: key); final Widget child; final Channel channel; final bool showLoading; + /// If passed the channel will load from this particular message. + final String initialMessageId; + /// Use this method to get the current [StreamChannelState] instance static StreamChannelState of(BuildContext context) { StreamChannelState streamChannelState; @@ -45,135 +49,123 @@ class StreamChannelState extends State { /// Current channel Channel get channel => widget.channel; + /// InitialMessageId + String get initialMessageId => widget.initialMessageId; + /// Current channel state stream Stream get channelStateStream => widget.channel.state.channelStateStream; - final BehaviorSubject _queryMessageController = BehaviorSubject(); + final _queryTopMessagesController = BehaviorSubject.seeded(false); + final _queryBottomMessagesController = BehaviorSubject.seeded(false); - /// The stream notifying the state of queryMessage call - Stream get queryMessage => _queryMessageController.stream; + /// The stream notifying the state of [_queryTopMessages] call + Stream get queryTopMessages => _queryTopMessagesController.stream; + + /// The stream notifying the state of [_queryBottomMessages] call + Stream get queryBottomMessages => _queryBottomMessagesController.stream; bool _topPaginationEnded = false; bool _bottomPaginationEnded = false; - /// Calls [channel.query] updating [queryMessage] stream - void queryMessages({QueryDirection direction = QueryDirection.top}) { - if (_queryMessageController.value == true || - (_topPaginationEnded && _bottomPaginationEnded)) { + Future _queryTopMessages({ + int limit = 20, + bool preferOffline = false, + }) async { + if (_topPaginationEnded || _queryTopMessagesController?.value == true) { return; } + _queryTopMessagesController.add(true); - _queryMessageController.add(true); - - String id; - PaginationParams params; - - final messageLimit = 25; - - if (channel.state.messages.isNotEmpty) { - switch (direction) { - case QueryDirection.top: - id = channel.state.messages.first.id; - params = PaginationParams( - lessThan: id, - limit: messageLimit, - ); - break; - case QueryDirection.bottom: - id = channel.state.messages.last.id; - params = PaginationParams( - greaterThan: id, - limit: messageLimit, - ); - break; - } + if (channel.state.messages.isEmpty) { + return _queryTopMessagesController.add(false); } - widget.channel - .query( - messagesPagination: params, - preferOffline: true, - ) - .then((res) { - if (res.messages.isEmpty || res.messages.length < messageLimit) { - switch (direction) { - case QueryDirection.top: - _topPaginationEnded = true; - break; - case QueryDirection.bottom: - _bottomPaginationEnded = true; - break; - } + final oldestMessage = channel.state.messages.first; + + try { + final state = await queryBeforeMessage( + oldestMessage.id, + limit: limit, + preferOffline: preferOffline, + ); + if (state.messages.isEmpty || state.messages.length < limit) { + _topPaginationEnded = true; } - _queryMessageController.add(false); - }).catchError((e, stack) { - if (!_queryMessageController.isClosed) { - _queryMessageController.addError(e, stack); + _queryTopMessagesController.add(false); + } catch (e, stk) { + _queryTopMessagesController.addError(e, stk); + } + } + + Future _queryBottomMessages({ + int limit = 20, + bool preferOffline = false, + }) async { + if (_bottomPaginationEnded || + _queryBottomMessagesController?.value == true || + channel?.state?.isUpToDate == true) return; + _queryBottomMessagesController.add(true); + + if (channel.state.messages.isEmpty) { + return _queryBottomMessagesController.add(false); + } + + final recentMessage = channel.state.messages.last; + + try { + final state = await queryAfterMessage( + recentMessage.id, + limit: limit, + preferOffline: preferOffline, + ); + if (state.messages.isEmpty || state.messages.length < limit) { + _bottomPaginationEnded = true; } - }); + _queryBottomMessagesController.add(false); + } catch (e, stk) { + _queryBottomMessagesController.addError(e, stk); + } + } + + /// Calls [channel.query] updating [queryMessage] stream + Future queryMessages({QueryDirection direction = QueryDirection.top}) { + if (direction == QueryDirection.top) return _queryTopMessages(); + return _queryBottomMessages(); } /// Calls [channel.getReplies] updating [queryMessage] stream Future getReplies( String parentId, { - QueryDirection direction = QueryDirection.top, + int limit = 50, + bool preferOffline = false, }) async { - if (_queryMessageController.value == true || - (_topPaginationEnded && _bottomPaginationEnded)) { - return; + if (_topPaginationEnded || _queryTopMessagesController.value) return; + _queryTopMessagesController.add(true); + + if (!channel.state.threads.containsKey(parentId)) { + return _queryTopMessagesController.add(false); } - _queryMessageController.add(true); + final thread = channel.state.threads[parentId]; - String id; - PaginationParams params; + if (thread.isEmpty) return _queryTopMessagesController.add(false); - final messageLimit = 50; + final message = thread.first; - if (widget.channel.state.threads.containsKey(parentId)) { - final thread = widget.channel.state.threads[parentId]; - if (thread != null && thread.isNotEmpty) { - switch (direction) { - case QueryDirection.top: - id = thread?.first?.id; - params = PaginationParams( - lessThan: id, - limit: messageLimit, - ); - break; - case QueryDirection.bottom: - id = thread?.last?.id; - params = PaginationParams( - greaterThan: id, - limit: messageLimit, - ); - break; - } + try { + final state = await queryBeforeMessage( + message.id, + limit: limit, + preferOffline: preferOffline, + ); + if (state.messages.isEmpty || state.messages.length < limit) { + _topPaginationEnded = true; } + _queryTopMessagesController.add(false); + } catch (e, stk) { + _queryTopMessagesController.addError(e, stk); } - - return widget.channel - .getReplies( - parentId, - params, - preferOffline: true, - ) - .then((res) { - if (res.messages.isEmpty || res.messages.length < messageLimit) { - switch (direction) { - case QueryDirection.top: - _topPaginationEnded = true; - break; - case QueryDirection.bottom: - _bottomPaginationEnded = true; - break; - } - } - _queryMessageController.add(false); - }).catchError((e, stack) { - _queryMessageController.addError(e, stack); - }); } /// Query the channel members and watchers @@ -190,41 +182,148 @@ class StreamChannelState extends State { ); } + /// Loads channel at specific message + Future loadChannelAtMessage( + String messageId, { + int before = 20, + int after = 20, + bool preferOffline = false, + }) { + return queryAtMessage( + messageId: messageId, + before: before, + after: after, + preferOffline: preferOffline, + ); + } + + /// + Future queryAtMessage({ + String messageId, + int before = 20, + int after = 20, + bool preferOffline = false, + }) async { + if (channel.state == null) return; + channel.state.isUpToDate = false; + channel.state.truncate(); + + if (messageId == null) { + await channel.query( + messagesPagination: PaginationParams( + limit: before, + ), + preferOffline: preferOffline, + ); + channel.state.isUpToDate = true; + return; + } + + return Future.wait([ + queryBeforeMessage( + messageId, + limit: before, + preferOffline: preferOffline, + ), + queryAfterMessage( + messageId, + limit: after, + preferOffline: preferOffline, + ), + ]); + } + + /// + Future queryBeforeMessage( + String messageId, { + int limit = 20, + bool preferOffline = false, + }) { + return channel.query( + messagesPagination: PaginationParams( + lessThan: messageId, + limit: limit, + ), + preferOffline: preferOffline, + ); + } + + /// + Future queryAfterMessage( + String messageId, { + int limit = 20, + bool preferOffline = false, + }) async { + final state = await channel.query( + messagesPagination: PaginationParams( + greaterThanOrEqual: messageId, + limit: limit, + ), + preferOffline: preferOffline, + ); + if (state.messages.isEmpty || state.messages.length < limit) { + channel.state.isUpToDate = true; + } + return state; + } + + /// Reloads the channel with latest message + Future reloadChannel() => queryAtMessage(before: 30); + + List> _futures; + + Future get _loadChannelAtMessage async { + try { + await loadChannelAtMessage(initialMessageId); + return true; + } catch (e, stk) { + print('Error: $e\nStack: $stk'); + rethrow; + } + } + + @override + void initState() { + super.initState(); + _futures = [widget.channel.initialized]; + if (initialMessageId != null) { + _futures.add(_loadChannelAtMessage); + } + } + @override void dispose() { - _queryMessageController.close(); + _queryTopMessagesController.close(); + _queryBottomMessagesController.close(); super.dispose(); } @override Widget build(BuildContext context) { - if (widget.channel == null) { - return Center( - child: CircularProgressIndicator(), - ); - } - return FutureBuilder( - future: widget.channel.initialized, - initialData: widget.channel.state != null, + Widget child = FutureBuilder>( + future: Future.wait(_futures), + initialData: [ + channel.state != null, + if (initialMessageId != null) false, + ], builder: (context, snapshot) { - if (widget.showLoading && (!snapshot.hasData || !snapshot.data)) { - return Container( - height: 30, - child: Center( - child: CircularProgressIndicator(), - ), + final initialized = snapshot.data[0]; + final dataLoaded = initialMessageId == null ? true : snapshot.data[1]; + if (widget.showLoading && (!initialized || !dataLoaded)) { + return Center( + child: CircularProgressIndicator(), ); } else if (snapshot.hasError) { - return Container( - height: 30, - child: Center( - child: Text(snapshot.error), - ), + return Center( + child: Text(snapshot.error), ); - } else { - return widget.child; } + return widget.child; }, ); + if (initialMessageId != null) { + child = Material(child: child); + } + return child; } } diff --git a/lib/src/user_list_view.dart b/lib/src/user_list_view.dart index b57e2d55..928ea39e 100644 --- a/lib/src/user_list_view.dart +++ b/lib/src/user_list_view.dart @@ -339,7 +339,9 @@ class _UserListViewState extends State ); return LazyLoadScrollView( - onEndOfPage: () => _listenUserPagination(usersBlocState), + onEndOfPage: () async { + return _listenUserPagination(usersBlocState); + }, child: child, ); }, diff --git a/pubspec.yaml b/pubspec.yaml index a226f9c3..55f2bc65 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -29,9 +29,10 @@ dependencies: image_picker: ^0.6.7+2 flutter_keyboard_visibility: ^3.3.0 stream_chat: - git: - url: https://github.com/GetStream/stream-chat-dart - ref: two-way-pagination + path: ../stream-chat-dart +# git: +# url: https://github.com/GetStream/stream-chat-dart +# ref: two-way-pagination mime: ^0.9.6+3 video_compress: ^2.1.1 visibility_detector: ^0.1.5 From 3f300bdfa020c7900cd06e771819a590e4c87afb Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Wed, 16 Dec 2020 16:57:43 +0530 Subject: [PATCH 0624/1140] ref git url in pubspec Signed-off-by: Sahil Kumar --- pubspec.yaml | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/pubspec.yaml b/pubspec.yaml index 55f2bc65..a226f9c3 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -29,10 +29,9 @@ dependencies: image_picker: ^0.6.7+2 flutter_keyboard_visibility: ^3.3.0 stream_chat: - path: ../stream-chat-dart -# git: -# url: https://github.com/GetStream/stream-chat-dart -# ref: two-way-pagination + git: + url: https://github.com/GetStream/stream-chat-dart + ref: two-way-pagination mime: ^0.9.6+3 video_compress: ^2.1.1 visibility_detector: ^0.1.5 From 8b4ff142bab22c8f214a16a22a03c8de318f4fed Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Wed, 16 Dec 2020 17:06:09 +0530 Subject: [PATCH 0625/1140] Merge conflicts Signed-off-by: Sahil Kumar --- lib/src/message_input.dart | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 447d49d9..dd7d90ca 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -21,7 +21,6 @@ import 'package:stream_chat_flutter/src/stream_svg_icon.dart'; import 'package:stream_chat_flutter/src/user_avatar.dart'; import 'package:substring_highlight/substring_highlight.dart'; import 'package:video_compress/video_compress.dart'; -import 'package:photo_manager/photo_manager.dart'; import '../stream_chat_flutter.dart'; import 'stream_channel.dart'; @@ -462,6 +461,7 @@ class MessageInputState extends State { } Timer _debounce; + void _onChanged(BuildContext context, String s) { if (_debounce?.isActive == true) _debounce.cancel(); _debounce = Timer( @@ -1956,7 +1956,11 @@ class MessageInputState extends State { message = await widget.preMessageSending(message); } - final channel = StreamChannel.of(context).channel; + final streamChannel = StreamChannel.of(context); + final channel = streamChannel.channel; + if (!channel.state.isUpToDate) { + await streamChannel.reloadChannel(); + } if (widget.editMessage == null || widget.editMessage.status == MessageSendingStatus.FAILED) { @@ -2043,6 +2047,7 @@ class MessageInputState extends State { } bool _initialized = false; + @override void didChangeDependencies() { if (widget.editMessage != null && !_initialized) { From 12105a3120017dc02c7758d93e12e3b3be993fff Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Wed, 16 Dec 2020 19:03:03 +0530 Subject: [PATCH 0626/1140] Merge fixes Signed-off-by: Sahil Kumar --- example/lib/new_chat_screen.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/example/lib/new_chat_screen.dart b/example/lib/new_chat_screen.dart index a2ce9ebf..54371c3b 100644 --- a/example/lib/new_chat_screen.dart +++ b/example/lib/new_chat_screen.dart @@ -358,7 +358,7 @@ class _NewChatScreenState extends State { context, Routes.CHANNEL_PAGE, ModalRoute.withName(Routes.HOME), - arguments: channel, + arguments: ChannelPageArgs(channel: channel), ); }, ), From c81111a1e20959529faadbd8c247b86824aa802d Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Wed, 16 Dec 2020 15:42:49 +0100 Subject: [PATCH 0627/1140] fix online status in new chat page --- lib/src/user_item.dart | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/src/user_item.dart b/lib/src/user_item.dart index f12e3e61..4c1af658 100644 --- a/lib/src/user_item.dart +++ b/lib/src/user_item.dart @@ -90,6 +90,8 @@ class UserItem extends StatelessWidget { } Widget _buildLastActive(context) { - return Text('Last online ${Jiffy(user.lastActive).fromNow()}'); + return user.online == true + ? Text('Online') + : Text('Last online ${Jiffy(user.lastActive).fromNow()}'); } } From 336580761510f39d472a67e27f7576f20d4ed44e Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Wed, 16 Dec 2020 15:45:07 +0100 Subject: [PATCH 0628/1140] fix unread count indicator --- lib/src/message_list_view.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/message_list_view.dart b/lib/src/message_list_view.dart index 12adaf3e..4f40feb1 100644 --- a/lib/src/message_list_view.dart +++ b/lib/src/message_list_view.dart @@ -529,7 +529,7 @@ class _MessageListViewState extends State { child: Padding( padding: const EdgeInsets.all(3.0), child: Text( - snapshot.data.toString(), + '$unreadCount', style: TextStyle( fontSize: 11, fontWeight: FontWeight.bold, From 4a165249a1918621cb07a8c394b35c80d638d80b Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Wed, 16 Dec 2020 15:47:35 +0100 Subject: [PATCH 0629/1140] revert api key --- example/lib/choose_user_page.dart | 2 +- example/pubspec.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/example/lib/choose_user_page.dart b/example/lib/choose_user_page.dart index 73b12425..dde87376 100644 --- a/example/lib/choose_user_page.dart +++ b/example/lib/choose_user_page.dart @@ -13,7 +13,7 @@ import 'routes/routes.dart'; const kStreamApiKey = 'STREAM_API_KEY'; const kStreamUserId = 'STREAM_USER_ID'; const kStreamToken = 'STREAM_TOKEN'; -const kDefaultStreamApiKey = 's2dxdhpxd94g'; +const kDefaultStreamApiKey = 'uj7qrdbfrzvg'; class ChooseUserPage extends StatelessWidget { @override diff --git a/example/pubspec.yaml b/example/pubspec.yaml index f9c71355..ef06f719 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -1,6 +1,6 @@ name: example description: A new Flutter project. -version: 1.0.91+94 +version: 1.0.92+95 environment: sdk: ">=2.2.2 <3.0.0" From 7fd98111d23dd14625bb52ad7301e3a7413212bd Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Wed, 16 Dec 2020 16:00:29 +0100 Subject: [PATCH 0630/1140] revert api key --- example/lib/choose_user_page.dart | 2 +- example/pubspec.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/example/lib/choose_user_page.dart b/example/lib/choose_user_page.dart index dde87376..a64013b9 100644 --- a/example/lib/choose_user_page.dart +++ b/example/lib/choose_user_page.dart @@ -19,7 +19,7 @@ class ChooseUserPage extends StatelessWidget { @override Widget build(BuildContext context) { final users = { - 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoidmlzaGFsIn0._JHWzo92fpTWZMZriJHXqOng6ShYVmWrdaIaPwEPKBg': + 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoidmlzaGFsIn0.lCz-idDgaZ-xszjnuB_hTfeIOhTFmJtTB2fEjhwrcCI': User( id: 'vishal', extraData: { diff --git a/example/pubspec.yaml b/example/pubspec.yaml index ef06f719..cec1b886 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -1,6 +1,6 @@ name: example description: A new Flutter project. -version: 1.0.92+95 +version: 1.0.93+96 environment: sdk: ">=2.2.2 <3.0.0" From e17a3c30b790ee493430a51527ed43de528de88a Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Thu, 17 Dec 2020 14:42:46 +0530 Subject: [PATCH 0631/1140] [LazyLoadScrollView] Fix callback logic Signed-off-by: Sahil Kumar --- lib/src/lazy_load_scroll_view.dart | 89 ++++++++++++++++-------------- lib/src/message_list_view.dart | 11 ++-- 2 files changed, 54 insertions(+), 46 deletions(-) diff --git a/lib/src/lazy_load_scroll_view.dart b/lib/src/lazy_load_scroll_view.dart index a3c344aa..99eeb861 100644 --- a/lib/src/lazy_load_scroll_view.dart +++ b/lib/src/lazy_load_scroll_view.dart @@ -15,7 +15,7 @@ class LazyLoadScrollView extends StatefulWidget { /// Called when the [child] reaches the end of the list final AsyncCallback onEndOfPage; - /// The offset to take into account when triggering [onEndOfPage] in pixels + /// The offset to take into account when triggering [onEndOfPage]/[onStartOfPage] in pixels final double scrollOffset; /// Used to determine if loading of new data has finished. You should use set this if you aren't using a FutureBuilder or StreamBuilder @@ -38,6 +38,7 @@ class LazyLoadScrollView extends StatefulWidget { class _LazyLoadScrollViewState extends State { _LoadingStatus _loadMoreStatus = _LoadingStatus.STABLE; + double _scrollPosition = 0.0; @override Widget build(BuildContext context) { @@ -49,59 +50,65 @@ class _LazyLoadScrollViewState extends State { bool _onNotification(Notification notification) { if (notification is ScrollUpdateNotification) { - if (notification.metrics.maxScrollExtent > notification.metrics.pixels && - notification.metrics.maxScrollExtent - notification.metrics.pixels <= - widget.scrollOffset) { - if (_loadMoreStatus != null && - _loadMoreStatus == _LoadingStatus.STABLE) { - _loadMoreStatus = _LoadingStatus.LOADING; - if (widget.onEndOfPage != null) { - widget.onEndOfPage().whenComplete(() { - _loadMoreStatus = _LoadingStatus.STABLE; - }); - } + final pixels = notification.metrics.pixels; + final extentBefore = notification.metrics.extentBefore; + final extentAfter = notification.metrics.extentAfter; + final scrollOffset = widget.scrollOffset; + + final scrollingDown = _scrollPosition < pixels; + + if (scrollOffset == null || scrollOffset == 0) { + if (extentAfter == 0) { + _onEndOfPage(); + } + if (extentBefore == 0) { + _onStartOfPage(); } - } - if (notification.metrics.minScrollExtent < notification.metrics.pixels && - notification.metrics.pixels - notification.metrics.minScrollExtent <= - widget.scrollOffset) { - if (_loadMoreStatus != null && - _loadMoreStatus == _LoadingStatus.STABLE) { - _loadMoreStatus = _LoadingStatus.LOADING; - if (widget.onStartOfPage != null) { - widget.onStartOfPage().whenComplete(() { - _loadMoreStatus = _LoadingStatus.STABLE; - }); + } else { + if (scrollingDown) { + if (extentAfter <= scrollOffset) { + _onEndOfPage(); + } + } else { + if (extentBefore <= scrollOffset) { + _onStartOfPage(); } } } + _scrollPosition = pixels; return true; } if (notification is OverscrollNotification) { if (notification.overscroll > 0) { - if (_loadMoreStatus != null && - _loadMoreStatus == _LoadingStatus.STABLE) { - _loadMoreStatus = _LoadingStatus.LOADING; - if (widget.onEndOfPage != null) { - widget.onEndOfPage().whenComplete(() { - _loadMoreStatus = _LoadingStatus.STABLE; - }); - } - } + _onEndOfPage(); } if (notification.overscroll < 0) { - if (_loadMoreStatus != null && - _loadMoreStatus == _LoadingStatus.STABLE) { - _loadMoreStatus = _LoadingStatus.LOADING; - if (widget.onStartOfPage != null) { - widget.onStartOfPage().whenComplete(() { - _loadMoreStatus = _LoadingStatus.STABLE; - }); - } - } + _onStartOfPage(); } return true; } return false; } + + void _onEndOfPage() { + if (_loadMoreStatus != null && _loadMoreStatus == _LoadingStatus.STABLE) { + _loadMoreStatus = _LoadingStatus.LOADING; + if (widget.onEndOfPage != null) { + widget.onEndOfPage().whenComplete(() { + _loadMoreStatus = _LoadingStatus.STABLE; + }); + } + } + } + + void _onStartOfPage() { + if (_loadMoreStatus != null && _loadMoreStatus == _LoadingStatus.STABLE) { + _loadMoreStatus = _LoadingStatus.LOADING; + if (widget.onStartOfPage != null) { + widget.onStartOfPage().whenComplete(() { + _loadMoreStatus = _LoadingStatus.STABLE; + }); + } + } + } } diff --git a/lib/src/message_list_view.dart b/lib/src/message_list_view.dart index 4f40feb1..d8a9d416 100644 --- a/lib/src/message_list_view.dart +++ b/lib/src/message_list_view.dart @@ -294,13 +294,13 @@ class _MessageListViewState extends State { if (!_upToDate) { _topPaginationActive = false; _bottomPaginationActive = true; - _paginateData(streamChannel, QueryDirection.bottom); + return _paginateData(streamChannel, QueryDirection.bottom); } }, onEndOfPage: () async { _topPaginationActive = true; _bottomPaginationActive = false; - _paginateData(streamChannel, QueryDirection.top); + return _paginateData(streamChannel, QueryDirection.top); }, child: ScrollablePositionedList.builder( key: ValueKey(initialIndex + initialAlignment), @@ -453,11 +453,12 @@ class _MessageListViewState extends State { }); } - void _paginateData(StreamChannelState channel, QueryDirection direction) { + Future _paginateData( + StreamChannelState channel, QueryDirection direction) { if (widget.parentMessage == null) { - channel.queryMessages(direction: direction); + return channel.queryMessages(direction: direction); } else { - channel.getReplies(widget.parentMessage.id); + return channel.getReplies(widget.parentMessage.id); } } From 84aa3fbb87df9acb858fa52aabbddcbfc5b84d2d Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Thu, 17 Dec 2020 17:10:45 +0530 Subject: [PATCH 0632/1140] Use localChannel if present instead of creating a new Signed-off-by: Sahil Kumar --- example/lib/main.dart | 7 +- lib/src/message_list_view.dart | 396 +++++++++++++++++---------------- lib/src/stream_channel.dart | 21 +- 3 files changed, 225 insertions(+), 199 deletions(-) diff --git a/example/lib/main.dart b/example/lib/main.dart index ca7006b0..1c61dde2 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -335,10 +335,11 @@ class _ChannelListPageState extends State { onItemTap: (messageResponse) async { final client = StreamChat.of(context).client; final message = messageResponse.message; - final channel = Channel.fromState( - client, - ChannelState(channel: messageResponse.channel), + final channel = client.channel( + messageResponse.channel.type, + id: messageResponse.channel.id, ); + await channel.watch(); Navigator.pushNamed( context, Routes.CHANNEL_PAGE, diff --git a/lib/src/message_list_view.dart b/lib/src/message_list_view.dart index d8a9d416..ca184d6b 100644 --- a/lib/src/message_list_view.dart +++ b/lib/src/message_list_view.dart @@ -183,7 +183,7 @@ class _MessageListViewState extends State { final messageIndex = messages.indexWhere((e) { return e.id == streamChannel.initialMessageId; }); - return totalMessages - messageIndex - 1; + return totalMessages - messageIndex; } return 0; } @@ -234,223 +234,235 @@ class _MessageListViewState extends State { initialAlignment = _initialAlignment; } - return StreamBuilder>( - stream: messagesStream?.map((messages) => messages - ?.where((e) => - !e.isDeleted || - (e.isDeleted && - e.user.id == streamChannel.channel.client.state.user.id)) - ?.toList()), - builder: (context, snapshot) { - if (!snapshot.hasData) { - return Center( - child: CircularProgressIndicator(), - ); - } - - final messageList = snapshot.data?.reversed?.toList() ?? []; - - if (messageList.isEmpty) { - if (_upToDate) { + return WillPopScope( + onWillPop: () async { + if (!_upToDate) { + await streamChannel.reloadChannel(); + } + return true; + }, + child: StreamBuilder>( + stream: messagesStream?.map((messages) => messages + ?.where((e) => + !e.isDeleted || + (e.isDeleted && + e.user.id == streamChannel.channel.client.state.user.id)) + ?.toList()), + builder: (context, snapshot) { + if (!snapshot.hasData) { return Center( - child: Text( - 'No chats here yet...', - style: TextStyle( - fontSize: 12, - color: Colors.black.withOpacity(.5), - ), - ), + child: CircularProgressIndicator(), ); } - } else { - messages = messageList; - } - final newMessagesListLength = messages.length; + final messageList = snapshot.data?.reversed?.toList() ?? []; - if (_bottomPaginationActive) { - if (_itemPositionListener.itemPositions.value?.isNotEmpty == true && - _messageListLength != null) { - final first = _itemPositionListener.itemPositions.value.first; - final diff = newMessagesListLength - _messageListLength; - if (diff > 0) { - initialIndex = first.index + diff; - initialAlignment = first.itemLeadingEdge; + if (messageList.isEmpty) { + if (_upToDate) { + return Center( + child: Text( + 'No chats here yet...', + style: TextStyle( + fontSize: 12, + color: Colors.black.withOpacity(.5), + ), + ), + ); } + } else { + messages = messageList; } - } else if (!_topPaginationActive && _upToDate) { - // Reset the index in-case we send any new message - initialIndex = 0; - initialAlignment = 0; - } - _messageListLength = newMessagesListLength; + final newMessagesListLength = messages.length; - return Stack( - alignment: Alignment.center, - children: [ - LazyLoadScrollView( - onStartOfPage: () async { - if (!_upToDate) { - _topPaginationActive = false; - _bottomPaginationActive = true; - return _paginateData(streamChannel, QueryDirection.bottom); - } - }, - onEndOfPage: () async { - _topPaginationActive = true; - _bottomPaginationActive = false; - return _paginateData(streamChannel, QueryDirection.top); - }, - child: ScrollablePositionedList.builder( - key: ValueKey(initialIndex + initialAlignment), - itemPositionsListener: _itemPositionListener, - addAutomaticKeepAlives: true, - initialScrollIndex: initialIndex ?? 0, - initialAlignment: initialAlignment ?? 0, - physics: widget.scrollPhysics, - itemScrollController: _scrollController, - reverse: true, - itemCount: messages.length + - 2 + - (widget.parentMessage != null ? 1 : 0), - itemBuilder: (context, i) { - if (i == messages.length + 2) { - if (widget.parentMessageBuilder != null) { - return widget.parentMessageBuilder( + if (_bottomPaginationActive) { + if (_itemPositionListener.itemPositions.value?.isNotEmpty == + true && + _messageListLength != null) { + final first = _itemPositionListener.itemPositions.value.first; + final diff = newMessagesListLength - _messageListLength; + if (diff > 0) { + initialIndex = first.index + diff; + initialAlignment = first.itemLeadingEdge; + } + } + } else if (!_topPaginationActive && _upToDate) { + // Reset the index in-case we send any new message + initialIndex = 0; + initialAlignment = 0; + } + + _messageListLength = newMessagesListLength; + + return Stack( + alignment: Alignment.center, + children: [ + LazyLoadScrollView( + onStartOfPage: () async { + if (!_upToDate) { + _topPaginationActive = false; + _bottomPaginationActive = true; + return _paginateData( + streamChannel, QueryDirection.bottom); + } + }, + onEndOfPage: () async { + _topPaginationActive = true; + _bottomPaginationActive = false; + return _paginateData(streamChannel, QueryDirection.top); + }, + child: ScrollablePositionedList.builder( + key: ValueKey(initialIndex + initialAlignment), + itemPositionsListener: _itemPositionListener, + addAutomaticKeepAlives: true, + initialScrollIndex: initialIndex ?? 0, + initialAlignment: initialAlignment ?? 0, + physics: widget.scrollPhysics, + itemScrollController: _scrollController, + reverse: true, + itemCount: messages.length + + 2 + + (widget.parentMessage != null ? 1 : 0), + itemBuilder: (context, i) { + if (i == messages.length + 2) { + if (widget.parentMessageBuilder != null) { + return widget.parentMessageBuilder( + context, + widget.parentMessage, + ); + } else { + return Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + buildParentMessage(widget.parentMessage), + Padding( + padding: + const EdgeInsets.symmetric(horizontal: 32), + child: Container( + padding: const EdgeInsets.all(8), + child: Text( + 'Start of thread', + textAlign: TextAlign.center, + ), + color: Theme.of(context) + .accentColor + .withAlpha(50), + ), + ), + ], + ); + } + } + if (i == messages.length + 1) { + return _buildLoadingIndicator( + streamChannel, + QueryDirection.top, + ); + } + if (i == 0) { + return _buildLoadingIndicator( + streamChannel, + QueryDirection.bottom, + ); + } + final message = messages[i - 1]; + final nextMessage = (i - 1) > 0 ? messages[i - 2] : null; + + Widget messageWidget; + + if (i == 1) { + messageWidget = _buildBottomMessage( context, - widget.parentMessage, + message, + messages, + streamChannel, + ); + } else if (i == messages.length - 1) { + messageWidget = _buildTopMessage( + context, + message, + messages, + streamChannel, ); } else { + if (widget.messageBuilder != null) { + messageWidget = Builder( + key: ValueKey('MESSAGE-${message.id}'), + builder: (_) => widget.messageBuilder( + context, + MessageDetails( + context, + message, + messages, + i, + ), + messages), + ); + } else { + messageWidget = buildMessage(message, messages, i); + } + } + + if (nextMessage != null && + !Jiffy(message.createdAt.toLocal()).isSame( + nextMessage.createdAt.toLocal(), Units.DAY)) { return Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ - buildParentMessage(widget.parentMessage), + messageWidget, Padding( padding: - const EdgeInsets.symmetric(horizontal: 32), - child: Container( - padding: const EdgeInsets.all(8), - child: Text( - 'Start of thread', - textAlign: TextAlign.center, - ), - color: - Theme.of(context).accentColor.withAlpha(50), - ), + const EdgeInsets.symmetric(vertical: 12.0), + child: widget.dateDividerBuilder != null + ? widget.dateDividerBuilder( + nextMessage.createdAt.toLocal()) + : DateDivider( + dateTime: nextMessage.createdAt.toLocal(), + ), ), ], ); } - } - if (i == messages.length + 1) { - return _buildLoadingIndicator( - streamChannel, - QueryDirection.top, - ); - } - if (i == 0) { - return _buildLoadingIndicator( - streamChannel, - QueryDirection.bottom, - ); - } - final message = messages[i - 1]; - final nextMessage = (i - 1) > 0 ? messages[i - 2] : null; - Widget messageWidget; - - if (i == 1) { - messageWidget = _buildBottomMessage( - context, - message, - messages, - streamChannel, - ); - } else if (i == messages.length - 1) { - messageWidget = _buildTopMessage( - context, - message, - messages, - streamChannel, - ); - } else { - if (widget.messageBuilder != null) { - messageWidget = Builder( - key: ValueKey('MESSAGE-${message.id}'), - builder: (_) => widget.messageBuilder( - context, - MessageDetails( - context, - message, - messages, - i, - ), - messages), - ); - } else { - messageWidget = buildMessage(message, messages, i); + return messageWidget; + }, + ), + ), + if (widget.showScrollToBottom) _buildScrollToBottom(), + Positioned( + top: 20.0, + child: ValueListenableBuilder>( + valueListenable: _itemPositionListener.itemPositions, + builder: (context, values, _) { + final items = _itemPositionListener.itemPositions?.value; + if (items.isEmpty || messages.isEmpty) { + return SizedBox(); } - } - 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(), - ), - ), - ], - ); - } + var index = _getTopElement(values).index; - return messageWidget; - }, + if (index > messages.length) { + return SizedBox(); + } + + if (index == messages.length) { + index = max(index - 1, 0); + } + + return widget.dateDividerBuilder != null + ? widget.dateDividerBuilder( + messages[index].createdAt.toLocal(), + ) + : DateDivider( + dateTime: messages[index].createdAt.toLocal(), + ); + }, + ), ), - ), - if (widget.showScrollToBottom) _buildScrollToBottom(), - Positioned( - top: 20.0, - child: ValueListenableBuilder>( - valueListenable: _itemPositionListener.itemPositions, - builder: (context, values, _) { - final items = _itemPositionListener.itemPositions?.value; - if (items.isEmpty || messages.isEmpty) { - return SizedBox(); - } - - var index = _getTopElement(values).index; - - if (index > messages.length) { - return SizedBox(); - } - - if (index == messages.length) { - index = max(index - 1, 0); - } - - return widget.dateDividerBuilder != null - ? widget.dateDividerBuilder( - messages[index].createdAt.toLocal(), - ) - : DateDivider( - dateTime: messages[index].createdAt.toLocal(), - ); - }, - ), - ), - ], - ); - }); + ], + ); + }), + ); } Future _paginateData( diff --git a/lib/src/stream_channel.dart b/lib/src/stream_channel.dart index 0ca87b96..001d98ff 100644 --- a/lib/src/stream_channel.dart +++ b/lib/src/stream_channel.dart @@ -307,16 +307,29 @@ class StreamChannelState extends State { if (initialMessageId != null) false, ], builder: (context, snapshot) { + if (snapshot.hasError) { + if (snapshot.error is Error) { + print((snapshot.error as Error).stackTrace); + } + var message = snapshot.error.toString(); + if (snapshot.error is DioError) { + final dioError = snapshot.error as DioError; + if (dioError.type == DioErrorType.RESPONSE) { + message = dioError.message; + } else { + message = 'Check your connection and retry'; + } + } + return Center( + child: Text(message), + ); + } final initialized = snapshot.data[0]; final dataLoaded = initialMessageId == null ? true : snapshot.data[1]; if (widget.showLoading && (!initialized || !dataLoaded)) { return Center( child: CircularProgressIndicator(), ); - } else if (snapshot.hasError) { - return Center( - child: Text(snapshot.error), - ); } return widget.child; }, From 7c24e7b202d00d6b7c74b8d2f05f61f22decfa5d Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Thu, 17 Dec 2020 19:42:07 +0530 Subject: [PATCH 0633/1140] feat: Added file and image screens, group info details --- lib/src/channel_file_display_screen.dart | 136 +++++++++++++++++++- lib/src/channel_media_display_screen.dart | 147 +++++++++++++++++++++- lib/src/chat_info_screen.dart | 46 ++++++- lib/src/group_info_screen.dart | 46 ++++++- lib/src/message_search_bloc.dart | 2 + pubspec.yaml | 2 +- 6 files changed, 364 insertions(+), 15 deletions(-) diff --git a/lib/src/channel_file_display_screen.dart b/lib/src/channel_file_display_screen.dart index d34a4b87..361aa808 100644 --- a/lib/src/channel_file_display_screen.dart +++ b/lib/src/channel_file_display_screen.dart @@ -1,7 +1,52 @@ +import 'package:cached_network_image/cached_network_image.dart'; import 'package:flutter/material.dart'; +import 'package:stream_chat_flutter/src/lazy_load_scroll_view.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; -class ChannelFileDisplayScreen extends StatelessWidget { +class ChannelFileDisplayScreen extends StatefulWidget { + /// The sorting used for the channels matching the filters. + /// Sorting is based on field and direction, multiple sorting options can be provided. + /// You can sort based on last_updated, last_message_at, updated_at, created_at or member_count. + /// Direction can be ascending or descending. + final List sortOptions; + + /// Pagination parameters + /// limit: the number of users to return (max is 30) + /// offset: the offset (max is 1000) + /// message_limit: how many messages should be included to each channel + final PaginationParams paginationParams; + + ChannelFileDisplayScreen({ + this.sortOptions, + this.paginationParams, + }); + + @override + _ChannelFileDisplayScreenState createState() => + _ChannelFileDisplayScreenState(); +} + +class _ChannelFileDisplayScreenState extends State { + @override + void initState() { + super.initState(); + final messageSearchBloc = MessageSearchBloc.of(context); + messageSearchBloc.search( + filter: { + 'cid': { + r'$in': ['messaging:${StreamChannel.of(context).channel.id}'] + } + }, + messageFilter: { + 'attachments.type': { + r'$in': ['file'], + }, + }, + sort: widget.sortOptions, + pagination: widget.paginationParams, + ); + } + @override Widget build(BuildContext context) { return Scaffold( @@ -31,6 +76,95 @@ class ChannelFileDisplayScreen extends StatelessWidget { ), backgroundColor: StreamChatTheme.of(context).primaryColor, ), + body: _buildMediaGrid(), + ); + } + + Widget _buildMediaGrid() { + final messageSearchBloc = MessageSearchBloc.of(context); + + return StreamBuilder>( + builder: (context, snapshot) { + if (snapshot.data == null) { + return Center( + child: CircularProgressIndicator( + backgroundColor: StreamChatTheme.of(context).accentColor, + ), + ); + } + + if (snapshot.data.isEmpty) { + return Center( + child: Text('Nothing here...'), + ); + } + + Map media = {}; + + for (var item in snapshot.data) { + item.message.attachments + .where((e) => e.type == 'file') + .forEach((e) { + media[e] = item.message; + }); + } + + return LazyLoadScrollView( + onEndOfPage: () => messageSearchBloc.search( + filter: { + 'cid': { + r'$in': ['messaging:${StreamChannel.of(context).channel.id}'] + } + }, + messageFilter: { + 'attachments.type': { + r'$in': ['file'] + }, + }, + sort: widget.sortOptions, + pagination: widget.paginationParams.copyWith( + offset: messageSearchBloc.messageResponses?.length ?? 0, + ), + ), + child: ListView.builder( + itemBuilder: (context, position) { + var channel = StreamChannel.of(context).channel; + + return Padding( + padding: const EdgeInsets.all(1.0), + child: InkWell( + onTap: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => StreamChannel( + channel: channel, + child: FullScreenMedia( + mediaAttachments: [ + media.keys.toList()[position], + ], + message: media.values.toList()[position], + sentAt: media.values.toList()[position].createdAt, + userName: media.values.toList()[position].user.name, + ), + ), + ), + ); + }, + child: Padding( + padding: const EdgeInsets.all(8.0), + child: FileAttachment( + attachment: media.keys.toList()[position], + ), + ), + ), + ); + }, + itemCount: media.length, + ), + ); + }, + stream: messageSearchBloc.messagesStream, ); } } diff --git a/lib/src/channel_media_display_screen.dart b/lib/src/channel_media_display_screen.dart index bcad35e2..dd2534b0 100644 --- a/lib/src/channel_media_display_screen.dart +++ b/lib/src/channel_media_display_screen.dart @@ -1,7 +1,50 @@ +import 'package:cached_network_image/cached_network_image.dart'; import 'package:flutter/material.dart'; +import 'package:stream_chat_flutter/src/lazy_load_scroll_view.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; +import 'package:video_player/video_player.dart'; + +class ChannelMediaDisplayScreen extends StatefulWidget { + /// The sorting used for the channels matching the filters. + /// Sorting is based on field and direction, multiple sorting options can be provided. + /// You can sort based on last_updated, last_message_at, updated_at, created_at or member_count. + /// Direction can be ascending or descending. + final List sortOptions; + + /// Pagination parameters + /// limit: the number of users to return (max is 30) + /// offset: the offset (max is 1000) + /// message_limit: how many messages should be included to each channel + final PaginationParams paginationParams; + + ChannelMediaDisplayScreen({this.sortOptions, this.paginationParams}); + + @override + _ChannelMediaDisplayScreenState createState() => + _ChannelMediaDisplayScreenState(); +} + +class _ChannelMediaDisplayScreenState extends State { + @override + void initState() { + super.initState(); + final messageSearchBloc = MessageSearchBloc.of(context); + messageSearchBloc.search( + filter: { + 'cid': { + r'$in': ['messaging:${StreamChannel.of(context).channel.id}'] + } + }, + messageFilter: { + 'attachments.type': { + r'$in': ['image', 'video'] + }, + }, + sort: widget.sortOptions, + pagination: widget.paginationParams, + ); + } -class ChannelMediaDisplayScreen extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( @@ -31,6 +74,108 @@ class ChannelMediaDisplayScreen extends StatelessWidget { ), backgroundColor: StreamChatTheme.of(context).primaryColor, ), + body: _buildMediaGrid(), + ); + } + + Widget _buildMediaGrid() { + final messageSearchBloc = MessageSearchBloc.of(context); + + return StreamBuilder>( + builder: (context, snapshot) { + if (snapshot.data == null) { + return Center( + child: CircularProgressIndicator( + backgroundColor: StreamChatTheme.of(context).accentColor, + ), + ); + } + + if (snapshot.data.isEmpty) { + return Center( + child: Text('Nothing here...'), + ); + } + + List<_AssetPackage> media = []; + + for (var item in snapshot.data) { + item.message.attachments + .where((e) => e.type == 'image' || e.type == 'video') + .forEach((e) { + VideoPlayerController controller; + if(e.type == 'video') { + controller = VideoPlayerController.network(e.assetUrl); + controller.initialize(); + } + media.add(_AssetPackage(e, item.message, controller)); + }); + } + + return LazyLoadScrollView( + onEndOfPage: () => messageSearchBloc.search( + filter: { + 'cid': { + r'$in': ['messaging:${StreamChannel.of(context).channel.id}'] + } + }, + messageFilter: { + 'attachments.type': { + r'$in': ['image', 'video'] + }, + }, + sort: widget.sortOptions, + pagination: widget.paginationParams.copyWith( + offset: messageSearchBloc.messageResponses?.length ?? 0, + ), + ), + child: GridView.builder( + gridDelegate: + SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 3), + itemBuilder: (context, position) { + var channel = StreamChannel.of(context).channel; + + return Padding( + padding: const EdgeInsets.all(1.0), + child: InkWell( + onTap: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => StreamChannel( + channel: channel, + child: FullScreenMedia( + mediaAttachments: [ + media[position].attachment, + ], + message: media[position].message, + sentAt: media[position].message.createdAt, + userName: media[position].message.user.name, + ), + ), + ), + ); + }, + child: media[position].attachment.type == 'image' ? CachedNetworkImage( + imageUrl: media[position].attachment.imageUrl, + fit: BoxFit.cover, + ) : VideoPlayer(media[position].videoPlayer), + ), + ); + }, + itemCount: media.length, + ), + ); + }, + stream: messageSearchBloc.messagesStream, ); } } + +class _AssetPackage { + Attachment attachment; + Message message; + VideoPlayerController videoPlayer; + + _AssetPackage(this.attachment, this.message, this.videoPlayer); +} diff --git a/lib/src/chat_info_screen.dart b/lib/src/chat_info_screen.dart index 436ff675..fd25bc97 100644 --- a/lib/src/chat_info_screen.dart +++ b/lib/src/chat_info_screen.dart @@ -174,10 +174,27 @@ class _ChatInfoScreenState extends State { ), trailing: StreamSvgIcon.right(), onTap: () { + final channel = StreamChannel.of(context).channel; + Navigator.push( - context, - MaterialPageRoute( - builder: (context) => ChannelMediaDisplayScreen())); + context, + MaterialPageRoute( + builder: (context) => StreamChannel( + channel: channel, + child: MessageSearchBloc( + child: ChannelMediaDisplayScreen( + sortOptions: [ + SortOption( + 'created_at', + direction: SortOption.ASC, + ), + ], + paginationParams: PaginationParams(limit: 20), + ), + ), + ), + ), + ); }, ), OptionListTile( @@ -188,10 +205,27 @@ class _ChatInfoScreenState extends State { ), trailing: StreamSvgIcon.right(), onTap: () { + final channel = StreamChannel.of(context).channel; + Navigator.push( - context, - MaterialPageRoute( - builder: (context) => ChannelFileDisplayScreen())); + context, + MaterialPageRoute( + builder: (context) => StreamChannel( + channel: channel, + child: MessageSearchBloc( + child: ChannelFileDisplayScreen( + sortOptions: [ + SortOption( + 'created_at', + direction: SortOption.ASC, + ), + ], + paginationParams: PaginationParams(limit: 20), + ), + ), + ), + ), + ); }, ), OptionListTile( diff --git a/lib/src/group_info_screen.dart b/lib/src/group_info_screen.dart index 7dd7ceaa..d097ed0e 100644 --- a/lib/src/group_info_screen.dart +++ b/lib/src/group_info_screen.dart @@ -361,10 +361,27 @@ class _GroupInfoScreenState extends State { ), trailing: StreamSvgIcon.right(), onTap: () { + var channel = StreamChannel.of(context).channel; + Navigator.push( - context, - MaterialPageRoute( - builder: (context) => ChannelMediaDisplayScreen())); + context, + MaterialPageRoute( + builder: (context) => StreamChannel( + channel: channel, + child: MessageSearchBloc( + child: ChannelMediaDisplayScreen( + sortOptions: [ + SortOption( + 'created_at', + direction: SortOption.ASC, + ), + ], + paginationParams: PaginationParams(limit: 20), + ), + ), + ), + ), + ); }, ), OptionListTile( @@ -375,10 +392,27 @@ class _GroupInfoScreenState extends State { ), trailing: StreamSvgIcon.right(), onTap: () { + var channel = StreamChannel.of(context).channel; + Navigator.push( - context, - MaterialPageRoute( - builder: (context) => ChannelFileDisplayScreen())); + context, + MaterialPageRoute( + builder: (context) => StreamChannel( + channel: channel, + child: MessageSearchBloc( + child: ChannelFileDisplayScreen( + sortOptions: [ + SortOption( + 'created_at', + direction: SortOption.ASC, + ), + ], + paginationParams: PaginationParams(limit: 20), + ), + ), + ), + ), + ); }, ), OptionListTile( diff --git a/lib/src/message_search_bloc.dart b/lib/src/message_search_bloc.dart index 0128bb22..ab277c4c 100644 --- a/lib/src/message_search_bloc.dart +++ b/lib/src/message_search_bloc.dart @@ -55,6 +55,7 @@ class MessageSearchBlocState extends State /// Calls [Client.search] updating [queryMessagesLoading] stream Future search({ Map filter, + Map messageFilter, List sort, String query, PaginationParams pagination, @@ -78,6 +79,7 @@ class MessageSearchBlocState extends State sort, query, pagination, + messageFilters: messageFilter, ); if (clear) { diff --git a/pubspec.yaml b/pubspec.yaml index b41f58c6..d5112694 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -28,7 +28,7 @@ dependencies: file_picker: ^2.0.12 image_picker: ^0.6.7+2 flutter_keyboard_visibility: ^3.3.0 - stream_chat: ^0.2.14 + stream_chat: ^0.2.19 mime: ^0.9.6+3 video_compress: ^2.1.1 visibility_detector: ^0.1.5 From 49377b46a21def9076b6de5cd1caee78de2014cf Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Thu, 17 Dec 2020 23:15:56 +0530 Subject: [PATCH 0634/1140] fix initialIndex bug Signed-off-by: Sahil Kumar --- example/lib/main.dart | 4 +- lib/src/message_list_view.dart | 78 ++++++++++++++++++++-------------- 2 files changed, 50 insertions(+), 32 deletions(-) diff --git a/example/lib/main.dart b/example/lib/main.dart index 1c61dde2..9f41efd5 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -339,7 +339,9 @@ class _ChannelListPageState extends State { messageResponse.channel.type, id: messageResponse.channel.id, ); - await channel.watch(); + if (channel.state == null) { + await channel.watch(); + } Navigator.pushNamed( context, Routes.CHANNEL_PAGE, diff --git a/lib/src/message_list_view.dart b/lib/src/message_list_view.dart index ca184d6b..254af757 100644 --- a/lib/src/message_list_view.dart +++ b/lib/src/message_list_view.dart @@ -183,22 +183,15 @@ class _MessageListViewState extends State { final messageIndex = messages.indexWhere((e) { return e.id == streamChannel.initialMessageId; }); - return totalMessages - messageIndex; + final index = totalMessages - messageIndex; + if (index != 0) return index - 1; + return index; } return 0; } double get _initialAlignment { if (widget.initialAlignment != null) return widget.initialAlignment; - final streamChannel = StreamChannel.of(context); - if (streamChannel.initialMessageId != null) { - final messages = streamChannel.channel.state.messages; - final messageIndex = messages.indexWhere((e) { - return e.id == streamChannel.initialMessageId; - }); - final isFirstMessage = messageIndex == 0; - return isFirstMessage ? 0 : 0.5; - } return 0; } @@ -212,13 +205,13 @@ class _MessageListViewState extends State { bool _topPaginationActive = false; bool _bottomPaginationActive = false; - bool get _paginationActive => _topPaginationActive || _bottomPaginationActive; - int initialIndex; double initialAlignment; List messages = []; + bool initialMessageHighlightComplete = false; + @override Widget build(BuildContext context) { final streamChannel = StreamChannel.of(context); @@ -229,11 +222,6 @@ class _MessageListViewState extends State { .map((threads) => threads[widget.parentMessage.id]) : streamChannel.channel.state?.messagesStream; - if (!_paginationActive && !_upToDate) { - initialIndex = _initialIndex; - initialAlignment = _initialAlignment; - } - return WillPopScope( onWillPop: () async { if (!_upToDate) { @@ -275,21 +263,22 @@ class _MessageListViewState extends State { final newMessagesListLength = messages.length; - if (_bottomPaginationActive) { - if (_itemPositionListener.itemPositions.value?.isNotEmpty == - true && - _messageListLength != null) { - final first = _itemPositionListener.itemPositions.value.first; - final diff = newMessagesListLength - _messageListLength; - if (diff > 0) { - initialIndex = first.index + diff; - initialAlignment = first.itemLeadingEdge; + if (_messageListLength != null) { + if (_bottomPaginationActive) { + if (_itemPositionListener.itemPositions.value?.isNotEmpty == + true) { + final first = _itemPositionListener.itemPositions.value.first; + final diff = newMessagesListLength - _messageListLength; + if (diff > 0) { + initialIndex = first.index + diff; + initialAlignment = first.itemLeadingEdge; + } } + } else if (!_topPaginationActive && _upToDate) { + // Reset the index in-case we send any new message + initialIndex = 0; + initialAlignment = 0; } - } else if (!_topPaginationActive && _upToDate) { - // Reset the index in-case we send any new message - initialIndex = 0; - initialAlignment = 0; } _messageListLength = newMessagesListLength; @@ -731,7 +720,7 @@ class _MessageListViewState extends State { final allRead = readList.length >= (channel.memberCount ?? 0) - 1; - return MessageWidget( + Widget child = MessageWidget( key: ValueKey('MESSAGE-${message.id}'), message: message, reverse: isMyMessage, @@ -773,6 +762,30 @@ class _MessageListViewState extends State { readList: readList, allRead: allRead, ); + + if (!initialMessageHighlightComplete && + widget.highlightInitialMessage && + _isInitialMessage(message.id)) { + final accentColor = Theme.of(context).accentColor; + child = TweenAnimationBuilder( + tween: ColorTween( + begin: accentColor.withOpacity(0.7), + end: Colors.transparent, + ), + duration: const Duration(seconds: 2), + child: child, + onEnd: () { + initialMessageHighlightComplete = true; + }, + builder: (_, color, child) { + return Container( + color: color, + child: child, + ); + }, + ); + } + return child; } StreamSubscription _messageNewListener; @@ -785,6 +798,9 @@ class _MessageListViewState extends State { final streamChannel = StreamChannel.of(context); + initialIndex = _initialIndex; + initialAlignment = _initialAlignment; + _messageNewListener = streamChannel.channel.on(EventType.messageNew).listen((event) { if (event.message.user.id == streamChannel.channel.client.state.user.id) { From 8ee4b585b8d80e3096e1f3c7b68d7f8c706136f4 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Fri, 18 Dec 2020 10:00:10 +0100 Subject: [PATCH 0635/1140] mark read only if the channel is up to date --- lib/src/message_list_view.dart | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/src/message_list_view.dart b/lib/src/message_list_view.dart index 254af757..6d1e61f2 100644 --- a/lib/src/message_list_view.dart +++ b/lib/src/message_list_view.dart @@ -511,6 +511,7 @@ class _MessageListViewState extends State { _bottomPaginationActive = false; _topPaginationActive = false; streamChannel.reloadChannel(); + streamChannel.channel.markRead(); } else { setState(() => _showScrollToBottom = false); _scrollController.scrollTo( @@ -642,7 +643,8 @@ class _MessageListViewState extends State { onVisibilityChanged: (visibility) { final isVisible = visibility.visibleBounds != Rect.zero; if (isVisible && !_bottomWasVisible) { - if (streamChannel.channel.config?.readEvents == true && + if (streamChannel.channel.state.isUpToDate && + streamChannel.channel.config?.readEvents == true && streamChannel.channel.state.unreadCount > 0) { streamChannel.channel.markRead(); } From 89d1d5f562a4ccaa9955ea9d1694cde9d5cc7748 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Fri, 18 Dec 2020 11:54:47 +0100 Subject: [PATCH 0636/1140] update llc dependency --- example/ios/Flutter/.last_build_id | 2 +- example/lib/main.dart | 12 ++++++++---- example/pubspec.yaml | 2 +- pubspec.yaml | 2 +- 4 files changed, 11 insertions(+), 7 deletions(-) diff --git a/example/ios/Flutter/.last_build_id b/example/ios/Flutter/.last_build_id index 20c7c514..e72273c3 100644 --- a/example/ios/Flutter/.last_build_id +++ b/example/ios/Flutter/.last_build_id @@ -1 +1 @@ -c3e639ccf9b069e37a7d1345194e6b99 \ No newline at end of file +13a41b8138c4868054e44b5158f3bdd6 \ No newline at end of file diff --git a/example/lib/main.dart b/example/lib/main.dart index 3fb47b66..4c37c57a 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -24,7 +24,7 @@ void main() async { final client = Client( apiKey ?? kDefaultStreamApiKey, - logLevel: Level.INFO, + logLevel: Level.SEVERE, showLocalNotification: (!kIsWeb && Platform.isAndroid) ? showLocalNotification : null, persistenceEnabled: true, @@ -213,12 +213,16 @@ class _HomePageState extends State { alignment: Alignment.bottomCenter, child: ListTile( onTap: () async { - await StreamChat.of(context).client.disconnect(); + Navigator.pop(context); final secureStorage = FlutterSecureStorage(); await secureStorage.deleteAll(); - Navigator.pop(context); - Navigator.pushReplacementNamed( + + StreamChat.of(context).client.disconnect( + clearUser: true, + ); + + await Navigator.pushReplacementNamed( context, Routes.CHOOSE_USER, ); diff --git a/example/pubspec.yaml b/example/pubspec.yaml index f9c71355..ef06f719 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -1,6 +1,6 @@ name: example description: A new Flutter project. -version: 1.0.91+94 +version: 1.0.92+95 environment: sdk: ">=2.2.2 <3.0.0" diff --git a/pubspec.yaml b/pubspec.yaml index b41f58c6..47139390 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -28,7 +28,7 @@ dependencies: file_picker: ^2.0.12 image_picker: ^0.6.7+2 flutter_keyboard_visibility: ^3.3.0 - stream_chat: ^0.2.14 + stream_chat: ^0.2.18 mime: ^0.9.6+3 video_compress: ^2.1.1 visibility_detector: ^0.1.5 From 7cfb1752fba709ba808f3c7361024dc9f2aca961 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Fri, 18 Dec 2020 17:11:46 +0530 Subject: [PATCH 0637/1140] fix newMessage jump bug Signed-off-by: Sahil Kumar --- lib/src/lazy_load_scroll_view.dart | 38 ++++++++++++++++++++++++++++-- lib/src/message_list_view.dart | 22 ++++++++++++++--- 2 files changed, 55 insertions(+), 5 deletions(-) diff --git a/lib/src/lazy_load_scroll_view.dart b/lib/src/lazy_load_scroll_view.dart index 99eeb861..2bc82a55 100644 --- a/lib/src/lazy_load_scroll_view.dart +++ b/lib/src/lazy_load_scroll_view.dart @@ -15,6 +15,15 @@ class LazyLoadScrollView extends StatefulWidget { /// Called when the [child] reaches the end of the list final AsyncCallback onEndOfPage; + /// Called when the list scrolling starts + final VoidCallback onPageScrollStart; + + /// Called when the list scrolling ends + final VoidCallback onPageScrollEnd; + + /// Called every time the [child] is in-between the list + final VoidCallback onInBetweenOfPage; + /// The offset to take into account when triggering [onEndOfPage]/[onStartOfPage] in pixels final double scrollOffset; @@ -27,6 +36,9 @@ class LazyLoadScrollView extends StatefulWidget { @required this.child, this.onStartOfPage, this.onEndOfPage, + this.onPageScrollStart, + this.onPageScrollEnd, + this.onInBetweenOfPage, this.isLoading = false, this.scrollOffset = 100, }) : assert(child != null), @@ -49,12 +61,34 @@ class _LazyLoadScrollViewState extends State { } bool _onNotification(Notification notification) { + if (notification is ScrollStartNotification) { + if (widget.onPageScrollStart != null) { + widget.onPageScrollStart(); + return true; + } + } + if (notification is ScrollEndNotification) { + if (widget.onPageScrollEnd != null) { + widget.onPageScrollEnd(); + return true; + } + } if (notification is ScrollUpdateNotification) { final pixels = notification.metrics.pixels; - final extentBefore = notification.metrics.extentBefore; - final extentAfter = notification.metrics.extentAfter; + final maxScrollExtent = notification.metrics.maxScrollExtent; + final minScrollExtent = notification.metrics.minScrollExtent; final scrollOffset = widget.scrollOffset; + if (pixels > (minScrollExtent + scrollOffset) && + pixels < (maxScrollExtent - scrollOffset)) { + if (widget.onInBetweenOfPage != null) { + widget.onInBetweenOfPage(); + return true; + } + } + + final extentBefore = notification.metrics.extentBefore; + final extentAfter = notification.metrics.extentAfter; final scrollingDown = _scrollPosition < pixels; if (scrollOffset == null || scrollOffset == 0) { diff --git a/lib/src/message_list_view.dart b/lib/src/message_list_view.dart index 254af757..f4ab3103 100644 --- a/lib/src/message_list_view.dart +++ b/lib/src/message_list_view.dart @@ -212,6 +212,8 @@ class _MessageListViewState extends State { bool initialMessageHighlightComplete = false; + bool _inBetweenList = false; + @override Widget build(BuildContext context) { final streamChannel = StreamChannel.of(context); @@ -264,7 +266,7 @@ class _MessageListViewState extends State { final newMessagesListLength = messages.length; if (_messageListLength != null) { - if (_bottomPaginationActive) { + if (_bottomPaginationActive || (_inBetweenList && _upToDate)) { if (_itemPositionListener.itemPositions.value?.isNotEmpty == true) { final first = _itemPositionListener.itemPositions.value.first; @@ -288,17 +290,27 @@ class _MessageListViewState extends State { children: [ LazyLoadScrollView( onStartOfPage: () async { + _inBetweenList = false; if (!_upToDate) { _topPaginationActive = false; _bottomPaginationActive = true; return _paginateData( - streamChannel, QueryDirection.bottom); + streamChannel, + QueryDirection.bottom, + ); } }, onEndOfPage: () async { + _inBetweenList = false; _topPaginationActive = true; _bottomPaginationActive = false; - return _paginateData(streamChannel, QueryDirection.top); + return _paginateData( + streamChannel, + QueryDirection.top, + ); + }, + onInBetweenOfPage: () { + _inBetweenList = true; }, child: ScrollablePositionedList.builder( key: ValueKey(initialIndex + initialAlignment), @@ -803,6 +815,10 @@ class _MessageListViewState extends State { _messageNewListener = streamChannel.channel.on(EventType.messageNew).listen((event) { + if (_upToDate) { + _bottomPaginationActive = false; + _topPaginationActive = false; + } if (event.message.user.id == streamChannel.channel.client.state.user.id) { WidgetsBinding.instance.addPostFrameCallback((_) { _scrollController.jumpTo( From 9e3248d4c9132cb52ec8e590185d444100b4675f Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Fri, 18 Dec 2020 17:13:55 +0530 Subject: [PATCH 0638/1140] minor refactor Signed-off-by: Sahil Kumar --- lib/src/message_list_view.dart | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/lib/src/message_list_view.dart b/lib/src/message_list_view.dart index 56d246bf..b56add20 100644 --- a/lib/src/message_list_view.dart +++ b/lib/src/message_list_view.dart @@ -655,9 +655,10 @@ class _MessageListViewState extends State { onVisibilityChanged: (visibility) { final isVisible = visibility.visibleBounds != Rect.zero; if (isVisible && !_bottomWasVisible) { - if (streamChannel.channel.state.isUpToDate && - streamChannel.channel.config?.readEvents == true && - streamChannel.channel.state.unreadCount > 0) { + final channel = streamChannel.channel; + if (_upToDate && + channel.config?.readEvents == true && + channel.state.unreadCount > 0) { streamChannel.channel.markRead(); } _bottomWasVisible = !isVisible; From 966548132304084135e7f2d2c320be4097eb61bb Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Fri, 18 Dec 2020 19:55:27 +0530 Subject: [PATCH 0639/1140] Change cupertinoActivitYIndicator to cicularProgressIndicator Signed-off-by: Sahil Kumar --- lib/src/message_list_view.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/message_list_view.dart b/lib/src/message_list_view.dart index b56add20..e2807775 100644 --- a/lib/src/message_list_view.dart +++ b/lib/src/message_list_view.dart @@ -592,7 +592,7 @@ class _MessageListViewState extends State { return Center( child: Padding( padding: const EdgeInsets.all(8.0), - child: const CupertinoActivityIndicator(), + child: const CircularProgressIndicator(), ), ); }); From 58cc196ecc331e445164a7d1745cf2cb4b428f27 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Fri, 18 Dec 2020 20:08:44 +0530 Subject: [PATCH 0640/1140] feat: group info screen details --- lib/src/group_info_screen.dart | 346 ++++++++++++++++++++++++++------- 1 file changed, 277 insertions(+), 69 deletions(-) diff --git a/lib/src/group_info_screen.dart b/lib/src/group_info_screen.dart index d097ed0e..642065dc 100644 --- a/lib/src/group_info_screen.dart +++ b/lib/src/group_info_screen.dart @@ -3,6 +3,7 @@ import 'dart:async'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:jiffy/jiffy.dart'; +import 'package:stream_chat_flutter/src/chat_info_screen.dart'; import 'package:stream_chat_flutter/src/option_list_tile.dart'; import 'package:stream_chat_flutter/src/stream_svg_icon.dart'; @@ -52,7 +53,7 @@ class _GroupInfoScreenState extends State { filter: {}, ); _nameController = TextEditingController.fromValue( - TextEditingValue(text: channel.channel.extraData['name'])); + TextEditingValue(text: channel.channel.extraData['name'] ?? '')); _searchController = TextEditingController()..addListener(_userNameListener); _nameController.addListener(() { @@ -160,60 +161,65 @@ class _GroupInfoScreenState extends State { itemCount: snapshot.data.members.length, itemBuilder: (context, position) { return Material( - child: Container( - height: 65.0, - child: Column( - children: [ - Row( - children: [ - Padding( - padding: const EdgeInsets.symmetric( - horizontal: 8.0, vertical: 12.0), - child: UserAvatar( - user: snapshot.data.members[position].user, - constraints: - BoxConstraints(maxHeight: 40.0, maxWidth: 40.0), + child: InkWell( + onTap: () { + var userMember = snapshot.data.members.firstWhere((e) => e.user.id == StreamChat.of(context).user.id); + _showUserInfoModal(snapshot.data.members[position].user, userMember.role == 'owner'); + }, + child: Container( + height: 65.0, + child: Column( + children: [ + Row( + children: [ + Padding( + padding: const EdgeInsets.symmetric( + horizontal: 8.0, vertical: 12.0), + child: UserAvatar( + user: snapshot.data.members[position].user, + constraints: BoxConstraints( + maxHeight: 40.0, maxWidth: 40.0), + ), ), - ), - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text( - snapshot.data.members[position].user.name, - style: TextStyle(fontWeight: FontWeight.bold), - ), - SizedBox( - height: 1.0, - ), - Text( - _getLastSeen( - snapshot.data.members[position].user), - style: TextStyle( - color: Colors.black.withOpacity(0.5)), - ), - ], + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + snapshot.data.members[position].user.name, + style: TextStyle(fontWeight: FontWeight.bold), + ), + SizedBox( + height: 1.0, + ), + Text( + _getLastSeen( + snapshot.data.members[position].user), + style: TextStyle( + color: Colors.black.withOpacity(0.5)), + ), + ], + ), ), - ), - Padding( - padding: const EdgeInsets.all(8.0), - child: Text( - snapshot.data.members[position].user.id == - channel.channel.createdBy.id - ? 'Owner' - : '', - style: - TextStyle(color: Colors.black.withOpacity(0.5)), + Padding( + padding: const EdgeInsets.all(8.0), + child: Text( + snapshot.data.members[position].role == 'owner' + ? 'Owner' + : '', + style: TextStyle( + color: Colors.black.withOpacity(0.5)), + ), ), - ), - ], - ), - Container( - height: 1.0, - color: Color(0xffdbdbdb), - ), - ], + ], + ), + Container( + height: 1.0, + color: Color(0xffdbdbdb), + ), + ], + ), ), ), color: Colors.white, @@ -227,7 +233,7 @@ class _GroupInfoScreenState extends State { Widget _buildNameTile() { var channel = StreamChannel.of(context).channel; - var channelName = channel.extraData['name']; + var channelName = channel.extraData['name'] ?? ''; return Material( color: Colors.white, @@ -415,23 +421,24 @@ class _GroupInfoScreenState extends State { ); }, ), - OptionListTile( - title: 'Leave Group', - leading: StreamSvgIcon.userRemove( - size: 24.0, - color: Colors.black.withOpacity(0.5), + if (!channel.channel.isDistinct) + OptionListTile( + title: 'Leave Group', + leading: StreamSvgIcon.userRemove( + size: 24.0, + color: Colors.black.withOpacity(0.5), + ), + trailing: Container( + height: 24.0, + width: 24.0, + ), + onTap: () async { + await channel.channel + .removeMembers([StreamChat.of(context).user.id]); + Navigator.pop(context); + Navigator.pop(context); + }, ), - trailing: Container( - height: 24.0, - width: 24.0, - ), - onTap: () async { - await channel.channel - .removeMembers([StreamChat.of(context).user.id]); - Navigator.pop(context); - Navigator.pop(context); - }, - ), ], ); } @@ -590,6 +597,207 @@ class _GroupInfoScreenState extends State { ); } + void _showUserInfoModal(User user, bool isUserAdmin) { + var channel = StreamChannel.of(context).channel; + + showModalBottomSheet( + context: context, + clipBehavior: Clip.antiAlias, + isScrollControlled: true, + builder: (context) { + return StreamChannel( + channel: channel, + child: Material( + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + SizedBox( + height: 24.0, + ), + Center( + child: Text( + user.name, + style: TextStyle( + fontSize: 16.0, + fontWeight: FontWeight.bold, + ), + ), + ), + SizedBox( + height: 5.0, + ), + _buildConnectedTitleState(user), + Center( + child: Padding( + padding: const EdgeInsets.all(16.0), + child: UserAvatar( + user: user, + constraints: BoxConstraints( + maxHeight: 64.0, + minHeight: 64.0, + ), + borderRadius: BorderRadius.circular(32.0), + ), + ), + ), + if (StreamChat.of(context).user.id != user.id) + _buildModalListTile( + StreamSvgIcon.user( + color: Color(0xff7a7a7a), + size: 24.0, + ), + 'View info', () async { + var client = StreamChat.of(context).client; + + var c = client.channel('messaging', extraData: { + 'members': [ + user.id, + StreamChat.of(context).user.id, + ], + }); + + await c.watch(); + + await Navigator.push( + context, + MaterialPageRoute( + builder: (context) => StreamChannel( + channel: c, + child: ChatInfoScreen( + user: user, + ), + ), + ), + ); + }), + _buildModalListTile( + StreamSvgIcon.message( + color: Color(0xff7a7a7a), + size: 24.0, + ), + 'Message', + () {}), + if (!channel.isDistinct && StreamChat.of(context).user.id != user.id && isUserAdmin) + _buildModalListTile( + StreamSvgIcon.userAdd( + color: Color(0xff7a7a7a), + size: 24.0, + ), + 'Make Owner', () { + // TODO: I have no clue how to make someone an owner + }), + if (!channel.isDistinct && StreamChat.of(context).user.id != user.id && isUserAdmin) + _buildModalListTile( + StreamSvgIcon.userRemove( + color: Colors.red, + size: 24.0, + ), + 'Remove From Group', () async { + await channel.removeMembers([user.id]); + Navigator.pop(context); + _memberQueryFuture = channel.queryMembers( + filter: {}, + ); + }, color: Colors.red), + _buildModalListTile( + StreamSvgIcon.close_small( + color: Color(0xff7a7a7a), + size: 24.0, + ), + 'Cancel', () { + Navigator.pop(context); + }), + ], + ), + ), + ); + }, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.only( + topLeft: Radius.circular(16.0), + topRight: Radius.circular(16.0), + ), + ), + ); + } + + void _showRemoveUserModal(User user) {} + + Widget _buildConnectedTitleState(User user) { + var alternativeWidget; + + final otherMember = user; + + if (otherMember != null) { + if (otherMember.online) { + alternativeWidget = Text( + 'Online', + style: TextStyle(color: Colors.black.withOpacity(0.5)), + ); + } else { + alternativeWidget = Text( + 'Last seen ${Jiffy(otherMember.lastActive).fromNow()}', + style: TextStyle(color: Colors.black.withOpacity(0.5)), + ); + } + } + + return Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + if (user.online) + Material( + type: MaterialType.circle, + child: Container( + padding: const EdgeInsets.symmetric(horizontal: 8.0), + constraints: BoxConstraints.tightFor( + width: 28, + height: 12, + ), + child: Material( + shape: CircleBorder(), + color: Color(0xff20E070), + ), + ), + color: Colors.white, + ), + alternativeWidget, + ], + ); + } + + Widget _buildModalListTile(Widget leading, String title, VoidCallback onTap, + {Color color = Colors.black}) { + return Material( + child: InkWell( + onTap: onTap, + child: Column( + children: [ + Container( + height: 1.0, + color: Color(0xffdbdbdb), + ), + Container( + height: 64.0, + child: Row( + children: [ + Padding( + padding: const EdgeInsets.all(16.0), + child: leading, + ), + Expanded( + child: Text( + title, + style: TextStyle(color: color, fontWeight: FontWeight.bold), + )) + ], + ), + ), + ], + ), + )); + } + String _getChannelName(double width, {List members}) { if (namedChanged) { return changedName; From 14aebadabf1edc2676b364cd8f4bea7cf762bafa Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Fri, 18 Dec 2020 15:42:31 +0100 Subject: [PATCH 0641/1140] fix markread --- example/ios/Flutter/.last_build_id | 2 +- example/ios/Podfile.lock | 4 ++-- example/lib/main.dart | 2 +- example/pubspec.yaml | 2 +- lib/src/message_list_view.dart | 4 +++- 5 files changed, 8 insertions(+), 6 deletions(-) diff --git a/example/ios/Flutter/.last_build_id b/example/ios/Flutter/.last_build_id index e72273c3..f57e1e1f 100644 --- a/example/ios/Flutter/.last_build_id +++ b/example/ios/Flutter/.last_build_id @@ -1 +1 @@ -13a41b8138c4868054e44b5158f3bdd6 \ No newline at end of file +c770358a10272b4ee1cdc2eb432445f6 \ No newline at end of file diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock index bf8c0e1a..f266b656 100644 --- a/example/ios/Podfile.lock +++ b/example/ios/Podfile.lock @@ -40,7 +40,7 @@ PODS: - Firebase/Messaging (6.33.0): - Firebase/CoreOnly - FirebaseMessaging (~> 4.7.0) - - firebase_core (0.5.2-1): + - firebase_core (0.5.3): - Firebase/CoreOnly (~> 6.33.0) - Flutter - firebase_messaging (7.0.3): @@ -258,7 +258,7 @@ SPEC CHECKSUMS: esys_flutter_share: 403498dab005b36ce1f8d7aff377e81f0621b0b4 file_picker: 3e6c3790de664ccf9b882732d9db5eaf6b8d4eb1 Firebase: 8db6f2d1b2c5e2984efba4949a145875a8f65fe5 - firebase_core: 7423d688a1c6f2f2d859d64ae26991be39989781 + firebase_core: 5d6a02f3d85acd5f8321c2d6d62877626a670659 firebase_messaging: 0aea2cd5885b65e19ede58ee3507f485c992cc75 FirebaseCore: d889d9e12535b7f36ac8bfbf1713a0836a3012cd FirebaseCoreDiagnostics: 770ac5958e1372ce67959ae4b4f31d8e127c3ac1 diff --git a/example/lib/main.dart b/example/lib/main.dart index c8bb34f5..f0f1e59b 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -24,7 +24,7 @@ void main() async { final client = Client( apiKey ?? kDefaultStreamApiKey, - logLevel: Level.SEVERE, + logLevel: Level.INFO, showLocalNotification: (!kIsWeb && Platform.isAndroid) ? showLocalNotification : null, persistenceEnabled: true, diff --git a/example/pubspec.yaml b/example/pubspec.yaml index ef06f719..cec1b886 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -1,6 +1,6 @@ name: example description: A new Flutter project. -version: 1.0.92+95 +version: 1.0.93+96 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 e2807775..df99687b 100644 --- a/lib/src/message_list_view.dart +++ b/lib/src/message_list_view.dart @@ -519,11 +519,13 @@ class _MessageListViewState extends State { color: Colors.black, ), onPressed: () { + if (unreadCount > 0) { + streamChannel.channel.markRead(); + } if (!_upToDate) { _bottomPaginationActive = false; _topPaginationActive = false; streamChannel.reloadChannel(); - streamChannel.channel.markRead(); } else { setState(() => _showScrollToBottom = false); _scrollController.scrollTo( From e3b268fb4552cf3901384782f825f84c5523bfb9 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Fri, 18 Dec 2020 15:53:14 +0100 Subject: [PATCH 0642/1140] fix padding --- lib/src/message_list_view.dart | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/src/message_list_view.dart b/lib/src/message_list_view.dart index df99687b..5a850ad3 100644 --- a/lib/src/message_list_view.dart +++ b/lib/src/message_list_view.dart @@ -745,7 +745,8 @@ class _MessageListViewState extends State { padding: EdgeInsets.only( left: 8.0, right: 8.0, - bottom: index == 0 ? 30 : (isNextUser ? 5 : 10), + bottom: index == 0 ? 30 : (isNextUser ? 2 : 7), + top: 3, ), showUsername: !isMyMessage && !isNextUser, showSendingIndicator: isMyMessage && From 74781fd24f6da2fc0f9868a6587394ccb2b5cc08 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Fri, 18 Dec 2020 15:54:13 +0100 Subject: [PATCH 0643/1140] fix message search date --- lib/src/message_search_item.dart | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/src/message_search_item.dart b/lib/src/message_search_item.dart index 3e786b9a..35b31aa8 100644 --- a/lib/src/message_search_item.dart +++ b/lib/src/message_search_item.dart @@ -77,16 +77,16 @@ class MessageSearchItem extends StatelessWidget { } Widget _buildDate(BuildContext context, Message message) { - final lastUpdatedAt = message.updatedAt; + final createdAt = message.createdAt; String stringDate; final now = DateTime.now(); - if (now.year != lastUpdatedAt.year || - now.month != lastUpdatedAt.month || - now.day != lastUpdatedAt.day) { - stringDate = Jiffy(lastUpdatedAt.toLocal()).format('dd/MM/yyyy'); + if (now.year != createdAt.year || + now.month != createdAt.month || + now.day != createdAt.day) { + stringDate = Jiffy(createdAt.toLocal()).format('dd/MM/yyyy'); } else { - stringDate = Jiffy(lastUpdatedAt.toLocal()).format('HH:mm'); + stringDate = Jiffy(createdAt.toLocal()).format('HH:mm'); } return Text( From 903dec9d1fdeb1b305a5f17e6164a943fba55d4a Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Mon, 21 Dec 2020 15:29:59 +0530 Subject: [PATCH 0644/1140] [Thread Header] Redesign wrt new ui Signed-off-by: Sahil Kumar --- lib/src/thread_header.dart | 79 +++++++++++++++++++++----------------- 1 file changed, 43 insertions(+), 36 deletions(-) diff --git a/lib/src/thread_header.dart b/lib/src/thread_header.dart index aa14cb61..cfb6b1f1 100644 --- a/lib/src/thread_header.dart +++ b/lib/src/thread_header.dart @@ -1,7 +1,9 @@ import 'package:flutter/material.dart'; import 'package:stream_chat/stream_chat.dart'; import 'package:stream_chat_flutter/src/stream_chat_theme.dart'; -import 'package:stream_chat_flutter/src/stream_svg_icon.dart'; + +import 'back_button.dart'; +import 'channel_name.dart'; /// ![screenshot](https://raw.githubusercontent.com/GetStream/stream-chat-flutter/master/screenshots/thread_header.png) /// ![screenshot](https://raw.githubusercontent.com/GetStream/stream-chat-flutter/master/screenshots/thread_header_paint.png) @@ -77,43 +79,48 @@ class ThreadHeader extends StatelessWidget implements PreferredSizeWidget { return AppBar( automaticallyImplyLeading: false, elevation: 1, + leading: showBackButton + ? StreamBackButton( + onPressed: onBackPressed, + showUnreads: true, + ) + : SizedBox(), backgroundColor: StreamChatTheme.of(context).channelTheme.channelHeaderTheme.color, - actions: [ - Container( - child: showBackButton - ? AspectRatio( - aspectRatio: 1, - child: IconButton( - onPressed: onBackPressed ?? () => Navigator.pop(context), - icon: StreamSvgIcon.close( - size: 24, - color: Theme.of(context).brightness == Brightness.dark - ? Colors.white - : Colors.black, - ), - ), - ) - : SizedBox(), - ), - ], - centerTitle: false, - title: Text.rich( - TextSpan( - text: 'Thread', - children: [ - TextSpan( - text: - ' ${parent.replyCount} ${parent.replyCount == 1 ? 'reply' : 'replies'}', - style: StreamChatTheme.of(context) - .channelTheme - .channelHeaderTheme - .lastMessageAt, - ), - ], - ), - style: - StreamChatTheme.of(context).channelTheme.channelHeaderTheme.title, + centerTitle: true, + title: Column( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + 'Thread Reply', + style: StreamChatTheme.of(context) + .channelTheme + .channelHeaderTheme + .title, + ), + SizedBox(height: 2), + Row( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + 'with ', + style: StreamChatTheme.of(context) + .channelTheme + .channelHeaderTheme + .lastMessageAt, + ), + ChannelName( + textStyle: StreamChatTheme.of(context) + .channelTheme + .channelHeaderTheme + .lastMessageAt, + ), + ], + ), + ], ), ); } From a4071c117e2e9a2b5cd3b93aca24318ce2e6b207 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Mon, 21 Dec 2020 15:31:13 +0530 Subject: [PATCH 0645/1140] [Message Input] Change "sendAsDm" checkbox title Signed-off-by: Sahil Kumar --- lib/src/message_input.dart | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index dec2b033..c46c899b 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -21,7 +21,6 @@ import 'package:stream_chat_flutter/src/stream_svg_icon.dart'; import 'package:stream_chat_flutter/src/user_avatar.dart'; import 'package:substring_highlight/substring_highlight.dart'; import 'package:video_compress/video_compress.dart'; -import 'package:photo_manager/photo_manager.dart'; import '../stream_chat_flutter.dart'; import 'stream_channel.dart'; @@ -302,7 +301,7 @@ class MessageInputState extends State { ), Padding( padding: const EdgeInsets.symmetric(horizontal: 16.0), - child: Text('Send also as direct message'), + child: Text('Also send as direct message'), ), ], ), From abf218595e3d31d8220d72784d43ddba0b26b27f Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Mon, 21 Dec 2020 11:43:15 +0100 Subject: [PATCH 0646/1140] update llc dependency --- example/ios/Flutter/.last_build_id | 2 +- example/lib/new_chat_screen.dart | 2 +- example/pubspec.yaml | 2 +- lib/src/channels_bloc.dart | 10 +++++----- lib/src/chat_info_screen.dart | 4 ++-- pubspec.yaml | 5 +---- 6 files changed, 11 insertions(+), 14 deletions(-) diff --git a/example/ios/Flutter/.last_build_id b/example/ios/Flutter/.last_build_id index f57e1e1f..e72273c3 100644 --- a/example/ios/Flutter/.last_build_id +++ b/example/ios/Flutter/.last_build_id @@ -1 +1 @@ -c770358a10272b4ee1cdc2eb432445f6 \ No newline at end of file +13a41b8138c4868054e44b5158f3bdd6 \ No newline at end of file diff --git a/example/lib/new_chat_screen.dart b/example/lib/new_chat_screen.dart index 54371c3b..f29b1483 100644 --- a/example/lib/new_chat_screen.dart +++ b/example/lib/new_chat_screen.dart @@ -84,7 +84,7 @@ class _NewChatScreenState extends State { paginationParams: PaginationParams( limit: 1, ), - ).first; + ); final _channelExisted = res.length == 1; if (_channelExisted) { diff --git a/example/pubspec.yaml b/example/pubspec.yaml index cec1b886..175cdaeb 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -1,6 +1,6 @@ name: example description: A new Flutter project. -version: 1.0.93+96 +version: 1.0.94+97 environment: sdk: ">=2.2.2 <3.0.0" diff --git a/lib/src/channels_bloc.dart b/lib/src/channels_bloc.dart index 474d9599..15167317 100644 --- a/lib/src/channels_bloc.dart +++ b/lib/src/channels_bloc.dart @@ -85,7 +85,7 @@ class ChannelsBlocState extends State paginationParams.offset == null || paginationParams.offset == 0; final oldChannels = List.from(channels ?? []); - client + await client .queryChannels( filter: filter, sort: sortOptions, @@ -93,19 +93,19 @@ class ChannelsBlocState extends State paginationParams: paginationParams, onlyOffline: onlyOffline, ) - .listen((channels) { + .then((channels) { if (clear) { _channelsController.add(channels); } else { final l = oldChannels + channels; _channelsController.add(l); } - }, onDone: () { - _queryChannelsLoadingController.sink.add(false); - }, onError: (err, stackTrace) { + }).catchError((err, stackTrace) { print(err); print(stackTrace); _queryChannelsLoadingController.addError(err, stackTrace); + }).whenComplete(() { + _queryChannelsLoadingController.sink.add(false); }); } catch (err, stackTrace) { _queryChannelsLoadingController.addError(err, stackTrace); diff --git a/lib/src/chat_info_screen.dart b/lib/src/chat_info_screen.dart index 0ec62c36..8d291f38 100644 --- a/lib/src/chat_info_screen.dart +++ b/lib/src/chat_info_screen.dart @@ -391,8 +391,8 @@ class __SharedGroupsScreenState extends State<_SharedGroupsScreen> { ), backgroundColor: StreamChatTheme.of(context).primaryColor, ), - body: StreamBuilder>( - stream: chat.client.queryChannels( + body: FutureBuilder>( + future: chat.client.queryChannels( filter: { r'$and': [ { diff --git a/pubspec.yaml b/pubspec.yaml index a226f9c3..12374291 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -28,10 +28,7 @@ dependencies: file_picker: ^2.0.12 image_picker: ^0.6.7+2 flutter_keyboard_visibility: ^3.3.0 - stream_chat: - git: - url: https://github.com/GetStream/stream-chat-dart - ref: two-way-pagination + stream_chat: ^0.2.20 mime: ^0.9.6+3 video_compress: ^2.1.1 visibility_detector: ^0.1.5 From 3c35a800a88a5f28d980aeb21a105cfea40f15b7 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Mon, 21 Dec 2020 12:14:31 +0100 Subject: [PATCH 0647/1140] fix loading --- lib/src/channels_bloc.dart | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/src/channels_bloc.dart b/lib/src/channels_bloc.dart index 15167317..0bae351c 100644 --- a/lib/src/channels_bloc.dart +++ b/lib/src/channels_bloc.dart @@ -100,12 +100,11 @@ class ChannelsBlocState extends State final l = oldChannels + channels; _channelsController.add(l); } + _queryChannelsLoadingController.sink.add(false); }).catchError((err, stackTrace) { print(err); print(stackTrace); _queryChannelsLoadingController.addError(err, stackTrace); - }).whenComplete(() { - _queryChannelsLoadingController.sink.add(false); }); } catch (err, stackTrace) { _queryChannelsLoadingController.addError(err, stackTrace); From b0093dc065bea3809d3fa797a327b78460811b54 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Mon, 21 Dec 2020 12:21:35 +0100 Subject: [PATCH 0648/1140] remove unnecessary .catchError --- lib/src/channels_bloc.dart | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/lib/src/channels_bloc.dart b/lib/src/channels_bloc.dart index 0bae351c..9b6e55bb 100644 --- a/lib/src/channels_bloc.dart +++ b/lib/src/channels_bloc.dart @@ -101,12 +101,10 @@ class ChannelsBlocState extends State _channelsController.add(l); } _queryChannelsLoadingController.sink.add(false); - }).catchError((err, stackTrace) { - print(err); - print(stackTrace); - _queryChannelsLoadingController.addError(err, stackTrace); }); } catch (err, stackTrace) { + print(err); + print(stackTrace); _queryChannelsLoadingController.addError(err, stackTrace); } } From 0968bff3ae269db10b4670b19546ffb75f9dc8b5 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Mon, 21 Dec 2020 20:29:12 +0530 Subject: [PATCH 0649/1140] rfac: Moved pages to sample app --- .../src => example/lib}/chat_info_screen.dart | 5 +- example/lib/customize_channel_preview.dart | 1 - .../lib}/group_info_screen.dart | 46 ++++++++++++++----- example/lib/main.dart | 40 ++++++++++++++++ example/lib/routes/app_routes.dart | 16 +++++++ example/lib/routes/routes.dart | 2 + lib/src/channel_header.dart | 40 +--------------- lib/src/channel_preview.dart | 36 +-------------- lib/stream_chat_flutter.dart | 3 ++ 9 files changed, 99 insertions(+), 90 deletions(-) rename {lib/src => example/lib}/chat_info_screen.dart (98%) rename {lib/src => example/lib}/group_info_screen.dart (95%) diff --git a/lib/src/chat_info_screen.dart b/example/lib/chat_info_screen.dart similarity index 98% rename from lib/src/chat_info_screen.dart rename to example/lib/chat_info_screen.dart index fd25bc97..07e36301 100644 --- a/lib/src/chat_info_screen.dart +++ b/example/lib/chat_info_screen.dart @@ -3,10 +3,7 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:jiffy/jiffy.dart'; -import '../stream_chat_flutter.dart'; -import 'channel_file_display_screen.dart'; -import 'channel_media_display_screen.dart'; -import 'option_list_tile.dart'; +import 'package:stream_chat_flutter/stream_chat_flutter.dart'; /// Detail screen for a 1:1 chat correspondence class ChatInfoScreen extends StatefulWidget { diff --git a/example/lib/customize_channel_preview.dart b/example/lib/customize_channel_preview.dart index 3809f780..3cd48d6e 100644 --- a/example/lib/customize_channel_preview.dart +++ b/example/lib/customize_channel_preview.dart @@ -84,7 +84,6 @@ class ChannelListPage extends StatelessWidget { channel: channel, ), title: ChannelName( - channel: channel, textStyle: StreamChatTheme.of(context).channelPreviewTheme.title.copyWith( color: Colors.black.withOpacity(opacity), diff --git a/lib/src/group_info_screen.dart b/example/lib/group_info_screen.dart similarity index 95% rename from lib/src/group_info_screen.dart rename to example/lib/group_info_screen.dart index 642065dc..5d1c2063 100644 --- a/lib/src/group_info_screen.dart +++ b/example/lib/group_info_screen.dart @@ -3,13 +3,12 @@ import 'dart:async'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:jiffy/jiffy.dart'; -import 'package:stream_chat_flutter/src/chat_info_screen.dart'; +import 'file:///Users/deven9852/Stream/stream-chat-flutter/example/lib/chat_info_screen.dart'; import 'package:stream_chat_flutter/src/option_list_tile.dart'; import 'package:stream_chat_flutter/src/stream_svg_icon.dart'; -import '../stream_chat_flutter.dart'; -import 'channel_file_display_screen.dart'; -import 'channel_media_display_screen.dart'; +import 'package:stream_chat_flutter/stream_chat_flutter.dart'; +import 'main.dart'; class GroupInfoScreen extends StatefulWidget { @override @@ -83,7 +82,6 @@ class _GroupInfoScreenState extends State { leadingWidth: 36.0, title: Column( children: [ - // TODO: Add member names instead of Demo (if name = null) FutureBuilder( future: _memberQueryFuture, builder: (context, snapshot) { @@ -163,8 +161,10 @@ class _GroupInfoScreenState extends State { return Material( child: InkWell( onTap: () { - var userMember = snapshot.data.members.firstWhere((e) => e.user.id == StreamChat.of(context).user.id); - _showUserInfoModal(snapshot.data.members[position].user, userMember.role == 'owner'); + var userMember = snapshot.data.members.firstWhere( + (e) => e.user.id == StreamChat.of(context).user.id); + _showUserInfoModal(snapshot.data.members[position].user, + userMember.role == 'owner'); }, child: Container( height: 65.0, @@ -675,9 +675,31 @@ class _GroupInfoScreenState extends State { color: Color(0xff7a7a7a), size: 24.0, ), - 'Message', - () {}), - if (!channel.isDistinct && StreamChat.of(context).user.id != user.id && isUserAdmin) + 'Message', () async { + var client = StreamChat.of(context).client; + + var c = client.channel('messaging', extraData: { + 'members': [ + user.id, + StreamChat.of(context).user.id, + ], + }); + + await c.watch(); + + await Navigator.push( + context, + MaterialPageRoute( + builder: (context) => StreamChannel( + channel: c, + child: ChannelPage(), + ), + ), + ); + }), + if (!channel.isDistinct && + StreamChat.of(context).user.id != user.id && + isUserAdmin) _buildModalListTile( StreamSvgIcon.userAdd( color: Color(0xff7a7a7a), @@ -686,7 +708,9 @@ class _GroupInfoScreenState extends State { 'Make Owner', () { // TODO: I have no clue how to make someone an owner }), - if (!channel.isDistinct && StreamChat.of(context).user.id != user.id && isUserAdmin) + if (!channel.isDistinct && + StreamChat.of(context).user.id != user.id && + isUserAdmin) _buildModalListTile( StreamSvgIcon.userRemove( color: Colors.red, diff --git a/example/lib/main.dart b/example/lib/main.dart index 4b529e23..8a67a7da 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -1,6 +1,8 @@ import 'dart:io'; import 'package:example/choose_user_page.dart'; +import 'package:example/chat_info_screen.dart'; +import 'package:example/group_info_screen.dart'; import 'package:example/new_chat_screen.dart'; import 'package:example/new_group_chat_screen.dart'; import 'package:flutter/cupertino.dart'; @@ -426,6 +428,44 @@ class ChannelPage extends StatelessWidget { backgroundColor: Color.fromRGBO(252, 252, 252, 1), appBar: ChannelHeader( showTypingIndicator: false, + onImageTap: () async { + var channel = StreamChannel.of(context).channel; + + if (channel.memberCount == 2 && channel.isDistinct) { + final currentUser = StreamChat.of(context).user; + final otherUser = channel.state.members.firstWhere( + (element) => element.user.id != currentUser.id, + orElse: () => null, + ); + if (otherUser != null) { + final pop = await Navigator.push( + context, + MaterialPageRoute( + builder: (context) => StreamChannel( + child: ChatInfoScreen( + user: otherUser.user, + ), + channel: channel, + ), + ), + ); + + if (pop == true) { + Navigator.pop(context); + } + } + } else { + await Navigator.push( + context, + MaterialPageRoute( + builder: (context) => StreamChannel( + child: GroupInfoScreen(), + channel: channel, + ), + ), + ); + } + }, ), body: Column( children: [ diff --git a/example/lib/routes/app_routes.dart b/example/lib/routes/app_routes.dart index 6b0529e1..f3261f72 100644 --- a/example/lib/routes/app_routes.dart +++ b/example/lib/routes/app_routes.dart @@ -7,6 +7,8 @@ import '../main.dart'; import '../group_chat_details_screen.dart'; import '../new_group_chat_screen.dart'; import '../new_chat_screen.dart'; +import '../chat_info_screen.dart'; +import '../group_info_screen.dart'; class AppRoutes { /// Add entry for new route here @@ -59,6 +61,20 @@ class AppRoutes { selectedUsers: args, ); }); + case Routes.CHAT_INFO_SCREEN: + return MaterialPageRoute( + settings: const RouteSettings(name: Routes.CHAT_INFO_SCREEN), + builder: (_) { + return ChatInfoScreen( + user: args, + ); + }); + case Routes.GROUP_INFO_SCREEN: + return MaterialPageRoute( + settings: const RouteSettings(name: Routes.GROUP_INFO_SCREEN), + builder: (_) { + return GroupInfoScreen(); + }); } } } diff --git a/example/lib/routes/routes.dart b/example/lib/routes/routes.dart index 0e0b1e57..0d2f4e5f 100644 --- a/example/lib/routes/routes.dart +++ b/example/lib/routes/routes.dart @@ -7,4 +7,6 @@ class Routes { static const String NEW_CHAT = '/new_chat'; static const String NEW_GROUP_CHAT = '/new_group_chat'; static const String NEW_GROUP_CHAT_DETAILS = '/new_group_chat_details'; + static const String CHAT_INFO_SCREEN = '/chat_info_screen'; + static const String GROUP_INFO_SCREEN = '/group_info_screen'; } diff --git a/lib/src/channel_header.dart b/lib/src/channel_header.dart index 73e44b35..4517d7a0 100644 --- a/lib/src/channel_header.dart +++ b/lib/src/channel_header.dart @@ -8,8 +8,6 @@ import 'package:stream_chat_flutter/src/stream_chat_theme.dart'; import '../stream_chat_flutter.dart'; import './channel_name.dart'; import 'channel_image.dart'; -import 'chat_info_screen.dart'; -import 'group_info_screen.dart'; import 'stream_channel.dart'; /// ![screenshot](https://raw.githubusercontent.com/GetStream/stream-chat-flutter/master/screenshots/channel_header.png) @@ -100,43 +98,7 @@ class ChannelHeader extends StatelessWidget implements PreferredSizeWidget { padding: const EdgeInsets.only(right: 10.0), child: Center( child: ChannelImage( - onTap: onImageTap ?? - () async { - if (channel.memberCount == 2 && channel.isDistinct) { - final currentUser = StreamChat.of(context).user; - final otherUser = channel.state.members.firstWhere( - (element) => element.user.id != currentUser.id, - orElse: () => null, - ); - if (otherUser != null) { - final pop = await Navigator.push( - context, - MaterialPageRoute( - builder: (context) => StreamChannel( - channel: channel, - child: ChatInfoScreen( - user: otherUser.user, - ), - ), - ), - ); - - if (pop == true) { - Navigator.pop(context); - } - } - } else { - await Navigator.push( - context, - MaterialPageRoute( - builder: (context) => StreamChannel( - channel: channel, - child: GroupInfoScreen(), - ), - ), - ); - } - }, + onTap: onImageTap, ), ), ), diff --git a/lib/src/channel_preview.dart b/lib/src/channel_preview.dart index ff727cfa..26f68812 100644 --- a/lib/src/channel_preview.dart +++ b/lib/src/channel_preview.dart @@ -2,13 +2,11 @@ import 'package:flutter/material.dart'; import 'package:flutter/widgets.dart'; import 'package:jiffy/jiffy.dart'; import 'package:stream_chat/stream_chat.dart'; -import 'package:stream_chat_flutter/src/group_info_screen.dart'; import 'package:stream_chat_flutter/src/stream_svg_icon.dart'; import '../stream_chat_flutter.dart'; import 'channel_name.dart'; import 'channel_unread_indicator.dart'; -import 'chat_info_screen.dart'; /// ![screenshot](https://raw.githubusercontent.com/GetStream/stream-chat-flutter/master/screenshots/channel_preview.png) /// ![screenshot](https://raw.githubusercontent.com/GetStream/stream-chat-flutter/master/screenshots/channel_preview_paint.png) @@ -62,39 +60,7 @@ class ChannelPreview extends StatelessWidget { } }, leading: ChannelImage( - onTap: onImageTap ?? - () { - if (channel.memberCount == 2 && channel.isDistinct) { - final currentUser = StreamChat.of(context).user; - final otherUser = channel.state.members.firstWhere( - (element) => element.user.id != currentUser.id, - orElse: () => null, - ); - if (otherUser != null) { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => StreamChannel( - channel: channel, - child: ChatInfoScreen( - user: otherUser.user, - ), - ), - ), - ); - } - } else { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => StreamChannel( - channel: channel, - child: GroupInfoScreen(), - ), - ), - ); - } - }, + onTap: onImageTap, ), title: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, diff --git a/lib/stream_chat_flutter.dart b/lib/stream_chat_flutter.dart index 5dd46fa3..799af175 100644 --- a/lib/stream_chat_flutter.dart +++ b/lib/stream_chat_flutter.dart @@ -44,3 +44,6 @@ export 'src/message_search_bloc.dart'; export 'src/message_search_item.dart'; export 'src/message_search_list_view.dart'; export 'src/unread_indicator.dart'; +export 'src/option_list_tile.dart'; +export 'src/channel_file_display_screen.dart'; +export 'src/channel_media_display_screen.dart'; From f8cf3a7d29a600603a9132db9eb3cd2e084b1997 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Mon, 21 Dec 2020 20:50:50 +0530 Subject: [PATCH 0650/1140] fmt: dartfmt --- lib/src/channel_file_display_screen.dart | 5 +---- lib/src/channel_media_display_screen.dart | 14 ++++++++------ 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/lib/src/channel_file_display_screen.dart b/lib/src/channel_file_display_screen.dart index 361aa808..8ea7daa9 100644 --- a/lib/src/channel_file_display_screen.dart +++ b/lib/src/channel_file_display_screen.dart @@ -1,4 +1,3 @@ -import 'package:cached_network_image/cached_network_image.dart'; import 'package:flutter/material.dart'; import 'package:stream_chat_flutter/src/lazy_load_scroll_view.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; @@ -102,9 +101,7 @@ class _ChannelFileDisplayScreenState extends State { Map media = {}; for (var item in snapshot.data) { - item.message.attachments - .where((e) => e.type == 'file') - .forEach((e) { + item.message.attachments.where((e) => e.type == 'file').forEach((e) { media[e] = item.message; }); } diff --git a/lib/src/channel_media_display_screen.dart b/lib/src/channel_media_display_screen.dart index dd2534b0..d47709cd 100644 --- a/lib/src/channel_media_display_screen.dart +++ b/lib/src/channel_media_display_screen.dart @@ -103,8 +103,8 @@ class _ChannelMediaDisplayScreenState extends State { item.message.attachments .where((e) => e.type == 'image' || e.type == 'video') .forEach((e) { - VideoPlayerController controller; - if(e.type == 'video') { + VideoPlayerController controller; + if (e.type == 'video') { controller = VideoPlayerController.network(e.assetUrl); controller.initialize(); } @@ -156,10 +156,12 @@ class _ChannelMediaDisplayScreenState extends State { ), ); }, - child: media[position].attachment.type == 'image' ? CachedNetworkImage( - imageUrl: media[position].attachment.imageUrl, - fit: BoxFit.cover, - ) : VideoPlayer(media[position].videoPlayer), + child: media[position].attachment.type == 'image' + ? CachedNetworkImage( + imageUrl: media[position].attachment.imageUrl, + fit: BoxFit.cover, + ) + : VideoPlayer(media[position].videoPlayer), ), ); }, From 4aa2a8946a8906dc5455b8992ea84b36af512e75 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Tue, 22 Dec 2020 17:45:08 +0530 Subject: [PATCH 0651/1140] feat: Added gridview for channel list view and changed implementation for image sharing --- lib/src/channel_image.dart | 6 ++ lib/src/channel_list_view.dart | 91 +++++++++++++++++---- lib/src/group_image.dart | 41 ++++++++-- lib/src/image_footer.dart | 143 ++++++++++++++++----------------- lib/src/user_avatar.dart | 3 + 5 files changed, 192 insertions(+), 92 deletions(-) diff --git a/lib/src/channel_image.dart b/lib/src/channel_image.dart index c3d76202..d79b2efa 100644 --- a/lib/src/channel_image.dart +++ b/lib/src/channel_image.dart @@ -52,6 +52,7 @@ class ChannelImage extends StatelessWidget { this.onTap, this.showOnlineStatus = true, this.borderRadius, + this.selected = false, }) : super(key: key); final BorderRadius borderRadius; @@ -67,6 +68,8 @@ class ChannelImage extends StatelessWidget { final bool showOnlineStatus; + final bool selected; + @override Widget build(BuildContext context) { final streamChat = StreamChat.of(context); @@ -99,6 +102,7 @@ class ChannelImage extends StatelessWidget { onTap(); } : null, + selected: selected, ); }); } else { @@ -111,12 +115,14 @@ class ChannelImage extends StatelessWidget { .toList(); return GroupImage( images: images, + borderRadius: borderRadius, constraints: constraints ?? StreamChatTheme.of(context) .channelPreviewTheme .avatarTheme .constraints, onTap: onTap, + selected: selected, ); } diff --git a/lib/src/channel_list_view.dart b/lib/src/channel_list_view.dart index 5dbc9f90..d5278f5e 100644 --- a/lib/src/channel_list_view.dart +++ b/lib/src/channel_list_view.dart @@ -74,6 +74,8 @@ class ChannelListView extends StatefulWidget { this.onStartChatPressed, this.swipeToAction = false, this.pullToRefresh = true, + this.crossAxisCount = 1, + this.selectedChannels = const [], }) : super(key: key); /// The builder that will be used in case of error @@ -134,6 +136,11 @@ class ChannelListView extends StatefulWidget { /// Callback used in the default empty list widget final VoidCallback onStartChatPressed; + /// The number of children in the cross axis. + final int crossAxisCount; + + final List selectedChannels; + @override _ChannelListViewState createState() => _ChannelListViewState(); } @@ -259,22 +266,35 @@ class _ChannelListViewState extends State } if (channels.isNotEmpty) { - child = ListView.custom( - physics: AlwaysScrollableScrollPhysics(), - controller: _scrollController, - childrenDelegate: SliverChildBuilderDelegate( - (context, i) { - return _itemBuilder(context, i, channels); + if (widget.crossAxisCount > 1) { + child = GridView.builder( + gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: widget.crossAxisCount), + itemCount: channels.length, + physics: AlwaysScrollableScrollPhysics(), + controller: _scrollController, + itemBuilder: (context, index) { + return _gridItemBuilder(context, index, channels); }, - childCount: (channels.length * 2) + 1, - findChildIndexCallback: (key) { - final ValueKey valueKey = key; - final index = channels.indexWhere( - (channel) => 'CHANNEL-${channel.id}' == valueKey.value); - return index != -1 ? (index * 2) : null; - }, - ), - ); + ); + } else { + child = ListView.custom( + physics: AlwaysScrollableScrollPhysics(), + controller: _scrollController, + childrenDelegate: SliverChildBuilderDelegate( + (context, i) { + return _itemBuilder(context, i, channels); + }, + childCount: (channels.length * 2) + 1, + findChildIndexCallback: (key) { + final ValueKey valueKey = key; + final index = channels.indexWhere( + (channel) => 'CHANNEL-${channel.id}' == valueKey.value); + return index != -1 ? (index * 2) : null; + }, + ), + ); + } } } @@ -581,6 +601,47 @@ class _ChannelListViewState extends State } } + Widget _gridItemBuilder(BuildContext context, int i, List channels) { + var channel = channels[i]; + + var selected = widget.selectedChannels.contains(channel); + + return Container( + key: ValueKey('CHANNEL-${channel.id}'), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + ChannelImage( + channel: channel, + borderRadius: BorderRadius.circular(32), + selected: selected, + constraints: BoxConstraints.tightFor( + width: 64, + height: 64, + ), + onTap: () { + widget.onChannelTap(channel, null); + }, + ), + SizedBox(height: 7), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 8), + child: StreamChannel( + child: ChannelName( + textStyle: TextStyle( + fontSize: 12, + fontWeight: FontWeight.w600, + ), + ), + channel: channel, + ), + ), + ], + ), + ); + } + Widget _buildQueryProgressIndicator( context, ChannelsBlocState channelsProvider, diff --git a/lib/src/group_image.dart b/lib/src/group_image.dart index 96e25f74..5f54377d 100644 --- a/lib/src/group_image.dart +++ b/lib/src/group_image.dart @@ -9,21 +9,33 @@ class GroupImage extends StatelessWidget { @required this.images, this.constraints, this.onTap, + this.borderRadius, + this.selected = false, + this.selectionColor = const Color(0xFF006CFF), + this.selectionThickness = 4, }) : super(key: key); final List images; final BoxConstraints constraints; final VoidCallback onTap; + final bool selected; + final BorderRadius borderRadius; + final Color selectionColor; + final double selectionThickness; @override Widget build(BuildContext context) { - return GestureDetector( + var avatar; + final streamChatTheme = StreamChatTheme.of(context); + + avatar = GestureDetector( onTap: onTap, child: ClipRRect( - borderRadius: StreamChatTheme.of(context) - .ownMessageTheme - .avatarTheme - .borderRadius, + borderRadius: borderRadius ?? + StreamChatTheme.of(context) + .ownMessageTheme + .avatarTheme + .borderRadius, child: Container( constraints: constraints ?? StreamChatTheme.of(context) @@ -91,5 +103,24 @@ class GroupImage extends StatelessWidget { ), ), ); + + if (selected) { + avatar = ClipRRect( + borderRadius: (borderRadius ?? + streamChatTheme.ownMessageTheme.avatarTheme.borderRadius) + + BorderRadius.circular(selectionThickness), + child: Container( + color: selectionColor, + height: 64.0, + width: 64.0, + child: Padding( + padding: EdgeInsets.all(selectionThickness), + child: avatar, + ), + ), + ); + } + + return avatar; } } diff --git a/lib/src/image_footer.dart b/lib/src/image_footer.dart index 3c37a66a..79c1f501 100644 --- a/lib/src/image_footer.dart +++ b/lib/src/image_footer.dart @@ -68,7 +68,7 @@ class _ImageFooterState extends State { String _userNameQuery; bool _isSearchActive = false; - Set _selectedUsers = {}; + List _selectedChannels = []; bool _loading = false; Timer _debounce; @@ -278,78 +278,86 @@ class _ImageFooterState extends State { ), clipBehavior: Clip.antiAlias, child: Scaffold( + resizeToAvoidBottomInset: false, body: UsersBloc( child: Column( children: [ _buildTextInputSection(modalSetState), + if (_userSearchMode) + SizedBox( + height: 22.0, + ), Expanded( - child: UserListView( - selectedUsers: _selectedUsers, - onUserTap: (user, _) { - _searchController.clear(); - if (!_selectedUsers.contains(user)) { - modalSetState(() { - _selectedUsers.add(user); - }); - } else { - modalSetState(() { - _selectedUsers.remove(user); - }); - } - }, - crossAxisCount: 4, - pagination: PaginationParams( - limit: 25, - ), - filter: { - if (_searchController.text.isNotEmpty) - 'name': { - r'$autocomplete': _userNameQuery, - }, - 'id': { - r'$ne': StreamChat.of(context).user.id, + child: ChannelsBloc( + child: ChannelListView( + selectedChannels: _selectedChannels, + onChannelTap: (user, _) { + _searchController.clear(); + if (!_selectedChannels.contains(user)) { + modalSetState(() { + _selectedChannels.add(user); + }); + } else { + modalSetState(() { + _selectedChannels.remove(user); + }); + } }, - }, - sort: [ - SortOption( - 'name', - direction: 1, + crossAxisCount: 4, + pagination: PaginationParams( + limit: 25, ), - ], - emptyBuilder: (_) { - return LayoutBuilder( - builder: (context, viewportConstraints) { - return SingleChildScrollView( - physics: AlwaysScrollableScrollPhysics(), - child: ConstrainedBox( - constraints: BoxConstraints( - minHeight: viewportConstraints.maxHeight, - ), - child: Center( - child: Column( - children: [ - Padding( - padding: const EdgeInsets.all(24), - child: StreamSvgIcon.search( - size: 96, - color: Colors.grey, + filter: { + if (_searchController.text.isNotEmpty) + 'name': { + r'$autocomplete': _userNameQuery, + }, + 'id': { + r'$ne': StreamChat.of(context).user.id, + }, + }, + sort: [ + SortOption( + 'name', + direction: 1, + ), + ], + emptyBuilder: (_) { + return LayoutBuilder( + builder: (context, viewportConstraints) { + return SingleChildScrollView( + physics: AlwaysScrollableScrollPhysics(), + child: ConstrainedBox( + constraints: BoxConstraints( + minHeight: + viewportConstraints.maxHeight, + ), + child: Center( + child: Column( + children: [ + Padding( + padding: const EdgeInsets.all(24), + child: StreamSvgIcon.search( + size: 96, + color: Colors.grey, + ), ), - ), - Text( - 'No user matches these keywords...'), - ], + Text( + 'No user matches these keywords...'), + ], + ), ), ), - ), - ); - }, - ); - }, + ); + }, + ); + }, + ), ), ), - if (_selectedUsers.isNotEmpty) + if (_selectedChannels.isNotEmpty) _buildShareTextInputSection(modalSetState), - if (!_userSearchMode && _selectedUsers.isEmpty) + if (!_userSearchMode && _selectedChannels.isEmpty) Align( alignment: Alignment.bottomCenter, child: Container( @@ -614,25 +622,16 @@ class _ImageFooterState extends State { final client = StreamChat.of(context).client; - for (var user in _selectedUsers) { - var c = client.channel('messaging', extraData: { - 'members': [ - user.id, - StreamChat.of(context).user.id, - ], - }); - - await c.watch(); - + for (var channel in _selectedChannels) { final message = Message( text: text, attachments: [attachments[widget.currentPage]], ); - await c.sendMessage(message); + await channel.sendMessage(message); } - _selectedUsers.clear(); + _selectedChannels.clear(); Navigator.pop(context); } diff --git a/lib/src/user_avatar.dart b/lib/src/user_avatar.dart index 756252cc..e698d773 100644 --- a/lib/src/user_avatar.dart +++ b/lib/src/user_avatar.dart @@ -61,12 +61,15 @@ class UserAvatar extends StatelessWidget { : streamChatTheme.defaultUserImage(context, user), ), ); + if (selected) { avatar = ClipRRect( borderRadius: (borderRadius ?? streamChatTheme.ownMessageTheme.avatarTheme.borderRadius) + BorderRadius.circular(selectionThickness), child: Container( + constraints: constraints ?? + streamChatTheme.ownMessageTheme.avatarTheme.constraints, color: selectionColor, child: Padding( padding: EdgeInsets.all(selectionThickness), From 209c5a3c24766e9ee472870b98320c3e63753f6c Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Tue, 22 Dec 2020 21:45:14 +0530 Subject: [PATCH 0652/1140] Initial implementation Signed-off-by: Sahil Kumar --- example/lib/main.dart | 1 + lib/src/message_actions_modal.dart | 2 +- lib/src/message_list_view.dart | 34 +- lib/src/message_reactions_modal.dart | 2 +- lib/src/message_widget.dart | 535 +++++++++++++++------------ lib/src/reply_indicator.dart | 56 --- lib/src/stream_channel.dart | 13 + lib/src/stream_chat_theme.dart | 19 +- lib/src/utils.dart | 9 + lib/stream_chat_flutter.dart | 1 - 10 files changed, 359 insertions(+), 313 deletions(-) delete mode 100644 lib/src/reply_indicator.dart diff --git a/example/lib/main.dart b/example/lib/main.dart index f0f1e59b..803df8e6 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -470,6 +470,7 @@ class ThreadPage extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( + backgroundColor: Color.fromRGBO(252, 252, 252, 1), appBar: ThreadHeader( parent: parent, ), diff --git a/lib/src/message_actions_modal.dart b/lib/src/message_actions_modal.dart index 1967cd2b..f4cd47c8 100644 --- a/lib/src/message_actions_modal.dart +++ b/lib/src/message_actions_modal.dart @@ -113,7 +113,7 @@ class MessageActionsModal extends StatelessWidget { messageTheme: messageTheme, showReactions: false, showUsername: false, - showReplyIndicator: false, + showThreadReplyIndicator: false, showUserAvatar: showUserAvatar, showTimestamp: false, translateUserAvatar: false, diff --git a/lib/src/message_list_view.dart b/lib/src/message_list_view.dart index 5a850ad3..24d32d88 100644 --- a/lib/src/message_list_view.dart +++ b/lib/src/message_list_view.dart @@ -241,7 +241,7 @@ class _MessageListViewState extends State { builder: (context, snapshot) { if (!snapshot.hasData) { return Center( - child: CircularProgressIndicator(), + child: const CircularProgressIndicator(), ); } @@ -336,18 +336,25 @@ class _MessageListViewState extends State { crossAxisAlignment: CrossAxisAlignment.stretch, children: [ buildParentMessage(widget.parentMessage), - Padding( - padding: - const EdgeInsets.symmetric(horizontal: 32), - child: Container( - padding: const EdgeInsets.all(8), + Container( + decoration: BoxDecoration( + gradient: LinearGradient( + colors: [ + Color(0XFFF7F7F7), + Color(0XFFFCFCFC), + ], + ), + ), + child: Padding( + padding: const EdgeInsets.all(8.0), child: Text( - 'Start of thread', + '${widget.parentMessage.replyCount} ${widget.parentMessage.replyCount == 1 ? 'Reply' : 'Replies'}', textAlign: TextAlign.center, + style: StreamChatTheme.of(context) + .channelTheme + .channelHeaderTheme + .lastMessageAt, ), - color: Theme.of(context) - .accentColor - .withAlpha(50), ), ), ], @@ -585,7 +592,7 @@ class _MessageListViewState extends State { if (!snapshot.data) { if (direction == QueryDirection.top) { return Container( - height: 50, + height: 52, width: double.infinity, ); } @@ -679,7 +686,8 @@ class _MessageListViewState extends State { final isMyMessage = message.user.id == StreamChat.of(context).user.id; return MessageWidget( - showReplyIndicator: false, + showThreadReplyIndicator: false, + showInChannelIndicator: false, message: message, reverse: isMyMessage, showUsername: !isMyMessage, @@ -748,6 +756,8 @@ class _MessageListViewState extends State { bottom: index == 0 ? 30 : (isNextUser ? 2 : 7), top: 3, ), + showInChannelIndicator: widget.parentMessage == null, + showThreadReplyIndicator: widget.parentMessage == null, showUsername: !isMyMessage && !isNextUser, showSendingIndicator: isMyMessage && (index == 0 || message.status != MessageSendingStatus.SENT) diff --git a/lib/src/message_reactions_modal.dart b/lib/src/message_reactions_modal.dart index db5d8710..e5043e62 100644 --- a/lib/src/message_reactions_modal.dart +++ b/lib/src/message_reactions_modal.dart @@ -105,7 +105,7 @@ class MessageReactionsModal extends StatelessWidget { showReactions: false, showUsername: false, showUserAvatar: showUserAvatar, - showReplyIndicator: false, + showThreadReplyIndicator: false, showTimestamp: false, translateUserAvatar: false, showSendingIndicator: DisplayWidget.gone, diff --git a/lib/src/message_widget.dart b/lib/src/message_widget.dart index c7c6acdb..4fe84311 100644 --- a/lib/src/message_widget.dart +++ b/lib/src/message_widget.dart @@ -99,8 +99,11 @@ class MessageWidget extends StatefulWidget { final bool allRead; - /// If true the widget will show the reply indicator - final bool showReplyIndicator; + /// If true the widget will show the thread reply indicator + final bool showThreadReplyIndicator; + + /// If true the widget will show the show in channel indicator + final bool showInChannelIndicator; /// The function called when tapping on UserAvatar final void Function(User) onUserAvatarTap; @@ -123,6 +126,7 @@ class MessageWidget extends StatefulWidget { /// Center user avatar with bottom of the message final bool translateUserAvatar; + /// MessageWidget({ Key key, @required this.message, @@ -139,7 +143,8 @@ class MessageWidget extends StatefulWidget { this.showReactionPickerIndicator = false, this.showUserAvatar = DisplayWidget.show, this.showSendingIndicator = DisplayWidget.show, - this.showReplyIndicator = true, + this.showThreadReplyIndicator = true, + this.showInChannelIndicator = true, this.onThreadTap, this.showUsername = true, this.showTimestamp = true, @@ -211,10 +216,23 @@ class MessageWidget extends StatefulWidget { } class _MessageWidgetState extends State { + bool get showThreadReplyIndicator => + widget.showThreadReplyIndicator && widget.message.replyCount > 0; + + bool get showUsername => widget.showUsername; + + bool get showTimeStamp => + widget.message.createdAt != null && widget.showTimestamp; + + bool get showReadList => widget.readList?.isNotEmpty == true; + + bool get showInChannel => + widget.showInChannelIndicator && widget.message?.showInChannel == true; + @override Widget build(BuildContext context) { var leftPadding = widget.showUserAvatar != DisplayWidget.gone - ? widget.messageTheme.avatarTheme.constraints.maxWidth + 16.0 + ? widget.messageTheme.avatarTheme.constraints.maxWidth + 14.5 : 6.0; final hasFiles = @@ -234,140 +252,151 @@ class _MessageWidgetState extends State { crossAxisAlignment: CrossAxisAlignment.start, mainAxisSize: MainAxisSize.min, children: [ - Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisSize: MainAxisSize.min, - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.end, + Stack( + alignment: AlignmentDirectional.bottomStart, + children: [ + Column( + crossAxisAlignment: CrossAxisAlignment.start, mainAxisSize: MainAxisSize.min, - children: [ - if (widget.showUserAvatar == DisplayWidget.show) - _buildUserAvatar(), - SizedBox( - width: 6, - ), - if (widget.showUserAvatar == DisplayWidget.hide) - SizedBox( - width: widget.messageTheme.avatarTheme.constraints - .maxWidth + - 8, - ), - Flexible( - child: PortalEntry( - portal: Container( - transform: Matrix4.translationValues(-16, 2, 0), - child: _buildReactionIndicator(context), - constraints: BoxConstraints(maxWidth: 22 * 6.0), - ), - portalAnchor: Alignment(-1.0, -1.0), - childAnchor: Alignment(1, -1.0), - child: Stack( - clipBehavior: Clip.none, - children: [ - 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) - ? Transform( - alignment: Alignment.center, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.end, + mainAxisSize: MainAxisSize.min, + children: [ + if (widget.showUserAvatar == DisplayWidget.show) + _buildUserAvatar(), + SizedBox(width: 6), + if (widget.showUserAvatar == DisplayWidget.hide) + SizedBox( + width: widget.messageTheme.avatarTheme + .constraints.maxWidth + + 8, + ), + Flexible( + child: PortalEntry( + portal: Container( + transform: + Matrix4.translationValues(-16, 2, 0), + child: _buildReactionIndicator(context), + constraints: + BoxConstraints(maxWidth: 22 * 6.0), + ), + portalAnchor: Alignment(-1.0, -1.0), + childAnchor: Alignment(1, -1.0), + child: Stack( + clipBehavior: Clip.none, + children: [ + 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) + ? Transform( + alignment: Alignment.center, + transform: Matrix4.rotationY( + widget.reverse ? pi : 0), + child: DeletedMessage( + reverse: widget.reverse, + borderRadiusGeometry: + widget.borderRadiusGeometry, + borderSide: widget.borderSide, + shape: widget.shape, + messageTheme: + widget.messageTheme, + ), + ) + : Material( + clipBehavior: Clip.antiAlias, + shape: widget.shape ?? + RoundedRectangleBorder( + side: isOnlyEmoji + ? BorderSide.none + : widget.borderSide ?? + BorderSide( + color: Theme.of(context) + .brightness == + Brightness + .dark + ? Colors.white + .withAlpha( + 24) + : Colors.black + .withAlpha( + 24), + ), + borderRadius: widget + .borderRadiusGeometry ?? + BorderRadius.zero, + ), + color: _getBackgroundColor(), + child: Padding( + padding: EdgeInsets.all( + hasFiles ? 2.0 : 0.0), + child: Column( + crossAxisAlignment: + CrossAxisAlignment.start, + mainAxisSize: + MainAxisSize.min, + children: [ + ..._parseAttachments( + context), + if (widget.message.text + .trim() + .isNotEmpty && + !isGiphy) + _buildTextBubble(context), + ], + ), + ), + ), + ), + if (widget.showReactionPickerIndicator) + Positioned( + right: 0, + top: -6, + child: Transform( transform: Matrix4.rotationY( widget.reverse ? pi : 0), - child: DeletedMessage( - reverse: widget.reverse, - borderRadiusGeometry: - widget.borderRadiusGeometry, - borderSide: widget.borderSide, - shape: widget.shape, - messageTheme: widget.messageTheme, - ), - ) - : Material( - clipBehavior: Clip.antiAlias, - shape: widget.shape ?? - RoundedRectangleBorder( - side: isOnlyEmoji - ? BorderSide.none - : widget.borderSide ?? - BorderSide( - color: Theme.of(context) - .brightness == - Brightness - .dark - ? Colors.white - .withAlpha(24) - : Colors.black - .withAlpha( - 24), - ), - borderRadius: widget - .borderRadiusGeometry ?? - BorderRadius.zero, - ), - color: _getBackgroundColor(), - child: Padding( - padding: EdgeInsets.all( - hasFiles ? 2.0 : 0.0), - child: Column( - crossAxisAlignment: - CrossAxisAlignment.start, - mainAxisSize: MainAxisSize.min, - children: [ - ..._parseAttachments(context), - if (widget.message.text - .trim() - .isNotEmpty && - !isGiphy) - _buildTextBubble(context), - ], + child: CustomPaint( + painter: ReactionBubblePainter( + widget.messageTheme + .reactionsBackgroundColor, + widget.messageTheme + .reactionsBorderColor, ), ), ), - ), - if (widget.showReactionPickerIndicator) - Positioned( - right: 0, - top: -6, - child: Transform( - transform: Matrix4.rotationY( - widget.reverse ? pi : 0), - child: CustomPaint( - painter: ReactionBubblePainter( - widget.messageTheme - .reactionsBackgroundColor, - widget.messageTheme - .reactionsBorderColor, - ), ), - ), - ), - ], + ], + ), + ), ), - ), + ], ), + if (showThreadReplyIndicator || + showUsername || + showTimeStamp || + showInChannel) + SizedBox(height: 20.0), ], ), - if (widget.showReplyIndicator && - widget.message.replyCount > 0) - _buildReplyIndicator(leftPadding), + if (showThreadReplyIndicator || + showUsername || + showTimeStamp || + showInChannel) + _buildBottomRows(leftPadding) ], ), - if ((widget.message.createdAt != null && - widget.showTimestamp) || - widget.showUsername || - widget.readList?.isNotEmpty == true) - _buildBottomRow(leftPadding), ], ), ), @@ -376,6 +405,113 @@ class _MessageWidgetState extends State { ); } + Widget _buildBottomRows(double leftPadding) { + final deleted = widget.message.isDeleted; + var children = []; + if (deleted) { + children.add( + Row( + mainAxisSize: MainAxisSize.min, + children: [ + StreamSvgIcon.eye( + color: Colors.black.withOpacity(0.5), + size: 16.0, + ), + SizedBox(width: 8.0), + Text( + 'Only visible to you', + style: TextStyle( + color: Colors.black.withOpacity(0.5), + fontSize: 12.0, + ), + ), + ], + ), + ); + } else { + final showSendingIndicator = + widget.showSendingIndicator == DisplayWidget.show; + final replyCount = widget.message.replyCount; + final msg = showInChannel + ? 'Thread Reply' + : replyCount != 0 + ? '$replyCount ${replyCount > 1 ? 'Thread Replies' : 'Thread Reply'}' + : 'Thread Reply'; + + final onThreadTap = () async { + try { + var message = widget.message; + if (showInChannel && message.parentId != null) { + final channel = StreamChannel.of(context); + message = await channel.getMessage(widget.message.parentId); + } + return widget.onThreadTap(message); + } catch (e, stk) { + print(e); + print(stk); + return null; + } + }; + + children.addAll([ + if (showSendingIndicator) _buildSendingIndicator(), + if (showReadList) + SizedBox.fromSize( + size: Size((widget.readList.length * 10.0) + 10, 17), + child: Padding( + padding: const EdgeInsets.only(left: 4.0), + child: _buildReadIndicator(), + ), + ), + if (showThreadReplyIndicator || showInChannel) + InkWell( + onTap: widget.onThreadTap != null ? onThreadTap : null, + child: Text(msg, style: widget.messageTheme?.replies), + ), + if (showUsername) + Text( + widget.message.user.name, + style: widget.messageTheme.replies.copyWith( + color: widget.messageTheme.createdAt.color, + ), + ), + if (showTimeStamp) + Text( + Jiffy(widget.message.createdAt.toLocal()).jm, + style: widget.messageTheme.createdAt, + ), + ]); + } + if (widget.reverse) children = children.reversed.toList(); + + return Padding( + padding: EdgeInsets.only(left: leftPadding), + child: Row( + crossAxisAlignment: CrossAxisAlignment.end, + children: [ + if (!deleted && (showThreadReplyIndicator || showInChannel)) + Container( + margin: EdgeInsets.only( + bottom: widget.messageTheme.replies.fontSize / 2), + child: CustomPaint( + size: const Size(16, 32), + painter: _ThreadReplyPainter( + color: widget.messageTheme.replyThreadColor, + ), + ), + ), + ...children.map( + (child) => Transform( + transform: Matrix4.rotationY(widget.reverse ? pi : 0), + alignment: Alignment.center, + child: child, + ), + ), + ].insertBetween(const SizedBox(width: 8.0)), + ), + ); + } + Widget _buildUrlAttachment() { var urlAttachment = widget.message.attachments .firstWhere((element) => element.ogScrapeUrl != null); @@ -394,87 +530,6 @@ class _MessageWidgetState extends State { ); } - Padding _buildBottomRow(double leftPadding) { - return Padding( - padding: EdgeInsets.only( - left: leftPadding, - top: 2, - ), - child: Row( - mainAxisAlignment: MainAxisAlignment.start, - mainAxisSize: MainAxisSize.min, - children: [ - Transform( - alignment: Alignment.center, - transform: Matrix4.rotationY(widget.reverse ? pi : 0), - child: RichText( - text: TextSpan( - style: widget.messageTheme.createdAt, - children: [ - if (widget.showUsername) - TextSpan( - text: widget.message.user.name, - style: TextStyle( - fontWeight: FontWeight.bold, - color: widget.messageTheme.createdAt.color - .withOpacity(1)), - ), - if (widget.message.createdAt != null && widget.showTimestamp) - TextSpan( - text: Jiffy(widget.message.createdAt.toLocal()) - .format(' HH:mm'), - ), - ], - ), - ), - ), - if (widget.showSendingIndicator == DisplayWidget.show) - _buildSendingIndicator(), - if (widget.readList?.isNotEmpty == true) - SizedBox.fromSize( - size: Size((widget.readList.length * 10.0) + 10, 17), - child: Transform( - alignment: Alignment.center, - transform: Matrix4.rotationY(widget.reverse ? pi : 0), - child: Padding( - padding: const EdgeInsets.only(left: 4.0), - child: _buildReadIndicator(), - ), - ), - ), - if (widget.message.isDeleted) - Transform( - transform: Matrix4.rotationY(widget.reverse ? pi : 0), - alignment: Alignment.center, - child: Padding( - padding: - const EdgeInsets.symmetric(horizontal: 8.0, vertical: 4.0), - child: Row( - mainAxisSize: MainAxisSize.min, - children: [ - StreamSvgIcon.eye( - color: Colors.black.withOpacity(0.5), - size: 16.0, - ), - SizedBox( - width: 8.0, - ), - Text( - 'Only visible to you', - style: TextStyle( - color: Colors.black.withOpacity(0.5), - fontSize: 12.0, - ), - ), - ], - ), - ), - ), - ], - ), - ); - } - bool get isGiphy => widget.message.attachments?.any((element) => element.type == 'giphy') == true; @@ -565,7 +620,7 @@ class _MessageWidgetState extends State { true, showReactions: widget.showReactions, showReply: - widget.showReplyIndicator && widget.onThreadTap != null, + widget.showThreadReplyIndicator && widget.onThreadTap != null, ), ); }); @@ -715,38 +770,13 @@ class _MessageWidgetState extends State { return; } - Widget _buildReplyIndicator(double leftPadding) { - return Padding( - padding: EdgeInsets.only( - left: leftPadding, - ), - child: Transform( - transform: Matrix4.rotationY(widget.reverse ? pi : 0), - alignment: Alignment.center, - child: ReplyIndicator( - message: widget.message, - reversed: widget.reverse, - messageTheme: widget.messageTheme, - onTap: widget.onThreadTap != null - ? () { - widget.onThreadTap(widget.message); - } - : null, - ), - ), - ); - } - Widget _buildSendingIndicator() { - return Padding( - padding: const EdgeInsets.only(right: 4.0), - child: Transform( - transform: Matrix4.rotationY(widget.reverse ? pi : 0), - alignment: Alignment.center, - child: SendingIndicator( - message: widget.message, - allRead: widget.allRead, - ), + return Container( + height: widget.messageTheme.createdAt.fontSize + 2, + width: widget.messageTheme.createdAt.fontSize + 2, + child: SendingIndicator( + message: widget.message, + allRead: widget.allRead, ), ); } @@ -958,3 +988,32 @@ class _MessageWidgetState extends State { } } } + +class _ThreadReplyPainter extends CustomPainter { + final Color color; + + const _ThreadReplyPainter({@required this.color}); + + @override + void paint(Canvas canvas, Size size) { + final paint = Paint() + ..color = color ?? Color(0XFFDBDBDB) + ..style = PaintingStyle.stroke + ..strokeWidth = 1 + ..strokeCap = StrokeCap.round; + + final path = Path() + ..moveTo(0, 0) + ..quadraticBezierTo(0, size.height * 0.38, 0, size.height * 0.50) + ..quadraticBezierTo( + 0, + size.height, + size.width, + size.height, + ); + canvas.drawPath(path, paint); + } + + @override + bool shouldRepaint(covariant CustomPainter oldDelegate) => false; +} diff --git a/lib/src/reply_indicator.dart b/lib/src/reply_indicator.dart deleted file mode 100644 index cdb1cd57..00000000 --- a/lib/src/reply_indicator.dart +++ /dev/null @@ -1,56 +0,0 @@ -import 'dart:math'; - -import 'package:flutter/material.dart'; -import 'package:stream_chat/stream_chat.dart'; -import 'package:stream_chat_flutter/stream_chat_flutter.dart'; - -/// A reply button indicator -class ReplyIndicator extends StatelessWidget { - final Message message; - final VoidCallback onTap; - final bool reversed; - final MessageTheme messageTheme; - - const ReplyIndicator({ - Key key, - this.message, - this.onTap, - this.reversed = false, - this.messageTheme, - }) : super(key: key); - - @override - Widget build(BuildContext context) { - var row = [ - Text( - 'Replies: ${message.replyCount}', - style: messageTheme?.replies, - ), - Transform( - transform: Matrix4.rotationY(reversed ? 0 : pi), - alignment: Alignment.center, - child: Icon( - Icons.subdirectory_arrow_left, - color: Theme.of(context).brightness == Brightness.dark - ? Colors.white12 - : Colors.black12, - ), - ), - ]; - - if (!reversed) { - row = row.reversed.toList(); - } - - return GestureDetector( - onTap: onTap, - child: Padding( - padding: const EdgeInsets.symmetric(vertical: 2.0), - child: Row( - mainAxisSize: MainAxisSize.min, - children: row, - ), - ), - ); - } -} diff --git a/lib/src/stream_channel.dart b/lib/src/stream_channel.dart index 001d98ff..d5a4b030 100644 --- a/lib/src/stream_channel.dart +++ b/lib/src/stream_channel.dart @@ -267,6 +267,19 @@ class StreamChannelState extends State { return state; } + /// + Future getMessage(String messageId) async { + var message = channel.state.messages.firstWhere( + (it) => it.id == messageId, + orElse: () => null, + ); + if (message == null) { + final response = await channel.getMessagesById([messageId]); + message = response.messages.first; + } + return message; + } + /// Reloads the channel with latest message Future reloadChannel() => queryAtMessage(before: 30); diff --git a/lib/src/stream_chat_theme.dart b/lib/src/stream_chat_theme.dart index 54b096d1..a0f552c4 100644 --- a/lib/src/stream_chat_theme.dart +++ b/lib/src/stream_chat_theme.dart @@ -191,6 +191,8 @@ class StreamChatThemeData { this.ownMessageTheme.messageBackgroundColor, avatarTheme: ownMessageTheme?.avatarTheme ?? this.ownMessageTheme.avatarTheme, + replyThreadColor: ownMessageTheme?.replyThreadColor ?? + this.ownMessageTheme.replyThreadColor, ) ?? this.ownMessageTheme, otherMessageTheme: otherMessageTheme?.copyWith( @@ -209,6 +211,8 @@ class StreamChatThemeData { this.otherMessageTheme.messageBackgroundColor, avatarTheme: otherMessageTheme?.avatarTheme ?? this.otherMessageTheme.avatarTheme, + replyThreadColor: ownMessageTheme?.replyThreadColor ?? + this.ownMessageTheme.replyThreadColor, ) ?? this.otherMessageTheme, reactionIcons: reactionIcons ?? this.reactionIcons, @@ -297,16 +301,17 @@ class StreamChatThemeData { color: isDark ? Colors.white.withOpacity(.5) : Colors.black.withOpacity(.5), - fontSize: 11, + fontSize: 12, ), replies: TextStyle( color: accentColor, - fontWeight: FontWeight.bold, + fontWeight: FontWeight.w600, fontSize: 12, ), messageBackgroundColor: isDark ? Color(0xff191919) : Color(0xffEAEAEA), reactionsBackgroundColor: isDark ? Colors.black : Colors.white, reactionsBorderColor: isDark ? Color(0xff191919) : Color(0xffEAEAEA), + replyThreadColor: isDark ? Color(0xff191919) : Color(0xffEAEAEA), avatarTheme: AvatarTheme( borderRadius: BorderRadius.circular(20), constraints: BoxConstraints.tightFor( @@ -330,17 +335,19 @@ class StreamChatThemeData { color: isDark ? Colors.white.withOpacity(.5) : Colors.black.withOpacity(.5), - fontSize: 11, + fontSize: 12, ), replies: TextStyle( color: accentColor, - fontWeight: FontWeight.bold, + fontWeight: FontWeight.w600, fontSize: 12, ), messageLinks: TextStyle( color: accentColor, ), messageBackgroundColor: isDark ? Colors.black : Colors.white, + replyThreadColor: + isDark ? Colors.white.withAlpha(24) : Colors.black.withAlpha(24), avatarTheme: AvatarTheme( borderRadius: BorderRadius.circular(20), constraints: BoxConstraints.tightFor( @@ -455,6 +462,7 @@ class MessageTheme { final Color messageBackgroundColor; final Color reactionsBackgroundColor; final Color reactionsBorderColor; + final Color replyThreadColor; final AvatarTheme avatarTheme; const MessageTheme({ @@ -465,6 +473,7 @@ class MessageTheme { this.messageBackgroundColor, this.reactionsBackgroundColor, this.reactionsBorderColor, + this.replyThreadColor, this.avatarTheme, this.createdAt, }); @@ -479,6 +488,7 @@ class MessageTheme { AvatarTheme avatarTheme, Color reactionsBackgroundColor, Color reactionsBorderColor, + Color replyThreadColor, }) => MessageTheme( messageText: messageText ?? this.messageText, @@ -492,6 +502,7 @@ class MessageTheme { reactionsBackgroundColor: reactionsBackgroundColor ?? this.reactionsBackgroundColor, reactionsBorderColor: reactionsBorderColor ?? this.reactionsBorderColor, + replyThreadColor: replyThreadColor ?? this.replyThreadColor, ); } diff --git a/lib/src/utils.dart b/lib/src/utils.dart index 74b1da64..681a28aa 100644 --- a/lib/src/utils.dart +++ b/lib/src/utils.dart @@ -92,3 +92,12 @@ Future showConfirmationDialog( /// Get random png with initials String getRandomPicUrl(User user) => 'https://getstream.io/random_png/?id=${user.id}&name=${user.name}'; + +/// List extension +extension ListX on List { + /// Insert any item inBetween the list items + List insertBetween(T item) => expand((e) sync* { + yield item; + yield e; + }).skip(1).toList(growable: false); +} diff --git a/lib/stream_chat_flutter.dart b/lib/stream_chat_flutter.dart index 5dd46fa3..1cef26a6 100644 --- a/lib/stream_chat_flutter.dart +++ b/lib/stream_chat_flutter.dart @@ -21,7 +21,6 @@ export 'src/message_list_view.dart'; export 'src/message_text.dart'; export 'src/message_widget.dart'; export 'src/reaction_picker.dart'; -export 'src/reply_indicator.dart'; export 'src/sending_indicator.dart'; export 'src/stream_channel.dart'; export 'src/stream_chat.dart'; From 011b939c282596d6318934155cd05ce794d79fc0 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Wed, 23 Dec 2020 13:58:02 +0530 Subject: [PATCH 0653/1140] [Thread Header] Fix channelName overflow Signed-off-by: Sahil Kumar --- lib/src/thread_header.dart | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/lib/src/thread_header.dart b/lib/src/thread_header.dart index cfb6b1f1..8e165af7 100644 --- a/lib/src/thread_header.dart +++ b/lib/src/thread_header.dart @@ -112,11 +112,13 @@ class ThreadHeader extends StatelessWidget implements PreferredSizeWidget { .channelHeaderTheme .lastMessageAt, ), - ChannelName( - textStyle: StreamChatTheme.of(context) - .channelTheme - .channelHeaderTheme - .lastMessageAt, + Flexible( + child: ChannelName( + textStyle: StreamChatTheme.of(context) + .channelTheme + .channelHeaderTheme + .lastMessageAt, + ), ), ], ), From c2633cecb253fa0c8dfca5abf8f303d487925a7a Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Wed, 23 Dec 2020 14:02:18 +0530 Subject: [PATCH 0654/1140] fix typo Signed-off-by: Sahil Kumar --- lib/src/message_widget.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/src/message_widget.dart b/lib/src/message_widget.dart index 4fe84311..c52e7f63 100644 --- a/lib/src/message_widget.dart +++ b/lib/src/message_widget.dart @@ -394,7 +394,7 @@ class _MessageWidgetState extends State { showUsername || showTimeStamp || showInChannel) - _buildBottomRows(leftPadding) + _buildBottomRow(leftPadding) ], ), ], @@ -405,7 +405,7 @@ class _MessageWidgetState extends State { ); } - Widget _buildBottomRows(double leftPadding) { + Widget _buildBottomRow(double leftPadding) { final deleted = widget.message.isDeleted; var children = []; if (deleted) { From 538029a5de21f168820de12edd4bc754d5be19c8 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Wed, 23 Dec 2020 14:48:23 +0530 Subject: [PATCH 0655/1140] [Stream Channel] Fix getReplies Signed-off-by: Sahil Kumar --- lib/src/stream_channel.dart | 59 +++++++++++++++++++++++++++++-------- 1 file changed, 47 insertions(+), 12 deletions(-) diff --git a/lib/src/stream_channel.dart b/lib/src/stream_channel.dart index d5a4b030..be6cb4a5 100644 --- a/lib/src/stream_channel.dart +++ b/lib/src/stream_channel.dart @@ -134,6 +134,40 @@ class StreamChannelState extends State { return _queryBottomMessages(); } + //if (_queryMessageController.value == true || _paginationEnded) { + // return; + // } + // + // _queryMessageController.add(true); + // + // String firstId; + // if (widget.channel.state.threads.containsKey(parentId)) { + // final thread = widget.channel.state.threads[parentId]; + // + // if (thread != null && thread.isNotEmpty) { + // firstId = thread?.first?.id; + // } + // } + // + // final messageLimit = 50; + // return widget.channel + // .getReplies( + // parentId, + // PaginationParams( + // lessThan: firstId, + // limit: messageLimit, + // ), + // preferOffline: true, + // ) + // .then((res) { + // if (res.messages.isEmpty || res.messages.length < messageLimit) { + // _paginationEnded = true; + // } + // _queryMessageController.add(false); + // }).catchError((e, stack) { + // _queryMessageController.addError(e, stack); + // }); + /// Calls [channel.getReplies] updating [queryMessage] stream Future getReplies( String parentId, { @@ -143,23 +177,24 @@ class StreamChannelState extends State { if (_topPaginationEnded || _queryTopMessagesController.value) return; _queryTopMessagesController.add(true); - if (!channel.state.threads.containsKey(parentId)) { - return _queryTopMessagesController.add(false); + Message message; + if (channel.state.threads.containsKey(parentId)) { + final thread = channel.state.threads[parentId]; + if (thread.isNotEmpty) { + message = thread.first; + } } - final thread = channel.state.threads[parentId]; - - if (thread.isEmpty) return _queryTopMessagesController.add(false); - - final message = thread.first; - try { - final state = await queryBeforeMessage( - message.id, - limit: limit, + final response = await channel.getReplies( + parentId, + PaginationParams( + lessThan: message?.id, + limit: limit, + ), preferOffline: preferOffline, ); - if (state.messages.isEmpty || state.messages.length < limit) { + if (response.messages.isEmpty || response.messages.length < limit) { _topPaginationEnded = true; } _queryTopMessagesController.add(false); From 6b97879009eed22aa42474ced2f423cf3f4d8459 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Wed, 23 Dec 2020 14:53:34 +0530 Subject: [PATCH 0656/1140] cleanup Signed-off-by: Sahil Kumar --- lib/src/stream_channel.dart | 34 ---------------------------------- 1 file changed, 34 deletions(-) diff --git a/lib/src/stream_channel.dart b/lib/src/stream_channel.dart index be6cb4a5..8b4b97ef 100644 --- a/lib/src/stream_channel.dart +++ b/lib/src/stream_channel.dart @@ -134,40 +134,6 @@ class StreamChannelState extends State { return _queryBottomMessages(); } - //if (_queryMessageController.value == true || _paginationEnded) { - // return; - // } - // - // _queryMessageController.add(true); - // - // String firstId; - // if (widget.channel.state.threads.containsKey(parentId)) { - // final thread = widget.channel.state.threads[parentId]; - // - // if (thread != null && thread.isNotEmpty) { - // firstId = thread?.first?.id; - // } - // } - // - // final messageLimit = 50; - // return widget.channel - // .getReplies( - // parentId, - // PaginationParams( - // lessThan: firstId, - // limit: messageLimit, - // ), - // preferOffline: true, - // ) - // .then((res) { - // if (res.messages.isEmpty || res.messages.length < messageLimit) { - // _paginationEnded = true; - // } - // _queryMessageController.add(false); - // }).catchError((e, stack) { - // _queryMessageController.addError(e, stack); - // }); - /// Calls [channel.getReplies] updating [queryMessage] stream Future getReplies( String parentId, { From beea7e1c673686398fe4f1b31078a4b05be12073 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Wed, 23 Dec 2020 14:57:03 +0530 Subject: [PATCH 0657/1140] [Message Actions Modal] Hide showInChannel Indicator Signed-off-by: Sahil Kumar --- lib/src/message_actions_modal.dart | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/src/message_actions_modal.dart b/lib/src/message_actions_modal.dart index f4cd47c8..8013a8b3 100644 --- a/lib/src/message_actions_modal.dart +++ b/lib/src/message_actions_modal.dart @@ -118,6 +118,7 @@ class MessageActionsModal extends StatelessWidget { showTimestamp: false, translateUserAvatar: false, showReactionPickerIndicator: true, + showInChannelIndicator: false, showSendingIndicator: DisplayWidget.gone, shape: messageShape, ), From 7efb6ca3dd25d07d12ba2f09e12dae36796840f1 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Wed, 23 Dec 2020 15:13:17 +0530 Subject: [PATCH 0658/1140] [MessageListView] Change parentMessage gradient alignment Signed-off-by: Sahil Kumar --- lib/src/message_list_view.dart | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/src/message_list_view.dart b/lib/src/message_list_view.dart index 24d32d88..a856db2b 100644 --- a/lib/src/message_list_view.dart +++ b/lib/src/message_list_view.dart @@ -339,6 +339,8 @@ class _MessageListViewState extends State { Container( decoration: BoxDecoration( gradient: LinearGradient( + begin: Alignment.topCenter, + end: Alignment.bottomCenter, colors: [ Color(0XFFF7F7F7), Color(0XFFFCFCFC), From bb490849521ecaeba839486d883b938f2efc4b1b Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Wed, 23 Dec 2020 15:30:41 +0530 Subject: [PATCH 0659/1140] Hide timeStamp and sendingIndicator for a threaded reply message Signed-off-by: Sahil Kumar --- lib/src/message_widget.dart | 38 +++++++++++++++++++++---------------- 1 file changed, 22 insertions(+), 16 deletions(-) diff --git a/lib/src/message_widget.dart b/lib/src/message_widget.dart index c52e7f63..9d81d679 100644 --- a/lib/src/message_widget.dart +++ b/lib/src/message_widget.dart @@ -428,23 +428,11 @@ class _MessageWidgetState extends State { ], ), ); - } else { - final showSendingIndicator = - widget.showSendingIndicator == DisplayWidget.show; - final replyCount = widget.message.replyCount; - final msg = showInChannel - ? 'Thread Reply' - : replyCount != 0 - ? '$replyCount ${replyCount > 1 ? 'Thread Replies' : 'Thread Reply'}' - : 'Thread Reply'; - + } else if (showInChannel) { final onThreadTap = () async { try { - var message = widget.message; - if (showInChannel && message.parentId != null) { - final channel = StreamChannel.of(context); - message = await channel.getMessage(widget.message.parentId); - } + final channel = StreamChannel.of(context); + final message = await channel.getMessage(widget.message.parentId); return widget.onThreadTap(message); } catch (e, stk) { print(e); @@ -452,6 +440,24 @@ class _MessageWidgetState extends State { return null; } }; + children.add( + InkWell( + onTap: widget.onThreadTap != null ? onThreadTap : null, + child: Text('Thread Reply', style: widget.messageTheme?.replies), + ), + ); + } else { + final showSendingIndicator = + widget.showSendingIndicator == DisplayWidget.show; + final replyCount = widget.message.replyCount; + final msg = replyCount != 0 + ? '$replyCount ${replyCount > 1 ? 'Thread Replies' : 'Thread Reply'}' + : 'Thread Reply'; + + final onThreadTap = () async { + var message = widget.message; + return widget.onThreadTap(message); + }; children.addAll([ if (showSendingIndicator) _buildSendingIndicator(), @@ -463,7 +469,7 @@ class _MessageWidgetState extends State { child: _buildReadIndicator(), ), ), - if (showThreadReplyIndicator || showInChannel) + if (showThreadReplyIndicator) InkWell( onTap: widget.onThreadTap != null ? onThreadTap : null, child: Text(msg, style: widget.messageTheme?.replies), From d0a9ee7fae30e27ec2e134b35e94563aaad3d485 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Wed, 23 Dec 2020 16:53:04 +0530 Subject: [PATCH 0660/1140] fix: Corrected shimmer --- lib/src/channel_list_view.dart | 125 +++++++++++++++++++++------------ 1 file changed, 80 insertions(+), 45 deletions(-) diff --git a/lib/src/channel_list_view.dart b/lib/src/channel_list_view.dart index d5278f5e..66ec09f7 100644 --- a/lib/src/channel_list_view.dart +++ b/lib/src/channel_list_view.dart @@ -312,11 +312,13 @@ class _ChannelListViewState extends State children: List.generate( 25, (i) { - if (i % 2 != 0) { - if (widget.separatorBuilder != null) { - return widget.separatorBuilder(context, i); + if (widget.crossAxisCount == 1) { + if (i % 2 != 0) { + if (widget.separatorBuilder != null) { + return widget.separatorBuilder(context, i); + } + return _separatorBuilder(context, i); } - return _separatorBuilder(context, i); } return _buildLoadingItem(); }, @@ -325,63 +327,96 @@ class _ChannelListViewState extends State } Shimmer _buildLoadingItem() { - return Shimmer.fromColors( - baseColor: Color(0xffE5E5E5), - highlightColor: Color(0xffffffff), - child: ListTile( - leading: Container( - decoration: BoxDecoration( - color: Colors.white, - shape: BoxShape.circle, - ), - constraints: BoxConstraints.tightFor( - height: 40, - width: 40, - ), + if (widget.crossAxisCount > 1) { + return Shimmer.fromColors( + baseColor: Color(0xffE5E5E5), + highlightColor: Color(0xffffffff), + child: Column( + children: [ + SizedBox( + height: 4.0, + ), + Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + for (int i = 0; i < widget.crossAxisCount; i++) + Container( + decoration: BoxDecoration( + color: Colors.white, + shape: BoxShape.circle, + ), + constraints: BoxConstraints.tightFor( + height: 70, + width: 70, + ), + ), + ], + ), + SizedBox( + height: 16.0, + ), + ], ), - title: Align( - alignment: Alignment.centerLeft, - child: Container( + ); + } else { + return Shimmer.fromColors( + baseColor: Color(0xffE5E5E5), + highlightColor: Color(0xffffffff), + child: ListTile( + leading: Container( decoration: BoxDecoration( color: Colors.white, - borderRadius: BorderRadius.circular(11), + shape: BoxShape.circle, ), constraints: BoxConstraints.tightFor( - height: 16, - width: 82, + height: 40, + width: 40, ), ), - ), - subtitle: Row( - children: [ - Align( - alignment: Alignment.centerLeft, - child: Container( - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(11), - ), - constraints: BoxConstraints.tightFor( - height: 16, - width: 238, - ), - ), - ), - Container( - margin: const EdgeInsets.only(left: 16), + title: Align( + alignment: Alignment.centerLeft, + child: Container( decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(11), ), constraints: BoxConstraints.tightFor( height: 16, - width: 42, + width: 82, ), ), - ], + ), + subtitle: Row( + children: [ + Align( + alignment: Alignment.centerLeft, + child: Container( + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(11), + ), + constraints: BoxConstraints.tightFor( + height: 16, + width: 238, + ), + ), + ), + Container( + margin: const EdgeInsets.only(left: 16), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(11), + ), + constraints: BoxConstraints.tightFor( + height: 16, + width: 42, + ), + ), + ], + ), ), - ), - ); + ); + } } Widget _buildErrorWidget( From 109b1a4e30f7ccac066074da7ac98371f8c1941d Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Wed, 23 Dec 2020 17:45:55 +0530 Subject: [PATCH 0661/1140] minor fix Signed-off-by: Sahil Kumar --- lib/src/message_list_view.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/message_list_view.dart b/lib/src/message_list_view.dart index cce0cc36..cac699d9 100644 --- a/lib/src/message_list_view.dart +++ b/lib/src/message_list_view.dart @@ -411,7 +411,7 @@ class _MessageListViewState extends State { if (widget.messageBuilder != null) { messageWidget = Builder( key: ValueKey('MESSAGE-${message.id}'), - builder: (_) => widget.messageBuilder( + builder: (context) => widget.messageBuilder( context, MessageDetails( context, From 47dafef2aca8ff793601f20ccb3295e33921beef Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Wed, 23 Dec 2020 18:04:38 +0530 Subject: [PATCH 0662/1140] flutter format Signed-off-by: Sahil Kumar --- lib/src/extension.dart | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/src/extension.dart b/lib/src/extension.dart index 22fb326a..f49c574f 100644 --- a/lib/src/extension.dart +++ b/lib/src/extension.dart @@ -8,7 +8,7 @@ extension StringExtension on String { extension ListX on List { /// Insert any item inBetween the list items List insertBetween(T item) => expand((e) sync* { - yield item; - yield e; - }).skip(1).toList(growable: false); + yield item; + yield e; + }).skip(1).toList(growable: false); } From db7593b6223934bb16aa380c9b8a00e79ff52e59 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Wed, 23 Dec 2020 19:03:28 +0530 Subject: [PATCH 0663/1140] [Message Input] fix icons padding Signed-off-by: Sahil Kumar --- lib/src/message_input.dart | 151 ++++++++++++++++++------------------- 1 file changed, 72 insertions(+), 79 deletions(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 1a7dfa2c..5d6c16e8 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -248,7 +248,7 @@ class MessageInputState extends State { ], ), Padding( - padding: const EdgeInsets.symmetric(vertical: 8.0), + padding: const EdgeInsets.all(8.0), child: _buildTextField(context), ), if (widget.parentMessage != null) @@ -367,17 +367,23 @@ class MessageInputState extends State { return AnimatedCrossFade( crossFadeState: _actionsShrunk ? CrossFadeState.showFirst : CrossFadeState.showSecond, - firstChild: IconButton( - onPressed: () { - setState(() { - _actionsShrunk = false; - }); - }, - visualDensity: VisualDensity.compact, - splashRadius: 24, - padding: const EdgeInsets.all(0), - icon: StreamSvgIcon.emptyCircleLeft( - color: StreamChatTheme.of(context).accentColor, + firstChild: Padding( + padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 8), + child: IconButton( + onPressed: () { + setState(() { + _actionsShrunk = false; + }); + }, + icon: StreamSvgIcon.emptyCircleLeft( + color: StreamChatTheme.of(context).accentColor, + ), + padding: const EdgeInsets.all(0), + constraints: BoxConstraints.tightFor( + height: 24, + width: 24, + ), + splashRadius: 24, ), ), secondChild: Row( @@ -456,7 +462,7 @@ class MessageInputState extends State { StreamChatTheme.of(context).accentColor, padding: EdgeInsets.zero, labelPadding: - EdgeInsets.symmetric(horizontal: 9.0), + EdgeInsets.symmetric(horizontal: 8.0), label: Row( mainAxisSize: MainAxisSize.min, mainAxisAlignment: MainAxisAlignment.center, @@ -466,7 +472,7 @@ class MessageInputState extends State { size: 16.0, ), Text( - _chosenCommand?.name?.toUpperCase() ?? "", + _chosenCommand?.name?.toUpperCase() ?? '', style: TextStyle( color: Colors.white, fontSize: 12.0), ), @@ -478,17 +484,12 @@ class MessageInputState extends State { suffixIcon: _commandEnabled ? IconButton( icon: StreamSvgIcon.close_small(), + splashRadius: 24, onPressed: () { - setState(() { - _commandEnabled = false; - }); + setState(() => _commandEnabled = false); }, ) : null, - suffixIconConstraints: BoxConstraints( - maxHeight: 24.0, - maxWidth: 40.0, - ), ), textCapitalization: TextCapitalization.sentences, ), @@ -1548,7 +1549,7 @@ class MessageInputState extends State { Widget _buildCommandButton() { return Padding( - padding: const EdgeInsets.all(8.0), + padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 8), child: IconButton( icon: StreamSvgIcon.lightning( color: _commandsOverlay != null @@ -1588,42 +1589,38 @@ class MessageInputState extends State { } Widget _buildAttachmentButton() { - var padding = widget.editMessage == null ? 4.0 : 8.0; - return Center( - child: Padding( - padding: - EdgeInsets.only(left: 8.0, right: padding, top: 8.0, bottom: 8.0), - child: IconButton( - icon: StreamSvgIcon.attach( - color: _openFilePickerSection - ? StreamChatTheme.of(context).accentColor - : Color(0xFF000000).withAlpha(128), - ), - padding: const EdgeInsets.all(0), - constraints: BoxConstraints.tightFor( - height: 24, - width: 24, - ), - splashRadius: 24, - onPressed: () async { - _emojiOverlay?.remove(); - _emojiOverlay = null; - _commandsOverlay?.remove(); - _commandsOverlay = null; - _mentionsOverlay?.remove(); - _mentionsOverlay = null; - - if (_openFilePickerSection) { - setState(() { - _animateContainer = true; - _openFilePickerSection = false; - _filePickerSize = _kMinMediaPickerSize; - }); - } else { - showAttachmentModal(); - } - }, + return Padding( + padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 8), + child: IconButton( + icon: StreamSvgIcon.attach( + color: _openFilePickerSection + ? StreamChatTheme.of(context).accentColor + : Color(0xFF000000).withAlpha(128), ), + padding: const EdgeInsets.all(0), + constraints: BoxConstraints.tightFor( + height: 24, + width: 24, + ), + splashRadius: 24, + onPressed: () async { + _emojiOverlay?.remove(); + _emojiOverlay = null; + _commandsOverlay?.remove(); + _commandsOverlay = null; + _mentionsOverlay?.remove(); + _mentionsOverlay = null; + + if (_openFilePickerSection) { + setState(() { + _animateContainer = true; + _openFilePickerSection = false; + _filePickerSize = _kMinMediaPickerSize; + }); + } else { + showAttachmentModal(); + } + }, ), ); } @@ -1924,33 +1921,29 @@ class MessageInputState extends State { Widget _buildIdleSendButton(BuildContext context) { return Padding( - padding: const EdgeInsets.all(8.0), - child: Center( - child: StreamSvgIcon( - assetName: _getIdleSendIcon(), - color: Colors.grey, - ), + padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 8), + child: StreamSvgIcon( + assetName: _getIdleSendIcon(), + color: Colors.grey, ), ); } Widget _buildSendButton(BuildContext context) { - return Center( - child: Padding( - padding: const EdgeInsets.all(8.0), - child: IconButton( - onPressed: sendMessage, - visualDensity: VisualDensity.compact, - padding: const EdgeInsets.all(0), - splashRadius: 24, - constraints: BoxConstraints.tightFor( - height: 24, - width: 24, - ), - icon: StreamSvgIcon( - assetName: _getSendIcon(), - color: StreamChatTheme.of(context).accentColor, - ), + return Padding( + padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 8), + child: IconButton( + onPressed: sendMessage, + visualDensity: VisualDensity.compact, + padding: const EdgeInsets.all(0), + splashRadius: 24, + constraints: BoxConstraints.tightFor( + height: 24, + width: 24, + ), + icon: StreamSvgIcon( + assetName: _getSendIcon(), + color: StreamChatTheme.of(context).accentColor, ), ), ); From 25342266a06dc1eeaa404992eb732dd5705c4ed4 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Fri, 25 Dec 2020 23:36:16 +0530 Subject: [PATCH 0664/1140] fix: Corrected keyboard --- lib/src/image_footer.dart | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/lib/src/image_footer.dart b/lib/src/image_footer.dart index 79c1f501..b1496de3 100644 --- a/lib/src/image_footer.dart +++ b/lib/src/image_footer.dart @@ -64,6 +64,7 @@ class _ImageFooterState extends State { bool _userSearchMode = false; TextEditingController _searchController; TextEditingController _messageController = TextEditingController(); + FocusNode _messageFocusNode = FocusNode(); String _userNameQuery; bool _isSearchActive = false; @@ -91,6 +92,7 @@ class _ImageFooterState extends State { void initState() { super.initState(); _searchController = TextEditingController()..addListener(_userNameListener); + _messageFocusNode.addListener(() {setState(() {});}); } @override @@ -258,7 +260,7 @@ class _ImageFooterState extends State { ); } - Widget _buildShareModal(context) { + void _buildShareModal(context) { showDialog( context: context, builder: (context) { @@ -266,7 +268,7 @@ class _ImageFooterState extends State { modalSetStateCallback = modalSetState; return Padding( padding: EdgeInsets.only( - top: _userSearchMode + top: _userSearchMode || _messageFocusNode.hasFocus ? 16.0 : MediaQuery.of(context).size.height / 2, left: 8.0, @@ -278,7 +280,6 @@ class _ImageFooterState extends State { ), clipBehavior: Clip.antiAlias, child: Scaffold( - resizeToAvoidBottomInset: false, body: UsersBloc( child: Column( children: [ @@ -552,6 +553,7 @@ class _ImageFooterState extends State { padding: const EdgeInsets.only(left: 8.0), child: TextField( controller: _messageController, + focusNode: _messageFocusNode, onChanged: (val) { modalSetState(() {}); }, From 0f36fdcf4f89a821cc0964edbdf8418f8cefb455 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Fri, 25 Dec 2020 23:36:35 +0530 Subject: [PATCH 0665/1140] fmt --- lib/src/image_footer.dart | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/src/image_footer.dart b/lib/src/image_footer.dart index b1496de3..c071bb30 100644 --- a/lib/src/image_footer.dart +++ b/lib/src/image_footer.dart @@ -92,7 +92,9 @@ class _ImageFooterState extends State { void initState() { super.initState(); _searchController = TextEditingController()..addListener(_userNameListener); - _messageFocusNode.addListener(() {setState(() {});}); + _messageFocusNode.addListener(() { + setState(() {}); + }); } @override From b58d00a5f0a6c8107e4eda928df8445aec75f36c Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Mon, 28 Dec 2020 15:29:29 +0530 Subject: [PATCH 0666/1140] feat: Added text theme instead of hardcoded styles --- lib/src/date_divider.dart | 10 +++++----- lib/src/file_attachment.dart | 13 +++++-------- lib/src/giphy_attachment.dart | 17 ++++++++++------- lib/src/image_actions_modal.dart | 9 ++++----- lib/src/image_footer.dart | 19 ++++--------------- lib/src/image_header.dart | 6 +----- lib/src/message_input.dart | 17 ++++++++++------- lib/src/message_widget.dart | 8 ++++---- lib/src/url_attachment.dart | 26 ++++++++++++++------------ lib/src/utils.dart | 2 +- 10 files changed, 58 insertions(+), 69 deletions(-) diff --git a/lib/src/date_divider.dart b/lib/src/date_divider.dart index 8fbe5f77..3b8c36c1 100644 --- a/lib/src/date_divider.dart +++ b/lib/src/date_divider.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:jiffy/jiffy.dart'; +import 'package:stream_chat_flutter/src/stream_chat_theme.dart'; /// It shows a date divider depending on the date difference class DateDivider extends StatelessWidget { @@ -49,11 +50,10 @@ class DateDivider extends StatelessWidget { ), child: Text( dayInfo, - style: TextStyle( - fontSize: 12, - color: Colors.white, - fontWeight: FontWeight.bold, - ), + style: StreamChatTheme.of(context).textTheme.footnoteBold.copyWith( + color: Colors.white, + fontWeight: FontWeight.bold, + ), ), ), ); diff --git a/lib/src/file_attachment.dart b/lib/src/file_attachment.dart index 4bba7779..c5e6c92f 100644 --- a/lib/src/file_attachment.dart +++ b/lib/src/file_attachment.dart @@ -88,10 +88,7 @@ class _FileAttachmentState extends State { children: [ Text( widget.attachment?.title ?? 'File', - style: TextStyle( - fontWeight: FontWeight.bold, - fontSize: 14.0, - ), + style: StreamChatTheme.of(context).textTheme.bodyBold, maxLines: 1, overflow: TextOverflow.ellipsis, ), @@ -100,10 +97,10 @@ class _FileAttachmentState extends State { ), Text( '${_getSizeText(widget.attachment.extraData['file_size'])}', - style: TextStyle( - color: Colors.black.withOpacity(0.5), - fontSize: 14.0, - ), + style: StreamChatTheme.of(context) + .textTheme + .body + .copyWith(color: Colors.black.withOpacity(0.5)), ), ], ), diff --git a/lib/src/giphy_attachment.dart b/lib/src/giphy_attachment.dart index 3e29b2f1..74dfeeb4 100644 --- a/lib/src/giphy_attachment.dart +++ b/lib/src/giphy_attachment.dart @@ -220,9 +220,12 @@ class GiphyAttachment extends StatelessWidget { }, child: Text( 'Cancel', - style: TextStyle( - fontWeight: FontWeight.bold, - color: Colors.black.withOpacity(0.5)), + style: StreamChatTheme.of(context) + .textTheme + .bodyBold + .copyWith( + color: Colors.black.withOpacity(0.5), + ), ), ), ), @@ -271,10 +274,10 @@ class GiphyAttachment extends StatelessWidget { ), Text( 'Only visible to you', - style: TextStyle( - color: Colors.black.withOpacity(0.5), - fontSize: 12.0, - ), + style: StreamChatTheme.of(context) + .textTheme + .footnote + .copyWith(color: Colors.black.withOpacity(0.5)), ), ], ), diff --git a/lib/src/image_actions_modal.dart b/lib/src/image_actions_modal.dart index fc81635c..2b2aa05e 100644 --- a/lib/src/image_actions_modal.dart +++ b/lib/src/image_actions_modal.dart @@ -66,11 +66,10 @@ class ImageActionsModal extends StatelessWidget { padding: const EdgeInsets.only(top: 8.0), child: Text( userName, - style: TextStyle( - fontSize: 16.0, - fontWeight: FontWeight.w700, - color: Colors.white, - ), + style: StreamChatTheme.of(context) + .textTheme + .headlineBold + .copyWith(color: Colors.white), ), ), Text( diff --git a/lib/src/image_footer.dart b/lib/src/image_footer.dart index 3c37a66a..f16be87d 100644 --- a/lib/src/image_footer.dart +++ b/lib/src/image_footer.dart @@ -130,11 +130,7 @@ class _ImageFooterState extends State { children: [ Text( '${widget.currentPage + 1} of ${widget.totalPages}', - style: TextStyle( - fontSize: 16.0, - fontWeight: FontWeight.w700, - color: Colors.black, - ), + style: StreamChatTheme.of(context).textTheme.headlineBold, ), ], ), @@ -182,11 +178,8 @@ class _ImageFooterState extends State { padding: const EdgeInsets.all(16.0), child: Text( 'Photos', - style: TextStyle( - fontSize: 16.0, - fontWeight: FontWeight.w700, - color: Colors.black, - ), + style: + StreamChatTheme.of(context).textTheme.headlineBold, ), ), ), @@ -490,11 +483,7 @@ class _ImageFooterState extends State { padding: const EdgeInsets.all(16.0), child: Text( 'Select a Chat to Share', - style: TextStyle( - fontSize: 16.0, - fontWeight: FontWeight.w700, - color: Colors.black, - ), + style: StreamChatTheme.of(context).textTheme.headlineBold, ), ), Padding( diff --git a/lib/src/image_header.dart b/lib/src/image_header.dart index 62c3f8ec..aae73057 100644 --- a/lib/src/image_header.dart +++ b/lib/src/image_header.dart @@ -81,11 +81,7 @@ class ImageHeader extends StatelessWidget implements PreferredSizeWidget { children: [ Text( userName, - style: TextStyle( - fontSize: 16.0, - fontWeight: FontWeight.w700, - color: Colors.black, - ), + style: StreamChatTheme.of(context).textTheme.headlineBold, ), Text( sentAt, diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 8436d526..e0f290fc 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -423,8 +423,10 @@ class MessageInputState extends State { ), Text( _chosenCommand?.name?.toUpperCase() ?? "", - style: TextStyle( - color: Colors.white, fontSize: 12.0), + style: StreamChatTheme.of(context) + .textTheme + .footnote + .copyWith(color: Colors.white), ), ], ), @@ -899,11 +901,12 @@ class MessageInputState extends State { Center( child: Text( 'Allow access to your gallery', - style: TextStyle( - fontSize: 14, - fontWeight: FontWeight.bold, - color: StreamChatTheme.of(context).accentColor, - ), + style: StreamChatTheme.of(context) + .textTheme + .bodyBold + .copyWith( + color: StreamChatTheme.of(context).accentColor, + ), ), ), ], diff --git a/lib/src/message_widget.dart b/lib/src/message_widget.dart index 9d81d679..3eb52e45 100644 --- a/lib/src/message_widget.dart +++ b/lib/src/message_widget.dart @@ -420,10 +420,10 @@ class _MessageWidgetState extends State { SizedBox(width: 8.0), Text( 'Only visible to you', - style: TextStyle( - color: Colors.black.withOpacity(0.5), - fontSize: 12.0, - ), + style: StreamChatTheme.of(context) + .textTheme + .footnote + .copyWith(color: Colors.black.withOpacity(0.5)), ), ], ), diff --git a/lib/src/url_attachment.dart b/lib/src/url_attachment.dart index ad314455..5ecaa1cc 100644 --- a/lib/src/url_attachment.dart +++ b/lib/src/url_attachment.dart @@ -51,10 +51,12 @@ class UrlAttachment extends StatelessWidget { ), child: Text( hostDisplayName, - style: TextStyle( - fontWeight: FontWeight.w700, - color: Color(0xFF006CFF), - ), + style: StreamChatTheme.of(context) + .textTheme + .bodyBold + .copyWith( + color: Color(0xFF006CFF), + ), ), ), decoration: BoxDecoration( @@ -81,18 +83,18 @@ class UrlAttachment extends StatelessWidget { urlAttachment.title.trim(), maxLines: 1, overflow: TextOverflow.ellipsis, - style: TextStyle( - fontWeight: FontWeight.w700, - fontSize: 12.0, - ), + style: StreamChatTheme.of(context) + .textTheme + .body + .copyWith(fontWeight: FontWeight.w700), ), if (urlAttachment.text != null) Text( urlAttachment.text, - style: TextStyle( - fontWeight: FontWeight.w400, - fontSize: 12.0, - ), + style: StreamChatTheme.of(context) + .textTheme + .body + .copyWith(fontWeight: FontWeight.w400), ), ], ), diff --git a/lib/src/utils.dart b/lib/src/utils.dart index 681a28aa..60eca678 100644 --- a/lib/src/utils.dart +++ b/lib/src/utils.dart @@ -45,7 +45,7 @@ Future showConfirmationDialog( ), Text( title, - style: TextStyle(fontWeight: FontWeight.bold, fontSize: 16.0), + style: StreamChatTheme.of(context).textTheme.headlineBold, ), SizedBox( height: 7.0, From 46c9858bd447fe1db44eb05b7a2571e7ce04dce0 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Mon, 28 Dec 2020 19:08:50 +0530 Subject: [PATCH 0667/1140] [Message Input] Add reply_to_message_id in case of threadless reply Signed-off-by: Sahil Kumar --- lib/src/message_input.dart | 38 ++++++++++++++++++------------- lib/src/message_widget.dart | 19 +++++++--------- lib/src/reply_message_widget.dart | 4 ++-- pubspec.yaml | 3 ++- 4 files changed, 34 insertions(+), 30 deletions(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 5d6c16e8..38814c2a 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -110,7 +110,7 @@ class MessageInput extends StatefulWidget { this.actionsLocation = ActionsLocation.left, this.attachmentThumbnailBuilders, this.focusNode, - this.replyMessage, + this.replyToMessage, }) : super(key: key); /// Message to edit @@ -160,7 +160,7 @@ class MessageInput extends StatefulWidget { final FocusNode focusNode; /// - final Message replyMessage; + final Message replyToMessage; @override MessageInputState createState() => MessageInputState(); @@ -203,9 +203,9 @@ class MessageInputState extends State { /// The editing controller passed to the input TextField TextEditingController textEditingController; - Message _replyMessage; + Message _replyToMessage; - bool get _hasReplyMessage => _replyMessage != null; + bool get _hasReplyToMessage => _replyToMessage != null; @override Widget build(BuildContext context) { @@ -224,7 +224,7 @@ class MessageInputState extends State { child: Column( mainAxisSize: MainAxisSize.min, children: [ - if (_hasReplyMessage) + if (_hasReplyToMessage) Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ @@ -242,7 +242,7 @@ class MessageInputState extends State { visualDensity: VisualDensity.compact, icon: StreamSvgIcon.close_small(), onPressed: () { - setState(() => _replyMessage = null); + setState(() => _replyToMessage = null); }, ), ], @@ -417,7 +417,7 @@ class MessageInputState extends State { mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ - _buildRepyToMessage(), + _buildReplyToMessage(), _buildAttachments(), LimitedBox( maxHeight: widget.maxHeight, @@ -1321,20 +1321,20 @@ class MessageInputState extends State { _commandsOverlay = null; } - Widget _buildRepyToMessage() { - if (!_hasReplyMessage) { + Widget _buildReplyToMessage() { + if (!_hasReplyToMessage) { return Offstage(); } - final containsUrl = _replyMessage.attachments + final containsUrl = _replyToMessage.attachments ?.any((element) => element.ogScrapeUrl != null) == true; return Transform( transform: Matrix4.rotationY(pi), alignment: Alignment.center, - child: ReplyMessageWidget( + child: ReplyToMessageWidget( reverse: true, showBorder: !containsUrl, - message: _replyMessage, + message: _replyToMessage, messageTheme: StreamChatTheme.of(context).otherMessageTheme, ), ); @@ -1982,7 +1982,7 @@ class MessageInputState extends State { textEditingController.clear(); _attachments.clear(); - _replyMessage = null; + _replyToMessage = null; setState(() { _messageIsPresent = false; @@ -2014,6 +2014,12 @@ class MessageInputState extends State { ); } + if (widget.replyToMessage != null) { + message = message.copyWith( + replyToMessageId: widget.replyToMessage.id, + ); + } + if (widget.preMessageSending != null) { message = await widget.preMessageSending(message); } @@ -2057,7 +2063,7 @@ class MessageInputState extends State { void initState() { super.initState(); - _replyMessage = widget.replyMessage; + _replyToMessage = widget.replyToMessage; _focusNode = widget.focusNode ?? FocusNode(); @@ -2124,8 +2130,8 @@ class MessageInputState extends State { @override void didUpdateWidget(MessageInput oldWidget) { super.didUpdateWidget(oldWidget); - if (widget.replyMessage?.id != _replyMessage?.id) { - _replyMessage = widget.replyMessage; + if (widget.replyToMessage?.id != _replyToMessage?.id) { + _replyToMessage = widget.replyToMessage; } } } diff --git a/lib/src/message_widget.dart b/lib/src/message_widget.dart index 7ff4ff6e..affcc351 100644 --- a/lib/src/message_widget.dart +++ b/lib/src/message_widget.dart @@ -58,9 +58,6 @@ class MessageWidget extends StatefulWidget { /// The message final Message message; - /// The replyMessage - final Message replyMessage; - /// The message theme final MessageTheme messageTheme; @@ -140,7 +137,6 @@ class MessageWidget extends StatefulWidget { Key key, @required this.message, @required this.messageTheme, - this.replyMessage, this.reverse = false, this.translateUserAvatar = true, this.shape, @@ -241,7 +237,7 @@ class _MessageWidgetState extends State { bool get showInChannel => widget.showInChannelIndicator && widget.message?.showInChannel == true; - bool get _hasReplyMessage => widget.replyMessage != null; + bool get _hasReplyToMessage => widget.message?.replyToMessage != null; @override Widget build(BuildContext context) { @@ -352,7 +348,7 @@ class _MessageWidgetState extends State { shape: widget.shape ?? RoundedRectangleBorder( side: isOnlyEmoji && - !_hasReplyMessage + !_hasReplyToMessage ? BorderSide.none : widget.borderSide ?? BorderSide( @@ -383,10 +379,11 @@ class _MessageWidgetState extends State { mainAxisSize: MainAxisSize.min, children: [ - if (_hasReplyMessage) - ReplyMessageWidget( + if (_hasReplyToMessage) + ReplyToMessageWidget( message: widget - .replyMessage, + .message + .replyToMessage, messageTheme: isMyMessage ? StreamChatTheme.of( context) @@ -941,7 +938,7 @@ class _MessageWidgetState extends State { if (widget.message.attachments ?.any((element) => element.ogScrapeUrl != null) == true && - !_hasReplyMessage) + !_hasReplyToMessage) _buildUrlAttachment(), ], ), @@ -953,7 +950,7 @@ class _MessageWidgetState extends State { widget.message.text.characters.every((c) => Emoji.byChar(c) != null); Color _getBackgroundColor() { - if (_hasReplyMessage) { + if (_hasReplyToMessage) { return widget.messageTheme.messageBackgroundColor; } diff --git a/lib/src/reply_message_widget.dart b/lib/src/reply_message_widget.dart index 56f3112f..c335906b 100644 --- a/lib/src/reply_message_widget.dart +++ b/lib/src/reply_message_widget.dart @@ -63,7 +63,7 @@ class _VideoAttachmentThumbnailState extends State<_VideoAttachmentThumbnail> { } /// -class ReplyMessageWidget extends StatelessWidget { +class ReplyToMessageWidget extends StatelessWidget { /// The message final Message message; @@ -84,7 +84,7 @@ class ReplyMessageWidget extends StatelessWidget { attachmentThumbnailBuilders; /// - ReplyMessageWidget({ + ReplyToMessageWidget({ Key key, @required this.message, @required this.messageTheme, diff --git a/pubspec.yaml b/pubspec.yaml index 12374291..1c99b03b 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -28,7 +28,8 @@ dependencies: file_picker: ^2.0.12 image_picker: ^0.6.7+2 flutter_keyboard_visibility: ^3.3.0 - stream_chat: ^0.2.20 + stream_chat: + path: ../stream-chat-dart mime: ^0.9.6+3 video_compress: ^2.1.1 visibility_detector: ^0.1.5 From a27efad01bdb317a20a7448bf232472a9beb2135 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Mon, 28 Dec 2020 19:09:16 +0530 Subject: [PATCH 0668/1140] testing changes, remove them when pushed Signed-off-by: Sahil Kumar --- example/lib/choose_user_page.dart | 4 ++-- example/lib/main.dart | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/example/lib/choose_user_page.dart b/example/lib/choose_user_page.dart index a64013b9..22582be9 100644 --- a/example/lib/choose_user_page.dart +++ b/example/lib/choose_user_page.dart @@ -13,13 +13,13 @@ import 'routes/routes.dart'; const kStreamApiKey = 'STREAM_API_KEY'; const kStreamUserId = 'STREAM_USER_ID'; const kStreamToken = 'STREAM_TOKEN'; -const kDefaultStreamApiKey = 'uj7qrdbfrzvg'; +const kDefaultStreamApiKey = 'hg4yvnb2g6pu'; class ChooseUserPage extends StatelessWidget { @override Widget build(BuildContext context) { final users = { - 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoidmlzaGFsIn0.lCz-idDgaZ-xszjnuB_hTfeIOhTFmJtTB2fEjhwrcCI': + 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoidmlzaGFsIn0.va4qzf2KTQctOJfqdtzcdETAMKgazshuJnYJCPmmaKY': User( id: 'vishal', extraData: { diff --git a/example/lib/main.dart b/example/lib/main.dart index 0fec35e3..7ef4a7d7 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -24,6 +24,7 @@ void main() async { final client = Client( apiKey ?? kDefaultStreamApiKey, + baseURL: 'https://chat-proxy-oregon.stream-io-api.com', logLevel: Level.INFO, showLocalNotification: (!kIsWeb && Platform.isAndroid) ? showLocalNotification : null, @@ -477,7 +478,7 @@ class _ChannelPageState extends State { ), MessageInput( focusNode: _focusNode, - replyMessage: _replyMessage, + replyToMessage: _replyMessage, ), ], ), From 08d2b32eff29f4d22c10486c4471a40dc45d2db7 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Mon, 28 Dec 2020 19:24:42 +0530 Subject: [PATCH 0669/1140] feat: Added color themes --- example/lib/choose_user_page.dart | 7 ++- lib/src/channel_bottom_sheet.dart | 2 +- lib/src/channel_list_view.dart | 10 ++-- lib/src/message_input.dart | 9 ++-- lib/src/message_list_view.dart | 4 +- lib/src/message_widget.dart | 8 +-- lib/src/stream_chat_theme.dart | 89 +++++++++++++++++++++++++++++++ lib/src/url_attachment.dart | 2 +- 8 files changed, 116 insertions(+), 15 deletions(-) diff --git a/example/lib/choose_user_page.dart b/example/lib/choose_user_page.dart index 8d88cb1b..205f2581 100644 --- a/example/lib/choose_user_page.dart +++ b/example/lib/choose_user_page.dart @@ -171,7 +171,9 @@ class ChooseUserPage extends StatelessWidget { .textTheme .footnote .copyWith( - color: Color(0xff7A7A7A), + color: StreamChatTheme.of(context) + .colorTheme + .grey, ), ), trailing: SvgPicture.asset( @@ -202,7 +204,8 @@ class ChooseUserPage extends StatelessWidget { .textTheme .footnote .copyWith( - color: Color(0xff7A7A7A), + color: + StreamChatTheme.of(context).colorTheme.grey, ), ), trailing: SvgPicture.asset( diff --git a/lib/src/channel_bottom_sheet.dart b/lib/src/channel_bottom_sheet.dart index 2d16bf6d..8e65c24d 100644 --- a/lib/src/channel_bottom_sheet.dart +++ b/lib/src/channel_bottom_sheet.dart @@ -73,7 +73,7 @@ class ChannelBottomSheet extends StatelessWidget { ListTile( leading: StreamSvgIcon.userRemove( size: 24, - color: Color(0xff7A7A7A), + color: StreamChatTheme.of(context).colorTheme.grey, ), title: Text( 'Leave Group', diff --git a/lib/src/channel_list_view.dart b/lib/src/channel_list_view.dart index b18fb39c..c04f80ed 100644 --- a/lib/src/channel_list_view.dart +++ b/lib/src/channel_list_view.dart @@ -203,7 +203,9 @@ class _ChannelListViewState extends State padding: const EdgeInsets.all(8.0), child: StreamSvgIcon.message( size: 136, - color: Color(0xffDBDBDB), + color: StreamChatTheme.of(context) + .colorTheme + .greyGainsboro, ), ), Padding( @@ -227,7 +229,9 @@ class _ChannelListViewState extends State .textTheme .body .copyWith( - color: Color(0xff7A7A7A), + color: StreamChatTheme.of(context) + .colorTheme + .grey, ), ), ), @@ -311,7 +315,7 @@ class _ChannelListViewState extends State Shimmer _buildLoadingItem() { return Shimmer.fromColors( baseColor: Color(0xffE5E5E5), - highlightColor: Color(0xffffffff), + highlightColor: StreamChatTheme.of(context).colorTheme.white, child: ListTile( leading: Container( decoration: BoxDecoration( diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index e0f290fc..79189d1d 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -724,7 +724,7 @@ class MessageInputState extends State { duration: _animateContainer ? Duration(milliseconds: 300) : Duration.zero, height: _openFilePickerSection ? _filePickerSize : 0, child: Material( - color: Color(0xFFF2F2F2), + color: StreamChatTheme.of(context).colorTheme.whiteSmoke, child: Column( children: [ Row( @@ -806,7 +806,8 @@ class MessageInputState extends State { width: 40.0, height: 4.0, decoration: BoxDecoration( - color: Color(0xFFF2F2F2), + color: + StreamChatTheme.of(context).colorTheme.whiteSmoke, borderRadius: BorderRadius.circular(4.0), ), ), @@ -854,7 +855,7 @@ class MessageInputState extends State { }, child: Container( constraints: BoxConstraints.expand(), - color: Color(0xfff2f2f2), + color: StreamChatTheme.of(context).colorTheme.whiteSmoke, child: Text( 'Add more files', style: TextStyle( @@ -887,7 +888,7 @@ class MessageInputState extends State { PhotoManager.openSetting(); }, child: Container( - color: Color(0xFFF2F2F2), + color: StreamChatTheme.of(context).colorTheme.whiteSmoke, child: Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.stretch, diff --git a/lib/src/message_list_view.dart b/lib/src/message_list_view.dart index d0743027..7452fd6d 100644 --- a/lib/src/message_list_view.dart +++ b/lib/src/message_list_view.dart @@ -342,7 +342,9 @@ class _MessageListViewState extends State { end: Alignment.bottomCenter, colors: [ Color(0XFFF7F7F7), - Color(0XFFFCFCFC), + StreamChatTheme.of(context) + .colorTheme + .whiteSmoke, ], ), ), diff --git a/lib/src/message_widget.dart b/lib/src/message_widget.dart index 3eb52e45..f3e5b108 100644 --- a/lib/src/message_widget.dart +++ b/lib/src/message_widget.dart @@ -502,6 +502,7 @@ class _MessageWidgetState extends State { child: CustomPaint( size: const Size(16, 32), painter: _ThreadReplyPainter( + context: context, color: widget.messageTheme.replyThreadColor, ), ), @@ -916,7 +917,7 @@ class _MessageWidgetState extends State { if (widget.message.attachments ?.any((element) => element.ogScrapeUrl != null) == true) { - return Color(0xFFE9F2FF); + return StreamChatTheme.of(context).colorTheme.blueAlice; } if (isOnlyEmoji) { @@ -997,13 +998,14 @@ class _MessageWidgetState extends State { class _ThreadReplyPainter extends CustomPainter { final Color color; + final BuildContext context; - const _ThreadReplyPainter({@required this.color}); + const _ThreadReplyPainter({this.context, @required this.color}); @override void paint(Canvas canvas, Size size) { final paint = Paint() - ..color = color ?? Color(0XFFDBDBDB) + ..color = color ?? StreamChatTheme.of(context).colorTheme.greyGainsboro ..style = PaintingStyle.stroke ..strokeWidth = 1 ..strokeCap = StrokeCap.round; diff --git a/lib/src/stream_chat_theme.dart b/lib/src/stream_chat_theme.dart index 4739f122..d4237270 100644 --- a/lib/src/stream_chat_theme.dart +++ b/lib/src/stream_chat_theme.dart @@ -45,6 +45,9 @@ class StreamChatThemeData { /// The text themes used in the widgets final TextTheme textTheme; + /// The text themes used in the widgets + final ColorTheme colorTheme; + /// Primary color of the chat widgets final Color primaryColor; @@ -84,6 +87,7 @@ class StreamChatThemeData { /// Create a theme from scratch StreamChatThemeData({ this.textTheme, + this.colorTheme, this.primaryColor, this.secondaryColor, this.accentColor, @@ -136,6 +140,7 @@ class StreamChatThemeData { /// Creates a copy of [StreamChatThemeData] with specified attributes overridden. StreamChatThemeData copyWith({ TextTheme textTheme, + ColorTheme colorTheme, Color primaryColor, Color secondaryColor, Color accentColor, @@ -160,6 +165,16 @@ class StreamChatThemeData { headline: textTheme?.headline, headlineBold: textTheme?.headlineBold, ), + colorTheme: this.colorTheme?.copyWith( + black: colorTheme?.black, + grey: colorTheme?.grey, + greyGainsboro: colorTheme?.greyGainsboro, + greyWhisper: colorTheme?.greyWhisper, + whiteSmoke: colorTheme?.whiteSmoke, + whiteSnow: colorTheme?.whiteSnow, + white: colorTheme?.white, + blueAlice: colorTheme?.blueAlice, + ), primaryColor: primaryColor ?? this.primaryColor, secondaryColor: secondaryColor ?? this.secondaryColor, primaryIconTheme: primaryIconTheme ?? this.primaryIconTheme, @@ -233,8 +248,10 @@ class StreamChatThemeData { final accentColor = Color(0xff006cff); final isDark = theme.brightness == Brightness.dark; final textTheme = TextTheme(); + final colorTheme = isDark ? ColorTheme.dark() : ColorTheme.light(); return StreamChatThemeData( textTheme: textTheme, + colorTheme: colorTheme, secondaryColor: Color(0xffEAEAEA), accentColor: accentColor, primaryColor: isDark ? Colors.black : Colors.white, @@ -454,6 +471,78 @@ class TextTheme { } } +enum ColorThemeType { + light, + dark, +} + +class ColorTheme { + final Color black; + final Color grey; + final Color greyGainsboro; + final Color greyWhisper; + final Color whiteSmoke; + final Color whiteSnow; + final Color white; + final Color blueAlice; + + ColorTheme.light({ + this.black = const Color(0xff000000), + this.grey = const Color(0xff7a7a7a), + this.greyGainsboro = const Color(0xffdbdbdb), + this.greyWhisper = const Color(0xffecebeb), + this.whiteSmoke = const Color(0xfff2f2f2), + this.whiteSnow = const Color(0xfffcfcfc), + this.white = const Color(0xffffffff), + this.blueAlice = const Color(0xffe9f2ff), + }); + + ColorTheme.dark({ + this.black = const Color(0xffffffff), + this.grey = const Color(0xff7a7a7a), + this.greyGainsboro = const Color(0xff2d2f2f), + this.greyWhisper = const Color(0xff1c1e22), + this.whiteSmoke = const Color(0xff13151b), + this.whiteSnow = const Color(0xff070A0D), + this.white = const Color(0xff101418), + this.blueAlice = const Color(0xff00193D), + }); + + ColorTheme copyWith({ + ColorThemeType type = ColorThemeType.light, + Color black, + Color grey, + Color greyGainsboro, + Color greyWhisper, + Color whiteSmoke, + Color whiteSnow, + Color white, + Color blueAlice, + }) { + return type == ColorThemeType.light + ? ColorTheme.light( + black: black ?? this.black, + grey: grey ?? this.grey, + greyGainsboro: greyGainsboro ?? this.greyGainsboro, + greyWhisper: greyWhisper ?? this.greyWhisper, + whiteSmoke: whiteSmoke ?? this.whiteSmoke, + whiteSnow: whiteSnow ?? this.whiteSnow, + white: white ?? this.white, + blueAlice: blueAlice ?? this.blueAlice, + ) + : ColorTheme.dark( + black: black ?? this.black, + grey: grey ?? this.grey, + greyGainsboro: greyGainsboro ?? this.greyGainsboro, + greyWhisper: greyWhisper ?? this.greyWhisper, + whiteSmoke: whiteSmoke ?? this.whiteSmoke, + whiteSnow: whiteSnow ?? this.whiteSnow, + white: white ?? this.white, + blueAlice: blueAlice ?? this.blueAlice, + ); + } +} + /// Channel theme data class ChannelTheme { /// Theme of the [ChannelHeader] widget diff --git a/lib/src/url_attachment.dart b/lib/src/url_attachment.dart index 5ecaa1cc..c655880d 100644 --- a/lib/src/url_attachment.dart +++ b/lib/src/url_attachment.dart @@ -63,7 +63,7 @@ class UrlAttachment extends StatelessWidget { borderRadius: BorderRadius.only( topRight: Radius.circular(16.0), ), - color: Color(0xFFE9F2FF), + color: StreamChatTheme.of(context).colorTheme.blueAlice, ), ), ), From c416d20cb63923fcf632f62929adde7a35774c6f Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Mon, 28 Dec 2020 22:14:43 +0530 Subject: [PATCH 0670/1140] Add mention screen Signed-off-by: Sahil Kumar --- example/lib/main.dart | 98 +++++++++++++++++++++++++++++++++- lib/src/message_list_view.dart | 13 +++-- 2 files changed, 105 insertions(+), 6 deletions(-) diff --git a/example/lib/main.dart b/example/lib/main.dart index 803df8e6..f43f5f8f 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -250,8 +250,71 @@ class _HomePageState extends State { class UserMentionPage extends StatelessWidget { @override Widget build(BuildContext context) { - return Center( - child: Text('On Pause Right Now!'), + final user = StreamChat.of(context).user; + return MessageSearchBloc( + child: MessageSearchListView( + messageQuery: '@${user.name}', + filters: { + 'members': { + r'$in': [user.id] + } + }, + sortOptions: [ + SortOption( + 'created_at', + direction: SortOption.ASC, + ), + ], + paginationParams: PaginationParams(limit: 20), + showResultCount: false, + emptyBuilder: (_, __) { + return LayoutBuilder( + builder: (context, viewportConstraints) { + return SingleChildScrollView( + physics: AlwaysScrollableScrollPhysics(), + child: ConstrainedBox( + constraints: BoxConstraints( + minHeight: viewportConstraints.maxHeight, + ), + child: Center( + child: Column( + children: [ + Padding( + padding: const EdgeInsets.all(24), + child: StreamSvgIcon.mentions( + size: 96, + color: Colors.grey, + ), + ), + Text('No mentions exist yet...'), + ], + ), + ), + ), + ); + }, + ); + }, + onItemTap: (messageResponse) async { + final client = StreamChat.of(context).client; + final message = messageResponse.message; + final channel = client.channel( + messageResponse.channel.type, + id: messageResponse.channel.id, + ); + if (channel.state == null) { + await channel.watch(); + } + Navigator.pushNamed( + context, + Routes.CHANNEL_PAGE, + arguments: ChannelPageArgs( + channel: channel, + initialMessage: message, + ), + ); + }, + ), ); } } @@ -336,6 +399,37 @@ class _ChannelListPageState extends State { ), ], paginationParams: PaginationParams(limit: 20), + emptyBuilder: (_, query) { + return LayoutBuilder( + builder: (context, viewportConstraints) { + return SingleChildScrollView( + physics: AlwaysScrollableScrollPhysics(), + child: ConstrainedBox( + constraints: BoxConstraints( + minHeight: + viewportConstraints.maxHeight, + ), + child: Center( + child: Column( + children: [ + Padding( + padding: const EdgeInsets.all(24), + child: StreamSvgIcon.search( + size: 96, + color: Colors.grey, + ), + ), + Text( + 'No results for \"$query\"...', + ), + ], + ), + ), + ), + ); + }, + ); + }, onItemTap: (messageResponse) async { final client = StreamChat.of(context).client; final message = messageResponse.message; diff --git a/lib/src/message_list_view.dart b/lib/src/message_list_view.dart index a856db2b..cd1d09e0 100644 --- a/lib/src/message_list_view.dart +++ b/lib/src/message_list_view.dart @@ -116,6 +116,7 @@ class MessageListView extends StatefulWidget { this.scrollController, this.itemPositionListener, this.highlightInitialMessage = false, + this.highlightColor = const Color(0XFFFBF4DD), }) : super(key: key); /// Function used to build a custom message widget @@ -162,6 +163,11 @@ class MessageListView extends StatefulWidget { /// Also See [StreamChannel] final bool highlightInitialMessage; + /// The color used for highlighting the initialMessage if there is any. + /// + /// Also See [highlightInitialMessage] + final Color highlightColor; + @override _MessageListViewState createState() => _MessageListViewState(); } @@ -796,13 +802,12 @@ class _MessageListViewState extends State { if (!initialMessageHighlightComplete && widget.highlightInitialMessage && _isInitialMessage(message.id)) { - final accentColor = Theme.of(context).accentColor; child = TweenAnimationBuilder( tween: ColorTween( - begin: accentColor.withOpacity(0.7), - end: Colors.transparent, + begin: widget.highlightColor, + end: Colors.white10, ), - duration: const Duration(seconds: 2), + duration: const Duration(seconds: 3), child: child, onEnd: () { initialMessageHighlightComplete = true; From 38d3140ab10c49327b591578a5673ba6eb5bdb6e Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Mon, 28 Dec 2020 23:30:35 +0530 Subject: [PATCH 0671/1140] [ChannelListView] Convert listView.custom into listView.separated Signed-off-by: Sahil Kumar --- lib/src/channel_list_view.dart | 38 ++++++++++++---------------------- 1 file changed, 13 insertions(+), 25 deletions(-) diff --git a/lib/src/channel_list_view.dart b/lib/src/channel_list_view.dart index 66ec09f7..5efa1e29 100644 --- a/lib/src/channel_list_view.dart +++ b/lib/src/channel_list_view.dart @@ -278,21 +278,19 @@ class _ChannelListViewState extends State }, ); } else { - child = ListView.custom( + child = ListView.separated( physics: AlwaysScrollableScrollPhysics(), - controller: _scrollController, - childrenDelegate: SliverChildBuilderDelegate( - (context, i) { - return _itemBuilder(context, i, channels); - }, - childCount: (channels.length * 2) + 1, - findChildIndexCallback: (key) { - final ValueKey valueKey = key; - final index = channels.indexWhere( - (channel) => 'CHANNEL-${channel.id}' == valueKey.value); - return index != -1 ? (index * 2) : null; - }, - ), + itemCount: + channels.isNotEmpty ? channels.length + 1 : channels.length, + separatorBuilder: (_, index) { + if (widget.separatorBuilder != null) { + return widget.separatorBuilder(context, index); + } + return _separatorBuilder(context, index); + }, + itemBuilder: (context, index) { + return _listItemBuilder(context, index, channels); + }, ); } } @@ -483,20 +481,10 @@ class _ChannelListViewState extends State ); } - Widget _itemBuilder(context, int i, List channels) { - if (i % 2 != 0) { - if (widget.separatorBuilder != null) { - return widget.separatorBuilder(context, i); - } - return _separatorBuilder(context, i); - } - - i = i ~/ 2; - + Widget _listItemBuilder(BuildContext context, int i, List channels) { final channelsProvider = ChannelsBloc.of(context); if (i < channels.length) { final channel = channels[i]; - ChannelTapCallback onTap; if (widget.onChannelTap != null) { onTap = widget.onChannelTap; From 38e3d541bbd410b492cb4e9e4e07bc7f035f7e06 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Mon, 28 Dec 2020 23:31:02 +0530 Subject: [PATCH 0672/1140] [Channel Image] Fix selection state Signed-off-by: Sahil Kumar --- lib/src/channel_image.dart | 41 ++++++++++++++++++++++++++++++++------ 1 file changed, 35 insertions(+), 6 deletions(-) diff --git a/lib/src/channel_image.dart b/lib/src/channel_image.dart index d79b2efa..ad3e930a 100644 --- a/lib/src/channel_image.dart +++ b/lib/src/channel_image.dart @@ -53,6 +53,8 @@ class ChannelImage extends StatelessWidget { this.showOnlineStatus = true, this.borderRadius, this.selected = false, + this.selectionColor = const Color(0xFF006CFF), + this.selectionThickness = 4, }) : super(key: key); final BorderRadius borderRadius; @@ -70,6 +72,10 @@ class ChannelImage extends StatelessWidget { final bool selected; + final Color selectionColor; + + final double selectionThickness; + @override Widget build(BuildContext context) { final streamChat = StreamChat.of(context); @@ -97,12 +103,10 @@ class ChannelImage extends StatelessWidget { .channelPreviewTheme .avatarTheme .constraints, - onTap: onTap != null - ? (_) { - onTap(); - } - : null, + onTap: onTap != null ? (_) => onTap() : null, selected: selected, + selectionColor: selectionColor, + selectionThickness: selectionThickness, ); }); } else { @@ -123,10 +127,12 @@ class ChannelImage extends StatelessWidget { .constraints, onTap: onTap, selected: selected, + selectionColor: selectionColor, + selectionThickness: selectionThickness, ); } - return ClipRRect( + Widget child = ClipRRect( borderRadius: borderRadius ?? StreamChatTheme.of(context) .channelPreviewTheme @@ -175,6 +181,29 @@ class ChannelImage extends StatelessWidget { ), ), ); + if (selected) { + child = ClipRRect( + borderRadius: (borderRadius ?? + StreamChatTheme.of(context) + .ownMessageTheme + .avatarTheme + .borderRadius) + + BorderRadius.circular(selectionThickness), + child: Container( + constraints: constraints ?? + StreamChatTheme.of(context) + .ownMessageTheme + .avatarTheme + .constraints, + color: selectionColor, + child: Padding( + padding: EdgeInsets.all(selectionThickness), + child: child, + ), + ), + ); + } + return child; }); } } From 27a83e77918279ee4d2f26c8b9c6a68842e69421 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Mon, 28 Dec 2020 23:32:57 +0530 Subject: [PATCH 0673/1140] Minor refactoring Signed-off-by: Sahil Kumar --- lib/src/image_footer.dart | 22 ++++++++-------------- 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/lib/src/image_footer.dart b/lib/src/image_footer.dart index c071bb30..00b38a90 100644 --- a/lib/src/image_footer.dart +++ b/lib/src/image_footer.dart @@ -16,8 +16,6 @@ import 'package:stream_chat_flutter/src/stream_chat.dart'; import 'package:stream_chat_flutter/src/stream_chat_theme.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; -import 'stream_channel.dart'; - class ImageFooter extends StatefulWidget { /// Callback to call when pressing the back button. /// By default it calls [Navigator.pop] @@ -66,8 +64,7 @@ class _ImageFooterState extends State { TextEditingController _messageController = TextEditingController(); FocusNode _messageFocusNode = FocusNode(); - String _userNameQuery; - bool _isSearchActive = false; + String _channelNameQuery; List _selectedChannels = []; bool _loading = false; @@ -81,8 +78,7 @@ class _ImageFooterState extends State { _debounce = Timer(const Duration(milliseconds: 350), () { if (mounted && modalSetStateCallback != null) { modalSetStateCallback(() { - _userNameQuery = _searchController.text; - _isSearchActive = _userNameQuery.isNotEmpty; + _channelNameQuery = _searchController.text; }); } }); @@ -294,15 +290,15 @@ class _ImageFooterState extends State { child: ChannelsBloc( child: ChannelListView( selectedChannels: _selectedChannels, - onChannelTap: (user, _) { + onChannelTap: (channel, _) { _searchController.clear(); - if (!_selectedChannels.contains(user)) { + if (!_selectedChannels.contains(channel)) { modalSetState(() { - _selectedChannels.add(user); + _selectedChannels.add(channel); }); } else { modalSetState(() { - _selectedChannels.remove(user); + _selectedChannels.remove(channel); }); } }, @@ -313,7 +309,7 @@ class _ImageFooterState extends State { filter: { if (_searchController.text.isNotEmpty) 'name': { - r'$autocomplete': _userNameQuery, + r'$autocomplete': _channelNameQuery, }, 'id': { r'$ne': StreamChat.of(context).user.id, @@ -346,7 +342,7 @@ class _ImageFooterState extends State { ), ), Text( - 'No user matches these keywords...'), + 'No chat matches these keywords...'), ], ), ), @@ -624,8 +620,6 @@ class _ImageFooterState extends State { _messageController.clear(); - final client = StreamChat.of(context).client; - for (var channel in _selectedChannels) { final message = Message( text: text, From 9c53a295ae8ea7aca5ff0a3c40ed1a50c68bddf4 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Tue, 29 Dec 2020 18:53:05 +0530 Subject: [PATCH 0674/1140] fixes for review --- example/lib/chat_info_screen.dart | 2 +- example/lib/group_info_screen.dart | 4 +-- lib/src/channel_file_display_screen.dart | 31 ++++++++++++++++- lib/src/channel_media_display_screen.dart | 41 ++++++++++++++++++++--- lib/src/stream_svg_icon.dart | 12 +++++++ lib/svgs/Icon_user_settings.svg | 5 +++ 6 files changed, 87 insertions(+), 8 deletions(-) create mode 100644 lib/svgs/Icon_user_settings.svg diff --git a/example/lib/chat_info_screen.dart b/example/lib/chat_info_screen.dart index eb12bfee..5f7f7c63 100644 --- a/example/lib/chat_info_screen.dart +++ b/example/lib/chat_info_screen.dart @@ -246,7 +246,7 @@ class _ChatInfoScreenState extends State { Widget _buildDeleteListTile() { return OptionListTile( - title: 'Delete', + title: 'Delete Conversation', leading: StreamSvgIcon.delete( color: Colors.red, size: 24.0, diff --git a/example/lib/group_info_screen.dart b/example/lib/group_info_screen.dart index 5d1c2063..b4972165 100644 --- a/example/lib/group_info_screen.dart +++ b/example/lib/group_info_screen.dart @@ -3,9 +3,9 @@ import 'dart:async'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:jiffy/jiffy.dart'; -import 'file:///Users/deven9852/Stream/stream-chat-flutter/example/lib/chat_info_screen.dart'; import 'package:stream_chat_flutter/src/option_list_tile.dart'; import 'package:stream_chat_flutter/src/stream_svg_icon.dart'; +import 'chat_info_screen.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; import 'main.dart'; @@ -701,7 +701,7 @@ class _GroupInfoScreenState extends State { StreamChat.of(context).user.id != user.id && isUserAdmin) _buildModalListTile( - StreamSvgIcon.userAdd( + StreamSvgIcon.Icon_user_settings( color: Color(0xff7a7a7a), size: 24.0, ), diff --git a/lib/src/channel_file_display_screen.dart b/lib/src/channel_file_display_screen.dart index 8ea7daa9..c8b34ea0 100644 --- a/lib/src/channel_file_display_screen.dart +++ b/lib/src/channel_file_display_screen.dart @@ -94,7 +94,36 @@ class _ChannelFileDisplayScreenState extends State { if (snapshot.data.isEmpty) { return Center( - child: Text('Nothing here...'), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + StreamSvgIcon.files( + size: 136.0, + color: Color(0xffdbdbdb), + ), + SizedBox( + height: 16.0, + ), + Text( + 'No Media', + style: TextStyle( + fontSize: 14.0, + color: Color(0xff000000), + ), + ), + SizedBox( + height: 8.0, + ), + Text( + 'Files sent in this chat will appear here', + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 14.0, + color: Color(0xff000000).withOpacity(0.5), + ), + ), + ], + ), ); } diff --git a/lib/src/channel_media_display_screen.dart b/lib/src/channel_media_display_screen.dart index d47709cd..41ec41b3 100644 --- a/lib/src/channel_media_display_screen.dart +++ b/lib/src/channel_media_display_screen.dart @@ -93,7 +93,36 @@ class _ChannelMediaDisplayScreenState extends State { if (snapshot.data.isEmpty) { return Center( - child: Text('Nothing here...'), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + StreamSvgIcon.pictures( + size: 136.0, + color: Color(0xffdbdbdb), + ), + SizedBox( + height: 16.0, + ), + Text( + 'No Media', + style: TextStyle( + fontSize: 14.0, + color: Color(0xff000000), + ), + ), + SizedBox( + height: 8.0, + ), + Text( + 'Photos or video sent in this chat will \nappear here', + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 14.0, + color: Color(0xff000000).withOpacity(0.5), + ), + ), + ], + ), ); } @@ -157,9 +186,13 @@ class _ChannelMediaDisplayScreenState extends State { ); }, child: media[position].attachment.type == 'image' - ? CachedNetworkImage( - imageUrl: media[position].attachment.imageUrl, - fit: BoxFit.cover, + ? ImageAttachment( + attachment: media[position].attachment, + message: media[position].message, + size: Size( + MediaQuery.of(context).size.width * 0.8, + MediaQuery.of(context).size.height * 0.3, + ), ) : VideoPlayer(media[position].videoPlayer), ), diff --git a/lib/src/stream_svg_icon.dart b/lib/src/stream_svg_icon.dart index 98ce0f8e..0d8e3a95 100644 --- a/lib/src/stream_svg_icon.dart +++ b/lib/src/stream_svg_icon.dart @@ -757,4 +757,16 @@ class StreamSvgIcon extends StatelessWidget { height: size, ); } + + factory StreamSvgIcon.Icon_user_settings({ + double size, + Color color, + }) { + return StreamSvgIcon( + assetName: 'Icon_user_settings.svg', + color: color, + width: size, + height: size, + ); + } } diff --git a/lib/svgs/Icon_user_settings.svg b/lib/svgs/Icon_user_settings.svg new file mode 100644 index 00000000..36ce6115 --- /dev/null +++ b/lib/svgs/Icon_user_settings.svg @@ -0,0 +1,5 @@ + + + + + From 7fd8a1ed57266718ea3e281426ffa009240f4d01 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Tue, 29 Dec 2020 23:10:41 +0530 Subject: [PATCH 0675/1140] feat: Added color theme implementations --- example/ios/Flutter/.last_build_id | 2 +- example/ios/Podfile.lock | 2 +- example/lib/advanced_options_page.dart | 36 +++++++---- example/lib/chips_input_text_field.dart | 23 +++++-- example/lib/choose_user_page.dart | 6 +- example/lib/custom_theme.dart | 5 +- example/lib/customize_channel_preview.dart | 5 +- example/lib/group_chat_details_screen.dart | 37 ++++++++--- example/lib/main.dart | 29 ++++++--- example/lib/new_chat_screen.dart | 42 +++++++++--- example/lib/new_group_chat_screen.dart | 34 +++++++--- example/lib/search_text_field.dart | 13 ++-- example/lib/stream_version.dart | 4 +- lib/src/attachment_error.dart | 4 +- lib/src/back_button.dart | 6 +- lib/src/channel_image.dart | 4 +- lib/src/channel_list_header.dart | 2 +- lib/src/channel_list_view.dart | 12 ++-- lib/src/channel_unread_indicator.dart | 2 +- lib/src/chat_info_screen.dart | 72 ++++++++++++++------- lib/src/date_divider.dart | 6 +- lib/src/deleted_message.dart | 14 ++-- lib/src/file_attachment.dart | 17 ++--- lib/src/full_screen_media.dart | 4 +- lib/src/giphy_attachment.dart | 47 ++++++++++---- lib/src/image_actions_modal.dart | 29 ++++++--- lib/src/image_footer.dart | 51 +++++++++------ lib/src/image_group.dart | 4 +- lib/src/image_header.dart | 4 +- lib/src/media_list_view.dart | 15 +++-- lib/src/message_actions_modal.dart | 5 +- lib/src/message_input.dart | 74 +++++++++++++++------- lib/src/message_list_view.dart | 10 ++- lib/src/message_reactions_modal.dart | 5 +- lib/src/message_search_list_view.dart | 20 ++++-- lib/src/message_widget.dart | 40 +++++++----- lib/src/reaction_bubble.dart | 10 ++- lib/src/stream_chat_theme.dart | 2 +- lib/src/unread_indicator.dart | 2 +- lib/src/user_avatar.dart | 2 +- lib/src/user_item.dart | 8 +-- lib/src/user_list_view.dart | 12 ++-- lib/src/utils.dart | 7 +- 43 files changed, 504 insertions(+), 224 deletions(-) diff --git a/example/ios/Flutter/.last_build_id b/example/ios/Flutter/.last_build_id index e72273c3..a2e31d3e 100644 --- a/example/ios/Flutter/.last_build_id +++ b/example/ios/Flutter/.last_build_id @@ -1 +1 @@ -13a41b8138c4868054e44b5158f3bdd6 \ No newline at end of file +209b1a40522bc1cb0ea3596a28cded5e \ No newline at end of file diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock index f266b656..af57742c 100644 --- a/example/ios/Podfile.lock +++ b/example/ios/Podfile.lock @@ -296,4 +296,4 @@ SPEC CHECKSUMS: PODFILE CHECKSUM: eb001256612a59f8f9e4d083ad8b9671e69dd184 -COCOAPODS: 1.10.0 +COCOAPODS: 1.8.3 diff --git a/example/lib/advanced_options_page.dart b/example/lib/advanced_options_page.dart index 6c922e3d..803c3e72 100644 --- a/example/lib/advanced_options_page.dart +++ b/example/lib/advanced_options_page.dart @@ -45,11 +45,11 @@ class _AdvancedOptionsPageState extends State { style: StreamChatTheme.of(context) .textTheme .headlineBold - .copyWith(color: Colors.black), + .copyWith(color: StreamChatTheme.of(context).colorTheme.black), ), leading: IconButton( icon: StreamSvgIcon.left( - color: Colors.black, + color: StreamChatTheme.of(context).colorTheme.black, ), onPressed: () { Navigator.pop(context); @@ -89,7 +89,7 @@ class _AdvancedOptionsPageState extends State { }, style: TextStyle( fontSize: 14, - color: Colors.black, + color: StreamChatTheme.of(context).colorTheme.black, ), decoration: InputDecoration( errorStyle: TextStyle(fontSize: 0), @@ -98,7 +98,10 @@ class _AdvancedOptionsPageState extends State { fontWeight: FontWeight.bold, color: _apiKeyError != null ? Color(0xffff3742) - : Colors.black.withOpacity(.5), + : StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(.5), ), border: UnderlineInputBorder( borderRadius: BorderRadius.circular(8), @@ -133,7 +136,7 @@ class _AdvancedOptionsPageState extends State { }, style: TextStyle( fontSize: 14, - color: Colors.black, + color: StreamChatTheme.of(context).colorTheme.black, ), textInputAction: TextInputAction.next, decoration: InputDecoration( @@ -143,7 +146,10 @@ class _AdvancedOptionsPageState extends State { fontSize: 14, color: _userIdError != null ? Color(0xffff3742) - : Colors.black.withOpacity(.5), + : StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(.5), ), border: UnderlineInputBorder( borderRadius: BorderRadius.circular(8), @@ -178,7 +184,7 @@ class _AdvancedOptionsPageState extends State { }, style: TextStyle( fontSize: 14, - color: Colors.black, + color: StreamChatTheme.of(context).colorTheme.black, ), textInputAction: TextInputAction.next, decoration: InputDecoration( @@ -188,7 +194,10 @@ class _AdvancedOptionsPageState extends State { fontSize: 14, color: _userTokenError != null ? Color(0xffff3742) - : Colors.black.withOpacity(.5), + : StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(.5), ), border: UnderlineInputBorder( borderRadius: BorderRadius.circular(8), @@ -210,7 +219,10 @@ class _AdvancedOptionsPageState extends State { labelStyle: TextStyle( fontSize: 14, fontWeight: FontWeight.bold, - color: Colors.black.withOpacity(.5), + color: StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(.5), ), border: UnderlineInputBorder( borderRadius: BorderRadius.circular(8), @@ -232,7 +244,7 @@ class _AdvancedOptionsPageState extends State { child: Text( 'Login', style: TextStyle( - color: Colors.white, + color: StreamChatTheme.of(context).colorTheme.white, fontSize: 16, ), ), @@ -257,7 +269,9 @@ class _AdvancedOptionsPageState extends State { child: Container( decoration: BoxDecoration( borderRadius: BorderRadius.circular(16), - color: Colors.white, + color: StreamChatTheme.of(context) + .colorTheme + .white, ), height: 100, width: 100, diff --git a/example/lib/chips_input_text_field.dart b/example/lib/chips_input_text_field.dart index efa3b10e..7291ef03 100644 --- a/example/lib/chips_input_text_field.dart +++ b/example/lib/chips_input_text_field.dart @@ -66,7 +66,7 @@ class ChipInputTextFieldState extends State> { onTap: _pauseItemAddition ? resumeItemAddition : null, child: Material( elevation: 1, - color: Colors.white, + color: StreamChatTheme.of(context).colorTheme.white, child: Container( child: Padding( padding: const EdgeInsets.fromLTRB(16, 16, 16, 16), @@ -81,7 +81,11 @@ class ChipInputTextFieldState extends State> { style: StreamChatTheme.of(context) .textTheme .footnote - .copyWith(color: Colors.black.withOpacity(.5)), + .copyWith( + color: StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(.5)), ), ), SizedBox(width: 12), @@ -115,7 +119,10 @@ class ChipInputTextFieldState extends State> { .textTheme .body .copyWith( - color: Colors.black.withOpacity(.5)), + color: StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(.5)), ), ), ], @@ -127,11 +134,17 @@ class ChipInputTextFieldState extends State> { child: IconButton( icon: _chips.isEmpty ? StreamSvgIcon.user( - color: Colors.black.withOpacity(0.5), + color: StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(0.5), size: 24, ) : StreamSvgIcon.userAdd( - color: Colors.black.withOpacity(0.5), + color: StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(0.5), size: 24, ), onPressed: resumeItemAddition, diff --git a/example/lib/choose_user_page.dart b/example/lib/choose_user_page.dart index 205f2581..18212253 100644 --- a/example/lib/choose_user_page.dart +++ b/example/lib/choose_user_page.dart @@ -113,7 +113,9 @@ class ChooseUserPage extends StatelessWidget { child: Container( decoration: BoxDecoration( borderRadius: BorderRadius.circular(16), - color: Colors.white, + color: StreamChatTheme.of(context) + .colorTheme + .white, ), height: 100, width: 100, @@ -189,7 +191,7 @@ class ChooseUserPage extends StatelessWidget { }, leading: CircleAvatar( child: StreamSvgIcon.settings( - color: Colors.black, + color: StreamChatTheme.of(context).colorTheme.black, ), backgroundColor: StreamChatTheme.of(context).secondaryColor, diff --git a/example/lib/custom_theme.dart b/example/lib/custom_theme.dart index 21db1c6c..90635993 100644 --- a/example/lib/custom_theme.dart +++ b/example/lib/custom_theme.dart @@ -50,9 +50,10 @@ class MyApp extends StatelessWidget { client: client, streamChatThemeData: StreamChatThemeData.fromTheme(theme).copyWith( ownMessageTheme: MessageTheme( - messageBackgroundColor: Colors.black, + messageBackgroundColor: + StreamChatTheme.of(context).colorTheme.black, messageText: TextStyle( - color: Colors.white, + color: StreamChatTheme.of(context).colorTheme.white, ), avatarTheme: AvatarTheme( borderRadius: BorderRadius.circular(8), diff --git a/example/lib/customize_channel_preview.dart b/example/lib/customize_channel_preview.dart index 3809f780..d06cdba7 100644 --- a/example/lib/customize_channel_preview.dart +++ b/example/lib/customize_channel_preview.dart @@ -87,7 +87,10 @@ class ChannelListPage extends StatelessWidget { channel: channel, textStyle: StreamChatTheme.of(context).channelPreviewTheme.title.copyWith( - color: Colors.black.withOpacity(opacity), + color: StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(opacity), ), ), subtitle: Text(subtitle), diff --git a/example/lib/group_chat_details_screen.dart b/example/lib/group_chat_details_screen.dart index c6d4331d..0c49c523 100644 --- a/example/lib/group_chat_details_screen.dart +++ b/example/lib/group_chat_details_screen.dart @@ -62,12 +62,12 @@ class _GroupChatDetailsScreenState extends State { backgroundColor: Color.fromRGBO(252, 252, 252, 1), appBar: AppBar( elevation: 1, - backgroundColor: Colors.white, + backgroundColor: StreamChatTheme.of(context).colorTheme.white, leading: const StreamBackButton(), title: Text( 'Name of Group Chat', style: TextStyle( - color: Colors.black, + color: StreamChatTheme.of(context).colorTheme.black, fontSize: 16, ), ), @@ -82,7 +82,10 @@ class _GroupChatDetailsScreenState extends State { 'NAME', style: TextStyle( fontSize: 12, - color: Colors.black.withOpacity(0.5), + color: StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(0.5), ), ), SizedBox(width: 16), @@ -99,7 +102,11 @@ class _GroupChatDetailsScreenState extends State { contentPadding: const EdgeInsets.all(0), hintText: 'Choose a group chat name', hintStyle: TextStyle( - fontSize: 14, color: Colors.black.withOpacity(.5)), + fontSize: 14, + color: StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(.5)), ), ), ), @@ -167,16 +174,28 @@ class _GroupChatDetailsScreenState extends State { separatorBuilder: (_, __) => Container( height: 1, color: Theme.of(context).brightness == Brightness.dark - ? Colors.white.withOpacity(0.1) - : Colors.black.withOpacity(0.1), + ? StreamChatTheme.of(context) + .colorTheme + .white + .withOpacity(0.1) + : StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(0.1), ), itemBuilder: (_, index) { if (index == _selectedUsers.length) { return Container( height: 1, color: Theme.of(context).brightness == Brightness.dark - ? Colors.white.withOpacity(0.1) - : Colors.black.withOpacity(0.1), + ? StreamChatTheme.of(context) + .colorTheme + .white + .withOpacity(0.1) + : StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(0.1), ); } final user = _selectedUsers[index]; @@ -200,7 +219,7 @@ class _GroupChatDetailsScreenState extends State { trailing: IconButton( icon: Icon( Icons.clear_rounded, - color: Colors.black, + color: StreamChatTheme.of(context).colorTheme.black, ), padding: const EdgeInsets.all(0), splashRadius: 24, diff --git a/example/lib/main.dart b/example/lib/main.dart index a79a6fb4..6f4562b6 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -55,10 +55,10 @@ class MyApp extends StatelessWidget { client: client, child: MaterialApp( debugShowCheckedModeBanner: false, - theme: ThemeData.light(), + theme: ThemeData.dark(), darkTheme: ThemeData.dark(), //TODO change to system once dark theme is implemented - themeMode: ThemeMode.light, + themeMode: ThemeMode.dark, onGenerateRoute: AppRoutes.generateRoute, initialRoute: client.state.user == null ? Routes.CHOOSE_USER : Routes.HOME, @@ -84,7 +84,9 @@ class _HomePageState extends State { overflow: Overflow.visible, children: [ StreamSvgIcon.message( - color: _isSelected(0) ? Colors.black : Colors.grey, + color: _isSelected(0) + ? StreamChatTheme.of(context).colorTheme.black + : Colors.grey, ), Positioned( top: -3, @@ -100,7 +102,9 @@ class _HomePageState extends State { overflow: Overflow.visible, children: [ StreamSvgIcon.mentions( - color: _isSelected(1) ? Colors.black : Colors.grey, + color: _isSelected(1) + ? StreamChatTheme.of(context).colorTheme.black + : Colors.grey, ), ], ), @@ -127,7 +131,7 @@ class _HomePageState extends State { unselectedLabelStyle: StreamChatTheme.of(context).textTheme.footnoteBold, type: BottomNavigationBarType.fixed, - selectedItemColor: Colors.black, + selectedItemColor: StreamChatTheme.of(context).colorTheme.black, unselectedItemColor: Colors.grey, onTap: (index) { setState(() => _currentIndex = index); @@ -179,7 +183,10 @@ class _HomePageState extends State { ), ListTile( leading: StreamSvgIcon.penWrite( - color: Colors.black.withOpacity(.5), + color: StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(.5), ), onTap: () { Navigator.popAndPushNamed( @@ -196,7 +203,10 @@ class _HomePageState extends State { ), ListTile( leading: StreamSvgIcon.contacts( - color: Colors.black.withOpacity(.5), + color: StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(.5), ), onTap: () { Navigator.popAndPushNamed( @@ -231,7 +241,10 @@ class _HomePageState extends State { ); }, leading: StreamSvgIcon.user( - color: Colors.black.withOpacity(.5), + color: StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(.5), ), title: Text( 'Sign out', diff --git a/example/lib/new_chat_screen.dart b/example/lib/new_chat_screen.dart index b89bdee1..0d8b9821 100644 --- a/example/lib/new_chat_screen.dart +++ b/example/lib/new_chat_screen.dart @@ -125,14 +125,14 @@ class _NewChatScreenState extends State { backgroundColor: Color.fromRGBO(252, 252, 252, 1), appBar: AppBar( elevation: 0, - backgroundColor: Colors.white, + backgroundColor: StreamChatTheme.of(context).colorTheme.white, leading: const StreamBackButton(), title: Text( 'New Chat', style: StreamChatTheme.of(context) .textTheme .headlineBold - .copyWith(color: Colors.black), + .copyWith(color: StreamChatTheme.of(context).colorTheme.black), ), centerTitle: true, ), @@ -157,7 +157,10 @@ class _NewChatScreenState extends State { children: [ Container( decoration: BoxDecoration( - color: Colors.black.withOpacity(0.05), + color: StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(0.05), borderRadius: BorderRadius.circular(12), ), padding: const EdgeInsets.only(left: 24), @@ -165,7 +168,10 @@ class _NewChatScreenState extends State { padding: const EdgeInsets.fromLTRB(8, 4, 12, 4), child: Text( user.name, - style: TextStyle(color: Colors.black), + style: TextStyle( + color: StreamChatTheme.of(context) + .colorTheme + .black), ), ), ), @@ -182,7 +188,7 @@ class _NewChatScreenState extends State { ), Positioned( child: StreamSvgIcon.close( - color: Colors.white, + color: StreamChatTheme.of(context).colorTheme.white, ), ), ], @@ -235,8 +241,14 @@ class _NewChatScreenState extends State { begin: Alignment.centerLeft, end: Alignment.centerRight, colors: [ - Colors.black.withOpacity(0.02), - Colors.white.withOpacity(0.05), + StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(0.02), + StreamChatTheme.of(context) + .colorTheme + .white + .withOpacity(0.05), ], stops: [0, 1], ), @@ -253,7 +265,11 @@ class _NewChatScreenState extends State { style: StreamChatTheme.of(context) .textTheme .footnote - .copyWith(color: Colors.black.withOpacity(.5))), + .copyWith( + color: StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(.5))), ), ), Expanded( @@ -318,7 +334,10 @@ class _NewChatScreenState extends State { .textTheme .footnote .copyWith( - color: Colors.black + color: StreamChatTheme.of( + context) + .colorTheme + .black .withOpacity(.5)), ), ], @@ -344,7 +363,10 @@ class _NewChatScreenState extends State { 'No chats here yet...', style: TextStyle( fontSize: 12, - color: Colors.black.withOpacity(.5), + color: StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(.5), ), ), ); diff --git a/example/lib/new_group_chat_screen.dart b/example/lib/new_group_chat_screen.dart index ba477a73..a00dbc07 100644 --- a/example/lib/new_group_chat_screen.dart +++ b/example/lib/new_group_chat_screen.dart @@ -62,12 +62,12 @@ class _NewGroupChatScreenState extends State { pinned: true, forceElevated: true, elevation: 1, - backgroundColor: Colors.white, + backgroundColor: StreamChatTheme.of(context).colorTheme.white, leading: const StreamBackButton(), title: Text( 'Add Group Members', style: TextStyle( - color: Colors.black, + color: StreamChatTheme.of(context).colorTheme.black, fontSize: 16, ), ), @@ -137,7 +137,9 @@ class _NewGroupChatScreenState extends State { }, child: Container( decoration: BoxDecoration( - color: Colors.white, + color: StreamChatTheme.of(context) + .colorTheme + .white, shape: BoxShape.circle, border: Border.all( color: Colors.grey.shade100, @@ -146,7 +148,9 @@ class _NewGroupChatScreenState extends State { child: Padding( padding: const EdgeInsets.all(0.0), child: StreamSvgIcon.close( - color: Colors.black, + color: StreamChatTheme.of(context) + .colorTheme + .black, size: 24, ), ), @@ -180,8 +184,14 @@ class _NewGroupChatScreenState extends State { begin: Alignment.centerLeft, end: Alignment.centerRight, colors: [ - Colors.black.withOpacity(0.02), - Colors.white.withOpacity(0.05), + StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(0.02), + StreamChatTheme.of(context) + .colorTheme + .white + .withOpacity(0.05), ], stops: [0, 1], ), @@ -196,7 +206,10 @@ class _NewGroupChatScreenState extends State { ? 'Matches for \"$_userNameQuery\"' : 'On the platform', style: TextStyle( - color: Colors.black.withOpacity(0.5), + color: StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(0.5), ), ), ), @@ -267,7 +280,10 @@ class _NewGroupChatScreenState extends State { .textTheme .footnote .copyWith( - color: Colors.black.withOpacity(.5)), + color: StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(.5)), ), ], ), @@ -299,7 +315,7 @@ class _HeaderDelegate extends SliverPersistentHeaderDelegate { Widget build( BuildContext context, double shrinkOffset, bool overlapsContent) { return Container( - color: Colors.white, + color: StreamChatTheme.of(context).colorTheme.white, child: child, ); } diff --git a/example/lib/search_text_field.dart b/example/lib/search_text_field.dart index 00859b59..1054446f 100644 --- a/example/lib/search_text_field.dart +++ b/example/lib/search_text_field.dart @@ -22,7 +22,7 @@ class SearchTextField extends StatelessWidget { return Container( height: 36, decoration: BoxDecoration( - color: Colors.white, + color: StreamChatTheme.of(context).colorTheme.white, border: Border.all( color: Colors.grey.shade300, ), @@ -48,15 +48,16 @@ class SearchTextField extends StatelessWidget { right: 8, ), child: StreamSvgIcon.search( - color: Colors.black, + color: StreamChatTheme.of(context).colorTheme.black, size: 24, ), ), hintText: hintText, - hintStyle: StreamChatTheme.of(context) - .textTheme - .body - .copyWith(color: Colors.black.withOpacity(.5)), + hintStyle: StreamChatTheme.of(context).textTheme.body.copyWith( + color: StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(.5)), contentPadding: const EdgeInsets.all(0), border: OutlineInputBorder( borderSide: BorderSide.none, diff --git a/example/lib/stream_version.dart b/example/lib/stream_version.dart index 113e36c0..a3d52ab6 100644 --- a/example/lib/stream_version.dart +++ b/example/lib/stream_version.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:yaml/yaml.dart'; +import 'package:stream_chat_flutter/stream_chat_flutter.dart'; class StreamVersion extends StatelessWidget { const StreamVersion({ @@ -28,7 +29,8 @@ class StreamVersion extends StatelessWidget { 'Stream SDK v ${streamChatDep}', style: TextStyle( fontSize: 14.5, - color: Colors.black.withOpacity(.13), + color: + StreamChatTheme.of(context).colorTheme.black.withOpacity(.13), ), ); }, diff --git a/lib/src/attachment_error.dart b/lib/src/attachment_error.dart index e08867b8..0b51e59c 100644 --- a/lib/src/attachment_error.dart +++ b/lib/src/attachment_error.dart @@ -3,6 +3,8 @@ import 'dart:io'; import 'package:flutter/material.dart'; import 'package:stream_chat/stream_chat.dart'; +import '../stream_chat_flutter.dart'; + class AttachmentError extends StatelessWidget { final Attachment attachment; final Size size; @@ -28,7 +30,7 @@ class AttachmentError extends StatelessWidget { child: Center( child: Icon( Icons.error_outline, - color: Colors.white, + color: StreamChatTheme.of(context).colorTheme.white, ), ), ), diff --git a/lib/src/back_button.dart b/lib/src/back_button.dart index 10b177d2..d4d7c53c 100644 --- a/lib/src/back_button.dart +++ b/lib/src/back_button.dart @@ -2,6 +2,8 @@ import 'package:flutter/material.dart'; import 'package:stream_chat_flutter/src/stream_svg_icon.dart'; import 'package:stream_chat_flutter/src/unread_indicator.dart'; +import '../stream_chat_flutter.dart'; + class StreamBackButton extends StatelessWidget { const StreamBackButton({ Key key, @@ -36,8 +38,8 @@ class StreamBackButton extends StatelessWidget { child: StreamSvgIcon.left( size: 24, color: Theme.of(context).brightness == Brightness.dark - ? Colors.white - : Colors.black, + ? StreamChatTheme.of(context).colorTheme.white + : StreamChatTheme.of(context).colorTheme.black, ), ), ), diff --git a/lib/src/channel_image.dart b/lib/src/channel_image.dart index c3d76202..b577a442 100644 --- a/lib/src/channel_image.dart +++ b/lib/src/channel_image.dart @@ -149,7 +149,9 @@ class ChannelImage extends StatelessWidget { ? snapshot.data['name'][0] : '', style: TextStyle( - color: Colors.white, + color: StreamChatTheme.of(context) + .colorTheme + .white, fontWeight: FontWeight.bold, ), ), diff --git a/lib/src/channel_list_header.dart b/lib/src/channel_list_header.dart index 41b283f5..09156d4c 100644 --- a/lib/src/channel_list_header.dart +++ b/lib/src/channel_list_header.dart @@ -145,7 +145,7 @@ class ChannelListHeader extends StatelessWidget implements PreferredSizeWidget { Widget _buildConnectedTitleState(BuildContext context) => Text( 'Stream Chat', style: StreamChatTheme.of(context).textTheme.headlineBold.copyWith( - color: Colors.black, + color: StreamChatTheme.of(context).colorTheme.black, ), ); diff --git a/lib/src/channel_list_view.dart b/lib/src/channel_list_view.dart index c04f80ed..701158e1 100644 --- a/lib/src/channel_list_view.dart +++ b/lib/src/channel_list_view.dart @@ -319,7 +319,7 @@ class _ChannelListViewState extends State child: ListTile( leading: Container( decoration: BoxDecoration( - color: Colors.white, + color: StreamChatTheme.of(context).colorTheme.white, shape: BoxShape.circle, ), constraints: BoxConstraints.tightFor( @@ -331,7 +331,7 @@ class _ChannelListViewState extends State alignment: Alignment.centerLeft, child: Container( decoration: BoxDecoration( - color: Colors.white, + color: StreamChatTheme.of(context).colorTheme.white, borderRadius: BorderRadius.circular(11), ), constraints: BoxConstraints.tightFor( @@ -346,7 +346,7 @@ class _ChannelListViewState extends State alignment: Alignment.centerLeft, child: Container( decoration: BoxDecoration( - color: Colors.white, + color: StreamChatTheme.of(context).colorTheme.white, borderRadius: BorderRadius.circular(11), ), constraints: BoxConstraints.tightFor( @@ -358,7 +358,7 @@ class _ChannelListViewState extends State Container( margin: const EdgeInsets.only(left: 16), decoration: BoxDecoration( - color: Colors.white, + color: StreamChatTheme.of(context).colorTheme.white, borderRadius: BorderRadius.circular(11), ), constraints: BoxConstraints.tightFor( @@ -622,8 +622,8 @@ class _ChannelListViewState extends State return Container( height: 1, color: Theme.of(context).brightness == Brightness.dark - ? Colors.white.withOpacity(0.1) - : Colors.black.withOpacity(0.1), + ? StreamChatTheme.of(context).colorTheme.white.withOpacity(0.1) + : StreamChatTheme.of(context).colorTheme.black.withOpacity(0.1), ); } diff --git a/lib/src/channel_unread_indicator.dart b/lib/src/channel_unread_indicator.dart index 8080b1e9..10a2aa48 100644 --- a/lib/src/channel_unread_indicator.dart +++ b/lib/src/channel_unread_indicator.dart @@ -36,7 +36,7 @@ class ChannelUnreadIndicator extends StatelessWidget { '${snapshot.data}', style: TextStyle( fontSize: 11, - color: Colors.white, + color: StreamChatTheme.of(context).colorTheme.white, ), ), ), diff --git a/lib/src/chat_info_screen.dart b/lib/src/chat_info_screen.dart index 8d291f38..132f3ea3 100644 --- a/lib/src/chat_info_screen.dart +++ b/lib/src/chat_info_screen.dart @@ -47,7 +47,7 @@ class _ChatInfoScreenState extends State { Widget _buildUserHeader() { return Material( - color: Colors.white, + color: StreamChatTheme.of(context).colorTheme.white, child: SafeArea( child: Stack( children: [ @@ -81,7 +81,11 @@ class _ChatInfoScreenState extends State { child: Text( widget.user.name, style: TextStyle( - color: Colors.black.withOpacity(0.5), fontSize: 16.0), + color: StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(0.5), + fontSize: 16.0), ), ), onTap: () {}, @@ -113,7 +117,7 @@ class _ChatInfoScreenState extends State { // title: 'Notifications', // leading: StreamSvgIcon.Icon_notification( // size: 24.0, - // color: Colors.black.withOpacity(0.5), + // color: StreamChatTheme.of(context).colorTheme.black.withOpacity(0.5), // ), // trailing: CupertinoSwitch( // value: true, @@ -128,7 +132,10 @@ class _ChatInfoScreenState extends State { title: 'Mute user', leading: StreamSvgIcon.mute( size: 23.0, - color: Colors.black.withOpacity(0.5), + color: StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(0.5), ), trailing: snapshot.data == null ? CircularProgressIndicator() @@ -149,7 +156,7 @@ class _ChatInfoScreenState extends State { // title: 'Block User', // leading: StreamSvgIcon.Icon_user_delete( // size: 24.0, - // color: Colors.black.withOpacity(0.5), + // color: StreamChatTheme.of(context).colorTheme.black.withOpacity(0.5), // ), // trailing: CupertinoSwitch( // value: widget.user.banned, @@ -167,7 +174,8 @@ class _ChatInfoScreenState extends State { title: 'Photos & Videos', leading: StreamSvgIcon.pictures( size: 32.0, - color: Colors.black.withOpacity(0.5), + color: + StreamChatTheme.of(context).colorTheme.black.withOpacity(0.5), ), trailing: StreamSvgIcon.right(), onTap: () { @@ -179,7 +187,8 @@ class _ChatInfoScreenState extends State { title: 'Files', leading: StreamSvgIcon.files( size: 32.0, - color: Colors.black.withOpacity(0.5), + color: + StreamChatTheme.of(context).colorTheme.black.withOpacity(0.5), ), trailing: StreamSvgIcon.right(), onTap: () { @@ -191,7 +200,8 @@ class _ChatInfoScreenState extends State { title: 'Shared groups', leading: StreamSvgIcon.Icon_group( size: 24.0, - color: Colors.black.withOpacity(0.5), + color: + StreamChatTheme.of(context).colorTheme.black.withOpacity(0.5), ), trailing: StreamSvgIcon.right(), onTap: () { @@ -248,12 +258,20 @@ class _ChatInfoScreenState extends State { if (otherMember.online) { alternativeWidget = Text( 'Online', - style: TextStyle(color: Colors.black.withOpacity(0.5)), + style: TextStyle( + color: StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(0.5)), ); } else { alternativeWidget = Text( 'Last seen ${Jiffy(otherMember.lastActive).fromNow()}', - style: TextStyle(color: Colors.black.withOpacity(0.5)), + style: TextStyle( + color: StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(0.5)), ); } } @@ -275,7 +293,7 @@ class _ChatInfoScreenState extends State { color: Color(0xff20E070), ), ), - color: Colors.white, + color: StreamChatTheme.of(context).colorTheme.white, ), alternativeWidget, ], @@ -307,7 +325,7 @@ class _OptionListTile extends StatelessWidget { height: 2.0, ), Material( - color: Colors.white, + color: StreamChatTheme.of(context).colorTheme.white, child: Container( height: 56.0, child: InkWell( @@ -365,14 +383,16 @@ class __SharedGroupsScreenState extends State<_SharedGroupsScreen> { var chat = StreamChat.of(context); return Scaffold( - backgroundColor: Colors.white, + backgroundColor: StreamChatTheme.of(context).colorTheme.white, appBar: AppBar( brightness: Theme.of(context).brightness, elevation: 1, centerTitle: true, title: Text( 'Shared Groups', - style: TextStyle(color: Colors.black, fontSize: 16.0), + style: TextStyle( + color: StreamChatTheme.of(context).colorTheme.black, + fontSize: 16.0), ), leading: Center( child: InkWell( @@ -381,7 +401,7 @@ class __SharedGroupsScreenState extends State<_SharedGroupsScreen> { }, child: Container( child: StreamSvgIcon.left( - color: Colors.black, + color: StreamChatTheme.of(context).colorTheme.black, size: 24.0, ), width: 24.0, @@ -488,7 +508,11 @@ class __SharedGroupsScreenState extends State<_SharedGroupsScreen> { padding: const EdgeInsets.all(8.0), child: Text( '${channel.memberCount} members', - style: TextStyle(color: Colors.black.withOpacity(0.5)), + style: TextStyle( + color: StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(0.5)), ), ) ], @@ -509,14 +533,16 @@ class _MediaDisplayScreen extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( - backgroundColor: Colors.white, + backgroundColor: StreamChatTheme.of(context).colorTheme.white, appBar: AppBar( brightness: Theme.of(context).brightness, elevation: 1, centerTitle: true, title: Text( 'Photos & Videos', - style: TextStyle(color: Colors.black, fontSize: 16.0), + style: TextStyle( + color: StreamChatTheme.of(context).colorTheme.black, + fontSize: 16.0), ), leading: Center( child: InkWell( @@ -525,7 +551,7 @@ class _MediaDisplayScreen extends StatelessWidget { }, child: Container( child: StreamSvgIcon.left( - color: Colors.black, + color: StreamChatTheme.of(context).colorTheme.black, size: 24.0, ), width: 24.0, @@ -543,14 +569,16 @@ class _FileDisplayScreen extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( - backgroundColor: Colors.white, + backgroundColor: StreamChatTheme.of(context).colorTheme.white, appBar: AppBar( brightness: Theme.of(context).brightness, elevation: 1, centerTitle: true, title: Text( 'Files', - style: TextStyle(color: Colors.black, fontSize: 16.0), + style: TextStyle( + color: StreamChatTheme.of(context).colorTheme.black, + fontSize: 16.0), ), leading: Center( child: InkWell( @@ -559,7 +587,7 @@ class _FileDisplayScreen extends StatelessWidget { }, child: Container( child: StreamSvgIcon.left( - color: Colors.black, + color: StreamChatTheme.of(context).colorTheme.black, size: 24.0, ), width: 24.0, diff --git a/lib/src/date_divider.dart b/lib/src/date_divider.dart index 3b8c36c1..9b1ba435 100644 --- a/lib/src/date_divider.dart +++ b/lib/src/date_divider.dart @@ -41,8 +41,8 @@ class DateDivider extends StatelessWidget { padding: const EdgeInsets.symmetric(horizontal: 8), decoration: BoxDecoration( color: (Theme.of(context).brightness == Brightness.light - ? Colors.black - : Colors.white) + ? StreamChatTheme.of(context).colorTheme.black + : StreamChatTheme.of(context).colorTheme.white) .withOpacity(0.5), borderRadius: BorderRadius.circular( 8, @@ -51,7 +51,7 @@ class DateDivider extends StatelessWidget { child: Text( dayInfo, style: StreamChatTheme.of(context).textTheme.footnoteBold.copyWith( - color: Colors.white, + color: StreamChatTheme.of(context).colorTheme.white, fontWeight: FontWeight.bold, ), ), diff --git a/lib/src/deleted_message.dart b/lib/src/deleted_message.dart index 9181d985..5921df43 100644 --- a/lib/src/deleted_message.dart +++ b/lib/src/deleted_message.dart @@ -41,8 +41,14 @@ class DeletedMessage extends StatelessWidget { side: borderSide ?? BorderSide( color: Theme.of(context).brightness == Brightness.dark - ? Colors.white.withAlpha(24) - : Colors.black.withAlpha(24), + ? StreamChatTheme.of(context) + .colorTheme + .white + .withAlpha(24) + : StreamChatTheme.of(context) + .colorTheme + .black + .withAlpha(24), ), ), child: Padding( @@ -58,8 +64,8 @@ class DeletedMessage extends StatelessWidget { style: messageTheme.messageText.copyWith( fontStyle: FontStyle.italic, color: (Theme.of(context).brightness == Brightness.dark - ? Colors.white - : Colors.black) + ? StreamChatTheme.of(context).colorTheme.white + : StreamChatTheme.of(context).colorTheme.black) .withOpacity(.5), ), ), diff --git a/lib/src/file_attachment.dart b/lib/src/file_attachment.dart index c5e6c92f..597add86 100644 --- a/lib/src/file_attachment.dart +++ b/lib/src/file_attachment.dart @@ -63,7 +63,7 @@ class _FileAttachmentState extends State { height: 56.0, margin: widget.trailing != null ? EdgeInsets.only(top: 4.0) : null, decoration: BoxDecoration( - color: Colors.white, + color: StreamChatTheme.of(context).colorTheme.white, borderRadius: widget.trailing != null ? BorderRadius.circular(16.0) : null, border: widget.trailing != null @@ -97,10 +97,11 @@ class _FileAttachmentState extends State { ), Text( '${_getSizeText(widget.attachment.extraData['file_size'])}', - style: StreamChatTheme.of(context) - .textTheme - .body - .copyWith(color: Colors.black.withOpacity(0.5)), + style: StreamChatTheme.of(context).textTheme.body.copyWith( + color: StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(0.5)), ), ], ), @@ -110,7 +111,7 @@ class _FileAttachmentState extends State { widget.trailing ?? IconButton( icon: StreamSvgIcon.cloud_download( - color: Colors.black, + color: StreamChatTheme.of(context).colorTheme.black, ), onPressed: () { launchURL(context, widget.attachment.assetUrl); @@ -138,13 +139,13 @@ class _FileAttachmentState extends State { // subtitle: Text( // '${attachment.extraData['file_size'] ?? 'N/A'} bytes', // style: TextStyle( - // color: Colors.black.withOpacity(0.5), + // color: StreamChatTheme.of(context).colorTheme.black.withOpacity(0.5), // ), // ), // trailing: trailing ?? // IconButton( // icon: StreamSvgIcon.cloud_download( - // color: Colors.black, + // color: StreamChatTheme.of(context).colorTheme.black, // ), // onPressed: () { // launchURL(context, attachment.assetUrl); diff --git a/lib/src/full_screen_media.dart b/lib/src/full_screen_media.dart index 7e3f3d7d..e6ecb64f 100644 --- a/lib/src/full_screen_media.dart +++ b/lib/src/full_screen_media.dart @@ -100,7 +100,9 @@ class _FullScreenMediaState extends State .channelTheme .channelHeaderTheme .color, - end: Colors.black) + end: StreamChatTheme.of(context) + .colorTheme + .black) .lerp(_controller.value), ), onTapUp: (a, b, c) { diff --git a/lib/src/giphy_attachment.dart b/lib/src/giphy_attachment.dart index 74dfeeb4..1f3bf9e6 100644 --- a/lib/src/giphy_attachment.dart +++ b/lib/src/giphy_attachment.dart @@ -112,7 +112,10 @@ class GiphyAttachment extends StatelessWidget { bottom: 16, left: 16, child: Material( - color: Colors.black.withOpacity(.5), + color: StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(.5), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12), ), @@ -124,13 +127,16 @@ class GiphyAttachment extends StatelessWidget { child: Row( children: [ StreamSvgIcon.lightning( - color: Colors.white, + color: + StreamChatTheme.of(context).colorTheme.white, size: 16, ), Text( 'GIPHY', style: TextStyle( - color: Colors.white, + color: StreamChatTheme.of(context) + .colorTheme + .white, fontWeight: FontWeight.bold, fontSize: 11, ), @@ -202,7 +208,10 @@ class GiphyAttachment extends StatelessWidget { height: 4.0, ), Container( - color: Colors.black.withOpacity(0.2), + color: StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(0.2), width: double.infinity, height: 0.5, ), @@ -224,14 +233,20 @@ class GiphyAttachment extends StatelessWidget { .textTheme .bodyBold .copyWith( - color: Colors.black.withOpacity(0.5), + color: StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(0.5), ), ), ), ), Container( width: 0.5, - color: Colors.black.withOpacity(0.2), + color: StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(0.2), height: 50.0, ), Expanded( @@ -266,7 +281,10 @@ class GiphyAttachment extends StatelessWidget { mainAxisSize: MainAxisSize.min, children: [ StreamSvgIcon.eye( - color: Colors.black.withOpacity(0.5), + color: StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(0.5), size: 16.0, ), SizedBox( @@ -277,7 +295,11 @@ class GiphyAttachment extends StatelessWidget { style: StreamChatTheme.of(context) .textTheme .footnote - .copyWith(color: Colors.black.withOpacity(0.5)), + .copyWith( + color: StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(0.5)), ), ], ), @@ -334,7 +356,10 @@ class GiphyAttachment extends StatelessWidget { bottom: 8, left: 8, child: Material( - color: Colors.black.withOpacity(.5), + color: StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(.5), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12), ), @@ -346,13 +371,13 @@ class GiphyAttachment extends StatelessWidget { child: Row( children: [ StreamSvgIcon.lightning( - color: Colors.white, + color: StreamChatTheme.of(context).colorTheme.white, size: 16, ), Text( 'GIPHY', style: TextStyle( - color: Colors.white, + color: StreamChatTheme.of(context).colorTheme.white, fontWeight: FontWeight.bold, fontSize: 11, ), diff --git a/lib/src/image_actions_modal.dart b/lib/src/image_actions_modal.dart index 2b2aa05e..45a60d60 100644 --- a/lib/src/image_actions_modal.dart +++ b/lib/src/image_actions_modal.dart @@ -34,7 +34,7 @@ class ImageActionsModal extends StatelessWidget { begin: Alignment.topCenter, end: Alignment.bottomCenter, colors: [ - Colors.black.withOpacity(0.8), + StreamChatTheme.of(context).colorTheme.black.withOpacity(0.8), Colors.transparent, ], stops: [0.0, 0.4], @@ -69,7 +69,9 @@ class ImageActionsModal extends StatelessWidget { style: StreamChatTheme.of(context) .textTheme .headlineBold - .copyWith(color: Colors.white), + .copyWith( + color: + StreamChatTheme.of(context).colorTheme.white), ), ), Text( @@ -77,14 +79,18 @@ class ImageActionsModal extends StatelessWidget { style: StreamChatTheme.of(context) .channelPreviewTheme .subtitle - .copyWith(color: Colors.white.withOpacity(0.5)), + .copyWith( + color: StreamChatTheme.of(context) + .colorTheme + .white + .withOpacity(0.5)), ), ], ), IconButton( icon: StreamSvgIcon.close( size: 24.0, - color: Colors.white, + color: StreamChatTheme.of(context).colorTheme.white, ), onPressed: () { Navigator.pop(context); @@ -114,7 +120,10 @@ class ImageActionsModal extends StatelessWidget { 'Reply', StreamSvgIcon.Icon_curve_line_left_up( size: 24.0, - color: Colors.black.withOpacity(0.5), + color: StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(0.5), ), () {}), _buildButton( @@ -122,7 +131,8 @@ class ImageActionsModal extends StatelessWidget { 'Show in Chat', StreamSvgIcon.eye( size: 24.0, - color: Colors.black, + color: + StreamChatTheme.of(context).colorTheme.black, ), () { Navigator.pop(context); Navigator.pop(context); @@ -132,7 +142,10 @@ class ImageActionsModal extends StatelessWidget { 'Save ${urls[currentIndex].type == 'video' ? 'Video' : 'Image'}', StreamSvgIcon.Icon_save( size: 24.0, - color: Colors.black.withOpacity(0.5), + color: StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(0.5), ), () async { var url = urls[currentIndex].imageUrl ?? urls[currentIndex].assetUrl ?? @@ -181,7 +194,7 @@ class ImageActionsModal extends StatelessWidget { {Color color}) { var titleStyle = TextStyle( fontSize: 14.5, - color: Colors.black, + color: StreamChatTheme.of(context).colorTheme.black, ); return Material( diff --git a/lib/src/image_footer.dart b/lib/src/image_footer.dart index f16be87d..762bd737 100644 --- a/lib/src/image_footer.dart +++ b/lib/src/image_footer.dart @@ -114,7 +114,7 @@ class _ImageFooterState extends State { IconButton( icon: StreamSvgIcon.icon_SHARE( size: 24.0, - color: Colors.black, + color: StreamChatTheme.of(context).colorTheme.black, ), onPressed: () { _buildShareModal(context); @@ -138,7 +138,7 @@ class _ImageFooterState extends State { ), IconButton( icon: StreamSvgIcon.Icon_grid( - color: Colors.black, + color: StreamChatTheme.of(context).colorTheme.black, ), onPressed: () { _buildPhotosModal(context); @@ -166,7 +166,7 @@ class _ImageFooterState extends State { children: [ Container( decoration: BoxDecoration( - color: Colors.white, + color: StreamChatTheme.of(context).colorTheme.white, borderRadius: BorderRadius.only( topRight: Radius.circular(16.0), topLeft: Radius.circular(16.0), @@ -187,7 +187,7 @@ class _ImageFooterState extends State { alignment: Alignment.centerRight, child: IconButton( icon: StreamSvgIcon.close( - color: Colors.black, + color: StreamChatTheme.of(context).colorTheme.black, ), onPressed: () { Navigator.pop(context); @@ -198,7 +198,7 @@ class _ImageFooterState extends State { ), ), Container( - color: Colors.white, + color: StreamChatTheme.of(context).colorTheme.white, child: GridView.builder( shrinkWrap: true, physics: NeverScrollableScrollPhysics(), @@ -346,7 +346,7 @@ class _ImageFooterState extends State { Align( alignment: Alignment.bottomCenter, child: Container( - color: Colors.white, + color: StreamChatTheme.of(context).colorTheme.white, height: 48.0, child: Material( child: InkWell( @@ -415,7 +415,7 @@ class _ImageFooterState extends State { Expanded( child: TextField( controller: _searchController, - cursorColor: Colors.black, + cursorColor: StreamChatTheme.of(context).colorTheme.black, autofocus: true, decoration: InputDecoration( isDense: true, @@ -425,19 +425,25 @@ class _ImageFooterState extends State { padding: const EdgeInsets.symmetric( vertical: 2.0, horizontal: 6.0), child: StreamSvgIcon.search( - color: Colors.black, + color: StreamChatTheme.of(context).colorTheme.black, ), ), hintText: 'Search', border: OutlineInputBorder( borderRadius: BorderRadius.circular(32.0), - borderSide: - BorderSide(color: Colors.black.withOpacity(0.08)), + borderSide: BorderSide( + color: StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(0.08)), ), focusedBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(32.0), - borderSide: - BorderSide(color: Colors.black.withOpacity(0.08)), + borderSide: BorderSide( + color: StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(0.08)), ), contentPadding: EdgeInsets.zero, ), @@ -448,7 +454,10 @@ class _ImageFooterState extends State { ), IconButton( icon: StreamSvgIcon.close_small( - color: Colors.black.withOpacity(0.5), + color: StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(0.5), ), onPressed: () { modalSetState(() { @@ -469,7 +478,7 @@ class _ImageFooterState extends State { padding: const EdgeInsets.symmetric(horizontal: 6.0), child: IconButton( icon: StreamSvgIcon.search( - color: Colors.black, + color: StreamChatTheme.of(context).colorTheme.black, ), iconSize: 24.0, onPressed: () { @@ -490,7 +499,7 @@ class _ImageFooterState extends State { padding: const EdgeInsets.symmetric(horizontal: 6.0), child: IconButton( icon: StreamSvgIcon.share_arrow( - color: Colors.black, + color: StreamChatTheme.of(context).colorTheme.black, ), onPressed: () async { var url = @@ -517,7 +526,7 @@ class _ImageFooterState extends State { return Align( alignment: Alignment.bottomCenter, child: Container( - color: Colors.white, + color: StreamChatTheme.of(context).colorTheme.white, height: 56.0, child: _loading ? Center( @@ -547,13 +556,19 @@ class _ImageFooterState extends State { border: OutlineInputBorder( borderRadius: BorderRadius.circular(32.0), borderSide: BorderSide( - color: Colors.black.withOpacity(0.16), + color: StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(0.16), ), ), focusedBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(32.0), borderSide: BorderSide( - color: Colors.black.withOpacity(0.16), + color: StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(0.16), )), contentPadding: EdgeInsets.symmetric(vertical: 12.0), ), diff --git a/lib/src/image_group.dart b/lib/src/image_group.dart index 44c15623..7bce22f9 100644 --- a/lib/src/image_group.dart +++ b/lib/src/image_group.dart @@ -83,7 +83,9 @@ class ImageGroup extends StatelessWidget { child: Text( '${images.length - 4} +', style: TextStyle( - color: Colors.white, + color: StreamChatTheme.of(context) + .colorTheme + .white, fontSize: 28, ), ), diff --git a/lib/src/image_header.dart b/lib/src/image_header.dart index aae73057..a9f1173f 100644 --- a/lib/src/image_header.dart +++ b/lib/src/image_header.dart @@ -50,7 +50,7 @@ class ImageHeader extends StatelessWidget implements PreferredSizeWidget { leading: showBackButton ? IconButton( icon: StreamSvgIcon.close( - color: Colors.black, + color: StreamChatTheme.of(context).colorTheme.black, size: 24.0, ), onPressed: onBackPressed, @@ -61,7 +61,7 @@ class ImageHeader extends StatelessWidget implements PreferredSizeWidget { actions: [ IconButton( icon: StreamSvgIcon.Icon_menu_point_v( - color: Colors.black, + color: StreamChatTheme.of(context).colorTheme.black, ), onPressed: () { _showMessageActionModalBottomSheet(context); diff --git a/lib/src/media_list_view.dart b/lib/src/media_list_view.dart index 5f52e9b5..d2b7ba69 100644 --- a/lib/src/media_list_view.dart +++ b/lib/src/media_list_view.dart @@ -6,6 +6,8 @@ import 'package:stream_chat_flutter/src/lazy_load_scroll_view.dart'; import 'package:stream_chat_flutter/src/stream_svg_icon.dart'; import 'dart:ui' as ui; +import '../stream_chat_flutter.dart'; + extension on Duration { String format() { final s = '$this'.split('.')[0].padLeft(8, '0'); @@ -80,7 +82,10 @@ class _MediaListViewState extends State { ? 1.0 : 0.0, child: Container( - color: Colors.black.withOpacity(0.5), + color: StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(0.5), alignment: Alignment.topRight, padding: const EdgeInsets.only( top: 8, @@ -88,10 +93,12 @@ class _MediaListViewState extends State { ), child: CircleAvatar( radius: 12, - backgroundColor: Colors.white, + backgroundColor: + StreamChatTheme.of(context).colorTheme.white, child: StreamSvgIcon.check( size: 24, - color: Colors.black, + color: + StreamChatTheme.of(context).colorTheme.black, ), ), ), @@ -113,7 +120,7 @@ class _MediaListViewState extends State { child: Text( media.videoDuration.format(), style: TextStyle( - color: Colors.white, + color: StreamChatTheme.of(context).colorTheme.white, ), ), ), diff --git a/lib/src/message_actions_modal.dart b/lib/src/message_actions_modal.dart index 8013a8b3..17b9a79e 100644 --- a/lib/src/message_actions_modal.dart +++ b/lib/src/message_actions_modal.dart @@ -69,7 +69,10 @@ class MessageActionsModal extends StatelessWidget { sigmaY: 10.8731, ), child: Container( - color: Colors.black.withOpacity(0.1), + color: StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(0.1), ), ), ), diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 79189d1d..73f98754 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -263,7 +263,10 @@ class MessageInputState extends State { border: _sendAsDm ? null : Border.all( - color: Colors.black.withOpacity(.5), + color: StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(.5), width: 2, ), borderRadius: BorderRadius.circular(3), @@ -273,7 +276,7 @@ class MessageInputState extends State { borderRadius: BorderRadius.circular(3), color: _sendAsDm ? StreamChatTheme.of(context).accentColor - : Colors.white, + : StreamChatTheme.of(context).colorTheme.white, child: InkWell( onTap: () { setState(() { @@ -288,7 +291,7 @@ class MessageInputState extends State { : CrossFadeState.showSecond, firstChild: StreamSvgIcon.check( size: 16.0, - color: Colors.white, + color: StreamChatTheme.of(context).colorTheme.white, ), secondChild: SizedBox( height: 16, @@ -418,7 +421,9 @@ class MessageInputState extends State { mainAxisAlignment: MainAxisAlignment.center, children: [ StreamSvgIcon.lightning( - color: Colors.white, + color: StreamChatTheme.of(context) + .colorTheme + .white, size: 16.0, ), Text( @@ -426,7 +431,10 @@ class MessageInputState extends State { style: StreamChatTheme.of(context) .textTheme .footnote - .copyWith(color: Colors.white), + .copyWith( + color: StreamChatTheme.of(context) + .colorTheme + .white), ), ], ), @@ -633,7 +641,10 @@ class MessageInputState extends State { Text( 'Instant Commands', style: TextStyle( - color: Colors.black.withOpacity(.5), + color: StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(.5), ), ) ], @@ -664,7 +675,9 @@ class MessageInputState extends State { backgroundColor: StreamChatTheme.of(context).accentColor, child: StreamSvgIcon.lightning( - color: Colors.white, + color: StreamChatTheme.of(context) + .colorTheme + .white, size: 12.5, ), maxRadius: 12, @@ -698,24 +711,33 @@ class MessageInputState extends State { ? StreamChatTheme.of(context).accentColor : (!_attachmentContainsFile ? StreamChatTheme.of(context).accentColor - : Colors.black.withOpacity(0.2)); + : StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(0.2)); break; case 1: return _attachmentContainsFile ? StreamChatTheme.of(context).accentColor : (_attachments.isEmpty - ? Colors.black.withOpacity(0.5) - : Colors.black.withOpacity(0.2)); + ? StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(0.5) + : StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(0.2)); break; case 2: return _attachmentContainsFile && _attachments.isNotEmpty - ? Colors.black.withOpacity(0.2) - : Colors.black.withOpacity(0.5); + ? StreamChatTheme.of(context).colorTheme.black.withOpacity(0.2) + : StreamChatTheme.of(context).colorTheme.black.withOpacity(0.5); break; case 3: return _attachmentContainsFile && _attachments.isNotEmpty - ? Colors.black.withOpacity(0.2) - : Colors.black.withOpacity(0.5); + ? StreamChatTheme.of(context).colorTheme.black.withOpacity(0.2) + : StreamChatTheme.of(context).colorTheme.black.withOpacity(0.5); break; } } @@ -791,7 +813,7 @@ class MessageInputState extends State { }, child: Container( decoration: BoxDecoration( - color: Colors.white, + color: StreamChatTheme.of(context).colorTheme.white, borderRadius: BorderRadius.only( topLeft: Radius.circular(16.0), topRight: Radius.circular(16.0), @@ -820,7 +842,7 @@ class MessageInputState extends State { Expanded( child: Container( decoration: BoxDecoration( - color: Colors.white, + color: StreamChatTheme.of(context).colorTheme.white, borderRadius: BorderRadius.circular(8.0), ), child: _buildPickerSection(), @@ -1023,7 +1045,7 @@ class MessageInputState extends State { CircleAvatar _buildGiphyIcon() { if (kIsWeb) { return CircleAvatar( - backgroundColor: Colors.black, + backgroundColor: StreamChatTheme.of(context).colorTheme.black, child: Image.asset( 'images/giphy_icon.png', package: 'stream_chat_flutter', @@ -1223,7 +1245,10 @@ class MessageInputState extends State { child: Text( 'Emoji matching "$query"', style: TextStyle( - color: Colors.black.withOpacity(.5), + color: StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(.5), ), ), ) @@ -1317,10 +1342,15 @@ class MessageInputState extends State { child: InkWell( child: CircleAvatar( backgroundColor: - Colors.black.withOpacity(0.2), + StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(0.2), maxRadius: 12.0, child: StreamSvgIcon.close( - color: Colors.white, + color: StreamChatTheme.of(context) + .colorTheme + .white, ), ), onTap: () { @@ -1405,11 +1435,11 @@ class MessageInputState extends State { _attachments.remove(attachment); }); }, - fillColor: Colors.black.withOpacity(.5), + fillColor: StreamChatTheme.of(context).colorTheme.black.withOpacity(.5), child: Center( child: StreamSvgIcon.close( size: 24, - color: Colors.white, + color: StreamChatTheme.of(context).colorTheme.white, ), ), ), diff --git a/lib/src/message_list_view.dart b/lib/src/message_list_view.dart index 7452fd6d..fd31b996 100644 --- a/lib/src/message_list_view.dart +++ b/lib/src/message_list_view.dart @@ -254,7 +254,11 @@ class _MessageListViewState extends State { style: StreamChatTheme.of(context) .textTheme .footnote - .copyWith(color: Colors.black.withOpacity(.5)), + .copyWith( + color: StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(.5)), ), ); } @@ -524,9 +528,9 @@ class _MessageListViewState extends State { clipBehavior: Clip.none, children: [ FloatingActionButton( - backgroundColor: Colors.white, + backgroundColor: StreamChatTheme.of(context).colorTheme.white, child: StreamSvgIcon.down( - color: Colors.black, + color: StreamChatTheme.of(context).colorTheme.black, ), onPressed: () { if (unreadCount > 0) { diff --git a/lib/src/message_reactions_modal.dart b/lib/src/message_reactions_modal.dart index e5043e62..a6a7e54c 100644 --- a/lib/src/message_reactions_modal.dart +++ b/lib/src/message_reactions_modal.dart @@ -60,7 +60,10 @@ class MessageReactionsModal extends StatelessWidget { sigmaY: 10.8731, ), child: Container( - color: Colors.black.withOpacity(0.1), + color: StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(0.1), ), ), ), diff --git a/lib/src/message_search_list_view.dart b/lib/src/message_search_list_view.dart index 087ae839..989234b3 100644 --- a/lib/src/message_search_list_view.dart +++ b/lib/src/message_search_list_view.dart @@ -4,6 +4,7 @@ import 'package:flutter/material.dart'; import 'package:stream_chat/stream_chat.dart'; import 'package:stream_chat_flutter/src/message_search_item.dart'; +import '../stream_chat_flutter.dart'; import 'lazy_load_scroll_view.dart'; import 'message_search_bloc.dart'; @@ -127,8 +128,8 @@ class _MessageSearchListViewState extends State { return Container( height: 1, color: Theme.of(context).brightness == Brightness.dark - ? Colors.white.withOpacity(0.1) - : Colors.black.withOpacity(0.1), + ? StreamChatTheme.of(context).colorTheme.white.withOpacity(0.1) + : StreamChatTheme.of(context).colorTheme.black.withOpacity(0.1), ); } @@ -313,8 +314,14 @@ class _MessageSearchListViewState extends State { begin: Alignment.centerLeft, end: Alignment.centerRight, colors: [ - Colors.black.withOpacity(0.02), - Colors.white.withOpacity(0.05), + StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(0.02), + StreamChatTheme.of(context) + .colorTheme + .white + .withOpacity(0.05), ], stops: [0, 1], ), @@ -327,7 +334,10 @@ class _MessageSearchListViewState extends State { child: Text( '${items.length} results', style: TextStyle( - color: Colors.black.withOpacity(0.5), + color: StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(0.5), ), ), ), diff --git a/lib/src/message_widget.dart b/lib/src/message_widget.dart index f3e5b108..7b185f97 100644 --- a/lib/src/message_widget.dart +++ b/lib/src/message_widget.dart @@ -327,10 +327,16 @@ class _MessageWidgetState extends State { .brightness == Brightness .dark - ? Colors.white + ? StreamChatTheme.of( + context) + .colorTheme + .white .withAlpha( 24) - : Colors.black + : StreamChatTheme.of( + context) + .colorTheme + .black .withAlpha( 24), ), @@ -414,16 +420,18 @@ class _MessageWidgetState extends State { mainAxisSize: MainAxisSize.min, children: [ StreamSvgIcon.eye( - color: Colors.black.withOpacity(0.5), + color: + StreamChatTheme.of(context).colorTheme.black.withOpacity(0.5), size: 16.0, ), SizedBox(width: 8.0), Text( 'Only visible to you', - style: StreamChatTheme.of(context) - .textTheme - .footnote - .copyWith(color: Colors.black.withOpacity(0.5)), + style: StreamChatTheme.of(context).textTheme.footnote.copyWith( + color: StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(0.5)), ), ], ), @@ -551,7 +559,7 @@ class _MessageWidgetState extends State { bottom: 0, top: 0, child: Material( - color: Colors.white, + color: StreamChatTheme.of(context).colorTheme.white, clipBehavior: Clip.antiAlias, shape: CircleBorder(), child: Padding( @@ -664,8 +672,8 @@ class _MessageWidgetState extends State { widget.borderSide ?? BorderSide( color: Theme.of(context).brightness == Brightness.dark - ? Colors.white.withAlpha(24) - : Colors.black.withAlpha(24), + ? StreamChatTheme.of(context).colorTheme.white.withAlpha(24) + : StreamChatTheme.of(context).colorTheme.black.withAlpha(24), ), borderRadius: widget.attachmentBorderRadiusGeometry ?? widget.borderRadiusGeometry ?? @@ -820,8 +828,8 @@ class _MessageWidgetState extends State { 'MESSAGE FAILED · CLICK TO TRY AGAIN', style: widget.messageTheme.messageText.copyWith( color: Theme.of(context).brightness == Brightness.dark - ? Colors.white.withOpacity(.5) - : Colors.black.withOpacity(.5), + ? StreamChatTheme.of(context).colorTheme.white.withOpacity(.5) + : StreamChatTheme.of(context).colorTheme.black.withOpacity(.5), fontSize: 11, ), ); @@ -831,8 +839,8 @@ class _MessageWidgetState extends State { 'MESSAGE UPDATE FAILED · CLICK TO TRY AGAIN', style: widget.messageTheme.messageText.copyWith( color: Theme.of(context).brightness == Brightness.dark - ? Colors.white.withOpacity(.5) - : Colors.black.withOpacity(.5), + ? StreamChatTheme.of(context).colorTheme.white.withOpacity(.5) + : StreamChatTheme.of(context).colorTheme.black.withOpacity(.5), fontSize: 11, ), ); @@ -842,8 +850,8 @@ class _MessageWidgetState extends State { 'MESSAGE DELETE FAILED · CLICK TO TRY AGAIN', style: widget.messageTheme.messageText.copyWith( color: Theme.of(context).brightness == Brightness.dark - ? Colors.white.withOpacity(.5) - : Colors.black.withOpacity(.5), + ? StreamChatTheme.of(context).colorTheme.white.withOpacity(.5) + : StreamChatTheme.of(context).colorTheme.black.withOpacity(.5), fontSize: 11, ), ); diff --git a/lib/src/reaction_bubble.dart b/lib/src/reaction_bubble.dart index 87dc7a92..f7c9c142 100644 --- a/lib/src/reaction_bubble.dart +++ b/lib/src/reaction_bubble.dart @@ -108,7 +108,10 @@ class ReactionBubble extends StatelessWidget { color: (!highlightOwnReactions || reaction.user.id == StreamChat.of(context).user.id) ? StreamChatTheme.of(context).accentColor - : Colors.black.withOpacity(.5), + : StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(.5), ) : Icon( Icons.help_outline_rounded, @@ -116,7 +119,10 @@ class ReactionBubble extends StatelessWidget { color: (!highlightOwnReactions || reaction.user.id == StreamChat.of(context).user.id) ? StreamChatTheme.of(context).accentColor - : Colors.black.withOpacity(.5), + : StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(.5), ), ); } diff --git a/lib/src/stream_chat_theme.dart b/lib/src/stream_chat_theme.dart index d4237270..573e646b 100644 --- a/lib/src/stream_chat_theme.dart +++ b/lib/src/stream_chat_theme.dart @@ -254,7 +254,7 @@ class StreamChatThemeData { colorTheme: colorTheme, secondaryColor: Color(0xffEAEAEA), accentColor: accentColor, - primaryColor: isDark ? Colors.black : Colors.white, + primaryColor: isDark ? colorTheme.black : colorTheme.white, primaryIconTheme: IconThemeData( color: isDark ? Colors.white : Colors.black.withOpacity(.5)), defaultChannelImage: (context, channel) => SizedBox(), diff --git a/lib/src/unread_indicator.dart b/lib/src/unread_indicator.dart index c9f42fad..42e6c78d 100644 --- a/lib/src/unread_indicator.dart +++ b/lib/src/unread_indicator.dart @@ -34,7 +34,7 @@ class UnreadIndicator extends StatelessWidget { '${snapshot.data}', style: TextStyle( fontSize: 11, - color: Colors.white, + color: StreamChatTheme.of(context).colorTheme.white, ), ), ), diff --git a/lib/src/user_avatar.dart b/lib/src/user_avatar.dart index 756252cc..c0b2a712 100644 --- a/lib/src/user_avatar.dart +++ b/lib/src/user_avatar.dart @@ -99,7 +99,7 @@ class UserAvatar extends StatelessWidget { color: Color(0xff20E070), ), ), - color: Colors.white, + color: StreamChatTheme.of(context).colorTheme.white, ), ), ), diff --git a/lib/src/user_item.dart b/lib/src/user_item.dart index 0c6c196d..49a6d5e3 100644 --- a/lib/src/user_item.dart +++ b/lib/src/user_item.dart @@ -76,7 +76,7 @@ class UserItem extends StatelessWidget { ? CircleAvatar( child: StreamSvgIcon.check( size: 20, - color: Colors.white, + color: StreamChatTheme.of(context).colorTheme.white, ), radius: 10, ) @@ -94,10 +94,8 @@ class UserItem extends StatelessWidget { user.online == true ? 'Online' : 'Last online ${Jiffy(user.lastActive).fromNow()}', - style: StreamChatTheme.of(context) - .textTheme - .footnote - .copyWith(color: Colors.black.withOpacity(.5)), + style: StreamChatTheme.of(context).textTheme.footnote.copyWith( + color: StreamChatTheme.of(context).colorTheme.black.withOpacity(.5)), ); } } diff --git a/lib/src/user_list_view.dart b/lib/src/user_list_view.dart index cc3c1125..1108c24d 100644 --- a/lib/src/user_list_view.dart +++ b/lib/src/user_list_view.dart @@ -356,7 +356,8 @@ class _UserListViewState extends State headerItem: (header) { return Container( key: ValueKey('HEADER-$header'), - color: Colors.black.withOpacity(0.05), + color: + StreamChatTheme.of(context).colorTheme.black.withOpacity(0.05), child: Padding( padding: const EdgeInsets.symmetric(horizontal: 8.0, vertical: 6), child: Text( @@ -364,7 +365,10 @@ class _UserListViewState extends State style: TextStyle( fontWeight: FontWeight.bold, fontSize: 14.5, - color: Colors.black.withOpacity(0.3)), + color: StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(0.3)), ), ), ); @@ -472,8 +476,8 @@ class _UserListViewState extends State return Container( height: 1, color: Theme.of(context).brightness == Brightness.dark - ? Colors.white.withOpacity(0.1) - : Colors.black.withOpacity(0.1), + ? StreamChatTheme.of(context).colorTheme.white.withOpacity(0.1) + : StreamChatTheme.of(context).colorTheme.black.withOpacity(0.1), ); } diff --git a/lib/src/utils.dart b/lib/src/utils.dart index 60eca678..f1f1b68a 100644 --- a/lib/src/utils.dart +++ b/lib/src/utils.dart @@ -25,7 +25,7 @@ Future showConfirmationDialog( String cancelText, }) { return showModalBottomSheet( - backgroundColor: Colors.white, + backgroundColor: StreamChatTheme.of(context).colorTheme.white, context: context, shape: RoundedRectangleBorder( borderRadius: BorderRadius.only( @@ -65,7 +65,10 @@ Future showConfirmationDialog( child: Text( cancelText, style: TextStyle( - color: Colors.black.withOpacity(0.5), + color: StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(0.5), fontWeight: FontWeight.w400), ), onPressed: () { From 23fef38f2c3d264542257d81df8b8fa5625836aa Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Tue, 29 Dec 2020 23:16:17 +0530 Subject: [PATCH 0676/1140] fix --- example/ios/Flutter/.last_build_id | 2 +- example/ios/Podfile.lock | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/example/ios/Flutter/.last_build_id b/example/ios/Flutter/.last_build_id index a2e31d3e..e72273c3 100644 --- a/example/ios/Flutter/.last_build_id +++ b/example/ios/Flutter/.last_build_id @@ -1 +1 @@ -209b1a40522bc1cb0ea3596a28cded5e \ No newline at end of file +13a41b8138c4868054e44b5158f3bdd6 \ No newline at end of file diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock index af57742c..f266b656 100644 --- a/example/ios/Podfile.lock +++ b/example/ios/Podfile.lock @@ -296,4 +296,4 @@ SPEC CHECKSUMS: PODFILE CHECKSUM: eb001256612a59f8f9e4d083ad8b9671e69dd184 -COCOAPODS: 1.8.3 +COCOAPODS: 1.10.0 From 27578c7a0a033aa69b0e2501d2533ed4d5c6a52d Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Wed, 30 Dec 2020 12:45:16 +0530 Subject: [PATCH 0677/1140] Minor ui fixes Signed-off-by: Sahil Kumar --- example/lib/chat_info_screen.dart | 33 +++++++++++++++- example/lib/group_info_screen.dart | 46 ++++++++++++----------- lib/src/channel_file_display_screen.dart | 21 ++++++----- lib/src/channel_media_display_screen.dart | 22 +++++++---- 4 files changed, 82 insertions(+), 40 deletions(-) diff --git a/example/lib/chat_info_screen.dart b/example/lib/chat_info_screen.dart index 5f7f7c63..53adebb7 100644 --- a/example/lib/chat_info_screen.dart +++ b/example/lib/chat_info_screen.dart @@ -381,12 +381,43 @@ class __SharedGroupsScreenState extends State<_SharedGroupsScreen> { }, ), builder: (context, snapshot) { - if (snapshot.data == null) { + if (!snapshot.hasData) { return Center( child: CircularProgressIndicator(), ); } + if (snapshot.data.isEmpty) { + return Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + StreamSvgIcon.message( + size: 136.0, + color: Color(0xffdbdbdb), + ), + SizedBox(height: 16.0), + Text( + 'No Shared Groups', + style: TextStyle( + fontSize: 14.0, + color: Color(0xff000000), + ), + ), + SizedBox(height: 8.0), + Text( + 'Group shared with User will appear here.', + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 14.0, + color: Color(0xff000000).withOpacity(0.5), + ), + ), + ], + ), + ); + } + return ListView.builder( itemCount: snapshot.data.length, itemBuilder: (context, position) { diff --git a/example/lib/group_info_screen.dart b/example/lib/group_info_screen.dart index b4972165..5a2d4a7d 100644 --- a/example/lib/group_info_screen.dart +++ b/example/lib/group_info_screen.dart @@ -671,32 +671,34 @@ class _GroupInfoScreenState extends State { ); }), _buildModalListTile( - StreamSvgIcon.message( - color: Color(0xff7a7a7a), - size: 24.0, - ), - 'Message', () async { - var client = StreamChat.of(context).client; + StreamSvgIcon.message( + color: Color(0xff7a7a7a), + size: 24.0, + ), + 'Message', + () async { + var client = StreamChat.of(context).client; - var c = client.channel('messaging', extraData: { - 'members': [ - user.id, - StreamChat.of(context).user.id, - ], - }); + var c = client.channel('messaging', extraData: { + 'members': [ + user.id, + StreamChat.of(context).user.id, + ], + }); - await c.watch(); + await c.watch(); - await Navigator.push( - context, - MaterialPageRoute( - builder: (context) => StreamChannel( - channel: c, - child: ChannelPage(), + await Navigator.push( + context, + MaterialPageRoute( + builder: (context) => StreamChannel( + channel: c, + child: ChannelPage(), + ), ), - ), - ); - }), + ); + }, + ), if (!channel.isDistinct && StreamChat.of(context).user.id != user.id && isUserAdmin) diff --git a/lib/src/channel_file_display_screen.dart b/lib/src/channel_file_display_screen.dart index c8b34ea0..c319b524 100644 --- a/lib/src/channel_file_display_screen.dart +++ b/lib/src/channel_file_display_screen.dart @@ -15,9 +15,13 @@ class ChannelFileDisplayScreen extends StatefulWidget { /// message_limit: how many messages should be included to each channel final PaginationParams paginationParams; - ChannelFileDisplayScreen({ + /// The builder used when the file list is empty. + final WidgetBuilder emptyBuilder; + + const ChannelFileDisplayScreen({ this.sortOptions, this.paginationParams, + this.emptyBuilder, }); @override @@ -93,6 +97,9 @@ class _ChannelFileDisplayScreenState extends State { } if (snapshot.data.isEmpty) { + if (widget.emptyBuilder != null) { + return widget.emptyBuilder(context); + } return Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, @@ -101,19 +108,15 @@ class _ChannelFileDisplayScreenState extends State { size: 136.0, color: Color(0xffdbdbdb), ), - SizedBox( - height: 16.0, - ), + SizedBox(height: 16.0), Text( - 'No Media', + 'No Files', style: TextStyle( fontSize: 14.0, color: Color(0xff000000), ), ), - SizedBox( - height: 8.0, - ), + SizedBox(height: 8.0), Text( 'Files sent in this chat will appear here', textAlign: TextAlign.center, @@ -127,7 +130,7 @@ class _ChannelFileDisplayScreenState extends State { ); } - Map media = {}; + final media = {}; for (var item in snapshot.data) { item.message.attachments.where((e) => e.type == 'file').forEach((e) { diff --git a/lib/src/channel_media_display_screen.dart b/lib/src/channel_media_display_screen.dart index 41ec41b3..21eeb611 100644 --- a/lib/src/channel_media_display_screen.dart +++ b/lib/src/channel_media_display_screen.dart @@ -17,7 +17,14 @@ class ChannelMediaDisplayScreen extends StatefulWidget { /// message_limit: how many messages should be included to each channel final PaginationParams paginationParams; - ChannelMediaDisplayScreen({this.sortOptions, this.paginationParams}); + /// The builder used when the file list is empty. + final WidgetBuilder emptyBuilder; + + const ChannelMediaDisplayScreen({ + this.sortOptions, + this.paginationParams, + this.emptyBuilder, + }); @override _ChannelMediaDisplayScreenState createState() => @@ -92,6 +99,9 @@ class _ChannelMediaDisplayScreenState extends State { } if (snapshot.data.isEmpty) { + if (widget.emptyBuilder != null) { + return widget.emptyBuilder(context); + } return Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, @@ -100,9 +110,7 @@ class _ChannelMediaDisplayScreenState extends State { size: 136.0, color: Color(0xffdbdbdb), ), - SizedBox( - height: 16.0, - ), + SizedBox(height: 16.0), Text( 'No Media', style: TextStyle( @@ -110,9 +118,7 @@ class _ChannelMediaDisplayScreenState extends State { color: Color(0xff000000), ), ), - SizedBox( - height: 8.0, - ), + SizedBox(height: 8.0), Text( 'Photos or video sent in this chat will \nappear here', textAlign: TextAlign.center, @@ -126,7 +132,7 @@ class _ChannelMediaDisplayScreenState extends State { ); } - List<_AssetPackage> media = []; + final media = <_AssetPackage>[]; for (var item in snapshot.data) { item.message.attachments From bf839e9bceae53552715a0b1ce8ab35a9793cc4b Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Wed, 30 Dec 2020 13:49:25 +0530 Subject: [PATCH 0678/1140] Added theme to main app --- example/lib/main.dart | 7 +- lib/src/stream_chat_theme.dart | 126 +++++++++++++++++++++++---------- 2 files changed, 94 insertions(+), 39 deletions(-) diff --git a/example/lib/main.dart b/example/lib/main.dart index 6f4562b6..ef281eac 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -52,10 +52,13 @@ class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return StreamChat( + streamChatThemeData: StreamChatThemeData.getDefaultTheme( + ThemeData.dark(), + ), client: client, child: MaterialApp( debugShowCheckedModeBanner: false, - theme: ThemeData.dark(), + theme: ThemeData.light(), darkTheme: ThemeData.dark(), //TODO change to system once dark theme is implemented themeMode: ThemeMode.dark, @@ -426,7 +429,7 @@ class ChannelPage extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( - backgroundColor: Color.fromRGBO(252, 252, 252, 1), + backgroundColor: StreamChatTheme.of(context).backgroundColor, appBar: ChannelHeader( showTypingIndicator: false, ), diff --git a/lib/src/stream_chat_theme.dart b/lib/src/stream_chat_theme.dart index 573e646b..5e6a0398 100644 --- a/lib/src/stream_chat_theme.dart +++ b/lib/src/stream_chat_theme.dart @@ -247,18 +247,17 @@ class StreamChatThemeData { static StreamChatThemeData getDefaultTheme(ThemeData theme) { final accentColor = Color(0xff006cff); final isDark = theme.brightness == Brightness.dark; - final textTheme = TextTheme(); + final textTheme = isDark ? TextTheme.dark() : TextTheme.light(); final colorTheme = isDark ? ColorTheme.dark() : ColorTheme.light(); return StreamChatThemeData( textTheme: textTheme, colorTheme: colorTheme, secondaryColor: Color(0xffEAEAEA), accentColor: accentColor, - primaryColor: isDark ? colorTheme.black : colorTheme.white, - primaryIconTheme: IconThemeData( - color: isDark ? Colors.white : Colors.black.withOpacity(.5)), + primaryColor: colorTheme.white, + primaryIconTheme: IconThemeData(color: colorTheme.black.withOpacity(.5)), defaultChannelImage: (context, channel) => SizedBox(), - backgroundColor: isDark ? Colors.black : Colors.white, + backgroundColor: colorTheme.white, defaultUserImage: (context, user) => Center( child: CachedNetworkImage( filterQuality: FilterQuality.high, @@ -280,7 +279,7 @@ class StreamChatThemeData { color: Color(0xff7A7A7A), ), lastMessageAt: textTheme.footnote.copyWith( - color: Colors.black.withOpacity(.5), + color: colorTheme.black.withOpacity(.5), ), ), channelTheme: ChannelTheme( @@ -295,20 +294,17 @@ class StreamChatThemeData { width: 40, ), ), - color: isDark ? Colors.black : Colors.white, + color: colorTheme.white, title: TextStyle( fontSize: 14, - color: isDark ? Colors.white : Colors.black, + color: colorTheme.black, ), lastMessageAt: TextStyle( fontSize: 11, - color: isDark - ? Colors.white.withOpacity(.5) - : Colors.black.withOpacity(.5), + color: colorTheme.black.withOpacity(.5), ), ), - inputBackground: - isDark ? Colors.black.withAlpha(12) : Colors.white.withAlpha(12), + inputBackground: colorTheme.white.withAlpha(12), inputGradient: LinearGradient(colors: [ Color(0xFF00AEFF), Color(0xFF0076FF), @@ -317,12 +313,10 @@ class StreamChatThemeData { ownMessageTheme: MessageTheme( messageText: TextStyle( fontSize: 14.5, - color: isDark ? Colors.white : Colors.black, + color: colorTheme.black, ), createdAt: TextStyle( - color: isDark - ? Colors.white.withOpacity(.5) - : Colors.black.withOpacity(.5), + color: colorTheme.black.withOpacity(.5), fontSize: 12, ), replies: TextStyle( @@ -331,7 +325,7 @@ class StreamChatThemeData { fontSize: 12, ), messageBackgroundColor: isDark ? Color(0xff191919) : Color(0xffEAEAEA), - reactionsBackgroundColor: isDark ? Colors.black : Colors.white, + reactionsBackgroundColor: colorTheme.white, reactionsBorderColor: isDark ? Color(0xff191919) : Color(0xffEAEAEA), replyThreadColor: isDark ? Color(0xff191919) : Color(0xffEAEAEA), avatarTheme: AvatarTheme( @@ -348,15 +342,13 @@ class StreamChatThemeData { otherMessageTheme: MessageTheme( reactionsBackgroundColor: isDark ? Color(0xff191919) : Color(0xffEAEAEA), - reactionsBorderColor: isDark ? Colors.black : Colors.white, + reactionsBorderColor: colorTheme.white, messageText: TextStyle( fontSize: 14.5, - color: isDark ? Colors.white : Colors.black, + color: colorTheme.black, ), createdAt: TextStyle( - color: isDark - ? Colors.white.withOpacity(.5) - : Colors.black.withOpacity(.5), + color: colorTheme.black.withOpacity(.5), fontSize: 12, ), replies: TextStyle( @@ -367,9 +359,8 @@ class StreamChatThemeData { messageLinks: TextStyle( color: accentColor, ), - messageBackgroundColor: isDark ? Colors.black : Colors.white, - replyThreadColor: - isDark ? Colors.white.withAlpha(24) : Colors.black.withAlpha(24), + messageBackgroundColor: colorTheme.white, + replyThreadColor: colorTheme.black.withAlpha(24), avatarTheme: AvatarTheme( borderRadius: BorderRadius.circular(20), constraints: BoxConstraints.tightFor( @@ -404,7 +395,13 @@ class StreamChatThemeData { } } +enum TextThemeType { + light, + dark, +} + class TextTheme { + final TextThemeType type; final TextStyle title; final TextStyle headlineBold; final TextStyle headline; @@ -414,7 +411,8 @@ class TextTheme { final TextStyle footnote; final TextStyle captionBold; - TextTheme({ + TextTheme.light({ + this.type = TextThemeType.light, this.title = const TextStyle( fontSize: 22, fontWeight: FontWeight.bold, @@ -448,6 +446,49 @@ class TextTheme { ), }); + TextTheme.dark({ + this.type = TextThemeType.dark, + this.title = const TextStyle( + fontSize: 22, + fontWeight: FontWeight.bold, + color: Colors.white, + ), + this.headlineBold = const TextStyle( + fontSize: 16, + fontWeight: FontWeight.bold, + color: Colors.white, + ), + this.headline = const TextStyle( + fontSize: 16, + fontWeight: FontWeight.w500, + color: Colors.white, + ), + this.bodyBold = const TextStyle( + fontSize: 14, + fontWeight: FontWeight.bold, + color: Colors.white, + ), + this.body = const TextStyle( + fontSize: 14, + fontWeight: FontWeight.w500, + color: Colors.white, + ), + this.footnoteBold = const TextStyle( + fontSize: 12, + fontWeight: FontWeight.w500, + color: Colors.white, + ), + this.footnote = const TextStyle( + fontSize: 12, + color: Colors.white, + ), + this.captionBold = const TextStyle( + fontSize: 10, + fontWeight: FontWeight.bold, + color: Colors.white, + ), + }); + TextTheme copyWith({ TextStyle body, TextStyle title, @@ -458,16 +499,27 @@ class TextTheme { TextStyle footnote, TextStyle captionBold, }) { - return TextTheme( - body: body ?? this.body, - title: title ?? this.title, - headlineBold: headlineBold ?? this.headlineBold, - headline: headline ?? this.headline, - bodyBold: bodyBold ?? this.bodyBold, - footnoteBold: footnoteBold ?? this.footnoteBold, - footnote: footnote ?? this.footnote, - captionBold: captionBold ?? this.captionBold, - ); + return type == TextThemeType.light + ? TextTheme.light( + body: body ?? this.body, + title: title ?? this.title, + headlineBold: headlineBold ?? this.headlineBold, + headline: headline ?? this.headline, + bodyBold: bodyBold ?? this.bodyBold, + footnoteBold: footnoteBold ?? this.footnoteBold, + footnote: footnote ?? this.footnote, + captionBold: captionBold ?? this.captionBold, + ) + : TextTheme.dark( + body: body ?? this.body, + title: title ?? this.title, + headlineBold: headlineBold ?? this.headlineBold, + headline: headline ?? this.headline, + bodyBold: bodyBold ?? this.bodyBold, + footnoteBold: footnoteBold ?? this.footnoteBold, + footnote: footnote ?? this.footnote, + captionBold: captionBold ?? this.captionBold, + ); } } From e8afb3e9a9858ff9f373b497d040498e099e38c7 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Wed, 30 Dec 2020 14:00:42 +0530 Subject: [PATCH 0679/1140] Removed type --- lib/src/stream_chat_theme.dart | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/lib/src/stream_chat_theme.dart b/lib/src/stream_chat_theme.dart index 5e6a0398..2b6a74ae 100644 --- a/lib/src/stream_chat_theme.dart +++ b/lib/src/stream_chat_theme.dart @@ -401,7 +401,6 @@ enum TextThemeType { } class TextTheme { - final TextThemeType type; final TextStyle title; final TextStyle headlineBold; final TextStyle headline; @@ -412,7 +411,6 @@ class TextTheme { final TextStyle captionBold; TextTheme.light({ - this.type = TextThemeType.light, this.title = const TextStyle( fontSize: 22, fontWeight: FontWeight.bold, @@ -447,7 +445,6 @@ class TextTheme { }); TextTheme.dark({ - this.type = TextThemeType.dark, this.title = const TextStyle( fontSize: 22, fontWeight: FontWeight.bold, @@ -490,6 +487,7 @@ class TextTheme { }); TextTheme copyWith({ + TextThemeType type = TextThemeType.light, TextStyle body, TextStyle title, TextStyle headlineBold, From d794a40b4be70616d2db10f48d627e87238dac7c Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Wed, 30 Dec 2020 14:22:40 +0530 Subject: [PATCH 0680/1140] fix bg --- lib/src/stream_chat_theme.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/stream_chat_theme.dart b/lib/src/stream_chat_theme.dart index 2b6a74ae..407a4fcd 100644 --- a/lib/src/stream_chat_theme.dart +++ b/lib/src/stream_chat_theme.dart @@ -257,7 +257,7 @@ class StreamChatThemeData { primaryColor: colorTheme.white, primaryIconTheme: IconThemeData(color: colorTheme.black.withOpacity(.5)), defaultChannelImage: (context, channel) => SizedBox(), - backgroundColor: colorTheme.white, + backgroundColor: colorTheme.whiteSnow, defaultUserImage: (context, user) => Center( child: CachedNetworkImage( filterQuality: FilterQuality.high, From 4e7fb6123c9e93d13f15007bec358bcfcfff3d7a Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Wed, 30 Dec 2020 14:50:13 +0530 Subject: [PATCH 0681/1140] fixes Signed-off-by: Sahil Kumar --- lib/src/channel_file_display_screen.dart | 4 +- lib/src/channel_list_view.dart | 11 +- lib/src/channel_media_display_screen.dart | 4 +- lib/src/image_footer.dart | 432 +++++++++++----------- 4 files changed, 225 insertions(+), 226 deletions(-) diff --git a/lib/src/channel_file_display_screen.dart b/lib/src/channel_file_display_screen.dart index c319b524..a6b1008e 100644 --- a/lib/src/channel_file_display_screen.dart +++ b/lib/src/channel_file_display_screen.dart @@ -90,9 +90,7 @@ class _ChannelFileDisplayScreenState extends State { builder: (context, snapshot) { if (snapshot.data == null) { return Center( - child: CircularProgressIndicator( - backgroundColor: StreamChatTheme.of(context).accentColor, - ), + child: const CircularProgressIndicator(), ); } diff --git a/lib/src/channel_list_view.dart b/lib/src/channel_list_view.dart index 5efa1e29..126e6d0d 100644 --- a/lib/src/channel_list_view.dart +++ b/lib/src/channel_list_view.dart @@ -75,6 +75,7 @@ class ChannelListView extends StatefulWidget { this.swipeToAction = false, this.pullToRefresh = true, this.crossAxisCount = 1, + this.padding, this.selectedChannels = const [], }) : super(key: key); @@ -139,6 +140,9 @@ class ChannelListView extends StatefulWidget { /// The number of children in the cross axis. final int crossAxisCount; + /// The amount of space by which to inset the children. + final EdgeInsetsGeometry padding; + final List selectedChannels; @override @@ -268,6 +272,7 @@ class _ChannelListViewState extends State if (channels.isNotEmpty) { if (widget.crossAxisCount > 1) { child = GridView.builder( + padding: widget.padding, gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: widget.crossAxisCount), itemCount: channels.length, @@ -279,6 +284,7 @@ class _ChannelListViewState extends State ); } else { child = ListView.separated( + padding: widget.padding, physics: AlwaysScrollableScrollPhysics(), itemCount: channels.isNotEmpty ? channels.length + 1 : channels.length, @@ -306,6 +312,7 @@ class _ChannelListViewState extends State Widget _buildLoadingWidget() { return ListView( + padding: widget.padding, physics: AlwaysScrollableScrollPhysics(), children: List.generate( 25, @@ -331,9 +338,7 @@ class _ChannelListViewState extends State highlightColor: Color(0xffffffff), child: Column( children: [ - SizedBox( - height: 4.0, - ), + SizedBox(height: 4.0), Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ diff --git a/lib/src/channel_media_display_screen.dart b/lib/src/channel_media_display_screen.dart index 21eeb611..ddf52c66 100644 --- a/lib/src/channel_media_display_screen.dart +++ b/lib/src/channel_media_display_screen.dart @@ -92,9 +92,7 @@ class _ChannelMediaDisplayScreenState extends State { builder: (context, snapshot) { if (snapshot.data == null) { return Center( - child: CircularProgressIndicator( - backgroundColor: StreamChatTheme.of(context).accentColor, - ), + child: const CircularProgressIndicator(), ); } diff --git a/lib/src/image_footer.dart b/lib/src/image_footer.dart index 00b38a90..97e40cba 100644 --- a/lib/src/image_footer.dart +++ b/lib/src/image_footer.dart @@ -16,7 +16,7 @@ import 'package:stream_chat_flutter/src/stream_chat.dart'; import 'package:stream_chat_flutter/src/stream_chat_theme.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; -class ImageFooter extends StatefulWidget { +class ImageFooter extends StatefulWidget implements PreferredSizeWidget { /// Callback to call when pressing the back button. /// By default it calls [Navigator.pop] final VoidCallback onBackPressed; @@ -61,12 +61,12 @@ class ImageFooter extends StatefulWidget { class _ImageFooterState extends State { bool _userSearchMode = false; TextEditingController _searchController; - TextEditingController _messageController = TextEditingController(); - FocusNode _messageFocusNode = FocusNode(); + final TextEditingController _messageController = TextEditingController(); + final FocusNode _messageFocusNode = FocusNode(); String _channelNameQuery; - List _selectedChannels = []; + final List _selectedChannels = []; bool _loading = false; Timer _debounce; @@ -103,52 +103,54 @@ class _ImageFooterState extends State { @override Widget build(BuildContext context) { - return SafeArea( - child: Container( - color: - StreamChatTheme.of(context).channelTheme.channelHeaderTheme.color, - padding: EdgeInsets.symmetric(vertical: 8.0), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - IconButton( - icon: StreamSvgIcon.icon_SHARE( - size: 24.0, - color: Colors.black, + return SizedBox.fromSize( + size: widget.preferredSize, + child: MediaQuery.removePadding( + context: context, + removeTop: true, + child: BottomAppBar( + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + IconButton( + icon: StreamSvgIcon.icon_SHARE( + size: 24.0, + color: Colors.black, + ), + onPressed: () { + _buildShareModal(context); + }, ), - onPressed: () { - _buildShareModal(context); - }, - ), - InkWell( - onTap: widget.onTitleTap, - child: Container( - child: Column( - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisAlignment: MainAxisAlignment.center, - mainAxisSize: MainAxisSize.min, - children: [ - Text( - '${widget.currentPage + 1} of ${widget.totalPages}', - style: TextStyle( - fontSize: 16.0, - fontWeight: FontWeight.w700, - color: Colors.black, + InkWell( + onTap: widget.onTitleTap, + child: Container( + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.center, + mainAxisSize: MainAxisSize.min, + children: [ + Text( + '${widget.currentPage + 1} of ${widget.totalPages}', + style: TextStyle( + fontSize: 16.0, + fontWeight: FontWeight.w700, + color: Colors.black, + ), ), - ), - ], + ], + ), ), ), - ), - IconButton( - icon: StreamSvgIcon.Icon_grid( - color: Colors.black, + IconButton( + icon: StreamSvgIcon.Icon_grid( + color: Colors.black, + ), + onPressed: () { + _buildPhotosModal(context); + }, ), - onPressed: () { - _buildPhotosModal(context); - }, - ), - ], + ], + ), ), ), ); @@ -258,8 +260,8 @@ class _ImageFooterState extends State { ); } - void _buildShareModal(context) { - showDialog( + void _buildShareModal(context) async { + final result = await showDialog( context: context, builder: (context) { return StatefulBuilder(builder: (context, modalSetState) { @@ -282,10 +284,6 @@ class _ImageFooterState extends State { child: Column( children: [ _buildTextInputSection(modalSetState), - if (_userSearchMode) - SizedBox( - height: 22.0, - ), Expanded( child: ChannelsBloc( child: ChannelListView( @@ -302,6 +300,7 @@ class _ImageFooterState extends State { }); } }, + padding: const EdgeInsets.symmetric(vertical: 8), crossAxisCount: 4, pagination: PaginationParams( limit: 25, @@ -342,7 +341,8 @@ class _ImageFooterState extends State { ), ), Text( - 'No chat matches these keywords...'), + 'No chat matches these keywords...', + ), ], ), ), @@ -360,42 +360,30 @@ class _ImageFooterState extends State { Align( alignment: Alignment.bottomCenter, child: Container( - color: Colors.white, - height: 48.0, - child: Material( - child: InkWell( - onTap: () async { - var url = widget - .mediaAttachments[widget.currentPage] - .imageUrl ?? - widget - .mediaAttachments[widget.currentPage] - .assetUrl ?? - widget - .mediaAttachments[widget.currentPage] - .thumbUrl; - - if (widget - .mediaAttachments[widget.currentPage] - .type == - 'video') { + height: kToolbarHeight, + child: SizedBox.expand( + child: RaisedButton( + onPressed: () async { + final attachment = widget + .mediaAttachments[widget.currentPage]; + var url = attachment.imageUrl ?? + attachment.assetUrl ?? + attachment.thumbUrl; + if (attachment.type == 'video') { await _saveVideo(url); - Navigator.pop(context); } else { await _saveImage(url); - Navigator.pop(context); } + Navigator.pop(context); }, - child: SizedBox.expand( - child: Center( - child: Text( - 'Save to Photos', - style: TextStyle( - color: StreamChatTheme.of(context) - .accentColor, - fontWeight: FontWeight.bold, - ), - ), + color: Colors.white, + elevation: 8, + child: Text( + 'Save to Photos', + style: TextStyle( + color: + StreamChatTheme.of(context).accentColor, + fontWeight: FontWeight.bold, ), ), ), @@ -411,62 +399,74 @@ class _ImageFooterState extends State { }); }, ); + if (result == null) { + _selectedChannels.clear(); + } } Widget _buildTextInputSection(modalSetState) { if (_userSearchMode) { return Column( children: [ - SizedBox( - height: 16.0, - ), + SizedBox(height: 16.0), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - SizedBox( - width: 16.0, - ), + SizedBox(width: 8.0), Expanded( - child: TextField( - controller: _searchController, - cursorColor: Colors.black, - autofocus: true, - decoration: InputDecoration( - isDense: true, - prefixIconConstraints: - BoxConstraints.tight(Size(36.0, 44.0)), - prefixIcon: Padding( - padding: const EdgeInsets.symmetric( - vertical: 2.0, horizontal: 6.0), - child: StreamSvgIcon.search( - color: Colors.black, + child: Container( + height: 36, + margin: const EdgeInsets.symmetric( + vertical: 8, + horizontal: 8, + ), + child: TextField( + controller: _searchController, + cursorColor: Colors.black, + autofocus: true, + decoration: InputDecoration( + prefixIconConstraints: BoxConstraints.tight(Size(40, 24)), + prefixIcon: Padding( + padding: const EdgeInsets.only(left: 8, right: 8), + child: StreamSvgIcon.search( + color: Colors.black, + size: 24, + ), ), + hintText: 'Search', + hintStyle: TextStyle( + color: Colors.black.withOpacity(0.5), + fontSize: 14, + ), + enabledBorder: OutlineInputBorder( + borderSide: BorderSide( + color: Colors.black.withOpacity(0.08), + ), + borderRadius: BorderRadius.circular(24), + ), + focusedBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(24.0), + borderSide: BorderSide( + color: Colors.black.withOpacity(0.08), + ), + ), + contentPadding: EdgeInsets.zero, ), - hintText: 'Search', - border: OutlineInputBorder( - borderRadius: BorderRadius.circular(32.0), - borderSide: - BorderSide(color: Colors.black.withOpacity(0.08)), - ), - focusedBorder: OutlineInputBorder( - borderRadius: BorderRadius.circular(32.0), - borderSide: - BorderSide(color: Colors.black.withOpacity(0.08)), - ), - contentPadding: EdgeInsets.zero, ), ), ), - SizedBox( - width: 8.0, - ), IconButton( icon: StreamSvgIcon.close_small( color: Colors.black.withOpacity(0.5), ), + splashRadius: 24, onPressed: () { modalSetState(() { - _userSearchMode = false; + if (_searchController.text.isNotEmpty) { + _searchController.text = ''; + } else { + _userSearchMode = false; + } }); setState(() {}); }, @@ -475,80 +475,80 @@ class _ImageFooterState extends State { ), ], ); - } else { - return Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Padding( - padding: const EdgeInsets.symmetric(horizontal: 6.0), - child: IconButton( - icon: StreamSvgIcon.search( - color: Colors.black, - ), - iconSize: 24.0, - onPressed: () { - modalSetState(() { - _userSearchMode = true; - }); - }, - ), - ), - Padding( - padding: const EdgeInsets.all(16.0), - child: Text( - 'Select a Chat to Share', - style: TextStyle( - fontSize: 16.0, - fontWeight: FontWeight.w700, - color: Colors.black, - ), - ), - ), - Padding( - padding: const EdgeInsets.symmetric(horizontal: 6.0), - child: IconButton( - icon: StreamSvgIcon.share_arrow( - color: Colors.black, - ), - onPressed: () async { - var url = - widget.mediaAttachments[widget.currentPage].imageUrl ?? - widget.mediaAttachments[widget.currentPage].assetUrl ?? - widget.mediaAttachments[widget.currentPage].thumbUrl; - var type = - widget.mediaAttachments[widget.currentPage].type == 'image' - ? 'jpg' - : url?.split('?')?.first?.split('.')?.last ?? 'jpg'; - var request = await HttpClient().getUrl(Uri.parse(url)); - var response = await request.close(); - var bytes = await consolidateHttpClientResponseBytes(response); - await Share.file('File', 'image.$type', bytes, 'image/$type'); - }, - ), - ), - ], - ); } + return Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Padding( + padding: const EdgeInsets.symmetric(horizontal: 6.0), + child: IconButton( + icon: StreamSvgIcon.search( + color: Colors.black, + ), + iconSize: 24.0, + onPressed: () { + modalSetState(() { + _userSearchMode = true; + }); + }, + ), + ), + Padding( + padding: const EdgeInsets.all(16.0), + child: Text( + 'Select a Chat to Share', + style: TextStyle( + fontSize: 16.0, + fontWeight: FontWeight.w700, + color: Colors.black, + ), + ), + ), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 6.0), + child: IconButton( + icon: StreamSvgIcon.share_arrow( + color: Colors.black, + ), + onPressed: () async { + final attachment = widget.mediaAttachments[widget.currentPage]; + var url = attachment.imageUrl ?? + attachment.assetUrl ?? + attachment.thumbUrl; + var type = attachment.type == 'image' + ? 'jpg' + : url?.split('?')?.first?.split('.')?.last ?? 'jpg'; + var request = await HttpClient().getUrl(Uri.parse(url)); + var response = await request.close(); + var bytes = await consolidateHttpClientResponseBytes(response); + await Share.file('File', 'image.$type', bytes, 'image/$type'); + }, + ), + ), + ], + ); } Widget _buildShareTextInputSection(modalSetState) { return Align( alignment: Alignment.bottomCenter, - child: Container( - color: Colors.white, - height: 56.0, - child: _loading - ? Center( - child: Padding( - padding: const EdgeInsets.all(8.0), - child: CircularProgressIndicator(), - ), - ) - : Row( - children: [ - Expanded( - child: Padding( - padding: const EdgeInsets.only(left: 8.0), + child: BottomAppBar( + child: Container( + height: 40.0, + margin: const EdgeInsets.symmetric( + vertical: 8, + horizontal: 8, + ), + child: _loading + ? Center( + child: Padding( + padding: const EdgeInsets.all(8.0), + child: CircularProgressIndicator(), + ), + ) + : Row( + children: [ + Expanded( child: TextField( controller: _messageController, focusNode: _messageFocusNode, @@ -560,54 +560,52 @@ class _ImageFooterState extends State { setState(() {}); }, decoration: InputDecoration( - isDense: true, prefixText: ' ', hintText: 'Add a comment', - border: OutlineInputBorder( - borderRadius: BorderRadius.circular(32.0), + enabledBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(24.0), borderSide: BorderSide( color: Colors.black.withOpacity(0.16), ), ), focusedBorder: OutlineInputBorder( - borderRadius: BorderRadius.circular(32.0), + borderRadius: BorderRadius.circular(24.0), borderSide: BorderSide( color: Colors.black.withOpacity(0.16), )), - contentPadding: EdgeInsets.symmetric(vertical: 12.0), + contentPadding: const EdgeInsets.all(0), ), ), ), - ), - IconTheme( - data: StreamChatTheme.of(context) - .channelTheme - .messageInputButtonIconTheme, - child: Center( - child: Padding( - padding: const EdgeInsets.all(8.0), - child: InkWell( - onTap: () async { - modalSetState(() { - _loading = true; - }); - await sendMessage(); - modalSetState(() { - _loading = false; - }); - }, - child: Transform.rotate( - angle: -pi / 2, - child: StreamSvgIcon.Icon_send_message( - color: StreamChatTheme.of(context).accentColor, - ), + SizedBox(width: 8), + IconTheme( + data: StreamChatTheme.of(context) + .channelTheme + .messageInputButtonIconTheme, + child: IconButton( + onPressed: () async { + modalSetState(() => _loading = true); + await sendMessage(); + modalSetState(() => _loading = false); + }, + splashRadius: 24, + visualDensity: VisualDensity.compact, + constraints: BoxConstraints.tightFor( + height: 24, + width: 24, + ), + padding: EdgeInsets.zero, + icon: Transform.rotate( + angle: -pi / 2, + child: StreamSvgIcon.Icon_send_message( + color: StreamChatTheme.of(context).accentColor, ), ), ), ), - ), - ], - ), + ], + ), + ), ), ); } From 7047f3d9a48d82e4d83bf7962d41aad97182a35b Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Wed, 30 Dec 2020 15:06:40 +0530 Subject: [PATCH 0682/1140] [Image Attachment] Add a property to hide/show image title Signed-off-by: Sahil Kumar --- lib/src/channel_media_display_screen.dart | 1 + lib/src/image_attachment.dart | 7 +++++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/src/channel_media_display_screen.dart b/lib/src/channel_media_display_screen.dart index ddf52c66..b65f27ab 100644 --- a/lib/src/channel_media_display_screen.dart +++ b/lib/src/channel_media_display_screen.dart @@ -193,6 +193,7 @@ class _ChannelMediaDisplayScreenState extends State { ? ImageAttachment( attachment: media[position].attachment, message: media[position].message, + showTitle: false, size: Size( MediaQuery.of(context).size.width * 0.8, MediaQuery.of(context).size.height * 0.3, diff --git a/lib/src/image_attachment.dart b/lib/src/image_attachment.dart index 2345b2b8..3210949b 100644 --- a/lib/src/image_attachment.dart +++ b/lib/src/image_attachment.dart @@ -12,6 +12,7 @@ class ImageAttachment extends StatelessWidget { final Message message; final MessageTheme messageTheme; final Size size; + final bool showTitle; const ImageAttachment({ Key key, @@ -19,6 +20,7 @@ class ImageAttachment extends StatelessWidget { @required this.message, @required this.size, this.messageTheme, + this.showTitle = true, }) : super(key: key); @override @@ -83,7 +85,7 @@ class ImageAttachment extends StatelessWidget { ), ), ), - if (attachment.title != null) + if (showTitle && attachment.title != null) Material( color: messageTheme.messageBackgroundColor, child: AttachmentTitle( @@ -93,7 +95,8 @@ class ImageAttachment extends StatelessWidget { ), ], ), - if (attachment.titleLink != null || attachment.ogScrapeUrl != null) + if (showTitle && + (attachment.titleLink != null || attachment.ogScrapeUrl != null)) Positioned.fill( child: Material( color: Colors.transparent, From ce06b18c193dcb4b7bc7830edf09c7af020e656f Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Wed, 30 Dec 2020 12:00:21 +0100 Subject: [PATCH 0683/1140] fix title style --- example/lib/group_info_screen.dart | 13 +++++++++---- example/pubspec.yaml | 2 +- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/example/lib/group_info_screen.dart b/example/lib/group_info_screen.dart index 5a2d4a7d..15ae0c10 100644 --- a/example/lib/group_info_screen.dart +++ b/example/lib/group_info_screen.dart @@ -5,9 +5,9 @@ import 'package:flutter/material.dart'; import 'package:jiffy/jiffy.dart'; import 'package:stream_chat_flutter/src/option_list_tile.dart'; import 'package:stream_chat_flutter/src/stream_svg_icon.dart'; -import 'chat_info_screen.dart'; - import 'package:stream_chat_flutter/stream_chat_flutter.dart'; + +import 'chat_info_screen.dart'; import 'main.dart'; class GroupInfoScreen extends StatefulWidget { @@ -90,7 +90,10 @@ class _GroupInfoScreenState extends State { members: snapshot.data?.members ?.map((e) => e.user) ?.toList()), - style: TextStyle(color: Colors.black), + style: TextStyle( + color: Colors.black, + fontSize: 16, + ), maxLines: 1, overflow: TextOverflow.ellipsis, ); @@ -104,7 +107,9 @@ class _GroupInfoScreenState extends State { return Text( '${channel.channel.memberCount} Members, ${snapshot?.data?.members?.where((e) => e.user.online)?.length ?? 0} Online', style: TextStyle( - color: Colors.black.withOpacity(0.5), fontSize: 12.0), + color: Colors.black.withOpacity(0.5), + fontSize: 12.0, + ), ); }), ], diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 175cdaeb..4c5a590b 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -1,6 +1,6 @@ name: example description: A new Flutter project. -version: 1.0.94+97 +version: 1.0.95+98 environment: sdk: ">=2.2.2 <3.0.0" From c7cc553e004581943a811a6445ac594a5267e87e Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Wed, 30 Dec 2020 12:08:26 +0100 Subject: [PATCH 0684/1140] fix debouncing called on pop --- example/lib/group_info_screen.dart | 8 +++++++- example/pubspec.yaml | 2 +- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/example/lib/group_info_screen.dart b/example/lib/group_info_screen.dart index 15ae0c10..1c926106 100644 --- a/example/lib/group_info_screen.dart +++ b/example/lib/group_info_screen.dart @@ -33,6 +33,9 @@ class _GroupInfoScreenState extends State { String changedName = ''; void _userNameListener() { + if (_searchController.text == _userNameQuery) { + return; + } if (_debounce?.isActive ?? false) _debounce.cancel(); _debounce = Timer(const Duration(milliseconds: 350), () { if (mounted && modalSetStateCallback != null) { @@ -492,7 +495,10 @@ class _GroupInfoScreenState extends State { r'$autocomplete': _userNameQuery, }, 'id': { - r'$ne': StreamChat.of(context).user.id, + r'$nin': [ + StreamChat.of(context).user.id, + ...channel.state.members.map((e) => e.userId), + ], }, }, sort: [ diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 4c5a590b..b4cbfad9 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -1,6 +1,6 @@ name: example description: A new Flutter project. -version: 1.0.95+98 +version: 1.0.96+99 environment: sdk: ">=2.2.2 <3.0.0" From cbf21f669f217fb276468a4a8ae71653a92404dc Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Wed, 30 Dec 2020 17:13:17 +0530 Subject: [PATCH 0685/1140] Added 99 limit for unreads and changed logic for date implementation --- lib/src/channel_preview.dart | 16 +++++++++++----- lib/src/channel_unread_indicator.dart | 3 ++- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/lib/src/channel_preview.dart b/lib/src/channel_preview.dart index 5f58e254..f7f67bae 100644 --- a/lib/src/channel_preview.dart +++ b/lib/src/channel_preview.dart @@ -155,12 +155,18 @@ class ChannelPreview extends StatelessWidget { String stringDate; final now = DateTime.now(); - if (now.year != lastMessageAt.year || - now.month != lastMessageAt.month || - now.day != lastMessageAt.day) { - stringDate = Jiffy(lastMessageAt.toLocal()).format('dd/MM/yyyy'); - } else { + var startOfDay = DateTime(now.year, now.month, now.day); + + if (lastMessageAt.millisecondsSinceEpoch >= + startOfDay.millisecondsSinceEpoch) { stringDate = Jiffy(lastMessageAt.toLocal()).format('HH:mm'); + } else if (lastMessageAt.millisecondsSinceEpoch >= + startOfDay.subtract(Duration(days: 1)).millisecondsSinceEpoch) { + stringDate = 'Yesterday'; + } else if (startOfDay.difference(lastMessageAt).inDays < 7) { + stringDate = Jiffy(lastMessageAt.toLocal()).EEEE; + } else { + stringDate = Jiffy(lastMessageAt.toLocal()).format('dd/MM/yyyy'); } return Text( diff --git a/lib/src/channel_unread_indicator.dart b/lib/src/channel_unread_indicator.dart index 8080b1e9..c15db13a 100644 --- a/lib/src/channel_unread_indicator.dart +++ b/lib/src/channel_unread_indicator.dart @@ -19,6 +19,7 @@ class ChannelUnreadIndicator extends StatelessWidget { if (!snapshot.hasData || snapshot.data == 0) { return SizedBox(); } + return Material( borderRadius: BorderRadius.circular(8), color: StreamChatTheme.of(context) @@ -33,7 +34,7 @@ class ChannelUnreadIndicator extends StatelessWidget { ), child: Center( child: Text( - '${snapshot.data}', + '${snapshot.data > 99 ? '99+' : snapshot.data}', style: TextStyle( fontSize: 11, color: Colors.white, From 8a390347a789c5359c3b76a0a1170015d9186fde Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Wed, 30 Dec 2020 20:50:33 +0530 Subject: [PATCH 0686/1140] feat: Added fixes and modal for group --- example/lib/main.dart | 27 +++++ lib/src/channel_actions_modal.dart | 162 +++++++++++++++++++++++++++++ lib/src/option_list_tile.dart | 68 ++++++++++++ lib/stream_chat_flutter.dart | 1 + 4 files changed, 258 insertions(+) create mode 100644 lib/src/channel_actions_modal.dart create mode 100644 lib/src/option_list_tile.dart diff --git a/example/lib/main.dart b/example/lib/main.dart index 803df8e6..ba6226c5 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -373,6 +373,10 @@ class _ChannelListPageState extends State { limit: 20, ), channelWidget: ChannelPage(), + onChannelLongPress: (channel) { + if (!channel.isDistinct) + _showChannelDetailsModal(channel); + }, ), ), ), @@ -383,6 +387,29 @@ class _ChannelListPageState extends State { ), ); } + + void _showChannelDetailsModal(Channel channel) { + showModalBottomSheet( + context: context, + builder: (context) { + return StreamChannel( + child: ChannelActionsModal( + onViewInfoTap: () { + // TODO: Go to group info screen when PR is merged + }, + ), + channel: channel); + }, + isScrollControlled: true, + clipBehavior: Clip.antiAlias, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.only( + topLeft: Radius.circular(16.0), + topRight: Radius.circular(16.0), + ), + ), + ); + } } class ChannelPageArgs { diff --git a/lib/src/channel_actions_modal.dart b/lib/src/channel_actions_modal.dart new file mode 100644 index 00000000..e8891a89 --- /dev/null +++ b/lib/src/channel_actions_modal.dart @@ -0,0 +1,162 @@ +import 'package:flutter/material.dart'; + +import '../stream_chat_flutter.dart'; +import 'channel_info.dart'; +import 'option_list_tile.dart'; + +class ChannelActionsModal extends StatefulWidget { + VoidCallback onViewInfoTap; + + ChannelActionsModal({this.onViewInfoTap}); + + @override + _ChannelActionsModalState createState() => _ChannelActionsModalState(); +} + +class _ChannelActionsModalState extends State { + @override + Widget build(BuildContext context) { + return Material( + clipBehavior: Clip.antiAlias, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.only( + topLeft: Radius.circular(16.0), + topRight: Radius.circular(16.0), + ), + ), + child: FutureBuilder( + future: StreamChannel.of(context).channel.queryMembers( + filter: {}, + ), + builder: (context, snapshot) { + if (!snapshot.hasData) { + return Container( + height: 100.0, + alignment: Alignment.center, + child: Padding( + padding: const EdgeInsets.all(16.0), + child: CircularProgressIndicator(), + ), + ); + } + + var userAsMember = snapshot.data.members + .firstWhere((e) => e.user.id == StreamChat.of(context).user.id); + var isOwner = userAsMember.role == 'owner'; + + return Column( + mainAxisSize: MainAxisSize.min, + children: [ + SizedBox( + height: 24.0, + ), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 16.0), + child: ChannelName( + textStyle: TextStyle( + fontSize: 16.0, + color: Color(0xff000000), + fontWeight: FontWeight.bold, + ), + ), + ), + SizedBox( + height: 5.0, + ), + ChannelInfo( + showTypingIndicator: false, + channel: StreamChannel.of(context).channel, + textStyle: + StreamChatTheme.of(context).channelPreviewTheme.subtitle, + ), + SizedBox( + height: 17.0, + ), + Container( + height: 94.0, + child: ListView.builder( + scrollDirection: Axis.horizontal, + itemCount: snapshot.data.members.length, + itemBuilder: (context, index) { + return Padding( + padding: const EdgeInsets.symmetric(horizontal: 8.0), + child: Column( + children: [ + UserAvatar( + user: snapshot.data.members[index].user, + constraints: BoxConstraints( + maxHeight: 64.0, + maxWidth: 64.0, + ), + borderRadius: BorderRadius.circular(32.0), + ), + SizedBox( + height: 6.0, + ), + Text( + snapshot.data.members[index].user.name, + style: TextStyle( + fontSize: 12.0, + fontWeight: FontWeight.w600, + ), + maxLines: 1, + overflow: TextOverflow.ellipsis, + ), + ], + ), + ); + }, + ), + ), + SizedBox( + height: 24, + ), + OptionListTile( + leading: StreamSvgIcon.user( + color: Color(0xff7a7a7a), + ), + title: 'View Info', + onTap: widget.onViewInfoTap, + ), + OptionListTile( + leading: StreamSvgIcon.userRemove( + color: Color(0xff7a7a7a), + ), + title: 'Leave Group', + onTap: () async { + var channel = StreamChannel.of(context).channel; + + await channel.removeMembers([StreamChat.of(context).user.id]); + Navigator.pop(context); + }, + ), + if (isOwner) + OptionListTile( + leading: StreamSvgIcon.delete( + color: Colors.red, + ), + title: 'Delete Conversation', + titleColor: Colors.red, + onTap: () async { + var channel = StreamChannel.of(context).channel; + + await channel.delete(); + Navigator.pop(context); + }, + ), + OptionListTile( + leading: StreamSvgIcon.close( + color: Color(0xff7a7a7a), + ), + title: 'Cancel', + onTap: () { + Navigator.pop(context); + }, + ), + ], + ); + }, + ), + ); + } +} diff --git a/lib/src/option_list_tile.dart b/lib/src/option_list_tile.dart new file mode 100644 index 00000000..c1f48b71 --- /dev/null +++ b/lib/src/option_list_tile.dart @@ -0,0 +1,68 @@ +import 'package:flutter/material.dart'; +import 'package:stream_chat_flutter/src/stream_svg_icon.dart'; + +class OptionListTile extends StatelessWidget { + final String title; + final StreamSvgIcon leading; + final Widget trailing; + final VoidCallback onTap; + final Color titleColor; + + OptionListTile({ + this.title, + this.leading, + this.trailing, + this.onTap, + this.titleColor, + }); + + @override + Widget build(BuildContext context) { + return Column( + children: [ + Container( + color: Color(0xffe6e6e6), + height: 2.0, + ), + Material( + color: Colors.white, + child: Container( + height: 56.0, + child: InkWell( + onTap: onTap, + child: Row( + children: [ + if (leading != null) + Expanded( + child: Center(child: leading), + ), + if (leading == null) + SizedBox( + width: 16.0, + ), + Expanded( + flex: 4, + child: Text( + title, + style: TextStyle( + fontWeight: FontWeight.w600, color: titleColor), + )), + Expanded( + flex: 2, + child: Padding( + padding: const EdgeInsets.only(right: 16.0), + child: Align( + alignment: Alignment.centerRight, + child: trailing ?? Container(), + ), + ), + ), + ], + ), + ), + ), + ), + ], + ); + } +} diff --git a/lib/stream_chat_flutter.dart b/lib/stream_chat_flutter.dart index 1cef26a6..e4d4752a 100644 --- a/lib/stream_chat_flutter.dart +++ b/lib/stream_chat_flutter.dart @@ -43,3 +43,4 @@ export 'src/message_search_bloc.dart'; export 'src/message_search_item.dart'; export 'src/message_search_list_view.dart'; export 'src/unread_indicator.dart'; +export 'src/channel_actions_modal.dart'; From cb518db1a2519330f9fdb79f854e6c2675266417 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Wed, 30 Dec 2020 16:22:14 +0100 Subject: [PATCH 0687/1140] apply colors and ui fixes --- analysis_options.yaml | 122 ++++++++++----------- example/lib/advanced_options_page.dart | 15 +-- example/lib/choose_user_page.dart | 4 +- example/lib/customize_channel_preview.dart | 1 - example/lib/customize_message_widget.dart | 1 - example/lib/main.dart | 37 +++---- example/lib/new_chat_screen.dart | 3 - example/lib/search_text_field.dart | 2 +- example/pubspec.yaml | 2 +- lib/src/attachment_title.dart | 2 +- lib/src/back_button.dart | 4 +- lib/src/channel_bottom_sheet.dart | 6 +- lib/src/channel_image.dart | 2 +- lib/src/channel_list_view.dart | 19 ++-- lib/src/channel_preview.dart | 2 +- lib/src/chat_info_screen.dart | 23 ++-- lib/src/date_divider.dart | 5 +- lib/src/file_attachment.dart | 5 +- lib/src/giphy_attachment.dart | 4 +- lib/src/group_image.dart | 2 +- lib/src/image_actions_modal.dart | 13 ++- lib/src/image_footer.dart | 7 +- lib/src/media_list_view.dart | 13 ++- lib/src/message_actions_modal.dart | 8 +- lib/src/message_input.dart | 72 ++++++------ lib/src/message_reactions_modal.dart | 6 +- lib/src/reaction_bubble.dart | 4 +- lib/src/reaction_picker.dart | 4 +- lib/src/sending_indicator.dart | 2 +- lib/src/stream_chat.dart | 8 +- lib/src/stream_chat_theme.dart | 61 ++++------- lib/src/user_avatar.dart | 4 +- 32 files changed, 225 insertions(+), 238 deletions(-) diff --git a/analysis_options.yaml b/analysis_options.yaml index 8d6f9064..42965ec7 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -1,63 +1,63 @@ -include: package:pedantic/analysis_options.yaml - -analyzer: - enable-experiment: - - extension-methods - exclude: - - lib/**/*.g.dart - - example/** - -linter: - rules: - # these rules are documented on and in the same order as - # the Dart Lint rules page to make maintenance easier - # https://github.com/dart-lang/linter/blob/master/example/all.yaml - # - always_declare_return_types - # - always_specify_types - # - annotate_overrides - # - avoid_as - - avoid_empty_else - - avoid_init_to_null - - avoid_return_types_on_setters - - avoid_web_libraries_in_flutter - - await_only_futures - - camel_case_types - - cancel_subscriptions - - close_sinks - # - comment_references # we do not presume as to what people want to reference in their dartdocs - # - constant_identifier_names # https://github.com/dart-lang/linter/issues/204 - - control_flow_in_finally - - empty_constructor_bodies - - empty_statements - - hash_and_equals - - implementation_imports - # - invariant_booleans - # - iterable_contains_unrelated_type - - library_names - # - library_prefixes - # - list_remove_unrelated_type - # - literal_only_boolean_expressions - - non_constant_identifier_names - # - one_member_abstracts - # - only_throw_errors - # - overridden_fields -# - package_api_docs - - package_names - - package_prefixed_library_names - - prefer_is_not_empty - # - prefer_mixin # https://github.com/dart-lang/language/issues/32 - - public_member_api_docs - - slash_for_doc_comments - # - sort_constructors_first - # - sort_unnamed_constructors_first - # - super_goes_last # no longer needed w/ Dart 2 - - test_types_in_equals - - throw_in_finally - # - type_annotate_public_apis # subset of always_specify_types - - type_init_formals - # - unawaited_futures - - unnecessary_brace_in_string_interps - - unnecessary_getters_setters - - unnecessary_statements +#include: package:pedantic/analysis_options.yaml +# +#analyzer: +# enable-experiment: +# - extension-methods +# exclude: +# - lib/**/*.g.dart +# - example/** +# +#linter: +# rules: +# # these rules are documented on and in the same order as +# # the Dart Lint rules page to make maintenance easier +# # https://github.com/dart-lang/linter/blob/master/example/all.yaml +# # - always_declare_return_types +# # - always_specify_types +# # - annotate_overrides +# # - avoid_as +# - avoid_empty_else +# - avoid_init_to_null +# - avoid_return_types_on_setters +# - avoid_web_libraries_in_flutter +# - await_only_futures +# - camel_case_types +# - cancel_subscriptions +# - close_sinks +# # - comment_references # we do not presume as to what people want to reference in their dartdocs +# # - constant_identifier_names # https://github.com/dart-lang/linter/issues/204 +# - control_flow_in_finally +# - empty_constructor_bodies +# - empty_statements +# - hash_and_equals +# - implementation_imports +# # - invariant_booleans +# # - iterable_contains_unrelated_type +# - library_names +# # - library_prefixes +# # - list_remove_unrelated_type +# # - literal_only_boolean_expressions +# - non_constant_identifier_names +# # - one_member_abstracts +# # - only_throw_errors +# # - overridden_fields +## - package_api_docs +# - package_names +# - package_prefixed_library_names +# - prefer_is_not_empty +# # - prefer_mixin # https://github.com/dart-lang/language/issues/32 +# - public_member_api_docs +# - slash_for_doc_comments +# # - sort_constructors_first +# # - sort_unnamed_constructors_first +# # - super_goes_last # no longer needed w/ Dart 2 +# - test_types_in_equals +# - throw_in_finally +# # - type_annotate_public_apis # subset of always_specify_types +# - type_init_formals +# # - unawaited_futures +# - unnecessary_brace_in_string_interps +# - unnecessary_getters_setters +# - unnecessary_statements - unrelated_type_equality_checks - valid_regexps diff --git a/example/lib/advanced_options_page.dart b/example/lib/advanced_options_page.dart index 803c3e72..d94514f3 100644 --- a/example/lib/advanced_options_page.dart +++ b/example/lib/advanced_options_page.dart @@ -3,12 +3,12 @@ import 'dart:io'; import 'package:example/stream_version.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_secure_storage/flutter_secure_storage.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; +import 'choose_user_page.dart'; import 'main.dart'; import 'notifications_service.dart'; -import 'choose_user_page.dart'; -import 'package:flutter_secure_storage/flutter_secure_storage.dart'; class AdvancedOptionsPage extends StatefulWidget { @override @@ -36,7 +36,7 @@ class _AdvancedOptionsPageState extends State { return Scaffold( resizeToAvoidBottomPadding: false, appBar: AppBar( - backgroundColor: StreamChatTheme.of(context).primaryColor, + backgroundColor: StreamChatTheme.of(context).colorTheme.white, elevation: 1, centerTitle: true, brightness: Theme.of(context).brightness, @@ -97,7 +97,7 @@ class _AdvancedOptionsPageState extends State { fontSize: 14, fontWeight: FontWeight.bold, color: _apiKeyError != null - ? Color(0xffff3742) + ? StreamChatTheme.of(context).colorTheme.accentRed : StreamChatTheme.of(context) .colorTheme .black @@ -145,7 +145,7 @@ class _AdvancedOptionsPageState extends State { fontWeight: FontWeight.bold, fontSize: 14, color: _userIdError != null - ? Color(0xffff3742) + ? StreamChatTheme.of(context).colorTheme.accentRed : StreamChatTheme.of(context) .colorTheme .black @@ -193,7 +193,7 @@ class _AdvancedOptionsPageState extends State { fontWeight: FontWeight.bold, fontSize: 14, color: _userTokenError != null - ? Color(0xffff3742) + ? StreamChatTheme.of(context).colorTheme.accentRed : StreamChatTheme.of(context) .colorTheme .black @@ -238,7 +238,8 @@ class _AdvancedOptionsPageState extends State { child: Align( alignment: Alignment.bottomCenter, child: FlatButton( - color: StreamChatTheme.of(context).accentColor, + color: + StreamChatTheme.of(context).colorTheme.accentBlue, minWidth: double.infinity, height: 48, child: Text( diff --git a/example/lib/choose_user_page.dart b/example/lib/choose_user_page.dart index 18212253..543c944d 100644 --- a/example/lib/choose_user_page.dart +++ b/example/lib/choose_user_page.dart @@ -1,5 +1,3 @@ -import 'package:example/advanced_options_page.dart'; -import 'package:example/main.dart'; import 'package:example/stream_version.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; @@ -194,7 +192,7 @@ class ChooseUserPage extends StatelessWidget { color: StreamChatTheme.of(context).colorTheme.black, ), backgroundColor: - StreamChatTheme.of(context).secondaryColor, + StreamChatTheme.of(context).colorTheme.accentBlue, ), title: Text( 'Advanced Options', diff --git a/example/lib/customize_channel_preview.dart b/example/lib/customize_channel_preview.dart index d06cdba7..29d22a82 100644 --- a/example/lib/customize_channel_preview.dart +++ b/example/lib/customize_channel_preview.dart @@ -84,7 +84,6 @@ class ChannelListPage extends StatelessWidget { channel: channel, ), title: ChannelName( - channel: channel, textStyle: StreamChatTheme.of(context).channelPreviewTheme.title.copyWith( color: StreamChatTheme.of(context) diff --git a/example/lib/customize_message_widget.dart b/example/lib/customize_message_widget.dart index fc614125..a3713b69 100644 --- a/example/lib/customize_message_widget.dart +++ b/example/lib/customize_message_widget.dart @@ -127,7 +127,6 @@ class ChannelPage extends StatelessWidget { showTimestamp: !details.isNextUser, showUsername: !details.isNextUser, showReactions: false, - showReplyIndicator: false, ); } } diff --git a/example/lib/main.dart b/example/lib/main.dart index ef281eac..9831f29f 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -1,8 +1,7 @@ +import 'dart:async'; import 'dart:io'; import 'package:example/choose_user_page.dart'; -import 'package:example/new_chat_screen.dart'; -import 'package:example/new_group_chat_screen.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; @@ -13,7 +12,6 @@ import 'notifications_service.dart'; import 'routes/app_routes.dart'; import 'routes/routes.dart'; import 'search_text_field.dart'; -import 'dart:async'; void main() async { WidgetsFlutterBinding.ensureInitialized(); @@ -51,21 +49,20 @@ class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { - return StreamChat( - streamChatThemeData: StreamChatThemeData.getDefaultTheme( - ThemeData.dark(), - ), - client: client, - child: MaterialApp( - debugShowCheckedModeBanner: false, - theme: ThemeData.light(), - darkTheme: ThemeData.dark(), - //TODO change to system once dark theme is implemented - themeMode: ThemeMode.dark, - onGenerateRoute: AppRoutes.generateRoute, - initialRoute: - client.state.user == null ? Routes.CHOOSE_USER : Routes.HOME, - ), + return MaterialApp( + builder: (context, child) { + return StreamChat( + client: client, + child: child, + ); + }, + debugShowCheckedModeBanner: false, + theme: ThemeData.light(), + darkTheme: ThemeData.dark(), + themeMode: ThemeMode.dark, + onGenerateRoute: AppRoutes.generateRoute, + initialRoute: + client.state.user == null ? Routes.CHOOSE_USER : Routes.HOME, ); } } @@ -120,6 +117,7 @@ class _HomePageState extends State { Widget build(BuildContext context) { final user = StreamChat.of(context).user; return Scaffold( + backgroundColor: StreamChatTheme.of(context).colorTheme.whiteSnow, appBar: ChannelListHeader( onNewChatButtonTap: () { Navigator.pushNamed(context, Routes.NEW_CHAT); @@ -128,6 +126,7 @@ class _HomePageState extends State { drawer: _buildDrawer(context, user), drawerEdgeDragWidth: 50, bottomNavigationBar: BottomNavigationBar( + backgroundColor: StreamChatTheme.of(context).colorTheme.white, currentIndex: _currentIndex, items: _navBarItems, selectedLabelStyle: StreamChatTheme.of(context).textTheme.footnoteBold, @@ -429,7 +428,7 @@ class ChannelPage extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( - backgroundColor: StreamChatTheme.of(context).backgroundColor, + backgroundColor: StreamChatTheme.of(context).colorTheme.whiteSnow, appBar: ChannelHeader( showTypingIndicator: false, ), diff --git a/example/lib/new_chat_screen.dart b/example/lib/new_chat_screen.dart index 0d8b9821..fa922a81 100644 --- a/example/lib/new_chat_screen.dart +++ b/example/lib/new_chat_screen.dart @@ -5,7 +5,6 @@ import 'package:stream_chat_flutter/stream_chat_flutter.dart'; import 'chips_input_text_field.dart'; import 'main.dart'; -import 'new_group_chat_screen.dart'; import 'routes/routes.dart'; class NewChatScreen extends StatefulWidget { @@ -37,8 +36,6 @@ class _NewChatScreenState extends State { bool _showUserList = true; - bool _channelExisted = false; - void _userNameListener() { if (_debounce?.isActive ?? false) _debounce.cancel(); _debounce = Timer(const Duration(milliseconds: 350), () { diff --git a/example/lib/search_text_field.dart b/example/lib/search_text_field.dart index 1054446f..8f943f11 100644 --- a/example/lib/search_text_field.dart +++ b/example/lib/search_text_field.dart @@ -24,7 +24,7 @@ class SearchTextField extends StatelessWidget { decoration: BoxDecoration( color: StreamChatTheme.of(context).colorTheme.white, border: Border.all( - color: Colors.grey.shade300, + color: StreamChatTheme.of(context).colorTheme.white, ), borderRadius: BorderRadius.circular(24), ), diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 4c5a590b..38362b26 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -1,6 +1,6 @@ name: example description: A new Flutter project. -version: 1.0.95+98 +version: 1.0.97+100 environment: sdk: ">=2.2.2 <3.0.0" diff --git a/lib/src/attachment_title.dart b/lib/src/attachment_title.dart index ab9cd2da..7ed42a59 100644 --- a/lib/src/attachment_title.dart +++ b/lib/src/attachment_title.dart @@ -32,7 +32,7 @@ class AttachmentTitle extends StatelessWidget { attachment.title, overflow: TextOverflow.ellipsis, style: messageTheme.messageText.copyWith( - color: StreamChatTheme.of(context).accentColor, + color: StreamChatTheme.of(context).colorTheme.accentBlue, fontWeight: FontWeight.bold, ), ), diff --git a/lib/src/back_button.dart b/lib/src/back_button.dart index d4d7c53c..52adeade 100644 --- a/lib/src/back_button.dart +++ b/lib/src/back_button.dart @@ -37,9 +37,7 @@ class StreamBackButton extends StatelessWidget { }, child: StreamSvgIcon.left( size: 24, - color: Theme.of(context).brightness == Brightness.dark - ? StreamChatTheme.of(context).colorTheme.white - : StreamChatTheme.of(context).colorTheme.black, + color: StreamChatTheme.of(context).colorTheme.black, ), ), ), diff --git a/lib/src/channel_bottom_sheet.dart b/lib/src/channel_bottom_sheet.dart index 8e65c24d..f4894b02 100644 --- a/lib/src/channel_bottom_sheet.dart +++ b/lib/src/channel_bottom_sheet.dart @@ -106,13 +106,13 @@ class ChannelBottomSheet extends StatelessWidget { ?.role)) ListTile( leading: StreamSvgIcon.delete( - color: Color(0xFFFF3742), + color: StreamChatTheme.of(context).colorTheme.accentRed, size: 24, ), title: Text( 'Delete chat', style: TextStyle( - color: Color(0xFFFF3742), + color: StreamChatTheme.of(context).colorTheme.accentRed, ), ), onTap: () async { @@ -124,7 +124,7 @@ class ChannelBottomSheet extends StatelessWidget { 'Are you sure you want to delete this conversation?', cancelText: 'CANCEL', icon: StreamSvgIcon.delete( - color: Colors.red, + color: StreamChatTheme.of(context).colorTheme.accentRed, ), ); var channel = StreamChannel.of(context).channel; diff --git a/lib/src/channel_image.dart b/lib/src/channel_image.dart index b577a442..3e436ee8 100644 --- a/lib/src/channel_image.dart +++ b/lib/src/channel_image.dart @@ -133,7 +133,7 @@ class ChannelImage extends StatelessWidget { .avatarTheme .constraints, decoration: BoxDecoration( - color: StreamChatTheme.of(context).accentColor, + color: StreamChatTheme.of(context).colorTheme.accentBlue, ), child: Stack( alignment: Alignment.center, diff --git a/lib/src/channel_list_view.dart b/lib/src/channel_list_view.dart index 701158e1..fcbe4452 100644 --- a/lib/src/channel_list_view.dart +++ b/lib/src/channel_list_view.dart @@ -253,7 +253,8 @@ class _ChannelListViewState extends State .bodyBold .copyWith( color: StreamChatTheme.of(context) - .accentColor, + .colorTheme + .accentBlue, ), ), ), @@ -501,9 +502,7 @@ class _ChannelListViewState extends State ); } else { final backgroundColor = - Theme.of(context).brightness == Brightness.light - ? Color(0xffEBEBEB) - : Color(0xff141414); + StreamChatTheme.of(context).colorTheme.whiteSmoke; child = Slidable( enabled: widget.swipeToAction, actionPane: SlidableBehindActionPane(), @@ -543,7 +542,7 @@ class _ChannelListViewState extends State IconSlideAction( color: backgroundColor, iconWidget: StreamSvgIcon.delete( - color: Color(0xFFFF3742), + color: StreamChatTheme.of(context).colorTheme.accentRed, ), onTap: () async { final res = await showConfirmationDialog( @@ -554,7 +553,9 @@ class _ChannelListViewState extends State 'Are you sure you want to delete this conversation?', cancelText: 'CANCEL', icon: StreamSvgIcon.delete( - color: Color(0xFFFF3742), + color: StreamChatTheme.of(context) + .colorTheme + .accentRed, ), ); if (res == true) { @@ -564,7 +565,7 @@ class _ChannelListViewState extends State ), ], child: Container( - color: StreamChatTheme.of(context).backgroundColor, + color: StreamChatTheme.of(context).colorTheme.whiteSnow, child: ChannelPreview( onLongPress: widget.onChannelLongPress, channel: channel, @@ -621,9 +622,7 @@ class _ChannelListViewState extends State Widget _separatorBuilder(context, i) { return Container( height: 1, - color: Theme.of(context).brightness == Brightness.dark - ? StreamChatTheme.of(context).colorTheme.white.withOpacity(0.1) - : StreamChatTheme.of(context).colorTheme.black.withOpacity(0.1), + color: StreamChatTheme.of(context).colorTheme.black.withOpacity(0.08), ); } diff --git a/lib/src/channel_preview.dart b/lib/src/channel_preview.dart index 05dab603..ee01d95d 100644 --- a/lib/src/channel_preview.dart +++ b/lib/src/channel_preview.dart @@ -130,7 +130,7 @@ class ChannelPreview extends StatelessWidget { .isAfter(channel .state.lastMessage.createdAt)) .length == - (channel.memberCount ?? 0), + ((channel.memberCount ?? 0) - 1), ), ); } diff --git a/lib/src/chat_info_screen.dart b/lib/src/chat_info_screen.dart index 132f3ea3..8017cb5b 100644 --- a/lib/src/chat_info_screen.dart +++ b/lib/src/chat_info_screen.dart @@ -1,4 +1,3 @@ -import 'package:emojis/emojis.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:jiffy/jiffy.dart'; @@ -21,7 +20,7 @@ class _ChatInfoScreenState extends State { Widget build(BuildContext context) { final channel = StreamChannel.of(context).channel; return Scaffold( - backgroundColor: Color(0xFFe6e6e6), + backgroundColor: StreamChatTheme.of(context).colorTheme.whiteSnow, body: ListView( children: [ _buildUserHeader(), @@ -47,7 +46,7 @@ class _ChatInfoScreenState extends State { Widget _buildUserHeader() { return Material( - color: StreamChatTheme.of(context).colorTheme.white, + color: StreamChatTheme.of(context).colorTheme.whiteSnow, child: SafeArea( child: Stack( children: [ @@ -96,7 +95,9 @@ class _ChatInfoScreenState extends State { top: 21, left: 16, child: InkWell( - child: StreamSvgIcon.left(), + child: StreamSvgIcon.left( + color: StreamChatTheme.of(context).colorTheme.black, + ), onTap: () { Navigator.of(context).pop(); }, @@ -218,7 +219,7 @@ class _ChatInfoScreenState extends State { Widget _buildDeleteListTile() { return _OptionListTile( - title: 'Delete', + title: 'Delete conversation', leading: StreamSvgIcon.delete( color: Colors.red, size: 24.0, @@ -290,7 +291,7 @@ class _ChatInfoScreenState extends State { ), child: Material( shape: CircleBorder(), - color: Color(0xff20E070), + color: StreamChatTheme.of(context).colorTheme.accentGreen, ), ), color: StreamChatTheme.of(context).colorTheme.white, @@ -321,11 +322,11 @@ class _OptionListTile extends StatelessWidget { return Column( children: [ Container( - color: Color(0xffe6e6e6), + color: StreamChatTheme.of(context).colorTheme.white, height: 2.0, ), Material( - color: StreamChatTheme.of(context).colorTheme.white, + color: StreamChatTheme.of(context).colorTheme.whiteSnow, child: Container( height: 56.0, child: InkWell( @@ -409,7 +410,7 @@ class __SharedGroupsScreenState extends State<_SharedGroupsScreen> { ), ), ), - backgroundColor: StreamChatTheme.of(context).primaryColor, + backgroundColor: StreamChatTheme.of(context).colorTheme.white, ), body: FutureBuilder>( future: chat.client.queryChannels( @@ -559,7 +560,7 @@ class _MediaDisplayScreen extends StatelessWidget { ), ), ), - backgroundColor: StreamChatTheme.of(context).primaryColor, + backgroundColor: StreamChatTheme.of(context).colorTheme.white, ), ); } @@ -595,7 +596,7 @@ class _FileDisplayScreen extends StatelessWidget { ), ), ), - backgroundColor: StreamChatTheme.of(context).primaryColor, + backgroundColor: StreamChatTheme.of(context).colorTheme.white, ), ); } diff --git a/lib/src/date_divider.dart b/lib/src/date_divider.dart index 9b1ba435..12070e51 100644 --- a/lib/src/date_divider.dart +++ b/lib/src/date_divider.dart @@ -40,10 +40,7 @@ class DateDivider extends StatelessWidget { child: Container( padding: const EdgeInsets.symmetric(horizontal: 8), decoration: BoxDecoration( - color: (Theme.of(context).brightness == Brightness.light - ? StreamChatTheme.of(context).colorTheme.black - : StreamChatTheme.of(context).colorTheme.white) - .withOpacity(0.5), + color: StreamChatTheme.of(context).colorTheme.black.withOpacity(0.5), borderRadius: BorderRadius.circular( 8, ), diff --git a/lib/src/file_attachment.dart b/lib/src/file_attachment.dart index 597add86..273cddf2 100644 --- a/lib/src/file_attachment.dart +++ b/lib/src/file_attachment.dart @@ -9,6 +9,7 @@ import 'package:stream_chat_flutter/src/stream_svg_icon.dart'; import 'package:stream_chat_flutter/src/utils.dart'; import 'package:video_compress/video_compress.dart'; import 'package:video_player/video_player.dart'; + import 'media_utils.dart'; enum FileAttachmentType { local, online } @@ -61,7 +62,6 @@ class _FileAttachmentState extends State { child: Container( width: widget.size?.width ?? 100, height: 56.0, - margin: widget.trailing != null ? EdgeInsets.only(top: 4.0) : null, decoration: BoxDecoration( color: StreamChatTheme.of(context).colorTheme.white, borderRadius: @@ -177,7 +177,8 @@ class _FileAttachmentState extends State { width: 20.0, height: 20.0, child: CircularProgressIndicator( - backgroundColor: StreamChatTheme.of(context).accentColor, + backgroundColor: + StreamChatTheme.of(context).colorTheme.accentBlue, ), ), ); diff --git a/lib/src/giphy_attachment.dart b/lib/src/giphy_attachment.dart index 1f3bf9e6..cc1a319f 100644 --- a/lib/src/giphy_attachment.dart +++ b/lib/src/giphy_attachment.dart @@ -260,7 +260,9 @@ class GiphyAttachment extends StatelessWidget { child: Text( 'Send', style: TextStyle( - color: StreamChatTheme.of(context).accentColor, + color: StreamChatTheme.of(context) + .colorTheme + .accentBlue, fontWeight: FontWeight.bold), ), ), diff --git a/lib/src/group_image.dart b/lib/src/group_image.dart index 96e25f74..f4f21b90 100644 --- a/lib/src/group_image.dart +++ b/lib/src/group_image.dart @@ -31,7 +31,7 @@ class GroupImage extends StatelessWidget { .avatarTheme .constraints, decoration: BoxDecoration( - color: StreamChatTheme.of(context).accentColor, + color: StreamChatTheme.of(context).colorTheme.accentBlue, ), child: Flex( direction: Axis.vertical, diff --git a/lib/src/image_actions_modal.dart b/lib/src/image_actions_modal.dart index 45a60d60..a80dd6e7 100644 --- a/lib/src/image_actions_modal.dart +++ b/lib/src/image_actions_modal.dart @@ -1,13 +1,14 @@ import 'dart:typed_data'; import 'dart:ui'; +import 'package:dio/dio.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; -import 'package:dio/dio.dart'; import 'package:image_gallery_saver/image_gallery_saver.dart'; -import '../stream_chat_flutter.dart'; import 'package:path_provider/path_provider.dart'; +import '../stream_chat_flutter.dart'; + class ImageActionsModal extends StatelessWidget { final Message message; final String userName; @@ -165,7 +166,9 @@ class ImageActionsModal extends StatelessWidget { 'Delete', StreamSvgIcon.delete( size: 24.0, - color: Color(0xffFF3742), + color: StreamChatTheme.of(context) + .colorTheme + .accentRed, ), () { Navigator.pop(context); @@ -175,7 +178,9 @@ class ImageActionsModal extends StatelessWidget { StreamChannel.of(context).channel.cid, ); }, - color: Color(0xffFF3742), + color: StreamChatTheme.of(context) + .colorTheme + .accentRed, ), ], ).toList(), diff --git a/lib/src/image_footer.dart b/lib/src/image_footer.dart index 762bd737..36b3d042 100644 --- a/lib/src/image_footer.dart +++ b/lib/src/image_footer.dart @@ -378,7 +378,8 @@ class _ImageFooterState extends State { 'Save to Photos', style: TextStyle( color: StreamChatTheme.of(context) - .accentColor, + .colorTheme + .accentBlue, fontWeight: FontWeight.bold, ), ), @@ -595,7 +596,9 @@ class _ImageFooterState extends State { child: Transform.rotate( angle: -pi / 2, child: StreamSvgIcon.Icon_send_message( - color: StreamChatTheme.of(context).accentColor, + color: StreamChatTheme.of(context) + .colorTheme + .accentBlue, ), ), ), diff --git a/lib/src/media_list_view.dart b/lib/src/media_list_view.dart index d2b7ba69..08ebfcc7 100644 --- a/lib/src/media_list_view.dart +++ b/lib/src/media_list_view.dart @@ -1,10 +1,11 @@ +import 'dart:ui' as ui; + import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_svg/flutter_svg.dart'; import 'package:photo_manager/photo_manager.dart'; import 'package:stream_chat_flutter/src/lazy_load_scroll_view.dart'; import 'package:stream_chat_flutter/src/stream_svg_icon.dart'; -import 'dart:ui' as ui; import '../stream_chat_flutter.dart'; @@ -148,7 +149,15 @@ class _MediaListViewState extends State { void _getMedia() async { final assetList = await PhotoManager.getAssetPathList( hasAll: true, - ).then((value) => value.singleWhere((element) => element.isAll)); + ).then((value) { + if (value?.isNotEmpty == true) { + return value.singleWhere((element) => element.isAll); + } + }); + + if (assetList == null) { + return; + } final media = await assetList.getAssetListPaged(_currentPage, 50); diff --git a/lib/src/message_actions_modal.dart b/lib/src/message_actions_modal.dart index 17b9a79e..3660bfec 100644 --- a/lib/src/message_actions_modal.dart +++ b/lib/src/message_actions_modal.dart @@ -69,10 +69,7 @@ class MessageActionsModal extends StatelessWidget { sigmaY: 10.8731, ), child: Container( - color: StreamChatTheme.of(context) - .colorTheme - .black - .withOpacity(0.1), + color: Colors.black.withOpacity(.2), ), ), ), @@ -146,6 +143,9 @@ class MessageActionsModal extends StatelessWidget { horizontal: 48.0, ), child: Material( + color: StreamChatTheme.of(context) + .colorTheme + .whiteSnow, clipBehavior: Clip.hardEdge, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(16), diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 73f98754..47e60992 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -275,7 +275,7 @@ class MessageInputState extends State { child: Material( borderRadius: BorderRadius.circular(3), color: _sendAsDm - ? StreamChatTheme.of(context).accentColor + ? StreamChatTheme.of(context).colorTheme.accentBlue : StreamChatTheme.of(context).colorTheme.white, child: InkWell( onTap: () { @@ -337,7 +337,7 @@ class MessageInputState extends State { child: Padding( padding: const EdgeInsets.all(8.0) + EdgeInsets.only(bottom: 3.0), child: StreamSvgIcon.emptyCircleLeft( - color: StreamChatTheme.of(context).accentColor, + color: StreamChatTheme.of(context).colorTheme.accentBlue, ), ), ), @@ -364,7 +364,7 @@ class MessageInputState extends State { decoration: BoxDecoration( borderRadius: BorderRadius.circular(24.0), border: Border.all( - color: Colors.grey, + color: StreamChatTheme.of(context).colorTheme.white, ), ), padding: _attachments.isEmpty ? null : EdgeInsets.all(6.0), @@ -411,8 +411,9 @@ class MessageInputState extends State { padding: const EdgeInsets.symmetric(horizontal: 8.0), child: Chip( - backgroundColor: - StreamChatTheme.of(context).accentColor, + backgroundColor: StreamChatTheme.of(context) + .colorTheme + .accentBlue, padding: EdgeInsets.zero, labelPadding: EdgeInsets.symmetric(horizontal: 9.0), @@ -612,12 +613,12 @@ class MessageInputState extends State { shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(8.0), ), - color: StreamChatTheme.of(context).primaryColor, + color: StreamChatTheme.of(context).colorTheme.white, clipBehavior: Clip.antiAlias, child: Container( constraints: BoxConstraints.loose(Size.fromHeight(400)), decoration: BoxDecoration( - color: StreamChatTheme.of(context).primaryColor, + color: StreamChatTheme.of(context).colorTheme.white, borderRadius: BorderRadius.circular(8.0)), child: ListView( padding: const EdgeInsets.all(0), @@ -635,7 +636,8 @@ class MessageInputState extends State { ), child: StreamSvgIcon.lightning( color: StreamChatTheme.of(context) - .accentColor, + .colorTheme + .accentBlue, ), ), Text( @@ -671,17 +673,6 @@ class MessageInputState extends State { ], ), ), - trailing: CircleAvatar( - backgroundColor: - StreamChatTheme.of(context).accentColor, - child: StreamSvgIcon.lightning( - color: StreamChatTheme.of(context) - .colorTheme - .white, - size: 12.5, - ), - maxRadius: 12, - ), //subtitle: Text(c.description), onTap: () { _setCommand(c); @@ -708,9 +699,9 @@ class MessageInputState extends State { switch (index) { case 0: return _attachments.isEmpty - ? StreamChatTheme.of(context).accentColor + ? StreamChatTheme.of(context).colorTheme.accentBlue : (!_attachmentContainsFile - ? StreamChatTheme.of(context).accentColor + ? StreamChatTheme.of(context).colorTheme.accentBlue : StreamChatTheme.of(context) .colorTheme .black @@ -718,7 +709,7 @@ class MessageInputState extends State { break; case 1: return _attachmentContainsFile - ? StreamChatTheme.of(context).accentColor + ? StreamChatTheme.of(context).colorTheme.accentBlue : (_attachments.isEmpty ? StreamChatTheme.of(context) .colorTheme @@ -881,7 +872,8 @@ class MessageInputState extends State { child: Text( 'Add more files', style: TextStyle( - color: StreamChatTheme.of(context).accentColor, + color: + StreamChatTheme.of(context).colorTheme.accentBlue, fontWeight: FontWeight.bold, ), ), @@ -919,7 +911,8 @@ class MessageInputState extends State { 'svgs/icon_picture_empty_state.svg', package: 'stream_chat_flutter', height: 140, - color: StreamChatTheme.of(context).accentColor, + color: + StreamChatTheme.of(context).colorTheme.accentBlue, ), Center( child: Text( @@ -928,7 +921,9 @@ class MessageInputState extends State { .textTheme .bodyBold .copyWith( - color: StreamChatTheme.of(context).accentColor, + color: StreamChatTheme.of(context) + .colorTheme + .accentBlue, ), ), ), @@ -1106,7 +1101,7 @@ class MessageInputState extends State { child: Card( margin: EdgeInsets.all(8.0), elevation: 2.0, - color: StreamChatTheme.of(context).primaryColor, + color: StreamChatTheme.of(context).colorTheme.white, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(8.0), ), @@ -1114,7 +1109,7 @@ class MessageInputState extends State { child: Container( constraints: BoxConstraints.loose(Size.fromHeight(400)), decoration: BoxDecoration( - color: StreamChatTheme.of(context).primaryColor, + color: StreamChatTheme.of(context).colorTheme.white, ), child: FutureBuilder>( future: queryMembers ?? Future.value(members), @@ -1142,7 +1137,8 @@ class MessageInputState extends State { subtitle: Text('@${m.userId}'), trailing: StreamSvgIcon.mentions( color: StreamChatTheme.of(context) - .accentColor, + .colorTheme + .accentBlue, ), onTap: () { _mentionedUsers.add(m.user); @@ -1207,7 +1203,7 @@ class MessageInputState extends State { child: Card( margin: EdgeInsets.all(8.0), elevation: 2.0, - color: StreamChatTheme.of(context).primaryColor, + color: StreamChatTheme.of(context).colorTheme.white, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(8.0), ), @@ -1222,7 +1218,7 @@ class MessageInputState extends State { offset: Offset(0, -4), ), ], - color: StreamChatTheme.of(context).primaryColor, + color: StreamChatTheme.of(context).colorTheme.white, ), child: ListView.builder( padding: const EdgeInsets.all(0), @@ -1238,7 +1234,9 @@ class MessageInputState extends State { padding: const EdgeInsets.symmetric(horizontal: 8.0), child: StreamSvgIcon.smile( - color: StreamChatTheme.of(context).accentColor, + color: StreamChatTheme.of(context) + .colorTheme + .accentBlue, ), ), Flexible( @@ -1528,8 +1526,8 @@ class MessageInputState extends State { const EdgeInsets.only(left: 4.0, right: 8.0, top: 8.0, bottom: 8.0), child: StreamSvgIcon.lightning( color: _commandsOverlay != null - ? StreamChatTheme.of(context).accentColor - : Color(0xFF000000).withAlpha(128), + ? StreamChatTheme.of(context).colorTheme.accentBlue + : StreamChatTheme.of(context).colorTheme.grey, ), ), onTap: () async { @@ -1566,8 +1564,8 @@ class MessageInputState extends State { EdgeInsets.only(left: 8.0, right: padding, top: 8.0, bottom: 8.0), child: StreamSvgIcon.attach( color: _openFilePickerSection - ? StreamChatTheme.of(context).accentColor - : Color(0xFF000000).withAlpha(128), + ? StreamChatTheme.of(context).colorTheme.accentBlue + : StreamChatTheme.of(context).colorTheme.grey, ), ), onTap: () async { @@ -1896,7 +1894,7 @@ class MessageInputState extends State { }, child: StreamSvgIcon( assetName: _getIdleSendIcon(), - color: Colors.grey, + color: StreamChatTheme.of(context).colorTheme.greyGainsboro, height: 24.0, width: 24.0, ), @@ -1914,7 +1912,7 @@ class MessageInputState extends State { }, child: StreamSvgIcon( assetName: _getSendIcon(), - color: StreamChatTheme.of(context).accentColor, + color: StreamChatTheme.of(context).colorTheme.accentBlue, height: 24.0, width: 24.0, ), diff --git a/lib/src/message_reactions_modal.dart b/lib/src/message_reactions_modal.dart index a6a7e54c..ba583728 100644 --- a/lib/src/message_reactions_modal.dart +++ b/lib/src/message_reactions_modal.dart @@ -60,10 +60,7 @@ class MessageReactionsModal extends StatelessWidget { sigmaY: 10.8731, ), child: Container( - color: StreamChatTheme.of(context) - .colorTheme - .black - .withOpacity(0.1), + color: Colors.black.withOpacity(0.2), ), ), ), @@ -140,6 +137,7 @@ class MessageReactionsModal extends StatelessWidget { horizontal: 8.0, ), child: Card( + color: StreamChatTheme.of(context).colorTheme.white, clipBehavior: Clip.hardEdge, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(16), diff --git a/lib/src/reaction_bubble.dart b/lib/src/reaction_bubble.dart index f7c9c142..d8f8c623 100644 --- a/lib/src/reaction_bubble.dart +++ b/lib/src/reaction_bubble.dart @@ -107,7 +107,7 @@ class ReactionBubble extends StatelessWidget { height: 16, color: (!highlightOwnReactions || reaction.user.id == StreamChat.of(context).user.id) - ? StreamChatTheme.of(context).accentColor + ? StreamChatTheme.of(context).colorTheme.accentBlue : StreamChatTheme.of(context) .colorTheme .black @@ -118,7 +118,7 @@ class ReactionBubble extends StatelessWidget { size: 16, color: (!highlightOwnReactions || reaction.user.id == StreamChat.of(context).user.id) - ? StreamChatTheme.of(context).accentColor + ? StreamChatTheme.of(context).colorTheme.accentBlue : StreamChatTheme.of(context) .colorTheme .black diff --git a/lib/src/reaction_picker.dart b/lib/src/reaction_picker.dart index b019ee79..5892a66d 100644 --- a/lib/src/reaction_picker.dart +++ b/lib/src/reaction_picker.dart @@ -89,7 +89,9 @@ class _ReactionPickerState extends State height: animations[index].value * 24.0, width: animations[index].value * 24.0, color: ownReactionIndex != -1 - ? StreamChatTheme.of(context).accentColor + ? StreamChatTheme.of(context) + .colorTheme + .accentBlue : Theme.of(context) .iconTheme .color diff --git a/lib/src/sending_indicator.dart b/lib/src/sending_indicator.dart index ce8915c3..5ec8a8a4 100644 --- a/lib/src/sending_indicator.dart +++ b/lib/src/sending_indicator.dart @@ -18,7 +18,7 @@ class SendingIndicator extends StatelessWidget { return Icon( Icons.done_all, size: 8, - color: StreamChatTheme.of(context).accentColor, + color: StreamChatTheme.of(context).colorTheme.accentBlue, ); } if (message.status == MessageSendingStatus.SENT || message.status == null) { diff --git a/lib/src/stream_chat.dart b/lib/src/stream_chat.dart index 2763db37..6866b0dd 100644 --- a/lib/src/stream_chat.dart +++ b/lib/src/stream_chat.dart @@ -76,8 +76,8 @@ class StreamChatState extends State with WidgetsBindingObserver { return Theme( data: materialTheme.copyWith( primaryIconTheme: streamTheme.primaryIconTheme, - accentColor: streamTheme.accentColor, - scaffoldBackgroundColor: streamTheme.backgroundColor, + accentColor: streamTheme.colorTheme.accentBlue, + scaffoldBackgroundColor: streamTheme.colorTheme.white, ), child: widget.child, ); @@ -92,11 +92,9 @@ class StreamChatState extends State with WidgetsBindingObserver { ) { final defaultTheme = StreamChatThemeData.getDefaultTheme(Theme.of(context)); final theme = defaultTheme.copyWith( - primaryColor: themeData?.primaryColor, defaultChannelImage: themeData?.defaultChannelImage, primaryIconTheme: themeData?.primaryIconTheme, defaultUserImage: themeData?.defaultUserImage, - backgroundColor: themeData?.backgroundColor, channelTheme: defaultTheme.channelTheme.copyWith( channelHeaderTheme: defaultTheme.channelTheme.channelHeaderTheme.copyWith( @@ -151,8 +149,6 @@ class StreamChatState extends State with WidgetsBindingObserver { reactionsBackgroundColor: themeData?.otherMessageTheme?.reactionsBackgroundColor, ), - accentColor: themeData?.accentColor, - secondaryColor: themeData?.secondaryColor, channelPreviewTheme: defaultTheme.channelPreviewTheme.copyWith( avatarTheme: defaultTheme.channelPreviewTheme.avatarTheme.copyWith( constraints: themeData?.channelPreviewTheme?.avatarTheme?.constraints, diff --git a/lib/src/stream_chat_theme.dart b/lib/src/stream_chat_theme.dart index 407a4fcd..f6b00ef8 100644 --- a/lib/src/stream_chat_theme.dart +++ b/lib/src/stream_chat_theme.dart @@ -48,18 +48,6 @@ class StreamChatThemeData { /// The text themes used in the widgets final ColorTheme colorTheme; - /// Primary color of the chat widgets - final Color primaryColor; - - /// Secondary color of the chat widgets - final Color secondaryColor; - - /// Accent color of the chat widgets - final Color accentColor; - - /// Background color of the chat widgets - final Color backgroundColor; - /// Theme of the [ChannelPreview] final ChannelPreviewTheme channelPreviewTheme; @@ -88,10 +76,6 @@ class StreamChatThemeData { StreamChatThemeData({ this.textTheme, this.colorTheme, - this.primaryColor, - this.secondaryColor, - this.accentColor, - this.backgroundColor, this.channelPreviewTheme, this.channelTheme, this.otherMessageTheme, @@ -107,11 +91,7 @@ class StreamChatThemeData { final defaultTheme = getDefaultTheme(theme); return defaultTheme.copyWith( - accentColor: theme.accentColor, primaryIconTheme: theme.primaryIconTheme, - primaryColor: theme.colorScheme.primary, - secondaryColor: theme.colorScheme.secondary, - backgroundColor: theme.scaffoldBackgroundColor, channelTheme: defaultTheme.channelTheme.copyWith( inputGradient: LinearGradient(colors: [ theme.accentColor.withOpacity(.5), @@ -141,10 +121,6 @@ class StreamChatThemeData { StreamChatThemeData copyWith({ TextTheme textTheme, ColorTheme colorTheme, - Color primaryColor, - Color secondaryColor, - Color accentColor, - Color backgroundColor, ChannelPreviewTheme channelPreviewTheme, ChannelTheme channelTheme, MessageTheme ownMessageTheme, @@ -175,13 +151,9 @@ class StreamChatThemeData { white: colorTheme?.white, blueAlice: colorTheme?.blueAlice, ), - primaryColor: primaryColor ?? this.primaryColor, - secondaryColor: secondaryColor ?? this.secondaryColor, primaryIconTheme: primaryIconTheme ?? this.primaryIconTheme, - accentColor: accentColor ?? this.accentColor, defaultChannelImage: defaultChannelImage ?? this.defaultChannelImage, defaultUserImage: defaultUserImage ?? this.defaultUserImage, - backgroundColor: backgroundColor ?? this.backgroundColor, channelPreviewTheme: this.channelPreviewTheme?.copyWith( title: channelPreviewTheme.title, subtitle: channelPreviewTheme.subtitle, @@ -252,12 +224,8 @@ class StreamChatThemeData { return StreamChatThemeData( textTheme: textTheme, colorTheme: colorTheme, - secondaryColor: Color(0xffEAEAEA), - accentColor: accentColor, - primaryColor: colorTheme.white, primaryIconTheme: IconThemeData(color: colorTheme.black.withOpacity(.5)), defaultChannelImage: (context, channel) => SizedBox(), - backgroundColor: colorTheme.whiteSnow, defaultUserImage: (context, user) => Center( child: CachedNetworkImage( filterQuality: FilterQuality.high, @@ -266,7 +234,7 @@ class StreamChatThemeData { ), ), channelPreviewTheme: ChannelPreviewTheme( - unreadCounterColor: Color(0xffff3742), + unreadCounterColor: colorTheme.accentRed, avatarTheme: AvatarTheme( borderRadius: BorderRadius.circular(20), constraints: BoxConstraints.tightFor( @@ -324,10 +292,10 @@ class StreamChatThemeData { fontWeight: FontWeight.w600, fontSize: 12, ), - messageBackgroundColor: isDark ? Color(0xff191919) : Color(0xffEAEAEA), + messageBackgroundColor: colorTheme.greyGainsboro, reactionsBackgroundColor: colorTheme.white, - reactionsBorderColor: isDark ? Color(0xff191919) : Color(0xffEAEAEA), - replyThreadColor: isDark ? Color(0xff191919) : Color(0xffEAEAEA), + reactionsBorderColor: colorTheme.greyWhisper, + replyThreadColor: colorTheme.greyWhisper, avatarTheme: AvatarTheme( borderRadius: BorderRadius.circular(20), constraints: BoxConstraints.tightFor( @@ -340,8 +308,7 @@ class StreamChatThemeData { ), ), otherMessageTheme: MessageTheme( - reactionsBackgroundColor: - isDark ? Color(0xff191919) : Color(0xffEAEAEA), + reactionsBackgroundColor: colorTheme.greyGainsboro, reactionsBorderColor: colorTheme.white, messageText: TextStyle( fontSize: 14.5, @@ -535,6 +502,9 @@ class ColorTheme { final Color whiteSnow; final Color white; final Color blueAlice; + final Color accentBlue; + final Color accentRed; + final Color accentGreen; ColorTheme.light({ this.black = const Color(0xff000000), @@ -545,6 +515,9 @@ class ColorTheme { this.whiteSnow = const Color(0xfffcfcfc), this.white = const Color(0xffffffff), this.blueAlice = const Color(0xffe9f2ff), + this.accentBlue = const Color(0xff005FFF), + this.accentRed = const Color(0xffFF3742), + this.accentGreen = const Color(0xff20E070), }); ColorTheme.dark({ @@ -556,6 +529,9 @@ class ColorTheme { this.whiteSnow = const Color(0xff070A0D), this.white = const Color(0xff101418), this.blueAlice = const Color(0xff00193D), + this.accentBlue = const Color(0xff005FFF), + this.accentRed = const Color(0xffFF3742), + this.accentGreen = const Color(0xff20E070), }); ColorTheme copyWith({ @@ -568,6 +544,9 @@ class ColorTheme { Color whiteSnow, Color white, Color blueAlice, + Color accentBlue, + Color accentRed, + Color accentGreen, }) { return type == ColorThemeType.light ? ColorTheme.light( @@ -579,6 +558,9 @@ class ColorTheme { whiteSnow: whiteSnow ?? this.whiteSnow, white: white ?? this.white, blueAlice: blueAlice ?? this.blueAlice, + accentBlue: accentBlue ?? this.accentBlue, + accentRed: accentRed ?? this.accentRed, + accentGreen: accentGreen ?? this.accentGreen, ) : ColorTheme.dark( black: black ?? this.black, @@ -589,6 +571,9 @@ class ColorTheme { whiteSnow: whiteSnow ?? this.whiteSnow, white: white ?? this.white, blueAlice: blueAlice ?? this.blueAlice, + accentBlue: accentBlue ?? this.accentBlue, + accentRed: accentRed ?? this.accentRed, + accentGreen: accentGreen ?? this.accentGreen, ); } } diff --git a/lib/src/user_avatar.dart b/lib/src/user_avatar.dart index c0b2a712..7411c994 100644 --- a/lib/src/user_avatar.dart +++ b/lib/src/user_avatar.dart @@ -47,7 +47,7 @@ class UserAvatar extends StatelessWidget { constraints: constraints ?? streamChatTheme.ownMessageTheme.avatarTheme.constraints, decoration: BoxDecoration( - color: streamChatTheme.accentColor, + color: streamChatTheme.colorTheme.accentBlue, ), child: hasImage ? CachedNetworkImage( @@ -96,7 +96,7 @@ class UserAvatar extends StatelessWidget { ), child: Material( shape: CircleBorder(), - color: Color(0xff20E070), + color: streamChatTheme.colorTheme.accentGreen, ), ), color: StreamChatTheme.of(context).colorTheme.white, From 60d9abe8fe99c6d6022baec4151cbaf7ee6568fd Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Wed, 30 Dec 2020 16:23:33 +0100 Subject: [PATCH 0688/1140] fix messageinput color --- example/lib/main.dart | 2 +- example/pubspec.yaml | 2 +- lib/src/message_input.dart | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/example/lib/main.dart b/example/lib/main.dart index 9831f29f..7c292f64 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -59,7 +59,7 @@ class MyApp extends StatelessWidget { debugShowCheckedModeBanner: false, theme: ThemeData.light(), darkTheme: ThemeData.dark(), - themeMode: ThemeMode.dark, + themeMode: ThemeMode.light, onGenerateRoute: AppRoutes.generateRoute, initialRoute: client.state.user == null ? Routes.CHOOSE_USER : Routes.HOME, diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 38362b26..268d93ce 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -1,6 +1,6 @@ name: example description: A new Flutter project. -version: 1.0.97+100 +version: 1.0.98+101 environment: sdk: ">=2.2.2 <3.0.0" diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 47e60992..92d09f4b 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -364,7 +364,7 @@ class MessageInputState extends State { decoration: BoxDecoration( borderRadius: BorderRadius.circular(24.0), border: Border.all( - color: StreamChatTheme.of(context).colorTheme.white, + color: StreamChatTheme.of(context).colorTheme.greyGainsboro, ), ), padding: _attachments.isEmpty ? null : EdgeInsets.all(6.0), From a766e404c585e74ced0db93e8120dce0f2ba1152 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Wed, 30 Dec 2020 21:22:03 +0530 Subject: [PATCH 0689/1140] fix: fixed for all chats --- example/lib/main.dart | 3 +- lib/src/channel_actions_modal.dart | 125 ++++++++++++++++++----------- 2 files changed, 81 insertions(+), 47 deletions(-) diff --git a/example/lib/main.dart b/example/lib/main.dart index ba6226c5..c283793a 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -374,8 +374,7 @@ class _ChannelListPageState extends State { ), channelWidget: ChannelPage(), onChannelLongPress: (channel) { - if (!channel.isDistinct) - _showChannelDetailsModal(channel); + _showChannelDetailsModal(channel); }, ), ), diff --git a/lib/src/channel_actions_modal.dart b/lib/src/channel_actions_modal.dart index e8891a89..ff8509d7 100644 --- a/lib/src/channel_actions_modal.dart +++ b/lib/src/channel_actions_modal.dart @@ -16,6 +16,8 @@ class ChannelActionsModal extends StatefulWidget { class _ChannelActionsModalState extends State { @override Widget build(BuildContext context) { + var channel = StreamChannel.of(context).channel; + return Material( clipBehavior: Clip.antiAlias, shape: RoundedRectangleBorder( @@ -72,42 +74,73 @@ class _ChannelActionsModalState extends State { SizedBox( height: 17.0, ), - Container( - height: 94.0, - child: ListView.builder( - scrollDirection: Axis.horizontal, - itemCount: snapshot.data.members.length, - itemBuilder: (context, index) { - return Padding( - padding: const EdgeInsets.symmetric(horizontal: 8.0), - child: Column( - children: [ - UserAvatar( - user: snapshot.data.members[index].user, - constraints: BoxConstraints( - maxHeight: 64.0, - maxWidth: 64.0, - ), - borderRadius: BorderRadius.circular(32.0), - ), - SizedBox( - height: 6.0, - ), - Text( - snapshot.data.members[index].user.name, - style: TextStyle( - fontSize: 12.0, - fontWeight: FontWeight.w600, - ), - maxLines: 1, - overflow: TextOverflow.ellipsis, - ), - ], + if (channel.isDistinct && channel.memberCount == 2) + Column( + children: [ + UserAvatar( + user: snapshot.data.members + .firstWhere((e) => e.user.id != userAsMember.user.id) + .user, + constraints: BoxConstraints( + maxHeight: 64.0, + maxWidth: 64.0, ), - ); - }, + borderRadius: BorderRadius.circular(32.0), + ), + SizedBox( + height: 6.0, + ), + Text( + snapshot.data.members + .firstWhere((e) => e.user.id != userAsMember.user.id) + .user + .name, + style: TextStyle( + fontSize: 12.0, + fontWeight: FontWeight.w600, + ), + maxLines: 1, + overflow: TextOverflow.ellipsis, + ), + ], + ), + if (!(channel.isDistinct && channel.memberCount == 2)) + Container( + height: 94.0, + child: ListView.builder( + scrollDirection: Axis.horizontal, + itemCount: snapshot.data.members.length, + itemBuilder: (context, index) { + return Padding( + padding: const EdgeInsets.symmetric(horizontal: 8.0), + child: Column( + children: [ + UserAvatar( + user: snapshot.data.members[index].user, + constraints: BoxConstraints( + maxHeight: 64.0, + maxWidth: 64.0, + ), + borderRadius: BorderRadius.circular(32.0), + ), + SizedBox( + height: 6.0, + ), + Text( + snapshot.data.members[index].user.name, + style: TextStyle( + fontSize: 12.0, + fontWeight: FontWeight.w600, + ), + maxLines: 1, + overflow: TextOverflow.ellipsis, + ), + ], + ), + ); + }, + ), ), - ), SizedBox( height: 24, ), @@ -118,18 +151,20 @@ class _ChannelActionsModalState extends State { title: 'View Info', onTap: widget.onViewInfoTap, ), - OptionListTile( - leading: StreamSvgIcon.userRemove( - color: Color(0xff7a7a7a), - ), - title: 'Leave Group', - onTap: () async { - var channel = StreamChannel.of(context).channel; + if (!channel.isDistinct) + OptionListTile( + leading: StreamSvgIcon.userRemove( + color: Color(0xff7a7a7a), + ), + title: 'Leave Group', + onTap: () async { + var channel = StreamChannel.of(context).channel; - await channel.removeMembers([StreamChat.of(context).user.id]); - Navigator.pop(context); - }, - ), + await channel + .removeMembers([StreamChat.of(context).user.id]); + Navigator.pop(context); + }, + ), if (isOwner) OptionListTile( leading: StreamSvgIcon.delete( From 2026058d300ad51096f33075f8aee1eea0a559c9 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Wed, 30 Dec 2020 21:23:35 +0530 Subject: [PATCH 0690/1140] fix: Corrected icon --- lib/src/channel_actions_modal.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/channel_actions_modal.dart b/lib/src/channel_actions_modal.dart index ff8509d7..424f5e38 100644 --- a/lib/src/channel_actions_modal.dart +++ b/lib/src/channel_actions_modal.dart @@ -180,7 +180,7 @@ class _ChannelActionsModalState extends State { }, ), OptionListTile( - leading: StreamSvgIcon.close( + leading: StreamSvgIcon.close_small( color: Color(0xff7a7a7a), ), title: 'Cancel', From 911581e0947a42e5c58958b6d439912305945403 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Wed, 30 Dec 2020 18:26:24 +0100 Subject: [PATCH 0691/1140] apply theme to new chat screens --- example/lib/advanced_options_page.dart | 13 +- example/lib/choose_user_page.dart | 6 +- example/lib/group_chat_details_screen.dart | 13 +- example/lib/main.dart | 203 +++++++++++---------- example/lib/new_chat_screen.dart | 6 +- example/lib/new_group_chat_screen.dart | 20 +- example/lib/search_text_field.dart | 2 +- example/pubspec.yaml | 2 +- lib/src/channel_list_view.dart | 8 +- lib/src/channel_unread_indicator.dart | 2 +- lib/src/full_screen_media.dart | 4 +- lib/src/image_actions_modal.dart | 5 +- lib/src/image_footer.dart | 8 +- lib/src/message_input.dart | 2 +- lib/src/message_list_view.dart | 6 +- lib/src/stream_chat_theme.dart | 8 + lib/src/unread_indicator.dart | 2 +- lib/src/user_item.dart | 2 + 18 files changed, 172 insertions(+), 140 deletions(-) diff --git a/example/lib/advanced_options_page.dart b/example/lib/advanced_options_page.dart index d94514f3..483e0902 100644 --- a/example/lib/advanced_options_page.dart +++ b/example/lib/advanced_options_page.dart @@ -34,6 +34,7 @@ class _AdvancedOptionsPageState extends State { @override Widget build(BuildContext context) { return Scaffold( + backgroundColor: StreamChatTheme.of(context).colorTheme.whiteSnow, resizeToAvoidBottomPadding: false, appBar: AppBar( backgroundColor: StreamChatTheme.of(context).colorTheme.white, @@ -107,7 +108,8 @@ class _AdvancedOptionsPageState extends State { borderRadius: BorderRadius.circular(8), borderSide: BorderSide.none, ), - fillColor: Color(0xffF5F5F5), + fillColor: + StreamChatTheme.of(context).colorTheme.whiteSmoke, filled: true, labelText: 'Chat API Key ${_apiKeyError != null ? ':$_apiKeyError' : ''}', @@ -155,7 +157,8 @@ class _AdvancedOptionsPageState extends State { borderRadius: BorderRadius.circular(8), borderSide: BorderSide.none, ), - fillColor: Color(0xffF5F5F5), + fillColor: + StreamChatTheme.of(context).colorTheme.whiteSmoke, filled: true, labelText: 'User ID ${_userIdError != null ? ':$_userIdError' : ''}', @@ -203,7 +206,8 @@ class _AdvancedOptionsPageState extends State { borderRadius: BorderRadius.circular(8), borderSide: BorderSide.none, ), - fillColor: Color(0xffF5F5F5), + fillColor: + StreamChatTheme.of(context).colorTheme.whiteSmoke, filled: true, labelText: 'User Token ${_userTokenError != null ? ':$_userTokenError' : ''}', @@ -228,7 +232,8 @@ class _AdvancedOptionsPageState extends State { borderRadius: BorderRadius.circular(8), borderSide: BorderSide.none, ), - fillColor: Color(0xffF5F5F5), + fillColor: + StreamChatTheme.of(context).colorTheme.whiteSmoke, filled: true, labelText: 'Username (optional)', ), diff --git a/example/lib/choose_user_page.dart b/example/lib/choose_user_page.dart index 543c944d..55bfa36c 100644 --- a/example/lib/choose_user_page.dart +++ b/example/lib/choose_user_page.dart @@ -58,6 +58,7 @@ class ChooseUserPage extends StatelessWidget { (_, value) => value..extraData['image'] = getRandomPicUrl(value)); return Scaffold( + backgroundColor: StreamChatTheme.of(context).colorTheme.whiteSnow, body: SafeArea( child: Column( crossAxisAlignment: CrossAxisAlignment.center, @@ -191,8 +192,9 @@ class ChooseUserPage extends StatelessWidget { child: StreamSvgIcon.settings( color: StreamChatTheme.of(context).colorTheme.black, ), - backgroundColor: - StreamChatTheme.of(context).colorTheme.accentBlue, + backgroundColor: StreamChatTheme.of(context) + .colorTheme + .greyWhisper, ), title: Text( 'Advanced Options', diff --git a/example/lib/group_chat_details_screen.dart b/example/lib/group_chat_details_screen.dart index 0c49c523..b186684f 100644 --- a/example/lib/group_chat_details_screen.dart +++ b/example/lib/group_chat_details_screen.dart @@ -59,7 +59,7 @@ class _GroupChatDetailsScreenState extends State { return false; }, child: Scaffold( - backgroundColor: Color.fromRGBO(252, 252, 252, 1), + backgroundColor: StreamChatTheme.of(context).colorTheme.whiteSnow, appBar: AppBar( elevation: 1, backgroundColor: StreamChatTheme.of(context).colorTheme.white, @@ -151,7 +151,16 @@ class _GroupChatDetailsScreenState extends State { children: [ Container( width: double.maxFinite, - color: Colors.grey.shade50, + decoration: BoxDecoration( + gradient: LinearGradient( + begin: Alignment.topCenter, + end: Alignment.bottomCenter, + colors: [ + StreamChatTheme.of(context).colorTheme.whiteSmoke, + StreamChatTheme.of(context).colorTheme.whiteSnow, + ], + ), + ), child: Padding( padding: const EdgeInsets.symmetric( vertical: 8, diff --git a/example/lib/main.dart b/example/lib/main.dart index 7c292f64..c51a8a4c 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -151,113 +151,116 @@ class _HomePageState extends State { Drawer _buildDrawer(BuildContext context, User user) { return Drawer( - 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: 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: Row( - children: [ - UserAvatar( - user: user, - showOnlineStatus: false, - constraints: BoxConstraints.tight(Size.fromRadius(20)), + 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, ), - Padding( - padding: const EdgeInsets.only(left: 16.0), - child: Text( - user.name, + ), + ), + 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: 16, - fontWeight: FontWeight.bold, + fontSize: 14.5, ), ), ), - ], - ), - ), - 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, - ), - ), - ), - ), - ), - ], + ], + ), ), ), ), @@ -488,7 +491,7 @@ class ThreadPage extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( - backgroundColor: Color.fromRGBO(252, 252, 252, 1), + backgroundColor: StreamChatTheme.of(context).colorTheme.whiteSnow, appBar: ThreadHeader( parent: parent, ), diff --git a/example/lib/new_chat_screen.dart b/example/lib/new_chat_screen.dart index fa922a81..4cebb564 100644 --- a/example/lib/new_chat_screen.dart +++ b/example/lib/new_chat_screen.dart @@ -119,7 +119,7 @@ class _NewChatScreenState extends State { @override Widget build(BuildContext context) { return Scaffold( - backgroundColor: Color.fromRGBO(252, 252, 252, 1), + backgroundColor: StreamChatTheme.of(context).colorTheme.whiteSnow, appBar: AppBar( elevation: 0, backgroundColor: StreamChatTheme.of(context).colorTheme.white, @@ -215,7 +215,9 @@ class _NewChatScreenState extends State { StreamNeumorphicButton( child: Center( child: StreamSvgIcon.contacts( - color: Color(0xFF006CFF), + color: StreamChatTheme.of(context) + .colorTheme + .accentBlue, size: 24, ), ), diff --git a/example/lib/new_group_chat_screen.dart b/example/lib/new_group_chat_screen.dart index a00dbc07..d094f5c0 100644 --- a/example/lib/new_group_chat_screen.dart +++ b/example/lib/new_group_chat_screen.dart @@ -3,9 +3,8 @@ import 'dart:async'; import 'package:flutter/material.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; -import 'group_chat_details_screen.dart'; -import 'search_text_field.dart'; import 'routes/routes.dart'; +import 'search_text_field.dart'; class NewGroupChatScreen extends StatefulWidget { @override @@ -53,7 +52,7 @@ class _NewGroupChatScreenState extends State { Widget build(BuildContext context) { return SafeArea( child: Scaffold( - backgroundColor: Color.fromRGBO(252, 252, 252, 1), + backgroundColor: StreamChatTheme.of(context).colorTheme.whiteSnow, body: NestedScrollView( floatHeaderSlivers: true, headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) { @@ -142,18 +141,17 @@ class _NewGroupChatScreenState extends State { .white, shape: BoxShape.circle, border: Border.all( - color: Colors.grey.shade100, - ), - ), - child: Padding( - padding: const EdgeInsets.all(0.0), - child: StreamSvgIcon.close( color: StreamChatTheme.of(context) .colorTheme - .black, - size: 24, + .whiteSnow, ), ), + child: StreamSvgIcon.close( + color: StreamChatTheme.of(context) + .colorTheme + .black, + size: 24, + ), ), ), ) diff --git a/example/lib/search_text_field.dart b/example/lib/search_text_field.dart index 8f943f11..ff34e8a9 100644 --- a/example/lib/search_text_field.dart +++ b/example/lib/search_text_field.dart @@ -24,7 +24,7 @@ class SearchTextField extends StatelessWidget { decoration: BoxDecoration( color: StreamChatTheme.of(context).colorTheme.white, border: Border.all( - color: StreamChatTheme.of(context).colorTheme.white, + color: StreamChatTheme.of(context).colorTheme.greyWhisper, ), borderRadius: BorderRadius.circular(24), ), diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 268d93ce..c5162d86 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -1,6 +1,6 @@ name: example description: A new Flutter project. -version: 1.0.98+101 +version: 1.0.99+102 environment: sdk: ">=2.2.2 <3.0.0" diff --git a/lib/src/channel_list_view.dart b/lib/src/channel_list_view.dart index 95d60f9c..e33f7e1f 100644 --- a/lib/src/channel_list_view.dart +++ b/lib/src/channel_list_view.dart @@ -336,8 +336,8 @@ class _ChannelListViewState extends State Shimmer _buildLoadingItem() { if (widget.crossAxisCount > 1) { return Shimmer.fromColors( - baseColor: Color(0xffE5E5E5), - highlightColor: Color(0xffffffff), + baseColor: StreamChatTheme.of(context).colorTheme.greyGainsboro, + highlightColor: StreamChatTheme.of(context).colorTheme.whiteSmoke, child: Column( children: [ SizedBox( @@ -367,8 +367,8 @@ class _ChannelListViewState extends State ); } else { return Shimmer.fromColors( - baseColor: Color(0xffE5E5E5), - highlightColor: StreamChatTheme.of(context).colorTheme.white, + baseColor: StreamChatTheme.of(context).colorTheme.greyGainsboro, + highlightColor: StreamChatTheme.of(context).colorTheme.whiteSmoke, child: ListTile( leading: Container( decoration: BoxDecoration( diff --git a/lib/src/channel_unread_indicator.dart b/lib/src/channel_unread_indicator.dart index 10a2aa48..8080b1e9 100644 --- a/lib/src/channel_unread_indicator.dart +++ b/lib/src/channel_unread_indicator.dart @@ -36,7 +36,7 @@ class ChannelUnreadIndicator extends StatelessWidget { '${snapshot.data}', style: TextStyle( fontSize: 11, - color: StreamChatTheme.of(context).colorTheme.white, + color: Colors.white, ), ), ), diff --git a/lib/src/full_screen_media.dart b/lib/src/full_screen_media.dart index e6ecb64f..7e3f3d7d 100644 --- a/lib/src/full_screen_media.dart +++ b/lib/src/full_screen_media.dart @@ -100,9 +100,7 @@ class _FullScreenMediaState extends State .channelTheme .channelHeaderTheme .color, - end: StreamChatTheme.of(context) - .colorTheme - .black) + end: Colors.black) .lerp(_controller.value), ), onTapUp: (a, b, c) { diff --git a/lib/src/image_actions_modal.dart b/lib/src/image_actions_modal.dart index a80dd6e7..168581c0 100644 --- a/lib/src/image_actions_modal.dart +++ b/lib/src/image_actions_modal.dart @@ -35,7 +35,7 @@ class ImageActionsModal extends StatelessWidget { begin: Alignment.topCenter, end: Alignment.bottomCenter, colors: [ - StreamChatTheme.of(context).colorTheme.black.withOpacity(0.8), + Colors.black.withOpacity(0.8), Colors.transparent, ], stops: [0.0, 0.4], @@ -110,10 +110,10 @@ class ImageActionsModal extends StatelessWidget { shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(16), ), - color: Color(0xffe5e5e5), child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: ListTile.divideTiles( + color: StreamChatTheme.of(context).colorTheme.greyWhisper, context: context, tiles: [ _buildButton( @@ -203,6 +203,7 @@ class ImageActionsModal extends StatelessWidget { ); return Material( + color: StreamChatTheme.of(context).colorTheme.white, child: InkWell( onTap: onTap, child: ListTile( diff --git a/lib/src/image_footer.dart b/lib/src/image_footer.dart index fa74ff9d..eff6110a 100644 --- a/lib/src/image_footer.dart +++ b/lib/src/image_footer.dart @@ -5,10 +5,10 @@ import 'dart:typed_data'; import 'package:cached_network_image/cached_network_image.dart'; import 'package:chewie/chewie.dart'; +import 'package:dio/dio.dart'; import 'package:esys_flutter_share/esys_flutter_share.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; -import 'package:dio/dio.dart'; import 'package:image_gallery_saver/image_gallery_saver.dart'; import 'package:path_provider/path_provider.dart'; import 'package:stream_chat/stream_chat.dart'; @@ -300,7 +300,7 @@ class _ImageFooterState extends State { limit: 25, ), filter: { - if (_searchController.text.isNotEmpty) + if (_channelNameQuery?.trim()?.isNotEmpty == true) 'name': { r'$autocomplete': _channelNameQuery, }, @@ -311,7 +311,7 @@ class _ImageFooterState extends State { sort: [ SortOption( 'name', - direction: 1, + direction: SortOption.ASC, ), ], emptyBuilder: (_) { @@ -356,6 +356,8 @@ class _ImageFooterState extends State { color: StreamChatTheme.of(context).colorTheme.white, height: 48.0, child: Material( + color: + StreamChatTheme.of(context).colorTheme.white, child: InkWell( onTap: () async { var url = widget diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 92d09f4b..c6f1d297 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -1343,7 +1343,7 @@ class MessageInputState extends State { StreamChatTheme.of(context) .colorTheme .black - .withOpacity(0.2), + .withOpacity(0.6), maxRadius: 12.0, child: StreamSvgIcon.close( color: StreamChatTheme.of(context) diff --git a/lib/src/message_list_view.dart b/lib/src/message_list_view.dart index fd31b996..3c6484dc 100644 --- a/lib/src/message_list_view.dart +++ b/lib/src/message_list_view.dart @@ -345,10 +345,12 @@ class _MessageListViewState extends State { begin: Alignment.topCenter, end: Alignment.bottomCenter, colors: [ - Color(0XFFF7F7F7), StreamChatTheme.of(context) .colorTheme .whiteSmoke, + StreamChatTheme.of(context) + .colorTheme + .whiteSnow, ], ), ), @@ -844,7 +846,7 @@ class _MessageListViewState extends State { } if (event.message.user.id == streamChannel.channel.client.state.user.id) { WidgetsBinding.instance.addPostFrameCallback((_) { - _scrollController.jumpTo( + _scrollController?.jumpTo( index: 0, ); }); diff --git a/lib/src/stream_chat_theme.dart b/lib/src/stream_chat_theme.dart index f6b00ef8..60e37b80 100644 --- a/lib/src/stream_chat_theme.dart +++ b/lib/src/stream_chat_theme.dart @@ -381,33 +381,41 @@ class TextTheme { this.title = const TextStyle( fontSize: 22, fontWeight: FontWeight.bold, + color: Colors.black, ), this.headlineBold = const TextStyle( fontSize: 16, fontWeight: FontWeight.bold, + color: Colors.black, ), this.headline = const TextStyle( fontSize: 16, fontWeight: FontWeight.w500, + color: Colors.black, ), this.bodyBold = const TextStyle( fontSize: 14, fontWeight: FontWeight.bold, + color: Colors.black, ), this.body = const TextStyle( fontSize: 14, fontWeight: FontWeight.w500, + color: Colors.black, ), this.footnoteBold = const TextStyle( fontSize: 12, fontWeight: FontWeight.w500, + color: Colors.black, ), this.footnote = const TextStyle( fontSize: 12, + color: Colors.black, ), this.captionBold = const TextStyle( fontSize: 10, fontWeight: FontWeight.bold, + color: Colors.black, ), }); diff --git a/lib/src/unread_indicator.dart b/lib/src/unread_indicator.dart index 42e6c78d..c9f42fad 100644 --- a/lib/src/unread_indicator.dart +++ b/lib/src/unread_indicator.dart @@ -34,7 +34,7 @@ class UnreadIndicator extends StatelessWidget { '${snapshot.data}', style: TextStyle( fontSize: 11, - color: StreamChatTheme.of(context).colorTheme.white, + color: Colors.white, ), ), ), diff --git a/lib/src/user_item.dart b/lib/src/user_item.dart index 49a6d5e3..50a8b7a7 100644 --- a/lib/src/user_item.dart +++ b/lib/src/user_item.dart @@ -74,6 +74,8 @@ class UserItem extends StatelessWidget { ), trailing: selected ? CircleAvatar( + backgroundColor: + StreamChatTheme.of(context).colorTheme.accentBlue, child: StreamSvgIcon.check( size: 20, color: StreamChatTheme.of(context).colorTheme.white, From 4f9b75392f8342368d670aab40a4cfdb42aafeb5 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Wed, 30 Dec 2020 18:30:52 +0100 Subject: [PATCH 0692/1140] apply theme to group info screen --- lib/src/chat_info_screen.dart | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/src/chat_info_screen.dart b/lib/src/chat_info_screen.dart index 8017cb5b..3a9c25ee 100644 --- a/lib/src/chat_info_screen.dart +++ b/lib/src/chat_info_screen.dart @@ -384,7 +384,7 @@ class __SharedGroupsScreenState extends State<_SharedGroupsScreen> { var chat = StreamChat.of(context); return Scaffold( - backgroundColor: StreamChatTheme.of(context).colorTheme.white, + backgroundColor: StreamChatTheme.of(context).colorTheme.whiteSnow, appBar: AppBar( brightness: Theme.of(context).brightness, elevation: 1, @@ -521,7 +521,8 @@ class __SharedGroupsScreenState extends State<_SharedGroupsScreen> { ), Container( height: 1.0, - color: Color(0xffe6e6e6), + color: + StreamChatTheme.of(context).colorTheme.black.withOpacity(.08), ), ], ); From f8ea85348619b4e8e0dfd81a4a06a4930c2fcd1c Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Thu, 31 Dec 2020 12:41:05 +0530 Subject: [PATCH 0693/1140] fix: fixed channel media issue --- lib/src/channel_media_display_screen.dart | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/lib/src/channel_media_display_screen.dart b/lib/src/channel_media_display_screen.dart index b65f27ab..ea6dabff 100644 --- a/lib/src/channel_media_display_screen.dart +++ b/lib/src/channel_media_display_screen.dart @@ -167,6 +167,7 @@ class _ChannelMediaDisplayScreenState extends State { SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 3), itemBuilder: (context, position) { var channel = StreamChannel.of(context).channel; + print('NAV'); return Padding( padding: const EdgeInsets.all(1.0), @@ -178,9 +179,9 @@ class _ChannelMediaDisplayScreenState extends State { builder: (context) => StreamChannel( channel: channel, child: FullScreenMedia( - mediaAttachments: [ - media[position].attachment, - ], + mediaAttachments: + media.map((e) => e.attachment).toList(), + startIndex: position, message: media[position].message, sentAt: media[position].message.createdAt, userName: media[position].message.user.name, @@ -190,13 +191,15 @@ class _ChannelMediaDisplayScreenState extends State { ); }, child: media[position].attachment.type == 'image' - ? ImageAttachment( - attachment: media[position].attachment, - message: media[position].message, - showTitle: false, - size: Size( - MediaQuery.of(context).size.width * 0.8, - MediaQuery.of(context).size.height * 0.3, + ? IgnorePointer( + child: ImageAttachment( + attachment: media[position].attachment, + message: media[position].message, + showTitle: false, + size: Size( + MediaQuery.of(context).size.width * 0.8, + MediaQuery.of(context).size.height * 0.3, + ), ), ) : VideoPlayer(media[position].videoPlayer), From 7f696236c446b4038d2e06eae08318bbc9af9ac0 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Thu, 31 Dec 2020 13:05:32 +0530 Subject: [PATCH 0694/1140] [Message Widget] Add message error state Signed-off-by: Sahil Kumar --- lib/src/message_actions_modal.dart | 30 +++++- lib/src/message_widget.dart | 147 +++++++++++------------------ lib/src/sending_indicator.dart | 9 -- lib/src/stream_svg_icon.dart | 25 +++++ 4 files changed, 107 insertions(+), 104 deletions(-) diff --git a/lib/src/message_actions_modal.dart b/lib/src/message_actions_modal.dart index 8013a8b3..2d482c0e 100644 --- a/lib/src/message_actions_modal.dart +++ b/lib/src/message_actions_modal.dart @@ -22,6 +22,7 @@ class MessageActionsModal extends StatelessWidget { final bool showDeleteMessage; final bool showCopyMessage; final bool showEditMessage; + final bool showResendMessage; final bool showReply; final bool reverse; final ShapeBorder messageShape; @@ -37,6 +38,7 @@ class MessageActionsModal extends StatelessWidget { this.onThreadTap, this.showCopyMessage = true, this.showReply = true, + this.showResendMessage = true, this.showUserAvatar = DisplayWidget.show, this.editMessageInputBuilder, this.messageShape, @@ -159,6 +161,8 @@ class MessageActionsModal extends StatelessWidget { message.status == null) && message.parentId == null) _buildReplyButton(context), + if (showResendMessage) + _buildResendMessage(context), if (showEditMessage) _buildEditMessage(context), if (showDeleteMessage) @@ -183,9 +187,10 @@ class MessageActionsModal extends StatelessWidget { } Widget _buildDeleteButton(BuildContext context) { + final isDeleteFailed = message.status == MessageSendingStatus.FAILED_DELETE; return ListTile( title: Text( - 'Delete message', + isDeleteFailed ? 'Retry deleting message' : 'Delete message', style: Theme.of(context).textTheme.headline6.copyWith(color: Colors.red), ), @@ -234,6 +239,29 @@ 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).accentColor, + ), + onTap: () { + Navigator.pop(context); + final client = StreamChat.of(context).client; + final channel = StreamChannel.of(context).channel; + if (isUpdateFailed) { + client.updateMessage(message, channel.cid); + } else { + channel.sendMessage(message); + } + }, + ); + } + void _showEditBottomSheet(BuildContext context) { final channel = StreamChannel.of(context).channel; showModalBottomSheet( diff --git a/lib/src/message_widget.dart b/lib/src/message_widget.dart index 9d81d679..ee165057 100644 --- a/lib/src/message_widget.dart +++ b/lib/src/message_widget.dart @@ -114,6 +114,9 @@ class MessageWidget extends StatefulWidget { /// Used in [MessageReactionsModal] and [MessageActionsModal] final bool showReactionPickerIndicator; + /// If true the widget will show the resendMessage indicator + final bool showResendMessage; + final List readList; /// If true show the users username next to the timestamp of the message @@ -157,6 +160,7 @@ class MessageWidget extends StatefulWidget { this.editMessageInputBuilder, this.textBuilder, Map customAttachmentBuilders, + this.showResendMessage = true, this.readList, this.padding, this.textPadding = const EdgeInsets.symmetric( @@ -229,6 +233,16 @@ class _MessageWidgetState extends State { bool get showInChannel => widget.showInChannelIndicator && widget.message?.showInChannel == true; + bool get isSendFailed => widget.message.status == MessageSendingStatus.FAILED; + + bool get isUpdateFailed => + widget.message.status == MessageSendingStatus.FAILED_UPDATE; + + bool get isDeleteFailed => + widget.message.status == MessageSendingStatus.FAILED_DELETE; + + bool get isFailedState => isSendFailed || isUpdateFailed || isDeleteFailed; + @override Widget build(BuildContext context) { var leftPadding = widget.showUserAvatar != DisplayWidget.gone @@ -298,9 +312,7 @@ class _MessageWidgetState extends State { ) : EdgeInsets.zero, child: (widget.message.isDeleted && - widget.message.status != - MessageSendingStatus - .FAILED_DELETE) + !isFailedState) ? Transform( alignment: Alignment.center, transform: Matrix4.rotationY( @@ -377,6 +389,21 @@ class _MessageWidgetState extends State { ), ), ), + if (isFailedState) + Positioned( + left: widget.reverse ? -6 : null, + right: widget.reverse ? null : -6, + bottom: 0, + child: Container( + decoration: BoxDecoration( + color: Colors.white, + shape: BoxShape.circle, + ), + child: StreamSvgIcon.error( + size: 20, + ), + ), + ), ], ), ), @@ -619,14 +646,19 @@ class _MessageWidgetState extends State { message: widget.message, editMessageInputBuilder: widget.editMessageInputBuilder, onThreadTap: widget.onThreadTap, - showCopyMessage: widget.message.text?.trim()?.isNotEmpty == true, + showResendMessage: + widget.showResendMessage && (isSendFailed || isUpdateFailed), + showCopyMessage: !isFailedState && + widget.message.text?.trim()?.isNotEmpty == true, showEditMessage: widget.showEditMessage && + !isDeleteFailed && widget.message.attachments ?.any((element) => element.type == 'giphy') != true, showReactions: widget.showReactions, - showReply: - widget.showThreadReplyIndicator && widget.onThreadTap != null, + showReply: widget.showThreadReplyIndicator && + !isFailedState && + widget.onThreadTap != null, ), ); }); @@ -729,7 +761,6 @@ class _MessageWidgetState extends State { final attachmentShape = widget.attachmentShape ?? widget.shape ?? _getDefaultShape(context); return GestureDetector( - onTap: () => retryMessage(context), onLongPress: () => onLongPress(context), child: Material( color: _getBackgroundColor(), @@ -744,17 +775,7 @@ class _MessageWidgetState extends State { child: Transform( transform: Matrix4.rotationY(widget.reverse ? pi : 0), alignment: Alignment.center, - child: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.end, - children: [ - getFailedMessageWidget( - context, - padding: const EdgeInsets.all(8.0), - ), - attachmentWidget, - ], - ), + child: attachmentWidget, ), ), ), @@ -809,55 +830,6 @@ class _MessageWidgetState extends State { ), ); - Widget getFailedMessageWidget( - BuildContext context, { - EdgeInsetsGeometry padding, - }) { - Widget failedWidget; - if (widget.message.status == MessageSendingStatus.FAILED) { - failedWidget = Text( - 'MESSAGE FAILED · CLICK TO TRY AGAIN', - style: widget.messageTheme.messageText.copyWith( - color: Theme.of(context).brightness == Brightness.dark - ? Colors.white.withOpacity(.5) - : Colors.black.withOpacity(.5), - fontSize: 11, - ), - ); - } - if (widget.message.status == MessageSendingStatus.FAILED_UPDATE) { - failedWidget = Text( - 'MESSAGE UPDATE FAILED · CLICK TO TRY AGAIN', - style: widget.messageTheme.messageText.copyWith( - color: Theme.of(context).brightness == Brightness.dark - ? Colors.white.withOpacity(.5) - : Colors.black.withOpacity(.5), - fontSize: 11, - ), - ); - } - if (widget.message.status == MessageSendingStatus.FAILED_DELETE) { - failedWidget = Text( - 'MESSAGE DELETE FAILED · CLICK TO TRY AGAIN', - style: widget.messageTheme.messageText.copyWith( - color: Theme.of(context).brightness == Brightness.dark - ? Colors.white.withOpacity(.5) - : Colors.black.withOpacity(.5), - fontSize: 11, - ), - ); - } - - if (failedWidget != null) { - return Padding( - padding: padding ?? EdgeInsets.zero, - child: failedWidget, - ); - } - - return SizedBox(); - } - Widget _buildTextBubble(BuildContext context) { Widget child = Transform( transform: Matrix4.rotationY(widget.reverse ? pi : 0), @@ -867,26 +839,20 @@ class _MessageWidgetState extends State { children: [ Padding( padding: widget.textPadding, - child: Column( - crossAxisAlignment: CrossAxisAlignment.end, - children: [ - getFailedMessageWidget(context), - widget.textBuilder != null - ? widget.textBuilder(context, widget.message) - : MessageText( - onLinkTap: widget.onLinkTap, - message: widget.message, - onMentionTap: widget.onMentionTap, - messageTheme: isOnlyEmoji - ? widget.messageTheme.copyWith( - messageText: - widget.messageTheme.messageText.copyWith( - fontSize: 40, - )) - : widget.messageTheme, - ), - ], - ), + child: widget.textBuilder != null + ? widget.textBuilder(context, widget.message) + : MessageText( + onLinkTap: widget.onLinkTap, + message: widget.message, + onMentionTap: widget.onMentionTap, + messageTheme: isOnlyEmoji + ? widget.messageTheme.copyWith( + messageText: + widget.messageTheme.messageText.copyWith( + fontSize: 40, + )) + : widget.messageTheme, + ), ), if (widget.message.attachments ?.any((element) => element.ogScrapeUrl != null) == @@ -896,7 +862,6 @@ class _MessageWidgetState extends State { ), ); return GestureDetector( - onTap: () => retryMessage(context), onLongPress: () => onLongPress(context), child: child, ); @@ -907,12 +872,6 @@ class _MessageWidgetState extends State { widget.message.text.characters.every((c) => Emoji.byChar(c) != null); Color _getBackgroundColor() { - if ((widget.message.status == MessageSendingStatus.FAILED || - widget.message.status == MessageSendingStatus.FAILED_UPDATE || - widget.message.status == MessageSendingStatus.FAILED_DELETE)) { - return Color(0xffd0021B).withOpacity(.1); - } - if (widget.message.attachments ?.any((element) => element.ogScrapeUrl != null) == true) { diff --git a/lib/src/sending_indicator.dart b/lib/src/sending_indicator.dart index ce8915c3..6006f62d 100644 --- a/lib/src/sending_indicator.dart +++ b/lib/src/sending_indicator.dart @@ -35,15 +35,6 @@ class SendingIndicator extends StatelessWidget { size: 8, ); } - if (message.status == MessageSendingStatus.FAILED || - message.status == MessageSendingStatus.FAILED_UPDATE || - message.status == MessageSendingStatus.FAILED_DELETE) { - return Icon( - Icons.error_outline, - size: 8, - ); - } - return SizedBox(); } } diff --git a/lib/src/stream_svg_icon.dart b/lib/src/stream_svg_icon.dart index 98ce0f8e..c75e9327 100644 --- a/lib/src/stream_svg_icon.dart +++ b/lib/src/stream_svg_icon.dart @@ -757,4 +757,29 @@ class StreamSvgIcon extends StatelessWidget { height: size, ); } + + factory StreamSvgIcon.error({ + double size, + Color color, + }) { + return StreamSvgIcon( + assetName: 'Icon_error.svg', + color: color, + width: size, + height: size, + ); + } + + + factory StreamSvgIcon.circle_up({ + double size, + Color color, + }) { + return StreamSvgIcon( + assetName: 'Icon_circle_up.svg', + color: color, + width: size, + height: size, + ); + } } From 168630fcade71ecf7f457bb038e46a478eae5222 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Thu, 31 Dec 2020 13:11:05 +0530 Subject: [PATCH 0695/1140] flutter format Signed-off-by: Sahil Kumar --- lib/src/stream_svg_icon.dart | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/src/stream_svg_icon.dart b/lib/src/stream_svg_icon.dart index c75e9327..63eef658 100644 --- a/lib/src/stream_svg_icon.dart +++ b/lib/src/stream_svg_icon.dart @@ -770,7 +770,6 @@ class StreamSvgIcon extends StatelessWidget { ); } - factory StreamSvgIcon.circle_up({ double size, Color color, From ef0bad11929623a533efc4dff5ca29bd42d80506 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Thu, 31 Dec 2020 14:18:12 +0530 Subject: [PATCH 0696/1140] [Message Widget] Modify read indicator as per new design v2 Signed-off-by: Sahil Kumar --- lib/src/channel_preview.dart | 6 ++++- lib/src/message_widget.dart | 45 ++++++++++++++++++++++------------ lib/src/sending_indicator.dart | 16 ++++++------ 3 files changed, 43 insertions(+), 24 deletions(-) diff --git a/lib/src/channel_preview.dart b/lib/src/channel_preview.dart index 5f58e254..d6623544 100644 --- a/lib/src/channel_preview.dart +++ b/lib/src/channel_preview.dart @@ -122,7 +122,11 @@ class ChannelPreview extends StatelessWidget { padding: const EdgeInsets.only(right: 4.0), child: SendingIndicator( message: channel.state.lastMessage, - allRead: channel.state.read + size: StreamChatTheme.of(context) + .channelPreviewTheme + .lastMessageAt + .fontSize, + isMessageRead: channel.state.read .where((element) => element.lastRead .isAfter(channel .state.lastMessage.createdAt)) diff --git a/lib/src/message_widget.dart b/lib/src/message_widget.dart index ee165057..226e98c0 100644 --- a/lib/src/message_widget.dart +++ b/lib/src/message_widget.dart @@ -228,7 +228,7 @@ class _MessageWidgetState extends State { bool get showTimeStamp => widget.message.createdAt != null && widget.showTimestamp; - bool get showReadList => widget.readList?.isNotEmpty == true; + bool get isMessageRead => widget.readList?.isNotEmpty == true; bool get showInChannel => widget.showInChannelIndicator && widget.message?.showInChannel == true; @@ -488,14 +488,14 @@ class _MessageWidgetState extends State { children.addAll([ if (showSendingIndicator) _buildSendingIndicator(), - if (showReadList) - SizedBox.fromSize( - size: Size((widget.readList.length * 10.0) + 10, 17), - child: Padding( - padding: const EdgeInsets.only(left: 4.0), - child: _buildReadIndicator(), - ), - ), + // if (showReadList) + // SizedBox.fromSize( + // size: Size((widget.readList.length * 10.0) + 10, 17), + // child: Padding( + // padding: const EdgeInsets.only(left: 4.0), + // child: _buildReadIndicator(), + // ), + // ), if (showThreadReplyIndicator) InkWell( onTap: widget.onThreadTap != null ? onThreadTap : null, @@ -798,14 +798,27 @@ class _MessageWidgetState extends State { } Widget _buildSendingIndicator() { - return Container( - height: widget.messageTheme.createdAt.fontSize + 2, - width: widget.messageTheme.createdAt.fontSize + 2, - child: SendingIndicator( - message: widget.message, - allRead: widget.allRead, - ), + final style = widget.messageTheme.createdAt; + Widget child = SendingIndicator( + message: widget.message, + isMessageRead: isMessageRead, + size: style.fontSize, ); + if (isMessageRead) { + child = Row( + children: [ + Text( + widget.readList.length.toString(), + style: style.copyWith( + color: StreamChatTheme.of(context).accentColor, + ), + ), + SizedBox(width: 2), + child, + ], + ); + } + return child; } Widget _buildUserAvatar() => Transform( diff --git a/lib/src/sending_indicator.dart b/lib/src/sending_indicator.dart index 6006f62d..34492167 100644 --- a/lib/src/sending_indicator.dart +++ b/lib/src/sending_indicator.dart @@ -4,27 +4,29 @@ import 'package:stream_chat_flutter/stream_chat_flutter.dart'; /// Used to show the sending status of the message class SendingIndicator extends StatelessWidget { final Message message; - final bool allRead; + final bool isMessageRead; + final double size; const SendingIndicator({ Key key, this.message, - this.allRead = false, + this.isMessageRead = false, + this.size = 12, }) : super(key: key); @override Widget build(BuildContext context) { - if (allRead) { + if (isMessageRead) { return Icon( - Icons.done_all, - size: 8, + Icons.done_all_rounded, + size: size, color: StreamChatTheme.of(context).accentColor, ); } if (message.status == MessageSendingStatus.SENT || message.status == null) { return Icon( Icons.done, - size: 8, + size: size, color: IconTheme.of(context).color.withOpacity(0.5), ); } @@ -32,7 +34,7 @@ class SendingIndicator extends StatelessWidget { message.status == MessageSendingStatus.UPDATING) { return Icon( Icons.access_time, - size: 8, + size: size, ); } return SizedBox(); From f02f8a27cbcfdcad16981d2803be9fe1ce8d6cb7 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Thu, 31 Dec 2020 14:19:03 +0530 Subject: [PATCH 0697/1140] fix: fixed group member list --- example/lib/group_info_screen.dart | 176 +++++++++++++++++++---------- lib/src/image_footer.dart | 5 +- 2 files changed, 121 insertions(+), 60 deletions(-) diff --git a/example/lib/group_info_screen.dart b/example/lib/group_info_screen.dart index 1c926106..3c469b9f 100644 --- a/example/lib/group_info_screen.dart +++ b/example/lib/group_info_screen.dart @@ -32,6 +32,8 @@ class _GroupInfoScreenState extends State { bool namedChanged = false; String changedName = ''; + int groupMemberListLength; + void _userNameListener() { if (_searchController.text == _userNameQuery) { return; @@ -161,78 +163,134 @@ class _GroupInfoScreenState extends State { ); } - return ListView.builder( - shrinkWrap: true, - physics: NeverScrollableScrollPhysics(), - itemCount: snapshot.data.members.length, - itemBuilder: (context, position) { - return Material( - child: InkWell( - onTap: () { - var userMember = snapshot.data.members.firstWhere( - (e) => e.user.id == StreamChat.of(context).user.id); - _showUserInfoModal(snapshot.data.members[position].user, - userMember.role == 'owner'); - }, - child: Container( - height: 65.0, - child: Column( - children: [ - Row( + groupMemberListLength ??= + snapshot.data.members.length > 6 ? 6 : snapshot.data.members.length; + + return Column( + children: [ + ListView.builder( + shrinkWrap: true, + physics: NeverScrollableScrollPhysics(), + itemCount: groupMemberListLength, + itemBuilder: (context, position) { + return Material( + child: InkWell( + onTap: () { + var userMember = snapshot.data.members.firstWhere( + (e) => e.user.id == StreamChat.of(context).user.id); + _showUserInfoModal(snapshot.data.members[position].user, + userMember.role == 'owner'); + }, + child: Container( + height: 65.0, + child: Column( children: [ - Padding( - padding: const EdgeInsets.symmetric( - horizontal: 8.0, vertical: 12.0), - child: UserAvatar( - user: snapshot.data.members[position].user, - constraints: BoxConstraints( - maxHeight: 40.0, maxWidth: 40.0), - ), - ), - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text( - snapshot.data.members[position].user.name, - style: TextStyle(fontWeight: FontWeight.bold), + Row( + children: [ + Padding( + padding: const EdgeInsets.symmetric( + horizontal: 8.0, vertical: 12.0), + child: UserAvatar( + user: snapshot.data.members[position].user, + constraints: BoxConstraints( + maxHeight: 40.0, maxWidth: 40.0), ), - SizedBox( - height: 1.0, + ), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + snapshot.data.members[position].user.name, + style: TextStyle( + fontWeight: FontWeight.bold), + ), + SizedBox( + height: 1.0, + ), + Text( + _getLastSeen( + snapshot.data.members[position].user), + style: TextStyle( + color: Colors.black.withOpacity(0.5)), + ), + ], ), - Text( - _getLastSeen( - snapshot.data.members[position].user), + ), + Padding( + padding: const EdgeInsets.all(8.0), + child: Text( + snapshot.data.members[position].role == + 'owner' + ? 'Owner' + : '', style: TextStyle( color: Colors.black.withOpacity(0.5)), ), - ], - ), + ), + ], ), - Padding( - padding: const EdgeInsets.all(8.0), - child: Text( - snapshot.data.members[position].role == 'owner' - ? 'Owner' - : '', - style: TextStyle( - color: Colors.black.withOpacity(0.5)), - ), + Container( + height: 1.0, + color: Color(0xffdbdbdb), ), ], ), - Container( - height: 1.0, - color: Color(0xffdbdbdb), - ), - ], + ), + ), + color: Colors.white, + ); + }, + ), + if (groupMemberListLength != snapshot.data.members.length) + InkWell( + onTap: () { + setState(() { + groupMemberListLength = snapshot.data.members.length; + }); + }, + child: Material( + child: Container( + height: 65.0, + child: Column( + children: [ + Expanded( + child: Row( + children: [ + Padding( + padding: const EdgeInsets.symmetric( + horizontal: 21.0, vertical: 12.0), + child: StreamSvgIcon.down( + color: Color(0xff7a7a7a), + ), + ), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + '${snapshot.data.members.length - groupMemberListLength} more', + style: + TextStyle(color: Color(0xff7a7a7a)), + ), + ], + ), + ), + ], + ), + ), + Container( + height: 1.0, + color: Color(0xffdbdbdb), + ), + ], + ), ), ), ), - color: Colors.white, - ); - }, + ], ); }, future: _memberQueryFuture, diff --git a/lib/src/image_footer.dart b/lib/src/image_footer.dart index 97e40cba..8a3738ac 100644 --- a/lib/src/image_footer.dart +++ b/lib/src/image_footer.dart @@ -104,7 +104,10 @@ class _ImageFooterState extends State { @override Widget build(BuildContext context) { return SizedBox.fromSize( - size: widget.preferredSize, + size: Size( + MediaQuery.of(context).size.width, + MediaQuery.of(context).padding.bottom + widget.preferredSize.height, + ), child: MediaQuery.removePadding( context: context, removeTop: true, From db932d4e32210681a652e61488b03260a34a60a6 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Thu, 31 Dec 2020 09:51:30 +0100 Subject: [PATCH 0698/1140] use system theme --- example/ios/Flutter/.last_build_id | 2 +- example/lib/main.dart | 2 +- example/pubspec.yaml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/example/ios/Flutter/.last_build_id b/example/ios/Flutter/.last_build_id index e72273c3..f57e1e1f 100644 --- a/example/ios/Flutter/.last_build_id +++ b/example/ios/Flutter/.last_build_id @@ -1 +1 @@ -13a41b8138c4868054e44b5158f3bdd6 \ No newline at end of file +c770358a10272b4ee1cdc2eb432445f6 \ No newline at end of file diff --git a/example/lib/main.dart b/example/lib/main.dart index c51a8a4c..0de1fbe1 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -59,7 +59,7 @@ class MyApp extends StatelessWidget { debugShowCheckedModeBanner: false, theme: ThemeData.light(), darkTheme: ThemeData.dark(), - themeMode: ThemeMode.light, + themeMode: ThemeMode.system, onGenerateRoute: AppRoutes.generateRoute, initialRoute: client.state.user == null ? Routes.CHOOSE_USER : Routes.HOME, diff --git a/example/pubspec.yaml b/example/pubspec.yaml index c5162d86..481bdd37 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -1,6 +1,6 @@ name: example description: A new Flutter project. -version: 1.0.99+102 +version: 1.0.100+103 environment: sdk: ">=2.2.2 <3.0.0" From a8171f7314116ba6bd1f0334afa57dc965e1a332 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Thu, 31 Dec 2020 09:57:21 +0100 Subject: [PATCH 0699/1140] ui fixes --- example/lib/group_chat_details_screen.dart | 1 + example/lib/new_chat_screen.dart | 1 + example/lib/new_group_chat_screen.dart | 9 +++++---- example/pubspec.yaml | 2 +- lib/src/attachment_error.dart | 6 +++--- 5 files changed, 11 insertions(+), 8 deletions(-) diff --git a/example/lib/group_chat_details_screen.dart b/example/lib/group_chat_details_screen.dart index b186684f..19674332 100644 --- a/example/lib/group_chat_details_screen.dart +++ b/example/lib/group_chat_details_screen.dart @@ -61,6 +61,7 @@ class _GroupChatDetailsScreenState extends State { child: Scaffold( backgroundColor: StreamChatTheme.of(context).colorTheme.whiteSnow, appBar: AppBar( + brightness: Theme.of(context).brightness, elevation: 1, backgroundColor: StreamChatTheme.of(context).colorTheme.white, leading: const StreamBackButton(), diff --git a/example/lib/new_chat_screen.dart b/example/lib/new_chat_screen.dart index 4cebb564..ddebe848 100644 --- a/example/lib/new_chat_screen.dart +++ b/example/lib/new_chat_screen.dart @@ -121,6 +121,7 @@ class _NewChatScreenState extends State { return Scaffold( backgroundColor: StreamChatTheme.of(context).colorTheme.whiteSnow, appBar: AppBar( + brightness: Theme.of(context).brightness, elevation: 0, backgroundColor: StreamChatTheme.of(context).colorTheme.white, leading: const StreamBackButton(), diff --git a/example/lib/new_group_chat_screen.dart b/example/lib/new_group_chat_screen.dart index d094f5c0..a81f2f51 100644 --- a/example/lib/new_group_chat_screen.dart +++ b/example/lib/new_group_chat_screen.dart @@ -50,14 +50,15 @@ class _NewGroupChatScreenState extends State { @override Widget build(BuildContext context) { - return SafeArea( - child: Scaffold( - backgroundColor: StreamChatTheme.of(context).colorTheme.whiteSnow, - body: NestedScrollView( + return Scaffold( + backgroundColor: StreamChatTheme.of(context).colorTheme.whiteSnow, + body: SafeArea( + child: NestedScrollView( floatHeaderSlivers: true, headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) { return [ SliverAppBar( + brightness: Theme.of(context).brightness, pinned: true, forceElevated: true, elevation: 1, diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 481bdd37..0fca32a4 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -1,6 +1,6 @@ name: example description: A new Flutter project. -version: 1.0.100+103 +version: 1.0.101+104 environment: sdk: ">=2.2.2 <3.0.0" diff --git a/lib/src/attachment_error.dart b/lib/src/attachment_error.dart index 0b51e59c..d24423c4 100644 --- a/lib/src/attachment_error.dart +++ b/lib/src/attachment_error.dart @@ -25,12 +25,12 @@ class AttachmentError extends StatelessWidget { return Center( child: Container( width: size?.width, - height: size?.height, - color: Color(0xffd0021B).withOpacity(.1), + height: size?.height ?? 200, + color: StreamChatTheme.of(context).colorTheme.accentRed.withOpacity(.1), child: Center( child: Icon( Icons.error_outline, - color: StreamChatTheme.of(context).colorTheme.white, + color: StreamChatTheme.of(context).colorTheme.black, ), ), ), From f011bf32fc46b917c06e9ef51280d754147e1aec Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Thu, 31 Dec 2020 10:24:25 +0100 Subject: [PATCH 0700/1140] apply theme to rest of the sdk --- example/lib/group_chat_details_screen.dart | 4 +++- example/lib/main.dart | 7 +++++-- example/lib/new_group_chat_screen.dart | 3 ++- example/pubspec.yaml | 2 +- lib/src/channel_image.dart | 11 +++++++---- lib/src/channel_info.dart | 2 +- lib/src/channel_list_header.dart | 4 ++-- lib/src/channel_list_view.dart | 5 ++++- lib/src/file_attachment.dart | 3 ++- lib/src/group_image.dart | 5 +++-- lib/src/message_list_view.dart | 5 ++++- lib/src/message_search_list_view.dart | 5 ++++- lib/src/message_widget.dart | 2 +- lib/src/url_attachment.dart | 4 +++- lib/src/user_avatar.dart | 5 +++-- lib/src/user_list_view.dart | 5 ++++- lib/src/utils.dart | 3 ++- 17 files changed, 51 insertions(+), 24 deletions(-) diff --git a/example/lib/group_chat_details_screen.dart b/example/lib/group_chat_details_screen.dart index 19674332..03b4877b 100644 --- a/example/lib/group_chat_details_screen.dart +++ b/example/lib/group_chat_details_screen.dart @@ -121,7 +121,9 @@ class _GroupChatDetailsScreenState extends State { padding: const EdgeInsets.all(0), icon: StreamSvgIcon.check( size: 24, - color: _isGroupNameEmpty ? Colors.grey : Color(0xFF006CFF), + color: _isGroupNameEmpty + ? Colors.grey + : StreamChatTheme.of(context).colorTheme.accentBlue, ), onPressed: _isGroupNameEmpty ? null diff --git a/example/lib/main.dart b/example/lib/main.dart index 0de1fbe1..8d436614 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -25,7 +25,7 @@ void main() async { logLevel: Level.INFO, showLocalNotification: (!kIsWeb && Platform.isAndroid) ? showLocalNotification : null, - persistenceEnabled: true, + persistenceEnabled: false, ); if (userId != null) { @@ -456,7 +456,10 @@ class ChannelPage extends StatelessWidget { right: 0, child: Container( alignment: Alignment.centerLeft, - color: Color(0xffFCFCFC).withOpacity(.9), + color: StreamChatTheme.of(context) + .colorTheme + .whiteSnow + .withOpacity(.9), child: TypingIndicator( alignment: Alignment.centerLeft, padding: const EdgeInsets.symmetric( diff --git a/example/lib/new_group_chat_screen.dart b/example/lib/new_group_chat_screen.dart index a81f2f51..505db69c 100644 --- a/example/lib/new_group_chat_screen.dart +++ b/example/lib/new_group_chat_screen.dart @@ -76,7 +76,8 @@ class _NewGroupChatScreenState extends State { if (_selectedUsers.isNotEmpty) IconButton( icon: StreamSvgIcon.arrow_right( - color: Color(0xFF006CFF), + color: + StreamChatTheme.of(context).colorTheme.accentBlue, ), onPressed: () async { final updatedList = await Navigator.pushNamed( diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 0fca32a4..944be796 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -1,6 +1,6 @@ name: example description: A new Flutter project. -version: 1.0.101+104 +version: 1.0.102+105 environment: sdk: ">=2.2.2 <3.0.0" diff --git a/lib/src/channel_image.dart b/lib/src/channel_image.dart index efd8700e..2f5862f3 100644 --- a/lib/src/channel_image.dart +++ b/lib/src/channel_image.dart @@ -53,7 +53,7 @@ class ChannelImage extends StatelessWidget { this.showOnlineStatus = true, this.borderRadius, this.selected = false, - this.selectionColor = const Color(0xFF006CFF), + this.selectionColor, this.selectionThickness = 4, }) : super(key: key); @@ -105,7 +105,8 @@ class ChannelImage extends StatelessWidget { .constraints, onTap: onTap != null ? (_) => onTap() : null, selected: selected, - selectionColor: selectionColor, + selectionColor: selectionColor ?? + StreamChatTheme.of(context).colorTheme.accentBlue, selectionThickness: selectionThickness, ); }); @@ -127,7 +128,8 @@ class ChannelImage extends StatelessWidget { .constraints, onTap: onTap, selected: selected, - selectionColor: selectionColor, + selectionColor: selectionColor ?? + StreamChatTheme.of(context).colorTheme.accentBlue, selectionThickness: selectionThickness, ); } @@ -197,7 +199,8 @@ class ChannelImage extends StatelessWidget { .ownMessageTheme .avatarTheme .constraints, - color: selectionColor, + color: selectionColor ?? + StreamChatTheme.of(context).colorTheme.accentBlue, child: Padding( padding: EdgeInsets.all(selectionThickness), child: child, diff --git a/lib/src/channel_info.dart b/lib/src/channel_info.dart index eda58f43..b1ab568d 100644 --- a/lib/src/channel_info.dart +++ b/lib/src/channel_info.dart @@ -134,7 +134,7 @@ class ChannelInfo extends StatelessWidget { child: Text( 'Try Again', style: textStyle.copyWith( - color: Color(0xFF006CFF), + color: StreamChatTheme.of(context).colorTheme.accentBlue, ), ), ), diff --git a/lib/src/channel_list_header.dart b/lib/src/channel_list_header.dart index 09156d4c..34f3cc76 100644 --- a/lib/src/channel_list_header.dart +++ b/lib/src/channel_list_header.dart @@ -99,7 +99,7 @@ class ChannelListHeader extends StatelessWidget implements PreferredSizeWidget { var color; switch (status) { case ConnectionStatus.connected: - color = Color(0xFF006CFF); + color = StreamChatTheme.of(context).colorTheme.accentBlue; break; case ConnectionStatus.connecting: color = Colors.grey; @@ -205,7 +205,7 @@ class ChannelListHeader extends StatelessWidget implements PreferredSizeWidget { .copyWith( fontSize: 16, fontWeight: FontWeight.bold, - color: Color(0xFF006CFF), + color: StreamChatTheme.of(context).colorTheme.accentBlue, ), ), ), diff --git a/lib/src/channel_list_view.dart b/lib/src/channel_list_view.dart index e33f7e1f..777fae57 100644 --- a/lib/src/channel_list_view.dart +++ b/lib/src/channel_list_view.dart @@ -684,7 +684,10 @@ class _ChannelListViewState extends State builder: (context, snapshot) { if (snapshot.hasError) { return Container( - color: Color(0xffd0021B).withAlpha(26), + color: StreamChatTheme.of(context) + .colorTheme + .accentRed + .withOpacity(.2), child: Padding( padding: const EdgeInsets.symmetric(vertical: 16.0), child: Center( diff --git a/lib/src/file_attachment.dart b/lib/src/file_attachment.dart index 273cddf2..92139530 100644 --- a/lib/src/file_attachment.dart +++ b/lib/src/file_attachment.dart @@ -67,7 +67,8 @@ class _FileAttachmentState extends State { borderRadius: widget.trailing != null ? BorderRadius.circular(16.0) : null, border: widget.trailing != null - ? Border.fromBorderSide(BorderSide(color: Color(0xFFE6E6E6))) + ? Border.fromBorderSide(BorderSide( + color: StreamChatTheme.of(context).colorTheme.greyWhisper)) : null, ), child: Row( diff --git a/lib/src/group_image.dart b/lib/src/group_image.dart index fc45aa59..4cfd655a 100644 --- a/lib/src/group_image.dart +++ b/lib/src/group_image.dart @@ -11,7 +11,7 @@ class GroupImage extends StatelessWidget { this.onTap, this.borderRadius, this.selected = false, - this.selectionColor = const Color(0xFF006CFF), + this.selectionColor, this.selectionThickness = 4, }) : super(key: key); @@ -110,7 +110,8 @@ class GroupImage extends StatelessWidget { streamChatTheme.ownMessageTheme.avatarTheme.borderRadius) + BorderRadius.circular(selectionThickness), child: Container( - color: selectionColor, + color: selectionColor ?? + StreamChatTheme.of(context).colorTheme.accentBlue, height: 64.0, width: 64.0, child: Padding( diff --git a/lib/src/message_list_view.dart b/lib/src/message_list_view.dart index 3c6484dc..a85beb0a 100644 --- a/lib/src/message_list_view.dart +++ b/lib/src/message_list_view.dart @@ -592,7 +592,10 @@ class _MessageListViewState extends State { builder: (context, snapshot) { if (snapshot.hasError) { return Container( - color: Color(0xffd0021B).withAlpha(26), + color: StreamChatTheme.of(context) + .colorTheme + .accentRed + .withOpacity(.2), child: Center( child: Text('Error loading messages'), ), diff --git a/lib/src/message_search_list_view.dart b/lib/src/message_search_list_view.dart index 989234b3..d59ae4a0 100644 --- a/lib/src/message_search_list_view.dart +++ b/lib/src/message_search_list_view.dart @@ -152,7 +152,10 @@ class _MessageSearchListViewState extends State { builder: (context, snapshot) { if (snapshot.hasError) { return Container( - color: Color(0xffd0021B).withAlpha(26), + color: StreamChatTheme.of(context) + .colorTheme + .accentRed + .withOpacity(.2), child: Padding( padding: const EdgeInsets.symmetric(vertical: 16.0), child: Center( diff --git a/lib/src/message_widget.dart b/lib/src/message_widget.dart index 7b185f97..acc8f03d 100644 --- a/lib/src/message_widget.dart +++ b/lib/src/message_widget.dart @@ -919,7 +919,7 @@ class _MessageWidgetState extends State { if ((widget.message.status == MessageSendingStatus.FAILED || widget.message.status == MessageSendingStatus.FAILED_UPDATE || widget.message.status == MessageSendingStatus.FAILED_DELETE)) { - return Color(0xffd0021B).withOpacity(.1); + return StreamChatTheme.of(context).colorTheme.accentRed.withOpacity(.1); } if (widget.message.attachments diff --git a/lib/src/url_attachment.dart b/lib/src/url_attachment.dart index c655880d..1909fc33 100644 --- a/lib/src/url_attachment.dart +++ b/lib/src/url_attachment.dart @@ -55,7 +55,9 @@ class UrlAttachment extends StatelessWidget { .textTheme .bodyBold .copyWith( - color: Color(0xFF006CFF), + color: StreamChatTheme.of(context) + .colorTheme + .accentBlue, ), ), ), diff --git a/lib/src/user_avatar.dart b/lib/src/user_avatar.dart index fb9a832a..688eff77 100644 --- a/lib/src/user_avatar.dart +++ b/lib/src/user_avatar.dart @@ -16,7 +16,7 @@ class UserAvatar extends StatelessWidget { this.borderRadius, this.onlineIndicatorAlignment = Alignment.topRight, this.selected = false, - this.selectionColor = const Color(0xFF006CFF), + this.selectionColor, this.selectionThickness = 4, }) : super(key: key); @@ -70,7 +70,8 @@ class UserAvatar extends StatelessWidget { child: Container( constraints: constraints ?? streamChatTheme.ownMessageTheme.avatarTheme.constraints, - color: selectionColor, + color: selectionColor ?? + StreamChatTheme.of(context).colorTheme.accentBlue, child: Padding( padding: EdgeInsets.all(selectionThickness), child: avatar, diff --git a/lib/src/user_list_view.dart b/lib/src/user_list_view.dart index 1108c24d..35692841 100644 --- a/lib/src/user_list_view.dart +++ b/lib/src/user_list_view.dart @@ -453,7 +453,10 @@ class _UserListViewState extends State builder: (context, snapshot) { if (snapshot.hasError) { return Container( - color: Color(0xffd0021B).withAlpha(26), + color: StreamChatTheme.of(context) + .colorTheme + .accentRed + .withOpacity(.2), child: Padding( padding: const EdgeInsets.symmetric(vertical: 16.0), child: Center( diff --git a/lib/src/utils.dart b/lib/src/utils.dart index f1f1b68a..32681d6e 100644 --- a/lib/src/utils.dart +++ b/lib/src/utils.dart @@ -55,7 +55,8 @@ Future showConfirmationDialog( height: 36.0, ), Container( - color: Color(0xffe6e6e6), + color: + StreamChatTheme.of(context).colorTheme.black.withOpacity(.08), height: 1.0, ), Row( From cf31f704d41d02381a9387b42240535712324ac8 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Thu, 31 Dec 2020 10:53:56 +0100 Subject: [PATCH 0701/1140] hide bubbles --- lib/src/message_actions_modal.dart | 5 ++++- lib/src/message_reactions_modal.dart | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/lib/src/message_actions_modal.dart b/lib/src/message_actions_modal.dart index 2d482c0e..2cd66807 100644 --- a/lib/src/message_actions_modal.dart +++ b/lib/src/message_actions_modal.dart @@ -119,7 +119,10 @@ class MessageActionsModal extends StatelessWidget { showUserAvatar: showUserAvatar, showTimestamp: false, translateUserAvatar: false, - showReactionPickerIndicator: true, + showReactionPickerIndicator: showReactions && + (message.status == + MessageSendingStatus.SENT || + message.status == null), showInChannelIndicator: false, showSendingIndicator: DisplayWidget.gone, shape: messageShape, diff --git a/lib/src/message_reactions_modal.dart b/lib/src/message_reactions_modal.dart index e5043e62..ed3038fd 100644 --- a/lib/src/message_reactions_modal.dart +++ b/lib/src/message_reactions_modal.dart @@ -110,7 +110,10 @@ class MessageReactionsModal extends StatelessWidget { translateUserAvatar: false, showSendingIndicator: DisplayWidget.gone, shape: messageShape, - showReactionPickerIndicator: true, + showReactionPickerIndicator: showReactions && + (message.status == + MessageSendingStatus.SENT || + message.status == null), ), ), ); From dde32437c82d1339c5b1a085ec62fd0200aafbb9 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Thu, 31 Dec 2020 11:10:03 +0100 Subject: [PATCH 0702/1140] fix messageinput send --- lib/src/message_actions_modal.dart | 3 ++- lib/src/message_input.dart | 4 ---- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/lib/src/message_actions_modal.dart b/lib/src/message_actions_modal.dart index 2cd66807..d2d25333 100644 --- a/lib/src/message_actions_modal.dart +++ b/lib/src/message_actions_modal.dart @@ -332,9 +332,10 @@ class MessageActionsModal extends StatelessWidget { ? editMessageInputBuilder(context, message) : MessageInput( editMessage: message, - onMessageSent: (_) { + preMessageSending: (m) { FocusScope.of(context).unfocus(); Navigator.pop(context); + return m; }, ), ), diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 8436d526..654aa068 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -1976,10 +1976,6 @@ class MessageInputState extends State { return sendingFuture.then((resp) { if (widget.onMessageSent != null) { widget.onMessageSent(resp.message); - } else { - if (widget.editMessage != null) { - Navigator.pop(context); - } } }); } From ab6a741183dfb6f14600019219f7b568a45f5cb1 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Thu, 31 Dec 2020 15:59:51 +0530 Subject: [PATCH 0703/1140] [Message Widget] fix error icon stack position Signed-off-by: Sahil Kumar --- lib/src/message_widget.dart | 47 +++++++++++++++++-------------------- 1 file changed, 22 insertions(+), 25 deletions(-) diff --git a/lib/src/message_widget.dart b/lib/src/message_widget.dart index 226e98c0..9834e097 100644 --- a/lib/src/message_widget.dart +++ b/lib/src/message_widget.dart @@ -243,6 +243,12 @@ class _MessageWidgetState extends State { bool get isFailedState => isSendFailed || isUpdateFailed || isDeleteFailed; + bool get showBottomRow => + showThreadReplyIndicator || + showUsername || + showTimeStamp || + showInChannel; + @override Widget build(BuildContext context) { var leftPadding = widget.showUserAvatar != DisplayWidget.gone @@ -267,6 +273,7 @@ class _MessageWidgetState extends State { mainAxisSize: MainAxisSize.min, children: [ Stack( + clipBehavior: Clip.none, alignment: AlignmentDirectional.bottomStart, children: [ Column( @@ -389,39 +396,29 @@ class _MessageWidgetState extends State { ), ), ), - if (isFailedState) - Positioned( - left: widget.reverse ? -6 : null, - right: widget.reverse ? null : -6, - bottom: 0, - child: Container( - decoration: BoxDecoration( - color: Colors.white, - shape: BoxShape.circle, - ), - child: StreamSvgIcon.error( - size: 20, - ), - ), - ), ], ), ), ), ], ), - if (showThreadReplyIndicator || - showUsername || - showTimeStamp || - showInChannel) - SizedBox(height: 20.0), + if (showBottomRow) SizedBox(height: 20.0), ], ), - if (showThreadReplyIndicator || - showUsername || - showTimeStamp || - showInChannel) - _buildBottomRow(leftPadding) + if (showBottomRow) _buildBottomRow(leftPadding), + if (isFailedState) + Positioned( + left: widget.reverse ? -3 : null, + right: widget.reverse ? null : -9, + bottom: showBottomRow ? 20 : 0, + child: Container( + decoration: BoxDecoration( + color: Colors.white, + shape: BoxShape.circle, + ), + child: StreamSvgIcon.error(size: 20), + ), + ), ], ), ], From f59db043c1c05c80b2ea6de493104d0c37e4150a Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Thu, 31 Dec 2020 16:15:16 +0530 Subject: [PATCH 0704/1140] minor ui fixes Signed-off-by: Sahil Kumar --- lib/src/message_actions_modal.dart | 4 +--- lib/src/message_reactions_modal.dart | 5 ++--- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/lib/src/message_actions_modal.dart b/lib/src/message_actions_modal.dart index d2d25333..fad73d93 100644 --- a/lib/src/message_actions_modal.dart +++ b/lib/src/message_actions_modal.dart @@ -130,9 +130,7 @@ class MessageActionsModal extends StatelessWidget { ), ); }), - SizedBox( - height: 8, - ), + SizedBox(height: 8), TweenAnimationBuilder( tween: Tween(begin: 0.0, end: 1.0), duration: Duration(milliseconds: 300), diff --git a/lib/src/message_reactions_modal.dart b/lib/src/message_reactions_modal.dart index ed3038fd..a8701f4d 100644 --- a/lib/src/message_reactions_modal.dart +++ b/lib/src/message_reactions_modal.dart @@ -110,6 +110,7 @@ class MessageReactionsModal extends StatelessWidget { translateUserAvatar: false, showSendingIndicator: DisplayWidget.gone, shape: messageShape, + showInChannelIndicator: false, showReactionPickerIndicator: showReactions && (message.status == MessageSendingStatus.SENT || @@ -118,9 +119,7 @@ class MessageReactionsModal extends StatelessWidget { ), ); }), - SizedBox( - height: 16, - ), + SizedBox(height: 8), if (message.latestReactions?.isNotEmpty == true) _buildReactionCard(context), ], From ca6bd62084fd5861089e9ff5db90abad099ba0d4 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Thu, 31 Dec 2020 16:32:45 +0530 Subject: [PATCH 0705/1140] fix: Added confirmation dialogs and fixed alignment --- example/lib/main.dart | 26 --- lib/src/channel_actions_modal.dart | 197 ---------------- lib/src/channel_bottom_sheet.dart | 360 +++++++++++++++-------------- lib/src/channel_list_view.dart | 22 +- lib/stream_chat_flutter.dart | 2 +- 5 files changed, 210 insertions(+), 397 deletions(-) delete mode 100644 lib/src/channel_actions_modal.dart diff --git a/example/lib/main.dart b/example/lib/main.dart index c283793a..803df8e6 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -373,9 +373,6 @@ class _ChannelListPageState extends State { limit: 20, ), channelWidget: ChannelPage(), - onChannelLongPress: (channel) { - _showChannelDetailsModal(channel); - }, ), ), ), @@ -386,29 +383,6 @@ class _ChannelListPageState extends State { ), ); } - - void _showChannelDetailsModal(Channel channel) { - showModalBottomSheet( - context: context, - builder: (context) { - return StreamChannel( - child: ChannelActionsModal( - onViewInfoTap: () { - // TODO: Go to group info screen when PR is merged - }, - ), - channel: channel); - }, - isScrollControlled: true, - clipBehavior: Clip.antiAlias, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.only( - topLeft: Radius.circular(16.0), - topRight: Radius.circular(16.0), - ), - ), - ); - } } class ChannelPageArgs { diff --git a/lib/src/channel_actions_modal.dart b/lib/src/channel_actions_modal.dart deleted file mode 100644 index 424f5e38..00000000 --- a/lib/src/channel_actions_modal.dart +++ /dev/null @@ -1,197 +0,0 @@ -import 'package:flutter/material.dart'; - -import '../stream_chat_flutter.dart'; -import 'channel_info.dart'; -import 'option_list_tile.dart'; - -class ChannelActionsModal extends StatefulWidget { - VoidCallback onViewInfoTap; - - ChannelActionsModal({this.onViewInfoTap}); - - @override - _ChannelActionsModalState createState() => _ChannelActionsModalState(); -} - -class _ChannelActionsModalState extends State { - @override - Widget build(BuildContext context) { - var channel = StreamChannel.of(context).channel; - - return Material( - clipBehavior: Clip.antiAlias, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.only( - topLeft: Radius.circular(16.0), - topRight: Radius.circular(16.0), - ), - ), - child: FutureBuilder( - future: StreamChannel.of(context).channel.queryMembers( - filter: {}, - ), - builder: (context, snapshot) { - if (!snapshot.hasData) { - return Container( - height: 100.0, - alignment: Alignment.center, - child: Padding( - padding: const EdgeInsets.all(16.0), - child: CircularProgressIndicator(), - ), - ); - } - - var userAsMember = snapshot.data.members - .firstWhere((e) => e.user.id == StreamChat.of(context).user.id); - var isOwner = userAsMember.role == 'owner'; - - return Column( - mainAxisSize: MainAxisSize.min, - children: [ - SizedBox( - height: 24.0, - ), - Padding( - padding: const EdgeInsets.symmetric(horizontal: 16.0), - child: ChannelName( - textStyle: TextStyle( - fontSize: 16.0, - color: Color(0xff000000), - fontWeight: FontWeight.bold, - ), - ), - ), - SizedBox( - height: 5.0, - ), - ChannelInfo( - showTypingIndicator: false, - channel: StreamChannel.of(context).channel, - textStyle: - StreamChatTheme.of(context).channelPreviewTheme.subtitle, - ), - SizedBox( - height: 17.0, - ), - if (channel.isDistinct && channel.memberCount == 2) - Column( - children: [ - UserAvatar( - user: snapshot.data.members - .firstWhere((e) => e.user.id != userAsMember.user.id) - .user, - constraints: BoxConstraints( - maxHeight: 64.0, - maxWidth: 64.0, - ), - borderRadius: BorderRadius.circular(32.0), - ), - SizedBox( - height: 6.0, - ), - Text( - snapshot.data.members - .firstWhere((e) => e.user.id != userAsMember.user.id) - .user - .name, - style: TextStyle( - fontSize: 12.0, - fontWeight: FontWeight.w600, - ), - maxLines: 1, - overflow: TextOverflow.ellipsis, - ), - ], - ), - if (!(channel.isDistinct && channel.memberCount == 2)) - Container( - height: 94.0, - child: ListView.builder( - scrollDirection: Axis.horizontal, - itemCount: snapshot.data.members.length, - itemBuilder: (context, index) { - return Padding( - padding: const EdgeInsets.symmetric(horizontal: 8.0), - child: Column( - children: [ - UserAvatar( - user: snapshot.data.members[index].user, - constraints: BoxConstraints( - maxHeight: 64.0, - maxWidth: 64.0, - ), - borderRadius: BorderRadius.circular(32.0), - ), - SizedBox( - height: 6.0, - ), - Text( - snapshot.data.members[index].user.name, - style: TextStyle( - fontSize: 12.0, - fontWeight: FontWeight.w600, - ), - maxLines: 1, - overflow: TextOverflow.ellipsis, - ), - ], - ), - ); - }, - ), - ), - SizedBox( - height: 24, - ), - OptionListTile( - leading: StreamSvgIcon.user( - color: Color(0xff7a7a7a), - ), - title: 'View Info', - onTap: widget.onViewInfoTap, - ), - if (!channel.isDistinct) - OptionListTile( - leading: StreamSvgIcon.userRemove( - color: Color(0xff7a7a7a), - ), - title: 'Leave Group', - onTap: () async { - var channel = StreamChannel.of(context).channel; - - await channel - .removeMembers([StreamChat.of(context).user.id]); - Navigator.pop(context); - }, - ), - if (isOwner) - OptionListTile( - leading: StreamSvgIcon.delete( - color: Colors.red, - ), - title: 'Delete Conversation', - titleColor: Colors.red, - onTap: () async { - var channel = StreamChannel.of(context).channel; - - await channel.delete(); - Navigator.pop(context); - }, - ), - OptionListTile( - leading: StreamSvgIcon.close_small( - color: Color(0xff7a7a7a), - ), - title: 'Cancel', - onTap: () { - Navigator.pop(context); - }, - ), - ], - ); - }, - ), - ); - } -} diff --git a/lib/src/channel_bottom_sheet.dart b/lib/src/channel_bottom_sheet.dart index 2d16bf6d..695f34c6 100644 --- a/lib/src/channel_bottom_sheet.dart +++ b/lib/src/channel_bottom_sheet.dart @@ -1,193 +1,209 @@ import 'package:flutter/material.dart'; -import 'package:stream_chat/stream_chat.dart'; -import 'package:stream_chat_flutter/src/stream_svg_icon.dart'; -import 'package:stream_chat_flutter/src/utils.dart'; -import 'package:stream_chat_flutter/stream_chat_flutter.dart'; +import '../stream_chat_flutter.dart'; import 'channel_info.dart'; -import 'channel_name.dart'; -import 'stream_chat.dart'; -import 'stream_chat_theme.dart'; -import 'user_avatar.dart'; +import 'option_list_tile.dart'; -class ChannelBottomSheet extends StatelessWidget { - const ChannelBottomSheet({ - Key key, - }) : super(key: key); +class ChannelBottomSheet extends StatefulWidget { + VoidCallback onViewInfoTap; + + ChannelBottomSheet({this.onViewInfoTap}); + @override + _ChannelBottomSheetState createState() => _ChannelBottomSheetState(); +} + +class _ChannelBottomSheetState extends State { @override Widget build(BuildContext context) { - final channel = StreamChannel.of(context).channel; - return SafeArea( - child: Padding( - padding: const EdgeInsets.all(8.0), - child: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - Padding( - padding: const EdgeInsets.symmetric( - vertical: 2.0, - ), - child: Center( - child: StreamChannel( - showLoading: false, - channel: channel, - child: ChannelName( - textStyle: - StreamChatTheme.of(context).channelPreviewTheme.title, - ), - ), - ), - ), - Padding( - padding: const EdgeInsets.symmetric( - vertical: 2.0, - ), - child: Center( - child: ChannelInfo( - channel: channel, - textStyle: - StreamChatTheme.of(context).channelPreviewTheme.subtitle, - ), - ), - ), - Padding( - padding: const EdgeInsets.symmetric( - vertical: 15.0, - ), - child: Center( - child: StreamBuilder>( - stream: channel.state.membersStream.map((event) => event - .where((m) => m.userId != StreamChat.of(context).user.id) - .toList()), - initialData: channel.state.members - .where((m) => m.userId != StreamChat.of(context).user.id) - .toList(), - builder: _buildMembers, - ), - ), - ), - Divider(), - if (channel.isGroup && !channel.isDistinct) - ListTile( - leading: StreamSvgIcon.userRemove( - size: 24, - color: Color(0xff7A7A7A), - ), - title: Text( - 'Leave Group', - style: TextStyle(fontWeight: FontWeight.bold), - ), - onTap: () async { - final confirm = await showConfirmationDialog( - context, - title: 'Leave Group', - okText: 'LEAVE', - question: 'Are you sure you want to leave this group?', - cancelText: 'CANCEL', - icon: StreamSvgIcon.userRemove( - color: Colors.red, - ), - ); - if (confirm == true) { - await channel - .removeMembers([StreamChat.of(context).user.id]); - Navigator.pop(context); - } - }, - ), - if ([ - 'admin', - 'owner', - ].contains(channel.state.members - .firstWhere((m) => m.userId == channel.client.state.user.id, - orElse: () => null) - ?.role)) - ListTile( - leading: StreamSvgIcon.delete( - color: Color(0xFFFF3742), - size: 24, - ), - title: Text( - 'Delete chat', - style: TextStyle( - color: Color(0xFFFF3742), - ), - ), - onTap: () async { - final res = await showConfirmationDialog( - context, - title: 'Delete Conversation', - okText: 'DELETE', - question: - 'Are you sure you want to delete this conversation?', - cancelText: 'CANCEL', - icon: StreamSvgIcon.delete( - color: Colors.red, - ), - ); - var channel = StreamChannel.of(context).channel; - if (res == true) { - await channel.delete().then((value) { - Navigator.pop(context); - }); - } - }, - ), - ], + var channel = StreamChannel.of(context).channel; + + var members = channel.state.members; + + var userAsMember = + members.firstWhere((e) => e.user.id == StreamChat.of(context).user.id); + var isOwner = userAsMember.role == 'owner'; + + return Material( + clipBehavior: Clip.antiAlias, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.only( + topLeft: Radius.circular(16.0), + topRight: Radius.circular(16.0), ), ), - ); - } - - Widget _buildMembers( - BuildContext context, - AsyncSnapshot> snapshot, - ) { - if (snapshot.data.isEmpty) { - return SizedBox(); - } - - return Container( - height: 83, - child: ListView( - padding: EdgeInsets.only( - left: (MediaQuery.of(context).size.width / 2) - 48, - ), - scrollDirection: Axis.horizontal, - children: snapshot.data.map((m) { - return Padding( - padding: const EdgeInsets.symmetric( - horizontal: 8.0, + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + SizedBox( + height: 24.0, + ), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 16.0), + child: ChannelName( + textStyle: TextStyle( + fontSize: 16.0, + color: Color(0xff000000), + fontWeight: FontWeight.bold, + ), ), - child: Column( - children: [ + ), + SizedBox( + height: 5.0, + ), + ChannelInfo( + showTypingIndicator: false, + channel: StreamChannel.of(context).channel, + textStyle: StreamChatTheme.of(context).channelPreviewTheme.subtitle, + ), + SizedBox( + height: 17.0, + ), + if (channel.isDistinct && channel.memberCount == 2) + Column( + children: [ UserAvatar( - showOnlineStatus: true, - user: m.user, - borderRadius: BorderRadius.circular(32), - constraints: BoxConstraints.tight( - Size.square(64), + user: members + .firstWhere((e) => e.user.id != userAsMember.user.id) + .user, + constraints: BoxConstraints( + maxHeight: 64.0, + maxWidth: 64.0, ), + borderRadius: BorderRadius.circular(32.0), ), - Padding( - padding: const EdgeInsets.only(top: 5.0), - child: Text( - m.user.name?.split(' ')?.elementAt(0), - style: StreamChatTheme.of(context) - .channelPreviewTheme - .title - .copyWith( - fontSize: 12, - ), + SizedBox( + height: 6.0, + ), + Text( + members + .firstWhere((e) => e.user.id != userAsMember.user.id) + .user + .name, + style: TextStyle( + fontSize: 12.0, + fontWeight: FontWeight.w600, ), + maxLines: 1, + overflow: TextOverflow.ellipsis, ), ], ), - ); - }).toList(), + if (!(channel.isDistinct && channel.memberCount == 2)) + Container( + height: 94.0, + child: ListView.builder( + scrollDirection: Axis.horizontal, + itemCount: members.length, + itemBuilder: (context, index) { + return Padding( + padding: const EdgeInsets.symmetric(horizontal: 8.0), + child: Column( + children: [ + UserAvatar( + user: members[index].user, + constraints: BoxConstraints( + maxHeight: 64.0, + maxWidth: 64.0, + ), + borderRadius: BorderRadius.circular(32.0), + ), + SizedBox( + height: 6.0, + ), + Text( + members[index].user.name, + style: TextStyle( + fontSize: 12.0, + fontWeight: FontWeight.w600, + ), + maxLines: 1, + overflow: TextOverflow.ellipsis, + ), + ], + ), + ); + }, + ), + ), + SizedBox( + height: 17.0, + ), + OptionListTile( + leading: StreamSvgIcon.user( + color: Color(0xff7a7a7a), + ), + title: 'View Info', + onTap: widget.onViewInfoTap, + ), + if (!channel.isDistinct) + OptionListTile( + leading: StreamSvgIcon.userRemove( + color: Color(0xff7a7a7a), + ), + title: 'Leave Group', + onTap: () async { + _showLeaveDialog(); + }, + ), + if (isOwner) + OptionListTile( + leading: StreamSvgIcon.delete( + color: Colors.red, + ), + title: 'Delete Conversation', + titleColor: Colors.red, + onTap: () async { + _showDeleteDialog(); + }, + ), + OptionListTile( + leading: StreamSvgIcon.close_small( + color: Color(0xff7a7a7a), + ), + title: 'Cancel', + onTap: () { + Navigator.pop(context); + }, + ), + ], ), ); } + + void _showDeleteDialog() async { + final res = await showConfirmationDialog( + context, + title: 'Delete Conversation', + okText: 'DELETE', + question: 'Are you sure you want to delete this conversation?', + cancelText: 'CANCEL', + icon: StreamSvgIcon.delete( + color: Colors.red, + ), + ); + var channel = StreamChannel.of(context).channel; + if (res == true) { + await channel.delete(); + Navigator.pop(context); + } + } + + void _showLeaveDialog() async { + final res = await showConfirmationDialog( + context, + title: 'Leave conversation', + okText: 'LEAVE', + question: 'Are you sure you want to leave this conversation?', + cancelText: 'CANCEL', + icon: StreamSvgIcon.userRemove( + color: Colors.red, + ), + ); + var channel = StreamChannel.of(context).channel; + if (res == true) { + await channel.removeMembers([StreamChat.of(context).user.id]); + Navigator.pop(context); + } + } } diff --git a/lib/src/channel_list_view.dart b/lib/src/channel_list_view.dart index 5efa1e29..b42377cf 100644 --- a/lib/src/channel_list_view.dart +++ b/lib/src/channel_list_view.dart @@ -560,7 +560,27 @@ class _ChannelListViewState extends State context: context, builder: (context) { return StreamChannel( - child: ChannelBottomSheet(), + child: ChannelBottomSheet( + onViewInfoTap: () { + if (channel.memberCount == 2 && + channel.isDistinct) { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => StreamChannel( + channel: channel, + child: ChatInfoScreen( + user: + channel.state.members.first.user, + ), + ), + ), + ); + } + + // TODO: Add group screen + }, + ), channel: channel, ); }, diff --git a/lib/stream_chat_flutter.dart b/lib/stream_chat_flutter.dart index e4d4752a..d2dfc692 100644 --- a/lib/stream_chat_flutter.dart +++ b/lib/stream_chat_flutter.dart @@ -43,4 +43,4 @@ export 'src/message_search_bloc.dart'; export 'src/message_search_item.dart'; export 'src/message_search_list_view.dart'; export 'src/unread_indicator.dart'; -export 'src/channel_actions_modal.dart'; +export 'src/chat_info_screen.dart'; From 88ba902ee381aedab092fb7526b1e692398d97b7 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Thu, 31 Dec 2020 16:38:20 +0530 Subject: [PATCH 0706/1140] merge fixes Signed-off-by: Sahil Kumar --- lib/src/message_actions_modal.dart | 2 +- lib/src/message_widget.dart | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/src/message_actions_modal.dart b/lib/src/message_actions_modal.dart index c5903ce3..adfe3cdd 100644 --- a/lib/src/message_actions_modal.dart +++ b/lib/src/message_actions_modal.dart @@ -251,7 +251,7 @@ class MessageActionsModal extends StatelessWidget { style: Theme.of(context).textTheme.headline6, ), leading: StreamSvgIcon.circle_up( - color: StreamChatTheme.of(context).accentColor, + color: StreamChatTheme.of(context).colorTheme.accentBlue, ), onTap: () { Navigator.pop(context); diff --git a/lib/src/message_widget.dart b/lib/src/message_widget.dart index afb3261d..61c6bf5c 100644 --- a/lib/src/message_widget.dart +++ b/lib/src/message_widget.dart @@ -816,7 +816,7 @@ class _MessageWidgetState extends State { Text( widget.readList.length.toString(), style: style.copyWith( - color: StreamChatTheme.of(context).accentColor, + color: StreamChatTheme.of(context).colorTheme.accentBlue, ), ), SizedBox(width: 2), From da3f9e7daeb225dcf80d8cdde38988d6de8bdea5 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Thu, 31 Dec 2020 12:11:57 +0100 Subject: [PATCH 0707/1140] apply theme to edit message --- example/lib/main.dart | 2 +- lib/src/message_actions_modal.dart | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/example/lib/main.dart b/example/lib/main.dart index 8d436614..018b2cab 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -59,7 +59,7 @@ class MyApp extends StatelessWidget { debugShowCheckedModeBanner: false, theme: ThemeData.light(), darkTheme: ThemeData.dark(), - themeMode: ThemeMode.system, + themeMode: ThemeMode.dark, onGenerateRoute: AppRoutes.generateRoute, initialRoute: client.state.user == null ? Routes.CHOOSE_USER : Routes.HOME, diff --git a/lib/src/message_actions_modal.dart b/lib/src/message_actions_modal.dart index adfe3cdd..3bdce507 100644 --- a/lib/src/message_actions_modal.dart +++ b/lib/src/message_actions_modal.dart @@ -273,6 +273,7 @@ class MessageActionsModal extends StatelessWidget { elevation: 2, clipBehavior: Clip.hardEdge, isScrollControlled: true, + backgroundColor: StreamChatTheme.of(context).colorTheme.white, shape: RoundedRectangleBorder( borderRadius: BorderRadius.only( topLeft: Radius.circular(32), From bb9052c331ba39c2522900ba23297bcfaa697b79 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Thu, 31 Dec 2020 17:37:20 +0530 Subject: [PATCH 0708/1140] fix: fixed alignment and font weight --- lib/src/channel_bottom_sheet.dart | 4 +++- lib/src/option_list_tile.dart | 15 +++++++++------ 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/lib/src/channel_bottom_sheet.dart b/lib/src/channel_bottom_sheet.dart index 695f34c6..2d7b726c 100644 --- a/lib/src/channel_bottom_sheet.dart +++ b/lib/src/channel_bottom_sheet.dart @@ -92,9 +92,11 @@ class _ChannelBottomSheetState extends State { if (!(channel.isDistinct && channel.memberCount == 2)) Container( height: 94.0, + alignment: Alignment.center, child: ListView.builder( scrollDirection: Axis.horizontal, itemCount: members.length, + shrinkWrap: true, itemBuilder: (context, index) { return Padding( padding: const EdgeInsets.symmetric(horizontal: 8.0), @@ -127,7 +129,7 @@ class _ChannelBottomSheetState extends State { ), ), SizedBox( - height: 17.0, + height: 24.0, ), OptionListTile( leading: StreamSvgIcon.user( diff --git a/lib/src/option_list_tile.dart b/lib/src/option_list_tile.dart index c1f48b71..040b1a00 100644 --- a/lib/src/option_list_tile.dart +++ b/lib/src/option_list_tile.dart @@ -41,12 +41,15 @@ class OptionListTile extends StatelessWidget { width: 16.0, ), Expanded( - flex: 4, - child: Text( - title, - style: TextStyle( - fontWeight: FontWeight.w600, color: titleColor), - )), + flex: 4, + child: Text( + title, + style: TextStyle( + fontWeight: FontWeight.bold, + color: titleColor, + ), + ), + ), Expanded( flex: 2, child: Padding( From 607a51daad46143d794136ae88257865f312abaa Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Thu, 31 Dec 2020 18:01:55 +0530 Subject: [PATCH 0709/1140] feat: added themes --- lib/src/channel_bottom_sheet.dart | 33 ++++++++++++------------------- lib/src/option_list_tile.dart | 21 ++++++++++++-------- 2 files changed, 26 insertions(+), 28 deletions(-) diff --git a/lib/src/channel_bottom_sheet.dart b/lib/src/channel_bottom_sheet.dart index 2d7b726c..130738d8 100644 --- a/lib/src/channel_bottom_sheet.dart +++ b/lib/src/channel_bottom_sheet.dart @@ -25,6 +25,7 @@ class _ChannelBottomSheetState extends State { var isOwner = userAsMember.role == 'owner'; return Material( + color: StreamChatTheme.of(context).colorTheme.white, clipBehavior: Clip.antiAlias, shape: RoundedRectangleBorder( borderRadius: BorderRadius.only( @@ -41,11 +42,7 @@ class _ChannelBottomSheetState extends State { Padding( padding: const EdgeInsets.symmetric(horizontal: 16.0), child: ChannelName( - textStyle: TextStyle( - fontSize: 16.0, - color: Color(0xff000000), - fontWeight: FontWeight.bold, - ), + textStyle: StreamChatTheme.of(context).textTheme.headlineBold, ), ), SizedBox( @@ -80,10 +77,7 @@ class _ChannelBottomSheetState extends State { .firstWhere((e) => e.user.id != userAsMember.user.id) .user .name, - style: TextStyle( - fontSize: 12.0, - fontWeight: FontWeight.w600, - ), + style: StreamChatTheme.of(context).textTheme.footnoteBold, maxLines: 1, overflow: TextOverflow.ellipsis, ), @@ -115,10 +109,9 @@ class _ChannelBottomSheetState extends State { ), Text( members[index].user.name, - style: TextStyle( - fontSize: 12.0, - fontWeight: FontWeight.w600, - ), + style: StreamChatTheme.of(context) + .textTheme + .footnoteBold, maxLines: 1, overflow: TextOverflow.ellipsis, ), @@ -133,7 +126,7 @@ class _ChannelBottomSheetState extends State { ), OptionListTile( leading: StreamSvgIcon.user( - color: Color(0xff7a7a7a), + color: StreamChatTheme.of(context).colorTheme.grey, ), title: 'View Info', onTap: widget.onViewInfoTap, @@ -141,7 +134,7 @@ class _ChannelBottomSheetState extends State { if (!channel.isDistinct) OptionListTile( leading: StreamSvgIcon.userRemove( - color: Color(0xff7a7a7a), + color: StreamChatTheme.of(context).colorTheme.grey, ), title: 'Leave Group', onTap: () async { @@ -151,17 +144,17 @@ class _ChannelBottomSheetState extends State { if (isOwner) OptionListTile( leading: StreamSvgIcon.delete( - color: Colors.red, + color: StreamChatTheme.of(context).colorTheme.accentRed, ), title: 'Delete Conversation', - titleColor: Colors.red, + titleColor: StreamChatTheme.of(context).colorTheme.accentRed, onTap: () async { _showDeleteDialog(); }, ), OptionListTile( leading: StreamSvgIcon.close_small( - color: Color(0xff7a7a7a), + color: StreamChatTheme.of(context).colorTheme.grey, ), title: 'Cancel', onTap: () { @@ -181,7 +174,7 @@ class _ChannelBottomSheetState extends State { question: 'Are you sure you want to delete this conversation?', cancelText: 'CANCEL', icon: StreamSvgIcon.delete( - color: Colors.red, + color: StreamChatTheme.of(context).colorTheme.accentRed, ), ); var channel = StreamChannel.of(context).channel; @@ -199,7 +192,7 @@ class _ChannelBottomSheetState extends State { question: 'Are you sure you want to leave this conversation?', cancelText: 'CANCEL', icon: StreamSvgIcon.userRemove( - color: Colors.red, + color: StreamChatTheme.of(context).colorTheme.accentRed, ), ); var channel = StreamChannel.of(context).channel; diff --git a/lib/src/option_list_tile.dart b/lib/src/option_list_tile.dart index 040b1a00..d551d33e 100644 --- a/lib/src/option_list_tile.dart +++ b/lib/src/option_list_tile.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:stream_chat_flutter/src/stream_chat_theme.dart'; import 'package:stream_chat_flutter/src/stream_svg_icon.dart'; class OptionListTile extends StatelessWidget { @@ -21,13 +22,13 @@ class OptionListTile extends StatelessWidget { return Column( children: [ Container( - color: Color(0xffe6e6e6), - height: 2.0, + color: StreamChatTheme.of(context).colorTheme.greyGainsboro, + height: 1.0, ), Material( - color: Colors.white, + color: StreamChatTheme.of(context).colorTheme.white, child: Container( - height: 56.0, + height: 63.0, child: InkWell( onTap: onTap, child: Row( @@ -44,10 +45,14 @@ class OptionListTile extends StatelessWidget { flex: 4, child: Text( title, - style: TextStyle( - fontWeight: FontWeight.bold, - color: titleColor, - ), + style: titleColor == null + ? StreamChatTheme.of(context).textTheme.bodyBold + : StreamChatTheme.of(context) + .textTheme + .bodyBold + .copyWith( + color: titleColor, + ), ), ), Expanded( From d03fda930192fca77343b018eecaf7201610a839 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Thu, 31 Dec 2020 18:23:46 +0530 Subject: [PATCH 0710/1140] Change themeMode to system --- 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 018b2cab..8d436614 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -59,7 +59,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 c1149bc80809aa8f27ec26fbd63fab3dbe96b8c0 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Thu, 31 Dec 2020 13:57:56 +0100 Subject: [PATCH 0711/1140] fix attachment text --- lib/src/image_group.dart | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/lib/src/image_group.dart b/lib/src/image_group.dart index 7bce22f9..e9b52f88 100644 --- a/lib/src/image_group.dart +++ b/lib/src/image_group.dart @@ -1,6 +1,4 @@ import 'package:cached_network_image/cached_network_image.dart'; -import 'package:carousel_slider/carousel_options.dart'; -import 'package:carousel_slider/carousel_slider.dart'; import 'package:flutter/material.dart'; import 'package:stream_chat/stream_chat.dart'; import 'package:stream_chat_flutter/src/full_screen_media.dart'; @@ -81,12 +79,10 @@ class ImageGroup extends StatelessWidget { color: Colors.black38, child: Center( child: Text( - '${images.length - 4} +', + '+ ${images.length - 4}', style: TextStyle( - color: StreamChatTheme.of(context) - .colorTheme - .white, - fontSize: 28, + color: Colors.white, + fontSize: 26, ), ), ), From 1a6d575e5aa8a1f2fd8508bdbb9bd74c22f4d892 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Thu, 31 Dec 2020 18:38:38 +0530 Subject: [PATCH 0712/1140] fix: fixes for review --- example/lib/group_info_screen.dart | 1 + lib/src/channel_file_display_screen.dart | 28 ++++-------------------- lib/src/option_list_tile.dart | 15 ++++++++----- 3 files changed, 14 insertions(+), 30 deletions(-) diff --git a/example/lib/group_info_screen.dart b/example/lib/group_info_screen.dart index 3c469b9f..31653db8 100644 --- a/example/lib/group_info_screen.dart +++ b/example/lib/group_info_screen.dart @@ -333,6 +333,7 @@ class _GroupInfoScreenState extends State { ), style: TextStyle( fontWeight: FontWeight.bold, + height: 0.82, ), ), ), diff --git a/lib/src/channel_file_display_screen.dart b/lib/src/channel_file_display_screen.dart index a6b1008e..0cd3d854 100644 --- a/lib/src/channel_file_display_screen.dart +++ b/lib/src/channel_file_display_screen.dart @@ -159,30 +159,10 @@ class _ChannelFileDisplayScreenState extends State { return Padding( padding: const EdgeInsets.all(1.0), - child: InkWell( - onTap: () { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => StreamChannel( - channel: channel, - child: FullScreenMedia( - mediaAttachments: [ - media.keys.toList()[position], - ], - message: media.values.toList()[position], - sentAt: media.values.toList()[position].createdAt, - userName: media.values.toList()[position].user.name, - ), - ), - ), - ); - }, - child: Padding( - padding: const EdgeInsets.all(8.0), - child: FileAttachment( - attachment: media.keys.toList()[position], - ), + child: Padding( + padding: const EdgeInsets.all(8.0), + child: FileAttachment( + attachment: media.keys.toList()[position], ), ), ); diff --git a/lib/src/option_list_tile.dart b/lib/src/option_list_tile.dart index c1f48b71..382db945 100644 --- a/lib/src/option_list_tile.dart +++ b/lib/src/option_list_tile.dart @@ -41,12 +41,15 @@ class OptionListTile extends StatelessWidget { width: 16.0, ), Expanded( - flex: 4, - child: Text( - title, - style: TextStyle( - fontWeight: FontWeight.w600, color: titleColor), - )), + flex: 4, + child: Text( + title, + style: TextStyle( + fontWeight: FontWeight.w600, + color: titleColor, + ), + ), + ), Expanded( flex: 2, child: Padding( From 328afc44d8d68ad201e80d899b4845679f99ae62 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Thu, 31 Dec 2020 18:53:33 +0530 Subject: [PATCH 0713/1140] merge fixes Signed-off-by: Sahil Kumar --- lib/src/message_input.dart | 5 +++-- lib/src/message_list_view.dart | 2 +- lib/src/reply_message_widget.dart | 14 +++++++------- lib/src/swipeable.dart | 6 +++++- 4 files changed, 16 insertions(+), 11 deletions(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index c9496a45..d014e390 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -231,7 +231,8 @@ class MessageInputState extends State { Padding( padding: const EdgeInsets.all(8.0), child: StreamSvgIcon.reply( - color: Colors.black.withOpacity(0.2), + color: + StreamChatTheme.of(context).colorTheme.greyGainsboro, ), ), Text( @@ -263,7 +264,7 @@ class MessageInputState extends State { ); if (widget.editMessage == null) { child = Material( - color: Colors.white, + color: StreamChatTheme.of(context).colorTheme.white, elevation: 8, child: child, ); diff --git a/lib/src/message_list_view.dart b/lib/src/message_list_view.dart index f5545e50..14a49255 100644 --- a/lib/src/message_list_view.dart +++ b/lib/src/message_list_view.dart @@ -825,7 +825,7 @@ class _MessageListViewState extends State { child = Swipeable( onSwipeEnd: () => widget.onMessageSwiped(message), backgroundIcon: StreamSvgIcon.reply( - color: StreamChatTheme.of(context).accentColor, + color: StreamChatTheme.of(context).colorTheme.accentBlue, ), child: child, ); diff --git a/lib/src/reply_message_widget.dart b/lib/src/reply_message_widget.dart index c335906b..1a4348f3 100644 --- a/lib/src/reply_message_widget.dart +++ b/lib/src/reply_message_widget.dart @@ -131,9 +131,11 @@ class ReplyToMessageWidget extends StatelessWidget { minHeight: 48.0, ), decoration: BoxDecoration( - color: _getBackgroundColor(), + color: _getBackgroundColor(context), border: showBorder - ? Border.all(color: Colors.black.withOpacity(0.08)) + ? Border.all( + color: StreamChatTheme.of(context).colorTheme.greyGainsboro, + ) : null, borderRadius: BorderRadius.only( topRight: Radius.circular(12), @@ -232,9 +234,7 @@ class ReplyToMessageWidget extends StatelessWidget { ShapeBorder _getDefaultShape(BuildContext context) { return RoundedRectangleBorder( side: BorderSide( - color: Theme.of(context).brightness == Brightness.dark - ? Colors.white.withAlpha(24) - : Colors.black.withAlpha(24), + color: StreamChatTheme.of(context).colorTheme.greyWhisper, ), borderRadius: BorderRadius.circular(8), ); @@ -308,9 +308,9 @@ class ReplyToMessageWidget extends StatelessWidget { }; } - Color _getBackgroundColor() { + Color _getBackgroundColor(BuildContext context) { if (_containsScrapeUrl) { - return Color(0xFFE9F2FF); + return StreamChatTheme.of(context).colorTheme.blueAlice; } return messageTheme.messageBackgroundColor; } diff --git a/lib/src/swipeable.dart b/lib/src/swipeable.dart index c2279e63..8280bf24 100644 --- a/lib/src/swipeable.dart +++ b/lib/src/swipeable.dart @@ -2,6 +2,8 @@ import 'dart:math' as math; import 'package:flutter/material.dart'; +import 'stream_chat_theme.dart'; + /// class Swipeable extends StatefulWidget { final Widget child; @@ -139,7 +141,9 @@ class _SwipeableState extends State with TickerProviderStateMixin { decoration: BoxDecoration( shape: BoxShape.circle, border: Border.all( - color: Colors.black.withOpacity(0.08), + color: StreamChatTheme.of(context) + .colorTheme + .greyGainsboro, ), ), child: widget.backgroundIcon, From eb16e15665ce6d15b3cd7f321f0f87be51bef63c Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Thu, 31 Dec 2020 18:58:56 +0530 Subject: [PATCH 0714/1140] flutter format Signed-off-by: Sahil Kumar --- lib/src/message_actions_modal.dart | 2 +- lib/src/message_widget.dart | 193 +++++++++++++++-------------- 2 files changed, 100 insertions(+), 95 deletions(-) diff --git a/lib/src/message_actions_modal.dart b/lib/src/message_actions_modal.dart index a57096db..050b5995 100644 --- a/lib/src/message_actions_modal.dart +++ b/lib/src/message_actions_modal.dart @@ -172,7 +172,7 @@ class MessageActionsModal extends StatelessWidget { _buildReplyButton(context), if (showThreadReply && (message.status == - MessageSendingStatus.SENT || + MessageSendingStatus.SENT || message.status == null) && message.parentId == null) _buildThreadReplyButton(context), diff --git a/lib/src/message_widget.dart b/lib/src/message_widget.dart index b4472261..a344068f 100644 --- a/lib/src/message_widget.dart +++ b/lib/src/message_widget.dart @@ -338,90 +338,94 @@ class _MessageWidgetState extends State { : 0, ) : EdgeInsets.zero, - child: (widget.message.isDeleted && - !isFailedState) - ? Transform( - alignment: Alignment.center, - transform: Matrix4.rotationY( - widget.reverse ? pi : 0), - child: DeletedMessage( - reverse: widget.reverse, - borderRadiusGeometry: - widget.borderRadiusGeometry, - borderSide: widget.borderSide, - shape: widget.shape, - messageTheme: - widget.messageTheme, - ), - ) - : GestureDetector( - onLongPress: () => - onLongPress(context), - child: Material( - clipBehavior: Clip.antiAlias, - shape: widget.shape ?? - RoundedRectangleBorder( - side: isOnlyEmoji - ? BorderSide.none - : widget.borderSide ?? - BorderSide( - color: Theme.of(context) - .brightness == - Brightness - .dark + child: + (widget.message.isDeleted && + !isFailedState) + ? Transform( + alignment: Alignment.center, + transform: Matrix4.rotationY( + widget.reverse ? pi : 0), + child: DeletedMessage( + reverse: widget.reverse, + borderRadiusGeometry: widget + .borderRadiusGeometry, + borderSide: + widget.borderSide, + shape: widget.shape, + messageTheme: + widget.messageTheme, + ), + ) + : GestureDetector( + onLongPress: () => + onLongPress(context), + child: Material( + clipBehavior: + Clip.antiAlias, + shape: widget.shape ?? + RoundedRectangleBorder( + side: isOnlyEmoji + ? BorderSide.none + : widget.borderSide ?? + BorderSide( + color: Theme.of(context).brightness == + Brightness + .dark + ? StreamChatTheme.of(context) + .colorTheme + .white + .withAlpha( + 24) + : StreamChatTheme.of(context) + .colorTheme + .black + .withAlpha(24), + ), + borderRadius: widget + .borderRadiusGeometry ?? + BorderRadius.zero, + ), + color: + _getBackgroundColor(), + child: Padding( + padding: EdgeInsets.all( + hasFiles ? 2.0 : 0.0), + child: Column( + crossAxisAlignment: + CrossAxisAlignment + .start, + mainAxisSize: + MainAxisSize.min, + children: [ + if (_hasReplyToMessage) + ReplyToMessageWidget( + message: widget + .message + .replyToMessage, + messageTheme: isMyMessage ? StreamChatTheme.of( context) - .colorTheme - .white - .withAlpha( - 24) + .otherMessageTheme : StreamChatTheme.of( context) - .colorTheme - .black - .withAlpha( - 24), + .ownMessageTheme, + reverse: widget + .reverse, ), - borderRadius: widget - .borderRadiusGeometry ?? - BorderRadius.zero, - ), - color: _getBackgroundColor(), - child: Padding( - padding: EdgeInsets.all( - hasFiles ? 2.0 : 0.0), - child: Column( - crossAxisAlignment: - CrossAxisAlignment.start, - mainAxisSize: - MainAxisSize.min, - children: [ - if (_hasReplyToMessage) - ReplyToMessageWidget( - message: widget - .message - .replyToMessage, - messageTheme: isMyMessage - ? StreamChatTheme.of( - context) - .otherMessageTheme - : StreamChatTheme.of( - context) - .ownMessageTheme, - reverse: widget - .reverse, + ..._parseAttachments( + context), + if (widget + .message.text + .trim() + .isNotEmpty && + !isGiphy) + _buildTextBubble( + context), + ], ), - ..._parseAttachments( - context), - if (widget.message.text - .trim() - .isNotEmpty && - !isGiphy) - _buildTextBubble(context), - ], + ), + ), ), - ), - ),), ), if (widget.showReactionPickerIndicator) Positioned( @@ -692,9 +696,10 @@ class _MessageWidgetState extends State { onReplyTap: widget.onReplyTap, onThreadReplyTap: widget.onThreadTap, showResendMessage: - widget.showResendMessage && (isSendFailed || isUpdateFailed), + widget.showResendMessage && (isSendFailed || isUpdateFailed), showCopyMessage: !isFailedState && - widget.message.text?.trim()?.isNotEmpty == true, showEditMessage: widget.showEditMessage && + widget.message.text?.trim()?.isNotEmpty == true, + showEditMessage: widget.showEditMessage && !isDeleteFailed && widget.message.attachments ?.any((element) => element.type == 'giphy') != @@ -704,7 +709,7 @@ class _MessageWidgetState extends State { !isFailedState && widget.onReplyTap != null, showThreadReply: - widget.showThreadReplyIndicator && widget.onThreadTap != null, + widget.showThreadReplyIndicator && widget.onThreadTap != null, ), ); }); @@ -807,22 +812,22 @@ class _MessageWidgetState extends State { final attachmentShape = widget.attachmentShape ?? widget.shape ?? _getDefaultShape(context); return Material( - color: _getBackgroundColor(), - clipBehavior: Clip.antiAlias, - shape: attachmentShape, - child: Padding( - padding: widget.attachmentPadding, - child: Material( - clipBehavior: Clip.hardEdge, - shape: attachmentShape, - type: MaterialType.transparency, - child: Transform( - transform: Matrix4.rotationY(widget.reverse ? pi : 0), - alignment: Alignment.center, - child: attachmentWidget, - ), + color: _getBackgroundColor(), + clipBehavior: Clip.antiAlias, + shape: attachmentShape, + child: Padding( + padding: widget.attachmentPadding, + child: Material( + clipBehavior: Clip.hardEdge, + shape: attachmentShape, + type: MaterialType.transparency, + child: Transform( + transform: Matrix4.rotationY(widget.reverse ? pi : 0), + alignment: Alignment.center, + child: attachmentWidget, ), ), + ), ); } From a35e8826897805ff78b0dd4cbb94a4560e6a5b64 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Thu, 31 Dec 2020 15:01:27 +0100 Subject: [PATCH 0715/1140] update app icon --- .../src/main/res/mipmap-hdpi/ic_launcher.png | Bin 2988 -> 5905 bytes .../src/main/res/mipmap-mdpi/ic_launcher.png | Bin 1840 -> 3283 bytes .../src/main/res/mipmap-xhdpi/ic_launcher.png | Bin 4096 -> 8478 bytes .../main/res/mipmap-xxhdpi/ic_launcher.png | Bin 6422 -> 15150 bytes .../main/res/mipmap-xxxhdpi/ic_launcher.png | Bin 8762 -> 21173 bytes example/assets/icon.png | Bin 40617 -> 15354 bytes example/ios/Runner.xcodeproj/project.pbxproj | 2 +- .../Icon-App-1024x1024@1x.png | Bin 52126 -> 331443 bytes .../AppIcon.appiconset/Icon-App-20x20@1x.png | Bin 572 -> 1055 bytes .../AppIcon.appiconset/Icon-App-20x20@2x.png | Bin 1472 -> 2712 bytes .../AppIcon.appiconset/Icon-App-20x20@3x.png | Bin 2358 -> 4674 bytes .../AppIcon.appiconset/Icon-App-29x29@1x.png | Bin 990 -> 1783 bytes .../AppIcon.appiconset/Icon-App-29x29@2x.png | Bin 2338 -> 4491 bytes .../AppIcon.appiconset/Icon-App-29x29@3x.png | Bin 3744 -> 7741 bytes .../AppIcon.appiconset/Icon-App-40x40@1x.png | Bin 1472 -> 2712 bytes .../AppIcon.appiconset/Icon-App-40x40@2x.png | Bin 3342 -> 6909 bytes .../AppIcon.appiconset/Icon-App-40x40@3x.png | Bin 5281 -> 11924 bytes .../AppIcon.appiconset/Icon-App-60x60@2x.png | Bin 5281 -> 11924 bytes .../AppIcon.appiconset/Icon-App-60x60@3x.png | Bin 8289 -> 19832 bytes .../AppIcon.appiconset/Icon-App-76x76@1x.png | Bin 3132 -> 6398 bytes .../AppIcon.appiconset/Icon-App-76x76@2x.png | Bin 6964 -> 16364 bytes .../Icon-App-83.5x83.5@2x.png | Bin 7597 -> 18363 bytes example/pubspec.yaml | 4 ++-- 23 files changed, 3 insertions(+), 3 deletions(-) diff --git a/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png index 8ec56ee792d137eb68a716c4a44e2e1ef96be32c..91797672c7ce9b88327a8f87325cb5895ca0c0d4 100644 GIT binary patch literal 5905 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 literal 2988 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 MrZy&3M(*+d0pjzbVgLXD diff --git a/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png index 2f7fdaa7e0c24641edac586d68e910dd7b916345..103da98b58d1b062818d94e10cae84e7c85d04cf 100644 GIT binary patch delta 3280 zcmV;>3@`Jr4$~QsBYzB;)0;IO#=SV)U+(Em@;kDMh!(%Nm*nQK^Emb-oD;B=OX(e zD(Uxo@AvL~_nvdV|2hBj-_GT5FYxpPXEcKK9_i=f6B5D7f`5mJUHgRca{oY^*vFG+ z#BzEY!&{A~a}HZ7PLx7UZmFueYYN<5wNj}dQTcj!_nZ{1 z@Q<3tx%L^NGdLKYVPGMATi#9tak5JMogncKfa~Z87CeFnvAk7%>8!Eji_goQzDcvH zuT?{>{(}V&dw)V67~tpo@SLU6!0EH}CXw945Y|SX&~C-MJuvj6Gx7|iAz^IqwB8c81c7n&N zv7u8Rn_8T;Xu9^onQTDQVYAx`;5B~sa~{1{r0J|OWtWld7>te!8Te56-jg@F$3|ED zl=x*wH+LvN!0`F6%X+WgptnNQwH$8`0~xSxL96%3b=HMNr?w=ucVD{#1Pq_|x^!?t zqRHANnty&*AkP+24gth!6`k7JrVwoi;EJAqo;^htw0gsXBwr6R;UF8lZbMI{ zIAKiE7rS6$j25+KdDlFEa8*1s^+lXX+Q7-YLj1(4zC+A3B<=!;854Fak|U^x80FO# za3UUl9#U-orxHs*sAAMH49Z9wQ?-kvw=9--5i|ZiknPjVwM9(Kis6 zO!F+3d?aKJ6W;j5f*E5aU_~63q?*Vq@Q4`Xgnw0k zHDJkh8#u0c5I`9?NT)WtgB)1E^A6Z~36wP$Q;)I6#*JWM7tsx@}fp$J+dOO}us6&eNu1ArOh6v!{LV){B0th|i0 zwA2j4V>^s?9W}1I3}zlt@miGEwr?(P7!;WH zfe!musNkYt@XaqZ$T%lLB~cHX)q-lZ5yOI5M25*RG(<`IuWPqvw+6Y_<*m|g%AKn( zeKZBVG35x0h=B%-9jL&!Cx2^j=r^7$L}$D=U52ku=&}2l1v;G>5rgaGe{EA0u2ed= zOTHdOH)NQ-z8brid0>2)3P}g5!HIcH8zaKwVcl^$*Mi;0&DeXq3iF3CX8AiO9t|7um!Lrm!N$|r3qo86f7ko3GwCF_Z zHf>$hTcnu3Rf}Cqx?$t1DvVoFgBqh8drttnj+x22Fe54)cx9p+!u!)vv*7zPb`bN> zYPzXT^L7&=2aE7rxPJtLdUeOv16u63Z|O~7!vWxfeYF_dkH@p4 zq==j8jDx4BirHbeS>RwD2=ZbPMO0+cNEMDSnVB?VfWzUyOJhgj(S8!Vw6+#ynnoi*OO>2eos$ih(Glpt74uA; zDrLmE;hiW~9Lv6mOXV%hDIGE1j7LK`Vnrlyca8d&?XONZo>lasMv!GebCy-9pEcLIyVgOn~0yD>MDyHR%HNWegr z7iyKa!GE6ri7;-E0TYHPNZ7#Pe6gK)Ung4U#LoYkk?^*fsECAgPC^bbol>hXuaa9T zc07k#F*UTrIE)Imps#;po^U(z6m*PdJ>iV?`!!Ix$oQi2lSepH#pP0)`cf98AwzE` zfQYbKw9SMey~TJoTuHtlR>y+!%31{XkYV9uN`Hvzl3n--_2&fB>PfrA1an$W8^CFFa@{2P#8 z!3vg(l1oWR!L(`9(7%8GR^-FO!&^4xe}6xbo@%Wvucjw;KAL3r*9y0-=|wj!ENy$` zuEtT~VHZ7DcT80!GBOg&mMs&=Q#|$5Qy4XBRI7FxtLFBKvwDM|3e z^p^^F;bQi0F)?v#ttM?_KTSKOHOHbei)Z+U?>VWz5B1T)YPk?vf40y=$iC|5ovw+v zxHy3{O;zngh@x_XZsMdDW|&M`OMlZoTE(f_lFV#f_t;tTpw+ug_n|_aS*XP0%hXst zO-91>`qYGhudknQq$i2er{C-C@f(-Vx>|TGyJh>_&6Jj?{v}ZMR-E=y-FxDemlD32POMIaQ_k6?yZ; zmp8xfom)Kc}dx$9^^q*wYs`Q zU%4Jx$?GLvBmKO6`iv9FgNM>mWyi1ENkl#I(%9S6YhpkbIDm#vg&H z*q~X66A_W6mZ{CeC~5{hE|ICEX{ia>RHh)2Rp1bmG)0=`BY z0biqyfUnW21UmWC0yf}eMeD86Y6Q9l0=dZ={4`*aQ^(P=)>)@j2z2lRvS!=S?J8N^ zXU*0y;UyiX&b0hmElxmF8P?9!&_BqA-^(p9YL|k#$n?yP*jIF%cS$X}UW*ctz_2vY zj$t?1u&2O{&wmOm_&X%@?Pg-aa1|@3+wtgf7fh?=NHj=*k=pnMtkMD9Ai<Flx%?bZagLw)J;d`f7oHF7A%7t;!j6&?77{XCMBclY+mtYE zrGbq}5@JTGV$8wg3?1789otC=Y%h7P=^WV3d)-EUnUf#TmR(mW%7 zrU~p4l#UP@yp$zQSCa6{bo_C){<||oIDVN6o9AhmI@;doJY4gp#Y3=XJ;TjV^hFzt#COLS{QbCgfIxo<5rbrm8LXn3EH#z@Q4AAFB#dD?fJQVtb~MC?w&TOw!PEvhdrz zg(eAUAb?_g)G!&&hwK>8U52ViSdyn>*TKvGy|n*Fh8H%tkous897=ZiKbTm(-3{j^ z1Ai9t3cCG(OSn^GuG?rBkXu7f5Fv*870iD49J`GGqX4DKT%YnOpd``qLnOem~(R|zA6Wn4!IkX!X=8N=s? zEg?s<2ypBzWLWp9fy78VUVTKxgG;zpJbxRyi1vzelN+z(7(%dU3Y!ZjtN4^$EHB@z zwR-;`2>0XBt>7mMx#S{Gt#*m%#1Y(G!u$tRgazB`Y1>5`n3GK3>=uEb$prX(X*q5T zrQ|dsSi!V=EUfy(tn-bV64UNOj1EJT5#xu-NPAdCP-jmmaeo+Td#4-YQVa^eHGcwn z&XFM!UVBUv5w8Y@VW6wjmH8HU{`lQnGUOcCl>nMKcl&K)H2j7Oo}hrBKpOqR)*T3`6s*jVJ`{^`7aJ%GH(C^{Vp5upU;kuq#%plcy~69dj+mGjY}v9!+&i64%$+;8 z_I>YbWy~03!{R)z2Q;Y``e2_)nsk#dD|jhR!J!g{NntihG{D9$JT6jxu79qJaPZpa zvjRqkLA4P>Wi>FQuS^@?R{IUtd}G4bU`n`xr60O$>!~Ida}tu*84Q2SM z$P`he=QT2Bj+g6v9ULT!TBb{YcNuP>ynG8I2YSD)ahn?9x!W`(JVz&g88`QoMJdt@ z0uVJ2k02YK(L|~b?WfSu_upzgJkB>)2Muxce^YcSOLIPA( zt(}99Z8iapZ;Bc2UQkV&v*}|`Txc)Zg}kRI3IYNGYK4!Bi$i#LIEspj;BYtuvA+xd z_p!|;!12>b&(Zwx9w}@#8!|I9F>&HVgocLJ6FxFBvi{f;UIsquw{V*?JhJevMgiGnl<8@lUTfXv3Qo2mgXs4 zelf9jN8QTQr$4reseiP7e1(pcGc=L#IBG~FCnwi_XPPF8%OpHPonEz3w^s7`pSgYC zGmK5C#{BzL(a6ZMBuMn>(?`6o(izrJF_}ThOE)gFC;qST^C@8ZD&F`T7~W4tx2q(o zzd+@*MZJQBbE3a)azpdqgZCP_`Ty*F8}GyaR|J}aHUhpz8yf*%rPMP)0}oLL_uU&rY!%WV1WY4xHv9~f};Mo;<)P7tH@F=vX|@v z;#DrPsT5QY5oHLJ4m#4^q!~@yBfL84~dMlKjAa5U8;TauPAqr62I6sArhbOs;b6jmNM}ySe;$mC1={{H#JFJ&Xu4-c_18XP+^kr6txAAtu7>00d|6i3miFq(w zg~(4{!TJW5iaT^>6eAc}YZ2eMHz1S1X4DraS7hxzk;VLWpx~Q?qgJId7fL12z56W{ z#?2Q%Y%Fl$0{tH&+LIL8w&%1brESKKRs}@$DAY4tfu1O{o=|MCQi3ZBWw(!Loo1Jhwf9}X`D(HO~Dij?Ntj<7M z3?JRgD`sx**xqwLD#<#2IQ`VBrTK|l_K|X0K!uT(*33ny8!ayYs`2UR43nNAZQc8o zNx`FM%{1Bk+7#$4D9GUn(LAAsZEnKdL3n0qnGGp9@BrI$NW_pnLplukBw2H6@#5s9 z`Rj=wOo)i!Te?NGtN_%+#wR9twCOv0YH-|~ImM;2&}+q3QhO^4w-)85L1-NXIxEoy z-!}3tAAH`o=bSm3A3pk5a^k0JNgc|O-*P^pr3AoG%@4{m59u%|eLjqJ9u z?oIhE1ZftAQX32=&rt8K@BgP?&lxZMvFF8Ca$;ilIa)%q3!?c25E;pEg?wJy`DY(!}%>k;)o$Sh8u9s zHzEKws_Tu zCrt?%xO{o4#>)Pg$ag{z0#UrMp&K_dVwv~VQ|s5_I)rdN0-)qi4IZ#!Sw_Bvy_=kE zlR@g9k#A*N4Op?9ZV@4@K@)}0Q~@y2_l6%3PEU}3`uC%i>pl5%EO z0-E3x8ZCgxNs}1U_gDIa58J#xEyw!j*8Ex^Eg{d!MiOoe+5sA`hubEltzX|LAv96| zu}t>2XQO*RcYJ4Rj#cs(`E`JBLKIUH6MtamiRHZ?LTqdb65Zzs?gcBkfuvwp{=_5K3>e=Qh>)i_4 zeUYLI@ASabft1@2xkXmA8?kgj)~69&NoZPL zbBwvJ7QjUJo;9_gEU-NtLcBS}yo*7iBFZJ<^lvHYUoAroUr=2DRQuD?q^-uhHTPQK zU)tYX(3`9X@BP-Clus6}BOI4j^#?Uu0M-7<#U`)dzqG$O!LWqW(5SwzPD#z!`30)9 zf=U6<`8$b;qE@3`nR!ijXK24;vf>>PA(xa|5z*t-nW@L-uOM7ooW7t^0B6rK0Wo8T znGnz#u-^9CU!pI?_=l~KNf<0UAco4@<5m}`L6AtEHQM}I2X`JnOmp^s-@?%fDg_`G zBfR^w&lPAbx4lXk^jd6~CB^UueT7;K?^%Jz-YJ4grMT5aYY>Gx3qtPy`|}#jfp4Ar z1OX^Vj%4%)PKGF2^&VW1W4o={FE7>Nt+5~JEGIdK-u->rk#)8|$evmr3qMc`WZoDz5W?B>OEhrI=8wNSJfJF3`B&Cl&={w)<1 z=o&4;=hJZ2w^KZEAijBq)msF2R4_X(en^jjtL3(fbei$}4ALp~I;5gB(D|CHe zSVk4t=E2|0Tma!dkIPR;Kv1{o0}2fcE$wY507`C{JOlrIzpb$CB>dp1e6$YtL$EJ{ z13zi-XrBj;@;ujp{t8$Y5b^H~wj9 zqx*$#*`*<&&E(^Mix}9l3%!XWi^GO>7DJzSmDdI8ipUIHQ z17LG7D^&zy%zGI)_(?co!t6^Alrjd}-ff40ucbrm6?D4^ffof0@1@-~6&x$}_Vtph z+Bnu^xdr2BCqjkz7ML*aK#^95Z{G`Z5lS_`+`?n@J6B*9g^}l0jM;Eq*$T4fFXL}L8dea-DKhnWRQGa+^7m?KY zQ=#*=3NW@ZBIydU-%5_Nu<#zRGG6fZv_b7%hG3-yRvU{mX&mG-w-FdaSAa@G2X^Ar zp)nl|CU@rpW#&@66EDW|BmC@ykdjue?2^M^=8>o6p(*B(Lw*#sgh1R`ZndQ~96yBtA27Gm;v z1Smz2c}XA=dl7TyLAGTGQZd4hwlHsLrM}YVI3uyGM-6yol@Xp&S%ZAi<+tjPwjDU7 zQWZnj;kpw*d3ibh{;02DcdJGgPJ+B73?c*Q&!O#t=F&7nQmO5H_Q`n zAj&FujO|;!lXmvX0{n7?hgc$aS4`5{7+lDfV$6rd*!~Zdi5m_Hx^=aUo{b#HYvsSldq@44zc9EP#65Yz}*#t5# z8D3hFjb1U4@F$v6b73j1ho;yjG)-so6rz-RG)lO}aZFesTq9nm*B&{e#~W)cAez#c zB31(@@y4qCT6Abth>3&!T+emddY-Se^-K+6RBf?NQ%ld$8hMaJ*6!qMJda*$B(3?y z#c7bsLmCyFSUjV{I13l3ZtPS;#xn>{f1HQC{|c;DaA#p@tiE=i770fRk(^~lC~50~ zzGA_ys)Du+r=?5MKRp3-eU@9L)D#6>Gce`qAp%k}r`NM%aQSfN8$fB}6w z%d063HG4V}^;JBwi|qbOXRr|;WQ5*Sj(p;?sK3fBDnnMD0ry6UF)B6y69y`3)!iw$ ziG-U{CZuumJqhO(T#%Xwz*o`OSdv!YTn39Jy9@B*0}!`y?p3eD-u;$98rZ?h$;fOE7-Fr7QS-EWk)Y&+A!w*4EQPoZ#c|V z`uJev`#O>xONEHY`3x$65wniN#6^K;JV?~$NqifP+N9*K6y?Sucq_zsX0R6~KN2Ri zdfveSH8ZrXRfVwma1l;kAxh}R_E&|CaL@5PL*F{m=md;9!nZdTqu0GQbZcF?-kJmq zP>(!~r-p^&sYm?KC6dKk;}w`24;=c?*nUC;i9}4y8I43dU^8c9_qk$nUKl71qO_!QW9!gFt(Qs z@q>cU+YttnfC=ZX*|2_J5jGykBe_K+t+7k<{~!wU0&%=e%{Ay7UubJ-@*)kDN`-0j zQt->NHm>H_tAhv&XGG)G)n(XtI2&qTPfUBn15XX|#=y=Z47fKKi>C9~aHtet9xTDR zt6J=z*A~%1m5CO$`=j2z3O$MEn=>V+JaHr&jw4CjkwxuXt?k|j771^M;L$l((Y>Pr z@lUGo^gvH|I2bv3*@~odW^6cULUw_fD1|?Qg2Qp(ln%$v^XM2M!SDw}m^v?$2wB}! zg`rjCu4{=BeNaJJ5T2S>h%aCBbM2onP=y^yIXIo}2ck%rx7&jEH*3)UUSM>;0F002 z@a!-z;b*Q0fTy_9>`)A!n~PLk2r&cKQ!4jm*7D(a;;l3!E{t+1PTv@km+WW{PsfPn zVbWT+AI`y!A0#A8FcW94gePhBGKD<^)|y1vbV5nWPsb;UNb4YK?4_O18L#eSC-P(u{ALomw2KWly6coiItlV(WfHnKg$SJas@KFJo zgHu|UQnLltvSO6;GDt}ik$YNDVP#QlU?JwUBsY@6i-hObJA}?KyqRMyMI|_;IK`Y^Ke+6NhO-J+LXU6r4x(uz*%x=IswN$yGl6+JX zE!dfuMH9Na_ z!2}wJiLq2z5ZB9!u>*t9@1Dvi=4`4B8}=8Hd+;P2W+0cT;0#)vxgwoyF|Z4Rcb*PG z`%u<(tZKpt$F{#g?}eL<_IxSNAqzgqW~6Lm~c(GAqU}6HcWU@Nlc7H=ntZ0C^GOQ;?k3hxEy(f zW=KdYa`w?wRSGH~iA{q|b0RRPi`|>n>PD#oriw7=Um8rjN}fG=h!6g@AfG4<<;1;z z5SOK9aWGy^Wt5LHH|q41M4gBgdOEco}f zZ1j#{iHTCDyw6B8pNQB2*v zlNA;oZT<4GI$db-Sy|oaF{;P$Ttp2=!VaZj-ODSB5PJ7NP zTEv^ojT?}uw{YaAvxbs%oY=%S16&1rqOX$J+&r8}=7q6=rrghim?#foqRwf6pH}HG z>+@n_qOADjg?5MxWbJ)ORM5e!(2M%|vQ%s$Erjz_36=M$Vq)q7&CELn6kz|y5sh-B z8jS|))~$m`B&sF|v)PQAx#HT#J8rys z^=c9gRrgDO8{sERk=b#gb|6AQ-B?Q2g^Qdy>(F_*1hza!r=(j}+<=;zXFe-Nm$nMQ z1W}TxNm}_@6h@Fl%SYL;KcJvyrPNpmA8#pUjNphL2o=VKoqaJoj$5$qn=4o|r-RV! zhrRv>o_@3qCXhsrI>w3pLO@?Fvw_(E)%#5-(3*%Q`d3Sqw7Oz!|ERUl9qvy1o#bD> ze7V-K&6_tPK0dzoMWnC`p7X=cmokx6I}qVXfMzSxB%SAM6^0^{p*WeoSF^bmU@Hm9 zQ$EhX_X{Ijc9}Zo*`qwLbgxlx+BHGXG0>qo-imR3XkSbS9wb`NI-;0!j=q@9iB?#M zwd8F+#QE8M#>s2`IJ;bnSC?0hqFyCY)GQK3ok>;UtuIYDe@!F|CQ-W|A1e{gxe@ZW zY}tZwoaJ5M0iX_U)EyTo>RCBb>3TPdP(rTJ06_mN67l!&TqA}n+Jh5tDF-G*X2#J|<=GwY9g3*0?I&6#wR0>Z_e~f0s zA;R#W)5L5$MiQl?c{p&EC4_rHTBR?>oe!xUMP;FXR|zg^yo4TGDgfHTd}Ixqo*N~< zDxUj)0oeau4k?$t6)5B!pLOQ9gOqzZH4*vWBpi+zzR;>OG>;!}g2w-Uo0pE$UqlO| zWVFJq{8$nt(eYUsdbDM$b@$T2oUPwm1(Lm_DyXWsi&}-M!XCApEK^%J65@a*5C{A?#PE5=xye6)kL-nJ ze2Xn5#LR}^sgHB9``w_*9>~t#uHzd?*tqoD60oLJFw$T|1#+;rg_8R3OAeQ^2G_)_ z)_%p1deuD+OT+D~65?|l3;oNj95D&?cU?9&`A!8J)x(Vco}tl@jW5o<@{_{Tl1I6> zPfsUFlrd%VPS5sl_cE7X*PFNM1&usTB{SG~pa>HO`??Ax{3Sn{SWW0h_xsj+kGc`) z(&Cd#+tzu8^Z3Yja&TVbBZxJk%B+o=Xm0Xd{AE9bQ{_d?*sBx z+5N!}pG7r$Uw=ao!rL-2~2@W8c03rpP3YiTOz(=zpe z=>Ad;9)C!JmYY>t9Sp+~GbnLoyEa?x=LQD{3%{BIs7n6QrAzU`3oi%+(@APhbRpIw zF)_Fwoa z3OVQ$!qll#>m0Fv!yq!!oO%5H zkG#8mv_x-enO1Ns!Eqkgal(p;vGq^Apsj&+vehJ?3WnPHqeqXrH9M8}vQK8-z4q-7 zYQ85zC{L{`A|m*d#D%N-KQwcO-ss<6@M3on=-mBplk$iFLh3y3G)EIAOu)*OD_uT; zg6`Mr^@3o&{PN4jhNZToQ^}W-e_XYuruI|R765%sL((6dN~g6v(GSXv`BocxTotYQia95Lpv-w?mR5XGKQt z3(G&UixodSN_g|rT?E=G_U7t5Y<)Ax?YZ>{Vbi8f!pPYA23}uJgk(E(=+Lf97tig> zujj>m^&3KBt9~wg{-xe8Ug)2m%lo!Oa(1ggZSv7`z;{0zG2{W6+f2GXA#B*NL7;^W zQ`Q0cd8ndio_Xe_wCj9pB5(0ya?SalRDoLfj9` z)F%Ym0!m6suyf~5VY`Z+^1~k;H6ty}nA6aG8=i$pB$pNuv0a^i=n=7Wz$E%U%!Z43 zXF)3W$C!7M@y&;As?E@@4^#+0{`e!rRTipIU!c?JU^E(qt_Vk-W}EZzw)K1We6<~J za!&WtU@u&-{hTy<#*kOeK5(%xtP^vWMMZi(43E5?f=zRyg^@Fg`UFAA?$M)1oyY8& zFXR@sR~Mf-zhKU|8EC|-?A;3>KOcN-tm*KYaZmJm?)VRBIlTYfwyUoKCj#Ggp@v{1f`k+w=He)48&o zy(345J>ET~nO|Q|+=2auN%FnpCxs2!yqSJEqT%&|cOJwNFX$~^n7z_~*H)HbOm8dh zZR?LdF|088i!L~)!k|-Le!gPG>B}a3^+Or5^2_;lQT{f=iSd(iQ%)oy8KPSL9Wie>c65qFyqD05QBB&)A~0k$010~P}@<|0^mPFPgVF%|Z=07!ix z;lzCVD3MKbp? zhx&_b*@p@FC!7BL7>es%3?vAFFE^G%{Rux~MM1ddqk~1}v^^6ir{03kSW(zge%+Cv z*X87Nir<$&zpM3U5dtMYDhLJVwhkJde>EuyH!!|*qs!s={D)hAe_}=Nhhish`#N18 z7DK-@cZ2u5t>MAJ7Ny9%aAXDjlwp??Tur*6``!3@M3Rb^BR2KmqI(~DVBEIF2pBpg zUwe0b%u@i-dVe3HTlojq?O#3SW!}=mc%$Euq-drEp@}@NQX5WXESeT^e*3|QA*&W= z6~d2xg|vC@e`_IPd0VJI3a{;-_Hvp$b1PJG9{KK*tj3`ER^-yJ1(Ad;Ju-4@){;&~ zyNz1<85=low5HI)->Kafv^zQ2mt(AjM|YlB^6X5DAEUwP+x3IaPNb#r^qVOs(?1>) zbn1(t9Y!pfPd{m{H`(gW<8MpwHg72lKhOM2!Y9oGO7=mY4(RWMPnz2yOuNWY$9Sz?>T2~QK>B0V6x(N9pPfRX3?~i z0PM(5;1L^JmYlw0`PHO_U$*WuYf@PEmtQVLKpV$P!kcwA_H}}%%=`Ip@L~&-H9sv} zlyrQ-dOjko)INWw_Ap{|qGbg@VIRQY`N&9Pa>kA?l8=45GN4oZknrx)rYk~w56~3D z!(^s@g1wo-pvumBd2&pUiZ9n^|8h9%;L@d<-#70=WTXWVVZ1PVp`I@vH78nL08ZE| zLt8{e-i3qT=IuGSM`RR-Ms=SWr)oQ9lq#@Yk0JxZl^85^$t>T@t%G+=X=8l6Io{8k zw-o24pDg`j^Um*oT(!e0vt&8ShMFJQX=&U%0XR`vLEah{mz8{K<0710vPfhW2l{u6 z>lfO(^I&o4B_duf1?VC~qoFw2 zs@Z!Y^Vd@c&RtA6>Mg0r6{d)f=mXd1rEW6$6gOW0RZ-=;T0|JRxe4dDmGLLGX?Hvi zR_yI33GNdU*ea%@!bjB!^7fGxp3z|zQGnVa@>P%~LVL)Z<+sq6j6$FQP%cef?eO60y%8O5k_UB~}

mD4Zu(e0Mh*}>&rSpSgS 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 diff --git a/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png index 89492aaa6155a2ab0e3f37c2cc737315565016f6..a111f50738c113d2140dc871e4987085afa2c37d 100644 GIT binary patch literal 15150 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 literal 6422 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 diff --git a/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png index dd30e06e2861798f277a9e4e444417f0f444e3f4..fc254c2599eae9c57035df9afa482e4a3fddf8c8 100644 GIT binary patch literal 21173 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 Y0}Dvfd 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

<>5{8FHRmJLp8Fp#2t+eq`i$^Rvu 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 literal 40617 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�RYnt5C)$ldjs#Q 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 literal 52126 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 NeyIK+|DM^q{{wI=gKz)< diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png index 95d13de016c50adba90f2c7c7cd635453462c743..c8a0b2a25288014c0704a8b2c6e5dd9b0837cc4d 100644 GIT binary patch delta 1035 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 LNkvXXu0mjf!$>(= delta 1455 zcmV;g1yK5!6~GISBYy>lNklWoUqHR^*Ry6wOA> zoEp%`|jtSbMCq4SstBx!^Ax-%YT0j(3ZLZ{Z%)hzv>3` zSKWaAsvFQ>bt>S@XGH`C2-tQ=hahy$Gdm4%$_NpwX3G#o0jlQ0&LX2zp4%yaW1bMO zE>=c86-Ml{B1*=UIt2$S{fG1$@W~JXY46x@{*r+mg*t3jW=#nj=gEj#>%y_~{#A3$ z0D}U6mq$uyY=1IQ*Jz^l22k5T-|1dQ7BURM6JL)61KSqK{QuaE3PwC8@wR!J736(j zL;6A)(^t9h`xSS8lUPN;#Qi-4^b7lU@7=m`hgu zf&hnwizq&+;iq4jR~U#1`+dNK!4e$(M6$Yol2aP?AJb{1FMKmVlR7Nfs$$;?5t0aG z9@Oys5Pu0hY`{0=Iu2CoST|ROZkSkk zTq17(oAzj!I8?;YFp} zkD#C+-nNoXp&zQ7=pixnGhjHQ$4TfO~&Y^O3y3<(vn=oJ~4YYo1_ z1(QX(te##hN3t9|Yn=PBe_k~x&8UccT=Kxh#Kd^u3JVK;;BG0>!TNUy5U8g_9iOIP z;S>v6IS6pI&iD7F8h0%9c6$$5S$|o`&d%m=1qB62OiV;sSs4Zn9EiNUJlO4a-Y?kh zeMX0hh2u^WZ*5XLGKA~eb@x3sHWp5&lUp$%Ap!aM`3MgWM|yg?2af6Xbkijjb?GUc zaw%C}6p@^qjI^{g4#$*{k%9jG`}_7kt#>UTJ1r7kGw^V4_eP0}i$i5)C4UEvii*PF z!-wH;IC$Ijn+(&2DVjEa?B)Of002ov JPDHLkV1m7BxfK8a diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png index 6e6c85b6a01e6b882444ef9d8b0d790809604aa9..64308e22e765dae90f21aa474f182692d9da1777 100644 GIT binary patch literal 4674 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 Ef;(sk5&!@I delta 2348 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 KMNUMnLSTaQVRKsm delta 969 zcmV;)12+8k4c-TkBYy*>Nkls@k@ zMe3l%r{9=lbo+#YW%FFT_l3a|o3qmDzswH5t#j_A-1}Fy>Fn$?(NvgQt~gMSTd*-| z+ZB&_l0g zIa`itlCbxu;XePzMS3Goku+^sdP#I8N|M}WYsyP0J)(m z$5k#WR)3{G;jNRXL&+Hm0|NtecXu@tP&srIe4aH%G}KU++nBKTpy;LGnUUb;`Cc#=Xoou<0F zn$FHnB9RCc6{R#ScC+M}jB}{GaT@Qnc)mT$Dt{S^@9#7y&|sTvA6cKplV_rzzS!-8_HeyygEHe>)6R*^%k93K9!|6x}E+VbKS$< zFRjY;Z*Ll4#?&0p@Ao^v*49>1sT8qTYzRE#LNPkj&aDfdPIKynW9Qg@`I|L=rgVX( zQGZreMtyxfp-_lqGD$~A$Iv`|FmgssgSrGC_KSs0AfF+%-_?>huHKb2F;FXj+% r%%Qm==-O+^YUG`9V*Re1aL_*i3afAC5vDHv00000NkvXXu0mjfc}eZK diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png index 7fe870d9965fe70801ba9b5aa561ef3e726d87b5..02ccbb45acfef3ab6b40c242ea412e5d63af0fcc 100644 GIT binary patch literal 4491 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 literal 3744 zcmbW4*FPH$pv6&JH8pDowJD|ctP-`wh&^KaiCqd z6k|eK#N9KNEUnSxSWKCeLM&ViZ`Kbv|KS2>2$Gv4)gl>%|3EEWS6-iBt`Dydu5X(l zhj9BiGE->BPtI1PV>XOeEWjWhRGVBsBtysCCh(1SM$>XVpEA{!;s0OyGi84&whn>b zN|gA^k4+p5@%!sFE_flrZP8m`#L_3_3CY2aLn*jI zCTLpfJQ!@thNq-yAGYgl=R&blzv?S!4+UW?kB2EBqV1#)tOAlPlq2hsh|iUJ4}6!# zGRC{4?-mJb+)okc0U;O9j!5ixSozG&rDyqg@Wa9DJ``l~w1*PL#*CMba@GYViGLj& z#=pVLzNHcQMfjFz0etE7lOEX4r(0!W|MOf0Hy3kfP~~EEx1?pXbtv1WMGB8oHQB9Vh!Wxy{Vncj>mZ0WY;W-2dc7ASl)~7yq3d}OTu;NF zk{r`);TBS#tPL|43|=fsjHyh*TVXq(m3dzmD2$ZG{XZ9+F>&64xdWQ^vfU9;ss5gP z4X7$J0qwm$GOkgpN(8MX?tmPj@4wdN@_^6y=`af&5a3_3u)FE8{7pG*a=jTQw!Fa= zgjX>vobdb2;kR0?g^MxWx@>7UI)t)ES@@rkaHlx+{b<``s{r`FSAQuyCL2-yfZ>5i zh)9fUK}@#GoO5W$DNaU2+XZ8&to%zOQt@wye$K~_N&Zwq5RTSj`G^6RsGo->r&cDu zG&f&(uH-AyKyk=xlr_(-r%N~XO>AOH(c;4$EV zKNBfw%l7J`|NPivK0I3v%!wu=p%}5oUB| z;#}PoQ|G(QfsaKH`Mm+ZyLUlL?#Zn@(S7Z_AL5p^R(m~X&ycDPWxl44Iov~zFBmm+3A4L!X6p0gEa3X-L zKUri^IbSh6g}nn{Z=I{APL7`?1(+l%8MmR-?{_b{7BGn|aflC(2|3a|eqTcikZ$Hd z@^KF)PT9CDQL@cYPfJTRUq1HcSBukGKlZx-kmV0F@zGytZNYFZy&W`5ERqw66ljW^k-o>mTIw~Sgs_g2y-PgrGY&#|rACVNa5;{PqI3;4sW*iw#P8ZQ+`8 zTj3W?&R@ni(Nqpq+E&Y2pU8PZ{!}&Wvso;8S3#yfRW5Mzc%5(MtL*5XbWfI8Zd>Ud z>Skks3xnmm2XN+4$z9Qe*u1Qojs#mmLAPG4HZx7xt>r~Ns90lnug;8bY4f22d#)N* zxoWwqUp=M-rjXu54Ftue&`L+V9pd7Ukp-&$z=d;{3xB{TP_v9ikR8E6`yqVQi z!+^n!u@BzSdu_kr=DCcd@U8}?bHCA2%}j)<1C4Kd%>qN+P@cBXW-x&*vXmtgRj=T;LlN^VYQ7=3cbCdZ4==phv5QM3_0YN};mhQOfK6?TQcr4F8EuTp`ZFl$S zD-u3-+w!pA#EG@>H!>rsr@)d_hCF?7+Z{#II zNBCtx;O|K)u1rCTEBs0?9S~UbsU}R1;zqGzWeJo$l9|^O_!)2Wy6i20GoS6aIuer1 z7+(ha^%t5at*Z{A_6d^4h^qx~zik>AD|6M$T3``zJeDGZMV>8>cj$OFeJ=HdQFwoq z$aTb&yl-4)7w09@$O3akA|QdZY+H;6TncI1eIJ679?h03Q>kmAVkCVb>8> zg@ww>K{;2fkRP{Y7k{U+v#7U;%~QGKy8Zmw(>YSmRJ~iO(Rrz8l*tMP`4qDjyS}F; zzHAWc=v&?X ziJN}ki6tlPuA2rfc_r@LRU$M1$|gS?hZUA{hppV})c8`n)VU%^q27tD1^@w~-R&Hs(5XfP>pm+C6<4Oll&zGIKgsvw_F0+)@cH9PS<+XIq^6 zCvj>z!^zX|Bq1BA&o_I|?NyPFWarZwM282*Up!0QuE5+xcAD_qiaspP@J}_T-6IV2 zM)qgg=ln#a$@ivn>3|q zr6J}eX0<_9^=_L zTgMF&op=%fqe9fKr=+B$WoNLYb+gyo!*_t9b`oS*IdoD;npY04#4xH6K9I)RP6M_0 z%FLcI%ddyz78Vx9g&mcNVZYd>!H~8Cavf%i5Vg-s8v#5D3RVu&lig8K`USF&W+H>g zyc)*uk6ie`FR15a3=Ytkfp`zTA#~c>U}oay7et~KwYHPzR)mNPi2RInTQ`to+SGFq z9eFVrD9`am2`=6qxKq+Wq=rVL$0`iis~x(zS{4KJ3eT5Uf36N5(4s1o-ou{H+}p5TGY5yD?RHZ*mI|MBio&?HY7k{g-y;ut2f`N@Wd^f@@6el zEl_xXbg;jlY~JXdsiYrT4opv*2rINj=#zBg!tBFua-wZ~Gi*m4W4AB`iKWjqUNY&) ztNlP(jKfQmaG;PGvbMB|EwWRVEp^=}rGx+Ow++A==fMBANxFIh5G8nix4XJU%;7#! zRVFPD;*N@6l*BsPaT088KQBiyVJtU#`w{|b|10bCv&$ZVl4YMYY0XcjXJFEp6pxzt zuYu|h;u>2xugoHJ_7-1KqYdpkodkVt;p>E+nC%lTtL5z zGK9mKFd-i|<_aEPY3H8-Y^EpQTpEoH^yi@(Iac`}O?Mm&%P{;Ou`TKL4vwh;5kwj@ R{*OF~bU=ohwa=ij{{u=RJS+eJ diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png index 5ad80187a2b9d75d67946055753881cefd525c76..e0d3b77d055c35ae81721dfba9f2d877ed56d53b 100644 GIT binary patch delta 2705 zcmV;C3U2kl3z!vCMm$V(6k^rHB{)JapxF-`p{ zdVJ%f$0(wSW{EkJS`KQKN*`lcGUwGP*6l`*2nq2dpPIp{o8A=wf0(zMF)fl2?0%q1%*Tm8h=CU`VLe1Mh_IVJt8IA z;6ol$l-t>;a-FIatmUPWrDR{t*`r_b=ZdQ#%Ye;xOLMX9ep96arPiy1227b?2zVrc z3m7)s;gVUIqTnJ>&0m#ijnSp;-5cbhf}WVvtuHN$^+$iSSACLm?)0Y{gxb^f5QIAi z$oO|Rg!GSp&VLXVKgU4@bQOt`L>`K++VM3-k%dsuMh{@ki~4tuerc(#GUuI|pFVg? ztT}AGJwS$m-#rsX2liXB&VitC2h}d38=w+cN#BVMnYqXu{@2;{hgK}CIkG+j4GkRt zm>XNxUf_M>Kagfs?z z)>NM7<+cHd&4oO;dWjf15=wsuw+SEt~ z>MA^d!2{waIHyBgmIS&TcpHw||aX3NO-J;J~@F&(zFFW>sCfzz`6Z zAma8MV`!8U|C((ALsJMeTCpmR3`lnvlF|o0G>PjRxPWCC-ykk9cDUzk?V$7ybz$9$ zCN$V3qDeRAJkbef&Rg->f0+&&jYBs1n?i=hvH^FG9OK|+wxbHva|)au)!L;{VtX%TIgy*f;C-UizbtD&U8CAFwkVPK z>lWZv;t9>6vq3~aCnbn*@Y759?j!|XYJV~diq>@R$EtjL4Q!sz4eu>u-5ld}`gD^e zT_j1zZ}l?l4j0Z_WONPCpwHbZOj&seM}E~3KyPrhIMsMM&5rGh_4xNZJ<6&D_!AJl zRs(+@ErFuIwvv9l@_`Lo4qUzGj1keSppA-b{?dPb0tyZ~Fm|BUb6-~F!p`pd~_Bvbp&8ouGw;Ql!p$X`mV05n>PA1ADE(9%*o)fjcieXiNpG@tQc{R5qb@U zod*SMFLvUM$=)rSpLr3V7LiPwZhzH`aP+JOiSO29J6FW%hTfal*MJ3^^RUBlv&B7Y#|LmN1i zs@3mVT6Q+NDUI>k2W2%J)_!5btT+QcFSg*@V_IbI0XFQiVPp)2@x#>EJm0I;++qn0 zPOioG40w$0&tTk87BpqTyeu1beD8*ngtHMb90vCQaW013yUDh*`1(fyg1hAyl*~I= z&UvcRQ{Y@96xp}8KNoO+AAc8C&CuhKB@L*xYCPVz`)6R+VK>x_0>R>)L=Blp#`$^* zK6)9iJt?C{n3mWskK|0AIE@0yz#J^%pU)YHO|l-Fm6eQ@{FpjgaXtx4i3#MFGDNf9 zU19mET2`>0C`BuPib&w_{2B+oTIPeCmkoIAbq5?GcX-Q5#S=BN3rFrCXtqwhTPm-gpe|J{rdG-^MVO0Hd(Rm z8*hM@Y?Wm!sawCL0w14*HVUHZOKL32wqj+X58g}=kdz^LtTxowjkrM!M)p(Vms$}Y z?v+Rcs7Ht&g|B|3$$!?W@b{-!yqeA9=SpBzqOJ)}Ai3V$xpT2*%^HM;h9V~?2PTur z^X%0pjo5X_f{OEMS+X4|W$Vrs?hGe&t6eD#+mKI+XpFkYPP|Wt!@tyHV3Zb-!3?qr zoJd&JNKzz?vLSfPy)H>b?9uLtfh=LVD@c9$Ny|?ZFAeke{*P3IN?=7qpyaWsyu3W5 zq@;MZRnc5QK>-#oUW_gzqsq$4g0HWy=er2EFvj#K1F6VNN1^FU6YJ{^UH zg&xf%C4VJh$dDn3h={mMD7!aq%2)!sx6#m4)d^?HEtd|ZF4Xi{u~wGvY}v_@SeUZ0 z5u0D}0mpiW-mqZ<3BEBNX7JH6e?QMqvsJeT(@hOBcOEI#qsxQ7L&<+}E3>)kC`5|0iYa37zo_CjTnUWYbVqTdpa?Vnv;=hw< zf9)!x_B^cB0d2ltw>m)~S97EK0 zVRwFQS=M4}d0y$wdet}YQIi20D|R10Wq&#Jj82=H67Z)NXX^tVp5%~y{4bvCTwT<>RKhAlNyhd+N~7_s>`?S6Gd{a-k=}dn*0yb^eQmNpX@OJ015yA LNkvXXu0mjf!$>(= delta 1455 zcmV;g1yK5!6~GISBYy>lNklWoUqHR^*Ry6wOA> zoEp%`|jtSbMCq4SstBx!^Ax-%YT0j(3ZLZ{Z%)hzv>3` zSKWaAsvFQ>bt>S@XGH`C2-tQ=hahy$Gdm4%$_NpwX3G#o0jlQ0&LX2zp4%yaW1bMO zE>=c86-Ml{B1*=UIt2$S{fG1$@W~JXY46x@{*r+mg*t3jW=#nj=gEj#>%y_~{#A3$ z0D}U6mq$uyY=1IQ*Jz^l22k5T-|1dQ7BURM6JL)61KSqK{QuaE3PwC8@wR!J736(j zL;6A)(^t9h`xSS8lUPN;#Qi-4^b7lU@7=m`hgu zf&hnwizq&+;iq4jR~U#1`+dNK!4e$(M6$Yol2aP?AJb{1FMKmVlR7Nfs$$;?5t0aG z9@Oys5Pu0hY`{0=Iu2CoST|ROZkSkk zTq17(oAzj!I8?;YFp} zkD#C+-nNoXp&zQ7=pixnGhjHQ$4TfO~&Y^O3y3<(vn=oJ~4YYo1_ z1(QX(te##hN3t9|Yn=PBe_k~x&8UccT=Kxh#Kd^u3JVK;;BG0>!TNUy5U8g_9iOIP z;S>v6IS6pI&iD7F8h0%9c6$$5S$|o`&d%m=1qB62OiV;sSs4Zn9EiNUJlO4a-Y?kh zeMX0hh2u^WZ*5XLGKA~eb@x3sHWp5&lUp$%Ap!aM`3MgWM|yg?2af6Xbkijjb?GUc zaw%C}6p@^qjI^{g4#$*{k%9jG`}_7kt#>UTJ1r7kGw^V4_eP0}i$i5)C4UEvii*PF z!-wH;IC$Ijn+(&2DVjEa?B)Of002ov JPDHLkV1m7BxfK8a diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png index 0a94384d619884c1e08692ac2e54434601202c9e..88ea9995566b4a378ad5dbb1af33567343999da1 100644 GIT binary patch literal 6909 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 a==cu|HXQ^Ofl^Qa0000dqZT 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 diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png index f049762f057fca745ca451c25a3f1052195be542..cc260e0f9799ca270addaf9d99c6059f7bc6ac7c 100644 GIT binary patch literal 11924 zcmV;FE^E<=P)-{ne@OD`n!BGOfgBoskWEL0l`iVc-dX)47KL9u)a{-r30f{F-{CPh)i z&=ErKErpU^F75j5{%7`bmrF>(1wtqv?~f&Sx4W}5^UV9s^S)D7j9X6PfT;`{wP+EW znwsh$KkyzW{lx0f=8B;1cgezgb(RO*6D^VXgg_SROV0W5;N|2m1BS6NfQ5m*$eerp zqP_U+1)Jg6Nn75rBgXX2$2e>8338poBV9IX_;4n5(f1s=-Sc@jy@+pg2D}kn+qR71 z;6Y&UU?3qLq8S=pc3|fg4Z96&sq+hJ#p`>wmS`I{P|8Jt4o4E%fYlDhX6NB> za5NdlogmLk2ukD-sWc&NL&V|jI?5!2AeDfTvT)e#mh6(EjEmypgUOD9BWE+R@{V0d zSiOrRk%oW(2BSvt`0`5zIvtPH)EiYTUdhc3@bcv>h717#S3pSm_p$b^UOM{zJsn#0 z%P4>(y8y^7F!6SW!+}DUK@r20DIV+P6Bx5qxSlC7xqlOpe?bhw0y#x!2Zio2QS%N` zG#EbHk&%&ebbsQH-{-}TUqY_Sg~7m(M#rLMO9$fP>$vcBBR3zwg9kH6NZ_fah=%_s z)W5@+`=gq)?Pd0Vw5#4%-Y~D25&yZ@#PB@F2};QjP#IBOmV+iL;sr|%n5`V2mSN)0 zXM$BKeD7}3ee@R{`n>T`cKVt9C1;nfypXtYvn3(nI04y?oE)C~1-5Ld!|Ys}+#CQ$ zMbZBmV(u8pAA7?a#g6Oa6aDxAb!dm4`6VJrPKk}-P2h{n90QlBWmu+$6zftb(n7~u zYI2YROeUb<`G#GTEhl&Fbl(&n_L2*>^9h@ik8N3*vt{W<#KzhM)18`n!~5$S5Af8f zEID|wSg!SdXyy1meI9w^^d*rdE8pbE&E$!xwKGnoLVW@1jS$FL#$@4eF^A?$9uA*p zhj)DPl@Y}mW7a2q*ZWPgxiAIP+{eapNKCw8K;IyMW5}_EK}-xp(`M+Rx{ZB0tn;Mt zW~jn<9J4VTZzC3x72TM;U5zjzYR`|S7&)C!>xX*0n|&hZ+{X1M_pbTAbjzZ@`Is0p zw!{*U>%X7AF#xyBA+-Tso!xlAh_5&Qu;+|Jbw1BV*p7q6O{J){6ROsQr5p-N8L3F# z>+zUj{RdbKafzEgi|kJtbP4I7Nx6^Lt2Wm+z%0>PJ~&&`H}cgV-ctJA6}$dli_}3F zlb{8+jqr?v(1l~?jGS5-&^>ls+Mb*Pv*(=H{@pKJTwESu+_V+f3()liFiVIOudqh8 zYu#|-J8Y-eK^gfrp2>2NCg#>v+v-IiXT>HSMMixyb&F|Vb?G>DvTfgth5LM>=GgVf ztPc`){Q-`PV@ZqULW2gp)_2(Fb9Wpua@GQeKvJ&zvu_fig)K30Aij2>Pt@c|eaB50 zw0^4JedJUzsh{iWLtkHji7zYrdSkPWBR5W$1jat{&wkQD{SN_qxd=e>DcO=Hy~iF* z-1EnrDMfSVZh+HVbJydE*9qV_a>R?-Vuyafw9T7$9(M#VS%g6SPlM|g#%ST0Gv=t) zy`P`^+xeYg@ky&EPbGCm2xfepgIxCj$Hp??6M1#k@YpW>-fQ0yho4Wz;>C6PoVo^>!S?N%d!JeLf6^`wJbN?U=I2fMq_IQ_VP zk{s8$2!t~wlhgNlee-WC-V2Pe*$hW;lL5@KQmyZUZ*E?_=@1)kw3LMx?}*nTnC#Pb z^<&ercOO{s@~h|eF8UEpkgo~ox&WB=uUyPivu2(xX>qUB&ffv|D#hjin{>t|Z9j0q z!i@CPJmaNA7sI}4xmJJ$%_ZQ@vIRf=lr`6mJK$ccFzlgoHtxYU{#t!#*2+ip`sQoiUR;!XU}XZXQj@O=;8@}c zB_<}SN6j%L{e74XyJMEGhcL{AYzNbJ(31Jd2NXL=onK14iebmA05}ebd?N09e(mh- zCq-dKvxB*#xYtPt^E!EvR}Y*~vgfba4?KjpxFbkRoZ)yU4xd+*%=?z4P~U(+xu$=Fr6n=X!Pscf5I21vK+YM=hlz#j96?H z1$FN8>hDYcTJZQt-cM7CoE)$2^&a53I94`yee)q7Z~N!pQ@oyFdnf!@kCJQP7?UDq zNXMsFnD(CkY$P$$UTLwn05f#RujBAl@mr7D{TSv>Y`NZrn9EW#nBb@fo|pX*|Ahsp zJUPEg@ebgqD1-+Nd`%MC?@=bpaU0FNxb-9@(~eG$PMf}c;e(G8T$n3O8t?{SMq!C; z(`Wd9=Wb5=UmwrC@xpNoD+%e*->>837xR;*e~&Bp$5#fJXz$%I?@iiv&_q}jd&e~2 z1d>Ly_~B>czxwsUrv0WC@JoWH-i_kQQh81FVo_x0d_7Y z(F|Yk%}*QlSS7dts;;o_h^n>>i8*8q-4yq~*rfB*^bbEhXTCSC}k=tp-!R;uFsKBTU zi@tyCh?K<7zorWeJQt;34sdEJAy)sW6c`(xrzXgL6>me9(^wj&t&BkVE327xI2o)oAa&s zc5N0yg7vox$V|3@l{_*kVRpjgz>c0LDgqo3z-Svj)ITG~$lY4&bE_8$U{-n>5+(E(}Dt0gn3qd-lTX z6GJrNT_4EJygi~;G-|Fw8vgvIDVm0P6p4U5X{ZA28dxxVrU5Fo?#5-Zu7qKjgQtyL z%lih7*tcTTULEOf4a6e50Ztt;0={j=#1xbYtofF=%@o{A=XT@QPr3`>QcLVAl&k0I zcb^V@T4!VTc^w?rW$9PF3PZ}^5Jf!G3m64MSwAcQT(%Dt*RWahp83VM{-kx9`;wwu zd^7oeJls(vnB}VI1O@%WmmA};$>)$~(LyX!*LPOyR0wGjDOK`@^6>86<@%y+bZ;>M zU}2LnB95RTU3udT&10QNX{iyT2k7y9PjR*2QlURb2Cz6dzX>9qxd<__UG^&uq2JWP z6qbSsj9EPP{E}#4jgtUyz~I3!Y&z1$Pa|(+Fy7j6XR{S(+rWg0L;Nd%>tf6FyXR-u zxt}M7pzk{=@Ye@JEWUO5Wnqb(?R9U&13#?L2m1Bzku3n6laPS6BacnXE4j7%Ut@^@ zk99QRtN%m`-#x+Hv^NKhBK^@Yn8otV=@{B86f_9yn!eDrr3l7#jnQLFGLj7;xK&5K zNtyU_S*$#u#o(Tq3G;ptI|mk~Y42&@{J~8JEVnGUbe34Rrp1^)uIXjxD9}$$OGe6a zz3~0aMGKS<9fk4tyWCpt0{XjmqS5h{lhEp;ZqbMr!(7TTF;R`0bjsAm{vxKkwq{54 zZk1icN;n61OHRqLTZ*BU72?xTjW09HXEQiF{N6d(S)IFoWu(4Ps%3a$S^-v0_N{PF zR1kyF1NE4@<`Pu8uv-yi!lpU9McuizZqo;hm~P42xZA)M8F`+L#H}MjbL6Zz{B4uV z2o?Q2e$H9&@(4&}9`lIFg{;gMJCCH}*Bu%R?j|aCqsWK2VFB2DLXDGWv!K)j)^CC8 zL|8@}*s6uWVBlyU%xnCDTjd(ed~Ij4Gi44H{mXf*WUa4OPoJAtP>6LOgj5JQ($7{q zk5MyIushiY3RTtjsx+a9|NbmmL^i=)k*xc7djFP>yuN#D2i=ml7Q42ZOhyE0fuBtx-T42H9S zg%x7PMlwl999i(fZhypWVWp%OkU%10Afg-hx^~KfN5kN++(>9(A}8x2HhdV2E-gfE z&2^1lKRV?S4yT7y39iRuP=ZKwdHocAdN%}*cGbD908MAzRDZ-R%Eav7EzoMTHRgx$ z_`tdvJe=Uru7Mu3ipeKZKZNRYHgeKVeOIAw?3@G+MhTgOhp*BGtrk$#ZJ znRE_kNPn1?4Wwk)NJA(DZz~qeD=jDp=!{545GVJFeZZ2>Dmg=raw|cZEmszCGUTQq zXJeLaJdZ!(&SLp0Is_x$n^msQ5gDh4oquxZd2{5jSofyBj0cu>yK## zB1eCBX%)?jnPlB$0W4PX#Zf}=D+cc{I{_5trIRX_XoY^?Pa{L9UW_Io3bc)8(KwVv zqhJOR#25FiA+LF)ni>wzfWNQKYwKtxd|9P$)PMr)r;>{Ta*Dk-&t_u*#taEAH_K&r zx(e^gMWB{J&(Q)LQS4p(83}k4?`)B%mNS*WkeHf z9(Mt9nF1QQ1AaanId}wUMNlbd!<0iJkwT;NL!izddJO}eiXqpKzdnGEykgbTyt>V< z%X(Gv%{}YZUkyCpQ-t64d%ptPWaXFut+atytPX4DfW*hSZLfFY;KhgvWQB^U>@QaC zL#pC!?!u5mqhz2aM}*#)`HG8Tq~2ypxOdYb2S&tgMOfp`ZWHOPh{a-rg@)jn8R2Q3xm8slqxWHt**u0S~>$+TZ738OYi5LZ?msMi36N9hRM~US@ zUGFA@q*fGKBxbRCmj#dBE2}XSNTmWn@F*bQ{e7N&v&#}xe(ojW1-vu&>{Ws55}}`j z43odl#q<&S3Ih~8U(q^MXv7|6qj|g1Kxl>1Yzx04*ZeYBNall2JgLGlNjS@~hmL^r*qg6(yXmWd1!L)Q!wb7%-qfW^Q|*#c zLO@=gW5KR%{}5UiiiVAwqJ3kLKrR}EFlZjeB3#cPSXVI%-k330sIh;15kkWv>TJkQ zsnTKnQ5`;8dLD7Z8&n8sR>+_5;qu?9n29+(pTi?9i^G9r4yV(3T*&3IKiPre3p>!b zX)`Ps8;&NSHMhuFE3$DaKa%w4wJZd2c^%Sl9r0;IA$EK1Ylg<-wLvW~;`2OwKi0o$ zQ%!zr62fBB2XfM4AH=e44jegt7E3lW#2m6vDhW9eal}O+ZUQd_aRxxF5VQ(AVU<<{ zYn`q_RDcEXFJ2y{qLn^ydI9_ilc~$`T&i%sq(Wz|l|d{o#l)ei%bvaMxC0AU9)rQI zC!~-?PO%t;CMk+dELhG=@ip z=P_rUMIc#MGquP8ky@L<@2l`D$BRqkyi@5)>mAi+o9kuSd$8gGWe?JjX4;V zTx_>Hs0Vh{F-n=H0Xn>N9NWHXf%c79w`rxBdh{L<0v_9keqDmlLK-A;4a8EVQ0`KriD+vHA_C3mVcWr6toWB`uOSP6e%1t?npE_4Y5H%?PQ$VtQmC#YxGtg36B8{O9CrpQ zr#B(op**BXC-G%2k4E2#nMgW$32mFG@YEn*JQeE)l?Nf(bJ~G@=Xe}Gor`6=R1k9p z$W?lntuk~EwPDi2EYk1$phW{2dbJT@>tPd~`|tt+gRiN4w4I2>sDlv(S_$bT0r+US z8Iy*}E0~~Xd;8*(H40?s7~rD~goU^w)0UYrao!%ZY|#`6lY9x2WS}5ybwFnk1`=(b zH3}#w(F(zW%Kg)fpEI#=i$8+>MD;f1l|Cll5s6k$ZbrtsUZj66XVz3J*L@I7`e7iT z(ge*}zuEB7&$*vtg zC?7)&zm2}j?^;t*DWq7m;Sz@TZs>N2Tru4vU&+z+KPF@vwQ!K{TD2THO&eUwH{-rH z(x4|4ab#boRyPZEnt83N99dUEw;e9RXTO>d8mO)JNpcdR3cd}xV(66pST&=);6Ay+ zr&L_vuG(eCA3HB$O_E#)S&C%-2#L_S%Td{nb$!>WD6tE5UsFeo*C8f(wD8WUJJ+Pi zLg1bcMdPOr!nCoSyT5U{7wPbYan>TNQkhOKyddSs$j%36yab=-Z3ydk=FMHkGLXlA zZ^i6iQxQg7Hl+_OqZ4&cuslcLT<6@e?MmUwYZRKALo8zWB0CQ+!tz%Z$|5y>q4>|d zTzvUjc_fHtzJDjeI$vswnF)DNYke!+M?rFFbw+`iXnQKrY7Ob1C4yEr4`+qKcWlfe z?ZbIn%7*?Bu@Bm=qAU&Rp34>hX1eBJE z#>`ihk;G-Y)sUbRAt4q0aSE2nOxz@EA+cTztWcBwnSqboPSRjdViv<>v4c2RV8sg3 zh)EyK*3FPB!|)cdG3V$-bx7L~i?wdnA}LiGEcwR(txpl+pVhcs8v1wA5JH}crC74X zL|EtL+^$@!gJC9p^?%pc@$oX^rYMvcaE}G;TZZ7-STXKvCPKHCzL@qrkXyv#hrf#P z$KE{bJtref+#xXW+D5b}sPxrb7GpltDk+9^wxL7IKn&_Ct}qaAA(z9?TO3F_PFVaQ z1`?^1xQjZ$Z{|^6UX#fLi`j_Q(Gon~#Rr|5g%CfOy=>sYC5BQh)+afTaxot(b}_h^ zRSK!X7gDMB@%YLjw&xd#?Zv0hOC#ELv{>tII)_%P!)HI9Kr3R7hu-fTVy1~x4g2^- zJ-%9-f#3i|jT%Q!$)sX(1PLbkw?k@t{YN_9UBC*%lmojs1HP1qjTxvB4hr_DuWeZS z&uOT%;qcYSaHSZIs|!g_&mb8zW5Te;h=1BysqQI0jC1PGvtL+o=*UShszwO$^M%gC zh2cHY%ea_~)=hk|eP+0O4A-UAuJ9}4c^~Rah+mRPSaq;h zrpPsP77`o)Gcjkc&AfmyUn}uA(drJZoLVgm`Dqv|pCCofE3L5juOj@urvUqs#lj%E z!*ewb!wTS)78k%rDZ$|TXgZN3uVS}9O7okZ&*7JC!~`ED+IpC3s|-P5%_t0fOKC)7TL3M#kSmo zN9midYjvj=LMtFSPm7srY#8&nq=M`8`r~>`Nl*$w0j1J=H=L&7snzQat1*9L2Hu?y z%zQl*L%TWEg}O2025E&O%fREcc{Z&7eG|;KFlXLMQ(?@u;_c_!;G$I?KmnG2~!X1d``5FN{NMQQwdpWESMly0chd#mnhL`R0i_x3itSFZN#nBL3&XB z@aC5nFn&JK>P}Xojlmce>m*%tEO+I5QY4Rf5Sp^KG~}Vym@?9-Ql8qnbgKhj!BgQ}7$erGmz$F&+ic{cR7LUrdSy7lYKLv>=mBL`i zm4v3v8&lH7oVECb&1T6W_y(hnUl2+2R_F*r(4bS;HM=R=L{|)Demg!I_q~1^{(+Ii z&%C;}MV}!hS}i47O;cEZ7+AKe5O04~fZokAFnnMK^y{P~Ca-*0lSa@eXg12&O^+i$>6v#WljW>+|sb5(6QUHG`~_iFiXn!Ewrf9LAFTOAPcu{B@W%OMwfI zXn;?bB;)5P6+@Y=qgW*W)C{d(JPnDzcQYnx5}Iz287R)bgnQaXV^KUE&n=%KZ@40c5SuifBNaC z3gEkxedNRbSeBTK)FNGt>!|2N(6pS4^8&>c741pkTcc4?WiHvl0?fdzU~6@Ru54w;ItfREFWPEMnWW66RHT4#y>(=Fl?IIna@G zmP1q^g8+>)8Z}{n1pnzDg$+p@b{x*d(rt{us3i(Lq!Ok|u+T99*Y6EZeDBK-E}wv+hqr%c3l?}`m^GNF)cy48*#Ks;=T?EN`e>D-+}n(GlA*HD;nA|;xHbP0 z0#r!j!CGiSI=EXqqX>m2JR18?6(jiRLiBEJ!ToLgG3b7UFm6rL82^M*tAF3eVd0-9 z96K*^oA^=_hhe>x?nwvU3e{XsaLdcZ2tY4gy0k`c-PezQwB^!hCYyRg^;QIg#iMM&KZR*wRtp~ zGObaTO`P79qQ>9H&3J!N7JPlR82Nw*{q9wxWdth(RK8kmgh-?oZllDks2~H=hd1)N z-0A7*c;%H>ux{PDD$l#Xee%gCy-LqTQm2gwLc5Vi2-|P!$=Z2RFRbn2>Yci_Z6Quw zw1{@q=d&`hk0}+p)<*O7T>(wqkNN8^3K1=5Zp+Q-wC6O~ep#vFX~asy$s%UfGl9k?vZ3XJ){fdgnuz^IMTXVVyc=Z?*A>|C)h zp6n96uY%1xbvDUx@St;#j(~sw?D_lq@0xah`wOG_`maD!=|Z6Fe+~z}jz+UE)*Y)B z7JiM0M$DTB@W8#HhOLPPQ8vSiE~Tkbm1 zr*>+}!nCo2a9w2rvuv9kBR)+dm8?N{uufp$HoJfM1vTWFVaw+{QFouX&Q~0eP|9WC zWaZ&O8cw{wxkdQwO{A(ap>pS?tk1m~&8?UY5av(Z&;Sui?an-j30u@Ftp?M@O@~c! zaZU}^efcG0Abcb{{p>#QQC;d|jW9K}zwA=tuJv|dGM>A__=>u={Wyn3f7`L=SQgYw zHaav7DGSyYdHpP!ww5U(&kPd2`zcL`&=ir%sD7S<)1Q#yOqO$v6qQ0FaCal8DZCQ6 z-Vmy50awUl8L8~q%7)(#K&Tf#4a==wm9Rjk)0qwN@nxH^=yW^`2BtLm=N0m1?{_g< z>u0)zFL9lwe47G|#2?Q-;3xc6VSO(-y0&16PfPpXh_d5qCCIJduRa=tS01hYO4oIJ z&TxnweH`kDMna>b^Te7r2(QsKs%t`3lep?CBFqn_e;st%lS9hd^Rl;&n2xY80<58I zBec|1`aVL@t|NbJ?sQKaE_(OQrE3;iX}rlK+^YkT-D6zJj z?b{7#6cXvwoN59L-V!SMnZ3r1KwNbd>PKMYN=WxBhbcXAJ8ZU+C~`WLRH=JCaAHi1 z9f|QLU^f!)UK)ma+D4dagTD_eOir8l^v$z(q!7#?gict_O1llA`{3Nsud1XrgeosD z5A){DyDSz>g{~u}69&eO8wV9})iT#d#4;5=PRJnu*V%leIuT)%i}CEIc|yFZx{kw?DO2## zM;~2wt~x^X#v5;7`SRt}KARFWA0O}5tI)6{!*I;q(PAWh_45V{9?T*kq2gYZf{^~> zqIlEly9N#)aVpKk(U;46^@KVQjaCoMz-+wGi@0q%;)dMd?N4Ys+m|ARN-3_ee@9h| zKq!b~$BxC09Xqh4(wjl6B2;td&UJ%ZSv%?VKm70mh7B9$bzUi94b-vxj?JqU*k#sB zo^N2O2ymM=eEOE3e{a(LosC+bW_^lE>u+u<9d+{eRb%x&+%)?}QX=JwZ#!pRh>%gh z3o}PNg@WYk>x+N>`3F6E^r!%`C!xy8$+=8(J!8={Ou2gXYD7kQKe8sw_{<|FgtMPJ zmM~zn@H!-q=T`)no`{WgY*~2UOa0z4oI74h?GsGDicw>YrnnW3dP76PK#DO^S`>N)o^Q+iZy2s#XScD>mLF zo#KraQhn_G=!ILh<0w6vj9<1@O;~fOR5H# zzI!Jo#=Pm%h=+QNOG_#))i*;uGU}UEsL!5XSc;#wXz^6{nu&r7z-OL$1`8G}sFGb% znK^SNA|fL2;)^eOH4)E!f7#!U=WSelcK5g6fxb?s3aNhMv)EXkQTz z$u4>O?Y9L|*1mmvZ_?rkxXkpAKK?)Q)fO;!E?-@Ax#q14k00l`*jR)82?%a1A4t4pZ!{h7y8!jjV(24a&d7n1`ZsEl$4Y!rbE&YW+YFU^xpqXojR2v zN3~I*EALH7`s2Ool(`R$AOGap3`s+iwSN8Ln^9;Wrnm(7eQzoHc2reZ4tgc2Nt06v zNs5k+7F?_vh7u{5`8|5{c!2yZsR>*v-fTX~+x?l$weM>>^d5U+>ltgrUCb4?`nvr^ z>7&Jn&vUV0j2w@2s{X|vRSDH(3i8&iTQ8ecnU-m0<40tm! zG5avQSY_(n?y^qb*qHR!{P$y@{$kC+)1};<*S!;v)p`tmClQ;Gcfsp3&tb;@w|6BlQCwm8pV@`wl;v1pDHN(rQ^hu^Qnf0w)~lMT z@t{$gdbCiFG_58oZB0dJ;#EYXUJy&Q)}qCF#0!t=Rs^dEg32lp5d}rq<&brk-PxJ< zI&a3cs9;=O4wWz23}jw*HuJszz4!m`|Gzh@8;tDr^du7!V`5@jydNDMEm&?7>qW;e zApGsT&*y^;_2ExXu(%B8&hA~bWRRj)PmIIIQ7@qUzr8_xV?7lF6Bgz`a?A%1J^aZ> z`B?D?c`d^FUFq2XQzs6c&Q)cffL0;+{_}WCrvF|0T}=O(*@MdNAn(qhS|lN$YZxp{ zt${{^BYZv1^C8VETlcuFq>^i135Qqg!APCCJ(;UIu^k|SZ_&J~)f{Xkm{>9jm^Q6c zlRj+1;5jGuuR&wt z>(89K$~X#T^PK<(nF}bK0Cwd9r0p*Re}5(H|ItqnFK_M*H8pM`ld|@J1(yGDhxdyc zAuuQig6a}CoH&;7lhD*gatWS^;QPP~W4LsFSJbTD<2U_MaLs~v|FDx}5QkP$toB-P zcj4IAi21hxNj%}*Ks|I1MBpcvf&&SO@%Bn2DJp9%P*fp>%eSQ9L>Yod-6*d8ytm~A0!~+B;!ewiM3P}cRl!z zsOH01#5RsR&qSz&+!v2Bb|Fdmc-#PIZq=NLlMqu+62PB1f9ZJ%Ccws9>Vt*5qhZ{X zrMjHF668x!QhR>?OAUW-39dR97ppnEj4Y^#aoA;l*4_jlQ1!ccY~8StJtNcCF|^+R zT|Ig{H?$KEKvTTs21s$GW>1o)I6V=>1(n@4-|cTfUT%3(l@u*N20zd%iFdcA|nBc$wKw%!;iM0br(TeElH-wW`N5% zX(Psa^eEGQPF*rPy?QZhjJ!RhRCo_sm$G=s$i~|zNkuP)jEq)&YFn*xSqKTC zYV($)?X1W=*DrGIde-fozLhoPbWQ3d-*&{v(_I3-T`bktPOn*;l>GhAz_NNF3$mFs zS9_!F+!!%w0GnowxS);;3-?u}%pEpn#**ACtQ*5(^b!U~_?0E%l-`a~sUd&Y;rM=2 zfRvVqTSaX`EW5dS+tArHu!}!Xsx$-<&z6w$W92&&a}k`G^#meQg6R(;HZ87WfN5Ha`OKzm}h4u?t;Of=V~===ULFoz>kL3Q++!&uRED>UWn-&OtyChRJl$#R?7(Rax70b6r;cal zr|dn#$n<5rwTihok5u`!7di&P1Y$2oR=2_AsmsgzYxY@y+2E=SkMJJ4ZQkH8<*>49 ziA$x<42*?kg?$;S)yrG?E`>;jAx#wI0)1)9+m)%=x9{Mln!hJ6V_DN(;rXI$!h=z% zqoCsu{3tXUj(=$sd1(ee{Yk^t*H8YQq44wR9;pfl^y};DGrXspBD9Btqs-S}2HI$% zz|0_uv2g##avzR?H`fV7GOWqTg6)x0*d*9l27=Z!|EEQ-Z@A7?9?Ge^T9kX~dg1xT zilZ0ha(N>g=+8HDp+KR)R!xkKhK@@xfmLgwpg_2Aqg7Q^8AUs)JTyDxS*xk~`g%k= zxckVI1ABP-cMq1kIR-ns`h;MoU|)+<*C5UzK+YoC9ZB7tc`8W?h4lb1(g9fB{>?O7 z(;(q$?@C#%PHNFsW5cydeM5awxwiVIS(kU6sVyq!+Zu_mXMMp~42lAZ#Egl^7}25X a==cu|HXQ^Ofl^Qa0000dqZT z4;_tXFG7g+?a4wIar05`dch2y+ql z7O#3pNdZ)pwvMnK4JSu>Z@(N8b`AjcUV;u9`~PmEh2XB%@nv@`sy?DSOdT#qA1pSb z;Hi;?f_WmV4gKJVqe7A-ZpPpidPFw~_N)qcxy?1~H!Gu-u)O(NuuUTP4RLvZcL;nM z2)tYu!t+BTLr|X?qFwL~-zMT_>WJZ`@*EJC8T$CJ%A(rlHHD@)FbWv73&cjA5j@8lt2qp+N4E$MM|X+M8LiwLP+8cJFEP zwFp1@A(FUmujB}9rbNEzjxs?;di?A`WFMwVMtH8mP+BbT)rDOlmSusI#p2+w<6h=6 z-I>ipeYb;udZzY5xVY!y`7AfSu*$XROa4{@1CON=*1*%#8o6l5;Cy|^dk=A}nxT#_ z%)M-J9~Fd5#dL_9?TeoWug?lGci9%F_%O3L0dih}o1hdUnT@Nbp{p~YtODOCjzV16 zypt3{5{qtLx(acGiAd-LomRXj;%fKDa&}er+(bmxzt#On`lNdjrT8r|rH^ko|6Jhw z+3Z(z{F>9-25rKBbKq)%YY}zKq{(&Y%KDi_I)lnx?3rHHl#QuGP-E?3H2{ee}dDotzvV zr^D3kZgvK27D=XAk{qe0Y(*yCXwrZNaB*w|Mf>>feR}h;YhuAC;x|0KV)!=2e8ej8 za+RUI|YUamh+xwjy9M(KL<2D9v9DVF?WCdcvq*c#zF*s(Tuxt9C9w4q5e33jz!$IN(i^C5B*f0nc~@jNfFstbYUaMAr0q_22<*!}7^X zfGr@6vg)_7ZueHn^)6N4ygtG6E8&#KPa4B1idxOEdG@?p)u|HEG5RsRu|r)|;x{#d z^pU17d}j>X)h+tHa6U?f^Bgp&9sTeW;(4;0q@?-&wlUB zWf*Q#<3@RiE(lM_g-BLsbDED31`k&y6QdUNex<5>kX<49J?6|_=hvFq%M|S{w;bMD zepl&s9}6_YY|ng$EBe-bX=r&n4ezQ+pK1OT&4=^ikLa-YS~tzKK{^+4$ylXXVC8&=+!&r`Fx3R#k1UA zTx|Ijw#$DqPZ}Zjok3 zdY!A1czX2c)Whv@A{vSJZP)S=Kh^CuQk1D@ew8t!aVLGW&dsMl?s54=z7JHH;#;4q zD3*bckAFF3enM+)l2@6YpzxBu!|!h+oTeJS(`K{i(vhK{q$3-;??b*oGi0Sbads^U zu^3T92uL`7dE2(@VrOQ-{gU}RI-ayxoT2X8FQQ1?r_BSQqEfIsU>AhTS{%EX>ywg!U@swYts%5f_#9L*EEF&pd z=5?h#t3Wre4@p3@)6(0$UEdhjGmL^{~ZT6&v2z@%OYJle}UB@&XrmYYDam`0>>YcyvCPiom@--Crso!{xrN4Ef}+Zc0nAbU(z!qh>}j(IsJ|K&{id^?opg zRI}%|k&6Y_kdI$C4Cg3)0t;31`qd26yU_l!&jFBUUt3i4HVhiVaC@GD+KlJsLZT&} z)?yO(waY5u=BJ_U6Kf)**B^uf4gLyfsS&W0AkT*n4AbxfDu=;oeW?MH2OHGErp=rr zGUUEvM`h-mln4CbOP`7iI13cn=5SdChGSzm@Rbr>_l?koZGRoJ9kTL0xW#7YBF(r4 zqkM0^)rj(NE1h|d>84qRh2-77?T@u>>^qAlP9hp-pAb#b-HUft80!I;O46y_F^?k8 zf6LpgY|j_&t!X2Fd#5hp=HL!ldlv!W>6l+_g^pmKX{~cY0&oQqt#!!cA+&=7S;D;R z?H28``Ux$NYA`Sy3uhZ?s(xkG$IV4km~u4kc@nH+L(6d%jx9}DPr=Q$K=Szt)wA%2 z3yooczu80Up3yV;93h2of2#i(trhUr9F)&~jpg$HBWew@k^x#DpW0hsl+_XKzanmm zKZ{gsxkl6*mmLwxn3op~d6G&7zAS>fEU{_hWx_a>gHZw8)!85WLk2ONzsCN{<~?-Oisv+d@b`3kCqZ1cGD=gs=T zQ&j^$m0xI^OQ1V7al}oiW7;?RBsDAL{p*yn+MYCWQ<*}Vg;H^_;LMzmH=I*M`tJwB!ynnQz(UEQE$)nPJlp=Yyp9-s2wJEj z;EJv)yJfAAOf;u!q-vlp*LpH^%_0fz{{f(Ba8RnA@EvIm+*|2Z*$xH3Hb*jv2HS{b z!u+J#yNeitlV?93YTz0o9CnyYoq>zn;nvg{*`HA>`Q>3rf8O+omD?*-5!Ya@+c^8_gb*#ALLOsKS;7+DeDc-u!&4w9pqH z9myXjBShMMRG9twq$f(R)a-!&=}u-1i+}OMK0v~XSZ|uymy9w1Z7WAMSo8M&0?nn9 zV=muMJkd4%RTR3sr+Ty7H#H-+lHZ`g$BxQvA-2}sOx7Oi5leEUgSv1uP>FPWNtFT!Vlim*~ z7G{Q-zYL4KIqfka5BL$X(*Z?6?Ka4X!Q3kDHDzLIf|~!ECL2V&q%V1PEKOm+c%wV@ zXyfB&%f!WlgZU;sevq`Z^!6W{CQrwmsgIQ}zL0mQ?*bD_p;_u}pWCPp zP~72vImsYXUwhXJ)*Q&nmqP|My}$dWPqW#LfTSe?eKJx zr+;#rDJmk6kSFg_sc$w?`Al&>fu2LbxOk-NO3JO&Wg2y zMu2irm;Es~W(K-_!a@v~nOuaaI~~_nM;cTWSIkL<7`{Aa?hN=*qIFr|Czl}nC~a4L z{|T@l7={|jdK9ONwg^i5z7b|(UmPSqo9baZ@l3Rg39*tYqz+uS6 z1c%Sw00Wy)bq)bX==P%vvIZ9#&O_{Cc6F#&i8vL9V$H30!#xzkXfixwadDM2JpTgH z)o-s}$}l#2o$z|i%#H=8@>dKF|4N!&aXqFet`^5Pse4eQ6fP0GH=EKO*+&g>I9kQh zoi*qmf5)Tl!&%KNgI&43;tg4BknSDaPt(G8odx7F9Q4%bnpM&Ff3gCDqP z!y-Gw&StJPDL#v~o=Txu;5d7d>4zBUYvMS)QboIzRSA&`C`U84R3hxuV{f+ZZa&EO z2PdA&+y^SZlgiw-v$JDW??OJ331s$H5wE1YfhXu%QemlnMD0cj{EaX1WCx1B-?OumR$|R@(l@u+95MiPEQLbg>`lWgs%0*c}#zz zu5V}vii^?EM$wWX@<;|r2~wr%rQ~jxeDXlxE`3{Kn%%ux&V@qOu%%obzl>S5rPlSm zP)HwNfb-r$i@0Oj=xja2HU*~XR*%vWSphg&9S+rU$wOVVp{yLj{ko|6;{DKCLm6@e zyUl`{!D*1swx5*z0UXTl1Fxp+2Z?)1%8XA{@4Ds>jI(R9MNk1`dBgJnAN_?3h4m*xNnWCW)1R3 zidSoB(iowTUaDE!s@Wi3@TKqWu(&>);r>cT&vJo~^9)F8&jN(Zpql|5oa6^~GL95= zlytf#KpM9MRHA&TrO3s&(N|lyL|RKirCO?8yq(P-giU-WLFBS>`fzHRbcdKezS&iY d|EvASH4Z#|KEv|B_P^`#j*h0G21?BV{y!8wN!$Pc diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png index b51e00a7e59da211b022b622a91217b0dab107fb..afe8e2c6d2e4b798c4a3eae230742db063830a26 100644 GIT binary patch literal 19832 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 literal 8289 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 diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png index 8c4973081f22d5f81b781442cb0eb6b18514317a..3909a483d707efe6902c05154f05975bd33e0811 100644 GIT binary patch literal 6398 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 diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png index c59c5739cdf36e1185d8a74be7e78ddfee41238e..46f6a20573a1afcd0efbc500fe25c1b63afe4e89 100644 GIT binary patch literal 16364 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

wfbU}SOG#?y4 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.2.2 <3.0.0" @@ -22,7 +22,7 @@ dev_dependencies: sdk: flutter flutter_driver: sdk: flutter - flutter_launcher_icons: ^0.8.0 + flutter_launcher_icons: ^0.8.1 test: any flutter: From 18b4598147eb5506ed24c61f7ce0da512079c413 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Thu, 31 Dec 2020 15:06:45 +0100 Subject: [PATCH 0716/1140] fix theme setting --- example/lib/advanced_options_page.dart | 3 +-- example/pubspec.yaml | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/example/lib/advanced_options_page.dart b/example/lib/advanced_options_page.dart index 483e0902..e24bd5da 100644 --- a/example/lib/advanced_options_page.dart +++ b/example/lib/advanced_options_page.dart @@ -350,8 +350,7 @@ class _AdvancedOptionsPageState extends State { return MaterialApp( theme: ThemeData.light(), darkTheme: ThemeData.dark(), - //TODO change to system once dark theme is implemented - themeMode: ThemeMode.light, + themeMode: ThemeMode.system, builder: (context, widget) { return StreamChat( child: widget, diff --git a/example/pubspec.yaml b/example/pubspec.yaml index ff13bc4e..b121751c 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -1,6 +1,6 @@ name: example description: A new Flutter project. -version: 1.0.103+106 +version: 1.0.104+107 environment: sdk: ">=2.2.2 <3.0.0" From 7678a91cd7b26de49fae79d3131c6a7b27133fd4 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Thu, 31 Dec 2020 15:37:07 +0100 Subject: [PATCH 0717/1140] update ios icon --- example/assets/{icon.png => android_icon.png} | Bin example/assets/ios_icon.png | Bin 0 -> 40617 bytes .../Icon-App-1024x1024@1x.png | Bin 331443 -> 52126 bytes .../AppIcon.appiconset/Icon-App-20x20@1x.png | Bin 1055 -> 572 bytes .../AppIcon.appiconset/Icon-App-20x20@2x.png | Bin 2712 -> 1472 bytes .../AppIcon.appiconset/Icon-App-20x20@3x.png | Bin 4674 -> 2358 bytes .../AppIcon.appiconset/Icon-App-29x29@1x.png | Bin 1783 -> 990 bytes .../AppIcon.appiconset/Icon-App-29x29@2x.png | Bin 4491 -> 2338 bytes .../AppIcon.appiconset/Icon-App-29x29@3x.png | Bin 7741 -> 3744 bytes .../AppIcon.appiconset/Icon-App-40x40@1x.png | Bin 2712 -> 1472 bytes .../AppIcon.appiconset/Icon-App-40x40@2x.png | Bin 6909 -> 3342 bytes .../AppIcon.appiconset/Icon-App-40x40@3x.png | Bin 11924 -> 5281 bytes .../AppIcon.appiconset/Icon-App-60x60@2x.png | Bin 11924 -> 5281 bytes .../AppIcon.appiconset/Icon-App-60x60@3x.png | Bin 19832 -> 8289 bytes .../AppIcon.appiconset/Icon-App-76x76@1x.png | Bin 6398 -> 3132 bytes .../AppIcon.appiconset/Icon-App-76x76@2x.png | Bin 16364 -> 6964 bytes .../Icon-App-83.5x83.5@2x.png | Bin 18363 -> 7597 bytes example/pubspec.yaml | 5 +++-- 18 files changed, 3 insertions(+), 2 deletions(-) rename example/assets/{icon.png => android_icon.png} (100%) create mode 100644 example/assets/ios_icon.png diff --git a/example/assets/icon.png b/example/assets/android_icon.png similarity index 100% rename from example/assets/icon.png rename to example/assets/android_icon.png diff --git a/example/assets/ios_icon.png b/example/assets/ios_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..314eb1db06c8771bc18c08234ab84940adfb033a GIT binary patch literal 40617 zcmeEt_aoK)`~M3?DM=aGIx2(|AtNKJvJxe`>@CS2hlY%-3dydJ9kMcx$~ef%p2wDT zj(v$*elXsOZBve7~iM0e|^@?8iz1pask zIzkOTkeq_gA&3XMrL3sum9#YK8*Mu0&%H%pN?pI?0=YK*36@T%cruweRd!b_oyw;lVjv|ra41>J6By!E&d zehzx}Sy6#ULFh=#A&N1`yu-ZmPylhN;TccEu}e6tH)h?hRxI__g}3P*9lnpZWHIz}LM1`TNkj&orbTrLa_)GQ{ zvI!K}r~?93MTj$>o={RibR7-Wb;V4*b(PwgSGO^5BR`cco{>RtUtb8|5+?~|i|Iu`&d>YSWC&JvS9!dZ?%et$$o zKDLhY&`@z&c`!|d8{~!{!}s9$hI)Ip3{FZamdRD@yZPj-45w}7X@8f-H<~kKEL4}F z3(gj9&wlY^AJVIlhQu<9BbOl7YNxCzA%$arKq?&j?xD$G&{SZ+Nzl%6S{{y}Px{6O zLEp{*LiX+bVn0*N=(eT6bMpLj4Gk~1Y{nrdkohC9II}47b4cFQOE1TMz3jsZ%F6jJ zLPNnVs0&bC18k7+2VZO93pox-7;FuY{fgU1T}Ox33hAJg9r$vT%+CCX#UXB^a>0Wuo}l&T4cpr$i$&00!olRipbXUmIxdVQcE8!c@ba(J;7bswtB zf-iU4NZJs%Tx;abx2mj7n5FH3^Stjp}pyDPxOYAT% zHN2dR7CW&ZqEkUlg#xHvGJ_ zO0e3uF%{n@lcV5_D)2$A+aELRZ!D=&9(+=9yM3t8%8G93WcFGVCBrOkChk< z=4uCuor;&P_$sacjm$>hm*ZYnYe6+a(eNAIIj%M$*04&h_+Pzj1Z|tvvSze2zVX@S zjF|&;GXccN?Qc)Ng;e9b{N@vptoIeh9nyZ z%7%S@bSOCN%VtFEbuN+f-nbuVnx`m^_+~5|n5X5sH zy!gFJf1x0vYPGqz38NX4xA^kCm@&zQ63PY~piU@3{;qQ0>J8a4hn%G%Pu=P5=8_m; z`MJ!jQbL>Y%BRSlm_S0Pja z>0$7Zx+4w@Vf!@~wjZ~EFURPgW@(Rx zQU_opinQBs04lfzhokkE1$+s{p_YX?9o>zF{w!2dEr{Q85ek%`m3fWZ0l#yMUji_rw$&j112 z`v1jR)Z3fGD^AW<;vP$wKoj~VtOY2Y;eI<^93-O{%V zpoB9-1we@!lr{(=VBAgUfthk&rAV2h*tSdKQ=|g`sDAV2%rzVnWNQs>w|zWZf)Rcy zf0&MxD1{>QuA=uap&5}hhXS=>3uzZw>N0rax*iahLyMcrpD;B0o=}$ax;O-KWhE4x zV&&+NS~v(A<>3z?T^(jl-Cbl4FH2v;aYMGM@Hf2Q>O!pj(2c=!3Hizj#>eEjc^a3O z5%!KiA0l7_-uXAgT=R^rBa^SO4{B;RRL890_#oR0umkGuDXH}AM!mZp94q+SqAC-y z=yev{oSZ@#Xq^s@=mr;_!Xe$QfqQK4goiKi0-Qc3`3~tqp&$k)&~&%vs-(72s8g{%q~J?E~>y{V5ys9aKI(|PDKS=GuZOFXU+59pn4AEg2JEwlmK>u zzLe81K2RlDmv2MRsZ1bb7=%kQgZ$$#Ba#3l=_b7F*=_vj^o6i@0&4jPett_GSZOb^ zDIUim;%hwANhl#NKGh}TTeSL$!~hQ<5osVRaN6i3*jxapB>X-ut=cNBN6262EKM|X z`HL*^SYKR?kk7w=G};pvUioVV^9s5=3|w$715gdW$Dkg(YT`@7(jN>5pnU!W4?U_Bj~*Vh~A5KFi?+uD%u@BZ51WR{$Us=&$+X} zn_6M*Uq%}Uj&no#%iQBD^zM zv?+lelvRen)a?6K(2=i>R1`&87x1gzZU0Z-4>C_^uye$nVXm*k z16XAJ6}yleC_8jSjIbEJ>}mjjTDf&YDg{Bn0q(GJWADn}-#SyAK6u^ZLUC-B1!>Mt z&_oq}u#%Tqf9dt8g$>&-%ETHwv^7`)NE06-8hb#hp@Sj-RY*HEdx9m#6DR2Vdtk-5rG3MS8ETc#FA1!i=mQ8ew)^rl z%fWkXz1P*kU=k69eSgundY}^|)}?vJ-Qr_`^zjcl?EiM$@fZr$R+f9b_EDY&vb_(C zZa8$1%@(a?3rou2PPrQ$H=idAf|SF^3dNz~wuO zGo#Xn4bv_DA`rEHHm(NU?TP98mOh`jPlAJR8do=L1Y`hiS8SasJPchu4Z=y-4rVpI zucmS_g?&8h2l%pGERo_62S*434j`NyV>vO+Fjd&QIn6mnROp@#gLGiaiXsGWzj@SW^{EV&*kTGt9rW8T8 z2NFgH-n~ll(s!4z9VuRJ31fr!;q;8t={1>6z5et9Xd5iX(6J_|)B=vDt1Z)GmSD#R4cY0x)Gd z;$VvwCRIauY)@5aP>+P7gDTFzH@m?^6U`8D-LxR#7>M*-gK=PV_MN(Bb?E|zeOOGJ zhijY>Nh2dOT1^>nH5IvQV_$z*l(0aX=Q*+vxa$L*sYOdycij#JCIA>s%NB+US`i5jWuNTD6!b~f8FxieD!K+_S35gXgao@AFG@$|g ze%6$we|&QI&X^kyU;uR2u?*0qc<@Dk+Bh#EaAW#g5Ap%jbB6gn_UofY=9@xEW|V*2 z($Y~%g9&Y?jzDs7;NI1Ap~U}|ZKd$(CX*Jyp|kSm7Qn-TFHc`XUG3D2DxB z3ODwxTn^&0`~8%*c$;L!JrOA9`-^jn1A|xl&ji|o2KVx(*$76sD*|NCXzN;Tx}6c| zUxQ9-ifx;fRqpPmM&iv{Cdm=Qe9d#~SpO@Y6@O-PS&OFr>VWzep}(7kIX1L^p{qHK zTHRA2u#i7vB?C|)Lv1c9V{Vs=nL1SaR?RJ8)r$CJdekBYU(M!?V~@etFnN#{RFIsS7^!4>N5lrx0;hqbZiR#C}pDTd^jik!pk_S&WUcyZ8D0@Ij!EHr6E3R0v| z4ylO*@L(jKVsUohZTK2i?~cVy{1R4a6Ti`36XRZea&V1Pr)s9=%cviLAhUWyGxJ=+1VAi)#mM~SA0{Eue6%bsB4^NgqkQ8nyLl*JfPF%OMkf*81{vp)by!O zQo`+1`Ww*pI3y@OXgOT>3O}A6Od?rj-D}~y+0aC@){V>J=0=;9WRf&mKzBVx_L%l> z60zqY<7;*5BaFh%kmjq1mv7`VdxRVPj4>Ro>^lTbFQ#fK~2s4iH=G zEv$EUV4}#@h0fV`1%H$qFx@n_OMJTQyQxvVmN^OKq=jK>Rh6f&(*Oaf_tbN;Rbux( z<1u~qM06+^kSdUr_4ptfcB7LhGhycO(n1QRUu<0?D$6 zI;x=%SrbA>UVA!17!9q!$21SD{c7IsYH#I6OCkUt3o|4O!c7lo_TzSjRV@UdQ&&AJ zU>yw>Z%WA1b_$F%oyPxAy}ho^6~K}K*C{t#NPN=+bAl|%bU$9|THRz#{-{)0_Q5q9 zbJNo<3P-If^Md>^Mw^~LQu-Hkr$so>gX;um56^d#PSZZhOSj@X>)@f{YM( zNtxyhN<6Gf4b$i7QvRdK*bVXWPuyP0Eidfxt64K-IN)$zyfuH#4H;T8kctGboGaB<$Vcyug4@FTRnFIkxEO<~`} zRkkT(hx)$bFW7BYb1u?NCyKx*(pRZ{H2UOW13)@BW68n;)AnCgJLu3zxABO z8ON5sLThC7qO9&gem(!uNG?6{9KO)8j8Bd9+l+}zOupez`7Vf{=9!0j%!Aw>QT3!= zYfGsr>s5zl%-I;BqZQVg;*xVY_Hwz`wmVSw<;Sch+)?6X!LYONYqb}rZ{y>xT#qdh1I^&zpT#^T2xSWs$TgcuAa&8zT(X)C zHfl0*M$)#p3fQ2{HoDvdJz$iuSHjg33X{TSJbS^hrqa7to9MM0{iC!Sd9{6Xelq>L z3!vSA9KtJV=wp04^N#?vl)b`EI5?rs?6^|ti!bXPJDv+5Q zMu+)80#zqXj(hpX4+r5v=S`X{y!LSDPuFf&x>;?BxFiEHZ#sAD8$oN4Hc(r_rlOXt z8T&`V5AL;7YC_+~1QCvNUFXYBV0X?JY3APxu(1|^E;_TEp{0W&bnxmF9^w*Fh%9$ zZAPdV9mWp7JA+m);WOLphxtD_|FRn+#N;tLv{18jbA7sJKIFL?6HWH^W04poD~u1F zc0TUT^z*6MiY!Jb6-hr=L&NUl59*8}d&HVXK{qU|L+BL4|P-Qhbr%@NAE5)p-I8%As?HE^0yfZKQ2~H~xY70nuD|vZkHs%J! z%8s`=`KgirGHTQ8h#qiOmxGqKi_F(MSie>TxQu&sXK|MP)f>N}Qe@<#^_Dw$7_XEDUT?8V!{sN8{2-13YfVu|oeifIxm$o$b>gK!-hj9Wd z6bO1Wmb}W@eCFHn>uroDcg~28J#Aok$v+%zZeqcY_#ISwkb6d?Ga@$V@T+QT*qSS- zm)Z>z-N3W9pa2%fcEl4$PTI}?wsd{G{9#vp=_eg`98KE;4!zamn;}3G16tCEQL~FW z6BO@-^u$Kw4+C%**?Jy|uA*=F_(nZYT}o+8!Su7#x;Cl28z_hTL<7w!`1PRkU02nP z1+Tv)nySx1NJbjhyAT2xN)s_*)pHLm1yhK&uASHKo9PbisS>R!K2N5}T^nLCx_I?k zScunnD4ut5KzGnZoDqt*Cf%&LOkOQmSc>n)^T9%QS2SJqB`Y3sR|NL>w2I+%ZPe2X zpf)_9zN1JRNDFFAy(Fo3zBrW~@#LtKyYys6e@A^xd3$53yf_p7x?D-akC!t)Hja@t zT1h|Mx+KVHy>{m%V6jvTZ;TsQL`3<5m5bzMOh5o}s6+ATqFh6R*(C?2^n z@{(%j7x!pUKtloA_k^m`-{kk?SluE*!LF*Or|eT{()L6%sGql}yknTP%hoDegkzN` z?nuExYK=?1f0X`WgNd@7RJ`y+~p#sw~oa4XYWo>QVY^z@%0Olr5- zEsDq91x7|d%B)K7&tC$=oyDpiJj%^Lt;6J6G;(@Ads}-?E+o`GpZZix$1QN6+wrs6 zAbx(s{Q7^ zT=$>a`&*ffgY%TAtZXRGPM!lX5gAYN%Pa!9Q(~#>KXr+L0W@~|V$|C+1d-u9sNyc* zeEv@Xk8}Ae&d6ZbkVj_80<)`oyCn&Y;0hWw(6+%~$1#SOKivn740|!VPwpM)>MYI{ zi~)Uc`D1ct5Qz9U$Za*1Q>}A%KS5vK?{Yz}CTApiBg!qgLYx5N&)}*nkm=kOWMk zdU*Cb;>~>z4%yRy$C=w968~l@Q`}L6#n${0lPx#!*nKdgx*d@Jk@DeefkR(WNqYZ1 z< zrMPuIM~mW)&bn$CS~^u^Z}2QabgJ2xUKQ57HFfo%-)a9R(5Cn6D}Nqb`;-hcHp0jT zISja~=Z{+!1pkHhaF~qc-ubR)= z_osn%BwSMA!KT+)co?(ijX?Z~b{qwxmN`=q{!|5u%fA1N80bm$cV!r|Ro8mu!*g8( z$U7~+??UGuwtuCgQ2ET}?KlTZ%H?9KS>U7vJG`3~p4`Jyy`2u15Te7Ca}&*IUsLf- zc?#OVLmD_^f?)aJx0}j_GT!*w_YM{x!Jy&2zuT*DbQNA=<3o7JZ|gBHyd!}44+il^ z4l4jQF9g&x%bbrP-yHvuS5vdvG$`&w{@X6NvoIv&_fQ95rBVTTx&iC`qZ{4DsaHT+ zBmrR?l+nn&Jr3HyC;J1hNHtJel?rP@&>A-5G5}F)=5Y=;7@^S0-8e9<5s4?}F)&pA zJ)qGuGt&rus70)1qyUT?l?qYdshQfQec6H184U~ zul=M7Ksc4;0a&Qk#~|%MpRf>I$QVOk&C<$2$B)pAt15$KsD4-Fctwg%S-__{%6!L< zX5m6^u3Pq}16t?RhZ%SQh`+#oezJxkb^{5gJUQp>wZo8W+Xo;e6}}^C*oP8ku-RUlPFA64jnA;2SA4dM zNxp*#YMVRIo7i?MLvGdsKz~Q%{iXpANxkuB*%v=T<0FF&{w@viwRZA>9jy~nHj^px zsjtm;_sBMcHu6F(y2|WznLDn51z8w^TzRE(+}{O(^|uto`ud5&t>3k^zCo|~O)=M& z>~KVCf*}U%Pc-=px&mpfE&E{90@_zPqN8%oJ5Z=e-L>?SF`zf7ZQ`4X;!b&u@n3nG zx5LdhSx)*AlB=erGFBoVFfU1VBD9GRc}R&eO;Z!8Ll#r!Z$~$DTNgvD5}BYRm}A58 z63$hI+00Q3#qB!P7mD^Ziv(tb2fIKVf|oF=@wQ-HM0L!ce+?VY3n~$qoGy~dJ||R{ zXUiwywj8w{6~3J>e{qtzA?RFE*~Do;ORjFaK!+99_ZJI*Oyq!Z{yWF}$B{Ml^%)tD z3uWY9J$ML<9W&)d)05Y`U8mv@q%p}b&{50UmshiZ1{-dr4d%vREdUHFcK38~U1;B^ z-c5omIKWgq=?608uo-LAuO|ORWOlPYS*V~kgD}U_rbtoe4G+w5V@6wIIp^2sv^5*R zTxt~^hYP8mn{(Y1-Xt;sy~CyKn$v3I?&=)?ycHgr#EkDwUjh(H04!@{|9Xpq8s2*G zgsJy>-u&Y~cXtj1TrB@bY8~im`93m6HP(4L)(WDR-8 z!2uI`)DZM8(U+@?s|ZYF+FbtWG80dGS;mPDQ|-*- z$5KS$^{3J&IME728Wf#u|Cwj*+}FJ% zmw!1LrKc{@i_rnI2+-ZJ0=?tslOF0!2`?c)y+~qFvmmoruCaYxg%32TkK>2&0A#KO z_AxQaG$D1J&P<2nrj+*qd9@Jx$eIS(f{FJ2^hSP6ytlJM{e%2H4zyWV#;48HD?qRW z0gsmUY%*#28a$`(%pT=8{(|VfeV7)K>ne?;PAVGNC5C>XA9FX=?t>>;C>XSBh1K(8siAOj z1D$N#z$%zs`+bB%xM;Ho5>w>fs2Y;>TN?ERV*AjReNlQmZ? znR_|O6tS{DQw6%L8KP5&k*4?7KRZZSV56h+!@)9&_=cOhI878AI^M}g300OpIf5CR zn;eePX#CuJspL)dTp%xbTLajqdvh@it&bDgGl@9%)Hm*kGB-kSkHWuX%;%wWqL z_I&pCK?8}MVFkoZbNSO;iXz~qyMv`qGHKT2hoqR`<_j+;$|{NUL`V=?yFpJT@)7vk zzC0<9ep(+}z@0E$SqM5Cg<8hBtZh73gyT-+_Rr<1)m<5IS?d72q8e!xEJ*nkfJzL& z>e609oNOw05Owvc4MB~jkssU%p zh1KV^NOJj-QU1hyjVC;yZOJwG2-!M;3_x99Ccj(2RQV>Yf$m7;U^pK&u@);QTkhrH4O zx=@0_Z|+rmPOR{t9_E`U?mF{eSn}%2;U-Sj(R088@i!>yR1(FEmHT%520N}v#jB;H zgrWS^7zV>^KrrZRx}&Ca7G?CdmU~tX_}%{Kelh9PVFmGn9TCa0`+prbur8VaSaK|y z4S%a;ZiCLOGEu96n`GdQZM_Hxg)x|&vpD(qPZo~M+SXaOPIdU7EG7MdH`x5fEq`+t zDW@?Rmt+EoAg0(QHFyqGM9{}h9r^eMD*(RfKa(qc_cATi!K8N$pWUpfy^7k6n;fZ? z@SSp?Pma8zOGp%rBuw2EfGW;yexjgncrNdH^`Y48{|9zaNoI(Lyq{;?4yIZ{dvOUd zV1a;Xz54aL8x(hh@A+wcqf7lNVEfjvIJ;I~bIel~UYQJ+*l^grwieZz4voKo+Y-Qs zt>o9I-PTw-G#U!Wbd<}Ucuo^tnvB&CeP|@a?540q-TRwZGjGXR<# z-MS!A9)LvHKUah6_*xL&JUxO+U96_eQ~j{n*Xo{lZHhaZ2g6rDb>foqEVA};z~J;>W;>qrS^ZDxT}L-^x4lY)jfe z`y7`uK0uVA0*t5i-z6r0-J+*YeZt6z@SG|@I7Wa3i{~&2L$0GpW|P|FRC}REZTicr zF0WcMq48pv^PY}c&TCAQs+yNq1vA{Wd%lyixcjK1tkZ(ElzI_lsWkhl+;@wMU^&6*p~Uk{$qfhgi$IIL zT-<(umX_kCqjF+E>tID~`EF)J!xJ${a+Li$uzTTeJ?yH&2pPxxhfP0Hf_<+7l#1PV z6(BD`ID-h@HX|#E4^4KoiwDbi&+k?G2(iip=Ou+b4K*|K7 zKD?kz8_Eo?-|x}HE{XlKv~^AN+mCkbRorzpK&0TTo!a!wAvUNg*DvCdBCN_IK)HDW zF99#l?lJ^><5P-}--4&HU_}OBZ9ginuS`+LR5>9CHXd;e#bF$D+cNYik$?z-eF|jP z2Qg!_h3I@QiGa;W1lOp}atk3lzP;XsqzIhL3Esfv=E&jI(5^kYeEq>z)9}hjjlU@1 zF>x_h89*ra#-HL0sS^D5?r(w9rcLvWjyHl&0+diBPu@kZD+vOmSCPq~@Pe^-|FM{S zAE}|>g}vn@WYi*{b5R3dEn8D{;#?bmF^galrq3N(NJ?YF+?=ivK~CR{ou7Bpr|U&_ z=t;Ehw2pGaOSd340fPzwo4Ras>U!|J*?GO-U#V?T<#RJX^ylkCfB&PVv60g?|F_hL z^fzjLsY_S~q}OcI+;2I(+x71QafzzEyrk4g3MQeNe*zMAQNvgN4UQFB_SYNric zLJsAccAhd7_d$Gr?~KSGAq(gW(_qV7{;<;x+Q6s3xw8wM3R>i385kr-qyfz|YMBlH z3P@#tzA)HX_!pc7*H3I2coUOLV4p9FG5JO{0t`rfz$VO@@8aRL?wPwf(*q9?aK7Cr zI<^}W3cq@2WI*%t+VLhAp?MGJn!CSU5OI#u(REIoMUpwj>?mPME}0ip)AoGaLl?lO`)_7IcseW?RXx1z?PNAMLh9#`Wi1B2nwGR{}9cB9RHiDpHxJi@F; z{br8(Auc5LIoSS;1Pe((7qlRSoTu!D`)<%DL@no-p4D5FH@`ek&j`&|TEi>b?ZE-F zU@rsK%UsXb&C+A8fDQq)0KK5=->;$;ncK*m-MpUU*aQZ!8FcS^_Z?b@%^oxbvj zTw>kjxZN&IB=s`JAE{oO9fW6M)1&g?VB)c^e#m+I_72{HbziN3S8MO#+zK}%yaimI z&<0*DrDKX6cKF<9M)tkCRVv*2MiYomQj)EY8``(c5$wArON?aglBeHH-#O-^FC;_~ zEG~e+saWj4XVcUR_q~f=6U81ENT1JB%I9<%wrRJR$%-+deAN6+?15tWThlSL?x!33 ziF-2*Q$G(x1FIFxG$Uk}!!7Ou=59c-DG}LMJA99x_siY;8-Iib5ED+%dtWt3UYBgb z$XRv(zsyV`tghf?m(cRo!IXilKsr<#9x87Q@Q{FuAf^J?UoGy)Mm5`@CX%WA+*jrC zKAg6)(~2!TdzD);70TOg4BA|;L~@xC1H>gbzF*#tPO^;Y4Z}c69uxHr;a^n~efC1X z!b1+W06q16eszIindAsuQO=jVzKocpCv931cKgAaw`uif0aB_p_F!9_Y)IG4j!TJf zY|!FczRb%A{SMiE__wqo|Arcsg!x7DJzJvDq)!$3E*Km(<}-0zHhr%@Cd;mbNdz)M zHvl4^fKY`&ye+RVkWg{Rth*v(-3f9Z1Tzvi@---;%Np1heY=1jG9NrfWi<)BZAh+3-x8LuGVK@XDgWoZITM+69Z^A>{5^xGO+!k zktlgrp4JKfz&$b?1Q5KSXCF$u`CnXIUa8-k1TT`w3-9$iKLA`9>~vn9I_QEbMKNHv z%PiEvX2R-P!+A<%mEG%KCERA7*N~~{@H4(*URyy}467|^|FqqCH zTBk6H@6k2KuE;zKLg?~rf1*o4i4vQ zQPefvbIrVa&_!vkOFjZ~EqDqs<|_mf$z$bF`qt!69W9QUtK_RYb-t^qL=SQ6_tI-o zgP);?ePH1gY{Weo>=+21F5?E8^J^rFpPv_pprFSOx11!UkbG7fQ=Jf~@srPWWpG_r;o#c+O z8fty-WbcnS7Xydz@Jd>fkw!7DtYxjcquh=D()W_JGQ0fMhkVs<964(z_BtZsitG19 z4$n8Pe#^I3GTurNgRW6$wI^j`>!ZOwPUQSRf|&R{i%XP8FCTe;q{kiLfFR08V_Ubcg6D;EpKTI&n1|ONf1}Haiw#&q&J>O>LB#YXGh`lY)#bA`Fr-U z&(PPM+R~LXIr>E1!|NE{k!wbc4oUB->a6wgSgy!gPBetRilHgLfECj!)QMI>HR&>Q zwQScPyMn$WqDC)VM-7dt`$TlVh^n^hV7rfzpp5b7$UW`%(9S2q?aRmGn>Q@En=Is{ zI&m|pO-04l5CWGJ$3WgQFva?1S$%a{GHh@=S($aVSX+VFRAH!$g0L#dBtd+9vWmX3 zXzmV2s`!}d?=w!*0$M+`R)2{&^61iz3*|Cg-@_UR}brg%G?7wDo z>TYh5K#n>Yc&XwWtLM71~4w^myA2z%;2 zUnvxBNy>$7cY4T#3Cu0eGfjOjhfh5nMZ>^9{|t?SSSv&ISX3F4i6vBhBOSRNy#MY3 zT#=P3tmS@%b{MZ!3J34OixtH-e>C5U#V1#F>#}%z`dIe}a3wR4)uVr`^Oq1hM~%vp z<5|gbNcLyPCC+%S6c}Yn9s_5NzZ-OS=IRkz5$U&wq_TLP&#h+6F{OBW9w}|(tw;z= zNf>zizJK`*vm+GE+}<0QKd_g5U7zX$A#kZln9|CH{)Q#zOQD4%ulEVKIgh!OJc&{A ztpYwBm$sWCATTdAx`^&XsAx`PAw`cE4AiETXR~&#GLYp$l61XB{xFbd3mBH97@KCf z>CWEyLlDDv>-otqsm7;c$_uKKK`wXx07R(u}U+4s6e^)m33izO%oG4@$kU zQ?DgVQx8M#`OSlp>dheJ+j-*PV{9SfOiA;py@C!ojXXgXF=>wL4=cDPvmOE3duejGhP(67(Fi zEgA6Cp8b3)D1$wDo`Kad2%XcQUz@Sg6Gda=c*O64%<&js>#pH@A);F|2X}|ckP}Kc2{F0(2r%FRq@QT5d(DfIm{ zQ}>AzPa7>3^DFbspHQYte73EYNjw!!2YnD>=S!wczmI-1pj;&5nr2qPjlk!L1AMy9 z>$TAIe7mLmotv#$7w#-?e^K#d`>_8gMg-;cICtF}lW?kH_Ua)Cjvp3Pj3f+s-qD-R zvAUUB)($w*ZqAs_iy9^8+%#-sup)Ke=cy~IL}mPfvZ5GeMopg!!*&Hp0vsfyni~CB zKJJ}B$ViFT{M;DwT2jh9eS;-82-w=j4(XVNwt@hcr+g=|kF}5@p;EeLhiz6zYR`Ua zchwl~A*}tq3}5niiks^0ul}!jBkf9i)y~yt$2E>@++a4@T3SCl_>vA1{n0WjO{jA$-0yV5p$kN;BkY-l*ct{n*p(9(LsiJrACa(rc|c>shWY7mgd#+d)LAP5VzrrU2AP&qMYy; zMZPs@9@BPFq&AAVpHFtv{G4rc$bPkyg(=c_WlK@rv?E2yHDpArPa@6M8UO%$QsN!0 z2}!vS2`!ML+I4LerQ19K#n;Zlo}`!ddVJ}Rnz$Djgo8k`;IG2CqF-qx6nLKzsCD< z8szlr=_Mt{Z<8se&`IwsKTq6ZJ#!G+9fa2dL#aTeO~1r)L7HJS#iwHKgPRoHce)?_gL)KMWpc}Z_=qyr zt^)?N5kz$Lp&L#&1-i*%eAfpcp7M-$0^lDC05s2~V^HhH5jVs`%P6;}P4MZV>p6LaAOJ8-F{D}l4 zTk#44q{w0igh1dPfh)$DPF0JKks>+gDA1G4LKDM-p{c^EoS;t)tK1ze762vt?6GzQW={)o{MPB1AKBDbwDXbpx-goLFSAMYE zWezGtYEPs_ePzAe&xqrCA%vZ*y=zVtc*?r^tl0*Y4BMLXXJDs;dh`7Frnz_%Arwso zUZ?%QwBY0s&%Y!i-0d;qG_&Q`mli={XE2D9{P&`NNH{aRS2~E^pVFx*B8s|26bhl! z9G$~2`soK;6>vA)=7;!6%VJkR2t~)R-<)9zP@X;utj}ku%4Au=ouEB*CE#yXE(Oa) zUTM2<1yd>jAcV!{;qS<&sx!U#sgvGx52{qi9pS$L?>Rp-ButAaq$sS#p)S-V|0D}h zW{hC8mB;F-A#YW~(r3rZ2HeCSIw#`_sExmDu)Snr8bMr^B0n)dgP3FN(_0|#L`w}o zX_gOkvw5CqO@5jpJ$NNkSiHiA@CC7$G6?`q3tti_IA3#xHbxgW49@k;=upx|lj`bA zlj5x4a$1MTfXcd;H@~11_ z*o<*L6Z&5NYnZvN!|2d$495#0dr)UPh*?(;vqSH0Cg|843lw4v1Z1RW0y(*pI^@ki zzDP3}{lhJKB3IVpWk}vna5*jDcV^E=O=D+AJ7@~dWlTx~HoG^sVC7kM#5fpT@avNd zQ-F65sjDZlwyWs$mneXgKi8hrrmq413J0K#iNW`-!Qk`95?6Y0`~*^1vJ1&=HmPdMbX*=b29HxiP z;?@iVG6vv0$f6{n)wAGRgjsc7_QukR_Rz$*(MI9!_9gug)AcEcLY%aJ4ovVfH6*VQ zT%|9J_Hc|*)?UJo*d?iHi!lC>!?l$rr_Uuyaa#PLcjbDy622oSgg*wheaq{MXf&Pdx6#O4 zid3(&)U4ls-VmlBd{==P20wY?WciWpBY=*Yc}8rrls*JS_mWwO?~{eCBP(sGCloEY zUkQb}I-NscK;4jSt7QAi!KQ= zsRS@*aAymL3GuOdCFR;*;HG0AVB+%?YeTF5XH=dx#^hD0(FU@hY>GL^6#ej+<*nn3 z6)JUX0P!6g6VtlY2#Hmy#>DpbaqYREwii4ZEgzk>>^d(rinilNtO2@*rd5}`c<6@k z_tY!K&0C(--r^76w0%<axK01N+=Hr21{UH~)F62URcIv=9jRrGR#hdiBNSQb?N2^aiqNj3PQI3?4IQxa`=3 z*Zpas05}^Rvp9kn*8wN303>KdJT-DVHR!m>kA>S@OKQqjSwU@!=(#vYPb!QWUY(88 zr&@?*a4(BTqa%uhDOpy>a7))5%*$R!QmRx{s?_BUKr7|Vyd=>9N&tj1c)Ik`CM*NF zwO_R;!1s9Z7ps;K`F>%<$0}gt`vwN-Jjdkvi9(aNlX5B8iy~uiJuA&URh@jiduBx z1rdpMct3!s!)17b!$gG&WIUEv#u`L!v#*GqMXXT*yGYNAw==mEE|*U!@}G2``&AxP zp^`=~IuNXoJ;_Y*{42%7@+wurvGz%+$nDb%U9tc`?i*IAfCy64N8vHQJvO5NdH?m{ zHZfJO?RTNkp%WZjjgqF|*|*@?tZ(*nHay|JJjGE{6Im92%f@lTjuRm$Nh?)OP(g8u zJ`w9g&HN`PGK>ww%)#Vyx0;Fed6YEo(j~Kn*weD^l|YrSQFhXU}a};K?GBh#1Y>2%> zmO95Mt@@*PxoKATkohYEmtN+OeUC87v;EBEZZDWrQ~E+ERNBssXCiGU(jwRTX|u_$ zP*AZ$w2JV_L3g-_u8Am68=VD2H+Ywaw?F3YEMYI>{;1uluZju*pxhY<^5*a;)f_=x z`LgHT7%ThjIyGzMk8*A<*M8=pn|!A756QoL)iC@wTwXgd@H;lW5p`y`3EI_ar`xBm z49w;-kYA-nN_8tYm~gC0D$i~p0pPF5Eb++wDb!28{DKpA;t?jRd?lRs zmo4@-$y0)v2BtQxpMH5cAvvnX+&)k{l%G&wmQb8ddd6=XEL44j_4_l0Y_VHk3l_92 z6!11$?~Vfm?d`iK5JFIOIH7vVJL~Jm8|1m$>u*iPJd{+vupqLy%to?T9_153AaHRu z0=!oC;4D9K?kGDn_RjRvN?oQ5FDYs%WI{Q2R0ZkKal`}5{_M9r9jl`vZQ@JA2$nsE z^4Ct1NAWT*1F(ak2o$jI_B^@bB{7xGqVtp5SQ6^$v!PiAxC^c&U4Q95OwChlpWLX> zbslEpu_Xcu9)L>amD`tq4)rf7aq9NMuqw|JZQfXYDxW_+AWzRepVQfrC_fVI3vwb7 z2pZmVUx9vr*-PMTTNo6zs+aeR;3cu4kaoROE?b4#7q{5=yV+5h7iJtqD4pvm>+z~9 zxkHbZMkHSp`l%~AUR!b$;K!<_^+>q{>IzsM18KzqU{4^iV1cwZdD~+N6i4hV)!Qc5 za0u9fk{zJLFCYO4|4$+CoVZcl!2V_yk5z5*3);VY93z47I|0%l$qK0 zqLcCxGwW-6TiQF1>&;SE%L!T~^R&tVr!9XN=n+C(0B3l>v8_4!fY`{iMf870zL;>oh+X8>q4YpsTg)?hUMwR6YA-0l17 zgi4jP>3l`>xHllF6zou_xSVs%(@)(m)<;8-TdwFyE+N6W5M(jRO~48WQ~RaJe_9!)i4zJvn=$zvi#l9T4@ye7%Ok%Q0P1qr8igslizuQi zFh#wwo~i`y;f%ZlM3w%v$-@5nVNwxpZ%^tHGDAnk^`P@~ zpj9!N(x;MJ$3|mO6a~u6CJMI`NFA{o6U;#}Mu!NyJPp)=zL}BRl8V#4Q%u~ijoj+Z z3V}KxE;~RSgJdhjmXl@X@Sw29Na8dO=Y1K+ahzucZ*|DN*FOAfjNOCrrl{A6T!}@p z@hy3I5dHqXC(VD^M5`p9Haf&Ll0&w61CUFIgl~-EB?0Yp1$`oNd+}Sr?X!1sc-Gif z{+3)xvMt?{Y5JYCUoxG}wTDfQD$ncQr;RK4ey~6$fwfE-#PsbgPb zrWi``*|uz8%OrpSFMPRI*zF>3IT|ekzD!_n{D2oEJhy-2N%h!UqBxac4c(3!kCTN? z=sD9O+AG3}@Q;PMrB@ppMvA5q@koB%wi{z`B)X$yDs|AQpS@m3+=XC523Y5{JA32?!1Uxc8yTTe%oT@ zA8oO&w(6ZM6Q7tC2n4^@CAp+-ENgMIx$|4>fPe7QXtf@p>)T~}B8?I%EOz8FNarhy zz9m8E`2g-JZIAUpYcaP1Hf4uF4_6F0Q6dy;gz1;*ryGn-_ZwEd61bVrpQXQny z+KIiDkkl(w#Z<)?XBY@*fNdk@zge`;1&E9%u06`Hx4=HV1XJ^*v7g$?UDBAJe8n6+ zVUO@n_i?XZ1vcvDA77lL&_chyJK*`b5{@OWzXbV5L zL;tsccVcG>Hw`D%J^aYvYi74-e-DO2bj3Hd zV%x>_TZX2|kC|F&fDZBt>H-#o{YTJhJ?j)#! zi!`to2Q^PE)-%2rrHUqT$;k5PpdKqn2A$zLTw; zkF%(T>px6AsO|OT|HF-*cjR%+gS?5i)AHSqRLZ?LPjhpP=2{f4MBp#GcABs$NoK$1*;qd*y04$t$<=s}@6oU}Y;iLgQ z1~tGS+El>mQa^PQa)(p`G+u8wq4<+#cE4`XCsaegHizZbmq5-C5qZos4^iq+DEL|f z{s-q@3Wk=kZz>q49+o+Ida!55=XKy(CiVz`{$5G??&LDPGF8}rO#`!ym(@n^B?P`J zvUn%A`rRuCvXCg;N%vv34K@N-v zx*Fe--&pN`X0%g`3>}gbV$t6J*@0x=m@m z!S_pVrtUrj%p)t)Ze^nT4-L); zOvrDM^<~K`HYIgLSgAbGAPd>*hUsA?Y!1}|HG~88y~k`rzuA1Auh~WQ?RE+k`eo2?x$Gg5+9Hf2W1A6 z&o#5-@HZ@@Z+Bi_k5_xID-h(OoIQ;Qg`Ca(GN7R)4tg))k0zw}U&l+Ab)Z-(&WU#J z`5|Xs9L-BGV5{b`ln-1KRtez$Au zY`g{=tWb>MvD4WHwUVVBw#Ips#3KzUCw4vAYr#zr%6W0}2)58IG+nxr7P474P+N{{L= zwGu5gssYc6*|SCxP3DN-_z9=;A+-E*=oQvtEz41}QiYIv;N`d03?^HZM_GJhJ!YHS zzw;IoI#pfS6u^N)XL;|Gc32zd0jekKdIpYUcrTb9n*&domf)lqV&G`AQZBvt7Tr(J zqpQi?H2!-HYK&1{{CRtV3NDZflSiF(;TE+Nvv?;wfwAc==pE<$&Ob4}7QPnFqExARRJa}T5_eG1;6k#+XLfIUQELF&&l zXKB@fT|QIA2mbiqnBsJK;ZS-@YULgcjNsPDNQh$S=kmcIv(cU)rJ z`q3ghC3E3+_nu|aOb12S)ZN@4B11=& zn>Xs?n06*8`WKD081K>fH^#F~Ll)f;Rx!mke`NUUQ0~Q#@e=}ya)-C5 zMAGk(C=qZRSMxkWZ#QHeE81YZZWR|D8aOa~!Yh)j*k1xk)#O0%Z|mO)rB;xp1T?5B z=V}EgMv~hTUoAeE&fXjSEQd@oAgU+DgiJn&N_e{PC4dDZ6b^8(vU~RXEL*_t1n*?} zUeKv@v8%yzf+TfTIAWlFzDXzeWq?G8YI^M!cp1`zQhdnC+rJw{ldnh>>kZx;#Hk?9 z7&BpEw-SUV1!pDezQLe;TYCjl*~5E<^@75RWJ~?;@mC>lZEXA$wN;qh6$)UuD4+(n zkXPZ4epbHn`%~9er)csUvOpwr(opzmT}XwaE`#?K!Z*e%-V>VHaqjwV(NHKWq!6LP zsWj;PkN+9PFlb3Yy*SmB9wE!;J9lmoqP?5W=0O{_BeG!xzOxl!(ehP%}i)3 zZ|=2xYC!|A)!Vo)YX#nJ$ZW5mmOiY2%!64DK+Kt4z%lpxs1L>FT6}3!49P3nSP!X) zwQigoh1h?NLeO*dSF8=HF2#%dofNSbhV^2-0!Jk$6bEq z>+Z{C(KB)KV&kk)Mg{=tiQkQs6bH-yxG4-fYz@U>X>)qS=_Am<)%x)GHtM*u;f9 zrT8sjpR9An9-JOh0)BH+Qn>V!VMulf($n+!iGr_l`G{Ryl8Dy#Sp!V z!kvE75mLTGMP!mxv5)up~NohDoKkm9^){ zO#B4E;&5I5i|xq%?nnXw8hQa);BcJRJ;-BRY95;@stqPXnR!Q&LztSW#SD`=Egg`&0`AIX<3GlS{7DvebJy*msr_6`qEo=Dp6e zn22PgQuqXymWQQp{3`MQs@DuUk$D;{){tU}+Lm zjz>^oK6sB+Q!a&6U5G7b>ROekdGL{-tl3QN-ZPioM-egiOF$9d5ll1lw{Sm*5ur69 zv;nH!^+HbsfAf}TS+dsY&@65cs1tm6x@BwLyTH%`6lj!A81z)MK8!A2H^6E>bJQyi zO7)AxZ^8c|I1E3#wnBSi+Yd}E)$J(|!C&q}?*Ps1*Ep{hWWCT`0@=y!RGKH`U!gSH zK$scO_o#arZ=h(d|9t8F5xZVWDiBJjPhjl$%}d&e)`~Ar9@%m5*l=PE8*5!#&qzLy zmIccZWJ2UVx>Rj$bcK04E!g1wp10kyMWL89eZhH3-Hy`@|}+yaCQ#>HUA1(Z^{YawoLH7>VN~P z^W8y>TGR1dM6V$?c>wYj?fijJ)k0ul#Z;su;|ygQ%Qz4UNbEVsg)uC{*yRL%mANcF z#cr~y1l4q9vH|a-0CXdDzUdSFnPIQzL?l;&%8dOcjsqH3&huFZFdl>r{vHX&GanYF z-sfUbEMbtQ`1E&3G6JXqsM8$@2U0Kg)<%VW>yMYZ)3~@e=~|ryJpgh?;?KXt>CHjk zPO!>q?)2`}^}(bAW#N(JPY-Va1>~}vRz+Mz;dcUzU<|#s_2MAI%U#g-=dz67wK0-) zs15r6w4P)VgdRYg_}#KRXlL((G`1s=&*vTxc$HU^O2a|BBF{s!4-+qP83;pXpX_Wd zs3RAX0P?WnfI1|wC4C{%$BPshPPPLce)@f$D+xU?lqFz-5V!YI%Vr{g*PY|hl8pEC z`?LjnoaV6%(8H-tEBrz+lnZ4>2lYyG_?yk8Kx#pAC=!~q>GoqFD-`BVm-}p!{c7KP zESvD6<0L;Z8`@-fh&U(0Hrw|#S7ex64D9u-wRe^gim;-ve|n`nzQjau58djpt%7wDGXjK~FJ|9M9e?mm~=O z{^^&S%nLXJA)7+=y1;{phCF?f#r!wyt#$YA5yPLvxS71TSG39YcfYzg{e14%Hn}(FK9I(#3oZe{X z(v_-gXcs&KIDMFEMeit6l`Selj|`BeV(-RFrlxANO&?jWU=FPk+$2iE0bpsjb`zyU zelaCl8^))G0?wKmwitJ)uD_iY?a;y$1-7l?_wiz&kcGi#YQx{6Vci$)s#wJ zB5rZaB_jhGVU+D^f@u`;O9p9Ez{H=wreosdLH&`?+j27nM~0jYphP_?*ps!KYK`SW zhfuMdTV?D`qgXH6jpiDN;+P>pewtQx?Vv{u{%@mprky6qSa=`~;GQaxnO_wPHtQ_& zpx-Ux*~-jRuMn`p-1+miB15?7mFwnr!clZ3oVY>J*acwP8H^iB!n7a>o2~A$f`InV zNM+WGcvn%M1(yi2&o8SFGb{lvg+NTW|5mVVyOfGgzI8fK$Fo!B(P$Apl+{9y=~Kp7 z6s0AEPgwu+rZ~%o&vP%3jgaFg+#K#=I-|3~i`cpm(v;K^!&uXOjTh}DxZZWbR8lol zRqub>Si7BHt{d>okoG=$4HZ2~_gm6E^({Jg(FGFUvEa7FG7HJ0iTo{~(5z&~rUFZ7 z<4sO?gjSj-G5esDtK=cl`a7lhd*3`|r=5~Ick|E9g18(8>9Tj%0!Kz#c;NjGDTrjw zAQq-48>h6lDQ<}(T>0a5E@;{C_bXKnPXEow-ptw3Frz4U-ugccL{p)tE3x=lne|dI z4XAFlL!(ng&)piq&~q5_W>f5RR%Y(81eBEgPyc8VAZ7~-g0{m!3$3%}0JA`a+AF{z z*NQ~veC*H$X+=orOs}mabl9?oK+piz%j4JosPWLCb1NtfEFNdxEhLy1!Q-b85@x1z z*O{ie6G_BzOB!Z65*B#^!o#{8{w}Bb-6z=`5wM(-t{j<6Ln~WNS6RpG{q_&>pWX;Ct!zAD*#kM`)IS zuKZOxpQ44g051mpm|jiqv;^PzY)g&zGV*gtYya9#S?oFS?CbzR#YU(72OC}CzF*&B z>4~=L^zAa#q_2G>J@?K#3PaKn&X4(=$zY~0A265^R zm}2MujraoS4pHtqcPSNC3!S-UrI+h}$Q9m$Sc*%i-WTu#0D<9kfX~>vgrZ&i0usgq zKh=V;1G$lbwEu-bQ<0ldz-+hwiM@5+cSNKI3&C2eGO3mK^&syY|(ALJIgF4x08~CKT&& z6QzFEd%cxf z&KuZ(xBT_u)4GHmj03F3v;=NaHOl@7LJGS^3){FM?H?8v-@ik%Z(r|ZuJ{d7^aV(p z?6aB5fgVXu)?RV@x%-&kE@JXV1hrH0V+2Z`;{5p0 zV=jYb5Ru9J*;npxi(lAV8dtM(ISkSj#Mgh!DqTvn>0v>p>96NA1C6bw_7+&l9T1(= zhRj$xL;RAvfJ+tZxi!Ksr4K+&y7*38G7t2z0jg-#x?3QEtm6ctfo?i!18sL;aLbvX z|CQVkT{O0`n4m_Ls-}o7y?>TYP^zn-`!$lvl0#F`n0D`0^o)0}P6G~n?8ye_$7OVk zFvl~L+UlVOm9>4*Az^CDvkkJ4sk+uAWAC$I@?XN`j@;3Ft*T)n4Q_}CjlD=GD6UT2 ziUCGi@Q$Nzi8P9>Y6Tf)ySF)YR2(RKI5ooz9gebFF8RgDmQ30<#8MsPD!~LfWHT=S;wwpe3br>7or* z06Dn0G7bSI&6a)qOoxy!PQI{~X*I8rpV5UIl7y)cU)tX;7OMY%ey?Mfzg}g^kRwyC zaZl@@$S#<_7g>`Wsb#3_>6l!veHyCng&*P39AJ$qxhKSNtjv&=Gg)zNoiSppIzT6>4eZiin+1r2g}aIj)+hp5ilC|S0{V&SeyXSdNq;A@29h3LI9rgK3Tu)YzGcDgM) ziT)(`bt%mS7Xox&EQDE(LG%7f`?d{|z@=eOH}V@Wz{%I?1gXpZbitdN zK_i^t?*y|SLO+erL5893t(_en+3i`wKPrv^{dlIXQxv6eQ154#JLB5ePV&;(SiBbW zplWW3+3!p7*+uK1M`3QSL6ReeJ`Xr?8M0lUM^WtOM;fnLPSo{XhyJ%jXvn7%KdQo| zwE68x&=N|VZI^*NHw}YX_t|m11UXmeK8g{88F`V~bCdqgsJfPYn31UbWYj?W!Gixb zAQ{wgC0aQ7(=)k2d=_+vDgbD|y;g~WZ}~QZm80int;GqU#w&ijAOX#T>2P!4)<0>} z1znF;vYBw@B{zx5gD7eUkpRl_1KTkB2yV<&&- zZ=1K|x0%&1iVBUzNTuyX`m1ySpc@3~ zbW}Fo|IV(GcSo3tND?taLOP&i7b)g4a;tm3v03u~DzfAiz?HxkKXG+$ETu>G_#|`{ zvPC`!_=F$uL??jXA=!NGSV${9+e_CfT_?}!xiOCbqzL7ITR?`YEmMB~ZXGf)mBU1N zMZkllprx`KT1YfobdB+6n%2JS5B+O_%!NzS+;G)ND82}RrZX|q9^G$IOPXc0+w9}% zWceEqiiQi}Z|SM);O0i`8~TIWIHQb0J&cw*x@-Xf4IY)0dkgTcw|u`4^hmgZT!)vu z_V+}N^$itfYa+M-r|k^4;b@d_(3)T@s#$j~drSQ(pZmBB;78)N#c&{ujlnfIxh~MW z`mb;l`R)~>dxoWao0)C4OOCz(dWGqD?YFB@{~G#e zCrm;@lMGU6HT1{Uh3zVlW;E@bPUl3tTU(06-=+%fR|R%8N>+va61G+wPk(%RYzO6! zPS8U;U;CC<0;N6|yPqT(L*hWg3G5|&+!FZCv4=L}Np~+zAq`3s>FJNqL2Gg2d1g(` zSq??fCh;ssu<}Q3JC0!C0@T~tDv>~=gq`P%x9_d{xMj>s=J%^ImH+@>1*<#A6ukgw zU$QTX?cTv0vwx))cP`66d4->Dh;!S;ChFccFLm_TLd6%1bwpK(eHDmTI*HKHVywJM?}2Ws0k+s1$e4@FZH6^t`75L4rkJ-}Qoophp> zZDVdvjvE#doRnwWoCoGG8j7f}R=06l*cEaNK(SFQvGPly!eVuzW9-vOi> zRh=@i{RlFOsL9oUGy)r`OUtxd4;1d#@qKIY3X>JxT8lmms95`?1&!*FUuNZ1!$}UB^g6hS^|wXIehdimR>@ zDgZlt#q|8mJk(fbl{y_+=SH_PqNk=g^eW||hF;B>Q;2BLGxo@yfcMwiiNr~lqq z`i;KEg}E}#bBno<>l+5{Ji}#`r}!GCDhK*Ta-~GfKdpZ0%L^lAuM_y?M#)}#m1^m* zg|7;c8dy)R`J6cOR6$qu4oVvrAN`b+-G*=HizIxF(L+q8*qd{Xqw}XhU;%N?38=3; zBNdd<29+f0HqO>AaQhkZq~Hd}wbIQa$%;$c-cum#SWwm#i)hgcrq3U|&pa=>J2P09jZl z{rl?#)9trFbH4nota#btt-0!wp;dDS^j72f4X|QHU zgI*wg_iyJGTxPVGR(=ARMH4 zlNA2f1;S#B*QqmS?(~*o*)3g;RAxjlwkP~GINuVvDvt^ctmLIILJHyfUeE@ zKdDz9@?dFa;!dxO4G&+TNu2z!M+$BoKX`vG_50-_bf$H>@J@q3PU2VPJEb&MX^`=r z=8G@@o60Yn$fQv*9Vv3vim3i*UoGv+%M%4Stccaagso4SFC_E=rOM8Ibqc!yE>cZX z4SR80xq__B3{Di?V2iu@t)+DGUJg0=W6YohY0Q#GWbuA2Llo})>w+Js0*T6f{74)w zaFx=q@XTU<8(s|Z?(ui;)zZ#_riCEg&Od`n;XApUMS%76tN;Yi`0cd z8l`C)KyMOQpMYVmHepX=u>5XxMnMsC?b@|>oL;Xi(YUAdalvRD>7aSHKnJDh7DNR@ z82}5Gu>nuaZ|eF)rSXR1gW!f!_C;b4 zr5jQ%$5g07xebRT2ZuBo)5n_%ab#2;lQ#+5)4iV@4^8LIHL-DSiNf19G;3!zJ0T~o zA}M$H`zFMT;R7^&7_HoUvV%IUv8(=q_UAt3+mD@ugyh~WggqnGiK!`h@XGocE%O{U zh1XsTg;)&U6TzUJjlL@RRL*<82Wg9`FudMCOd80bpe(p0ahJJJ|I1O$7j2#A&vvqM zS6=H0e$$RQ^k#Wc`Au%g=Bh!$$*><+Cls809(SXRLR_`@TO4bHppfi?X?a%>lyZ|Y zrpIPp)Yq*&Yi#h5VS{Bt?&LdO^ac2&F+2csoGW_V`E@=0Pnk4n?{nw7cYta7F5Y;#%-vHQ zyC$^=DEVF(O|Hcc*vN+^M+8(s##oyCK0Ivm>U_WMH&Av>$S-va(w#o6FULROD7<1t z;#wPp*~!6uRXcM@6g`B7+K2X^%UeI;llw99Pmz- ze@OYob`OKs=CkW9WXQ<)jAs%Bd>V~9Xr&eS;pcb&Jk_AKd3Dr+4)jHq?x)!Q&s?Zy z(JC4Swbq8O4H^qF$ikT6k-vja{GJMJKuo_=RHhpxUacB}x@*SO^?5nfOT3ux&d4_5 zBhm=9oaI(Xh27PoePp*@Wy}GGHk6F+oY}r+V{`iUpS8U&+5C(bic$|4sxY@UG#jDD zh|yH!UOk4CeNPiGOlZtux3w{N@(2^aCu@Jd>dg_L9GAJaDB-+oelF{(mevla?I0i) zd9O`LawR+C-mHyr8~D8mFc~Q)jLE+n6hRwItnZiXjU4r~b>-+Eid6qj$zDf~w3k&@ zYv=zxbIXx{iz=Hw*E;l-bI(*RXHDZ+z-IwI7M)L=*|_@z)4S}lM&uvi)2sEE*>Wy2 z$Xz`_?tqS0t|L#7X_*H`+}9P;|L6o4Sq`!ilS=h97_d(`$7`R3GU%v1*?r}_T`z&+=-^P?wsAPtYV2Ol<3{? z`kkpsM>?(r8Y1^_z`is0$r#34sWjBFUAk%5cjN-JnapPwG$Nb;KFwE5OFqEsN!-;_ z<+iS_OHLK;Y)roW^WQviWtcs_x?-P8a0L_fV&*m?e~l#B4ppnhaNe|?$7R;Giw+4v zR+mE?lmg#fqu4v-tyu>t26$$aJZH4@h_0^2VbN$x8t!Y^E;;=7fdD!~qD$Apd^u7u zUFvT5mDEp(RvibviSlJ7Wm9E-(T(AF2M8bLFg`o5l|m z>Qzg->8_!ESu|d_tUwpyeyGGk4-?ynR=us$O(v_`D-nU_X2fWD7;&ynGhPWVeNf30 zezp7~kpTfeP1f7RrfN~$eD>m+#xJ8X5nC|s?@97oooDd{!2ggNezE_P{iYN}dH9g% zi76-1O0tMyylJYtsDQIqdIktxzA%0^r!&y3nM$Hjb(<=*o>ifw)(H1rmObAzq+2ut>La{j43_<_%&l zB+lY>*EV^BSDkrwew_;Q=i%`K<$51P0%#wqY13;8F4+LDLqhMZvGW~OYrE*3a90n5 z(;9v{Jb-IoJK3!dApy`z>~sr0gL$R1x~-L{&%Afw8h%%Y?!Utd-BUjdmBmck`5{xG z&$KL@7a{b>nKrZLm?TY5LTX>N*L?H%{k7Fp41B|p{;uZu@wg9ozaV4An|oJJ&C?d+Oy zrGy(Wn3aFnhml%4@^XPn3SNEHAR2bUrFI-K`G#;n$C|+VSP4`Dyu}46^!L5hst%By?oPn?~i^{nkFYj8(E zQR=D|_x&U28|6$J16USmitElaO!?ZuN-IlIBv_$Zf+^QLWyyh;CkLYVV6(1ko9$VD zJlhh%psnJohcDEDXx0@GXb3d%@~e^%S`(^yh!@+@prr?Bwl&f3twB^{lzy)~V}8Th z229ya3;xOcg8zO45nk|#*@l|l+&2TkIhn-~tEIiF4NVQnxC_8tU$Yo1M|2N-j>kgY zFY9gYm04B14e6%Z;xI?AI;+JP+{c5-N(P_$}zN+#VKc8 z`f~k1_iPtFa4pzx-;Y9({Ijvc*&E*NUfsuo74-HRQ}_EFRLO0tE2QCkNSqh!{0J^9 z3pXNmAH2H#sP)`+4v09mznHQXciC>EOy#KO60OPT+H(Gh?A0y-M?vVV zxZ;5Lk?I>S2+FMj=chw*_w(G5dZDJ=sUkW5zD!>;An>9~ub0i@t3Ms@JojSYSCw7I zEH-(Qs?9fb?mOW(o5jIyX|-@GQcp+8Rd#VcBXKi~kq911cq?{JJ!*;BYOeU}#+k$H z4Cl+TRXq-e^i`Ozc->zQgRm!+WcfOJeg+04zFQkoRM&7;g5LngV($gNCXd;AdF1i_ zkChZ+AnnkjC6#}t8pRz;PQ33r`;WU1k+7EoMw*-6HvL6ilUYT3o>xZHJ^b>W4{O6RZEC)8Yq*m`RKK zMoG)go6#PJABPzmE==kBE#zR=4$-TxBk3?-ZC9epO9N^_7@AGeJ^Y*@>n}Y&rrf`y zEXsc`CFa_yPzqj0qhtK~;cesokMFBx{=~(79ouH#wklZik4Ni#Qtb~?JYKicht-8N z8||p@8KgQV9{1z_ce+s~bvcfaeydiB6b7y9ys3hrR_;<`>|uX}`I4IR^iywCW$dB$ zo59y@0>`MFchSbuH?8}=e|V|p-Jz?`{!FG={bSTb z@zUs@j`*jW&_2H#DH?&qB9)7pU#exBY<;rSe^FFPGa!pMLR)F&yt~f?;WkpU*9Azg zzfb?U6u@eM)WY3$eerzd53!A`bsr@svL%(aqfr%?IE;4KC*9X6O4j%D&&3`ZM2-Iz8lG-FvqqWbk^&qTv&lO+QDz~P-Gf)D7L5>e2zYgHBt3ye)J4YJcZL<8%B%X~^!$zjzoj&h@Nj`gOV)B== zO-LstcuwFd`X!N`I_j>MPM--W=pOnVK9S9_B0=B8UdGsO&hWex`*-l$u==?0emkTT z@8sF5GSuvu`GQ?-50{FzTkw)^&?hliFMR@U-7D87e_m;&BNm2g=xk$X`jTlv3bUhj z2cZ8^5B~$}8R?+TcZuNSyzI<@zR5Szyh++!aQ;U_Mk*9rS0U z4xhBs#cn2tR%a*b`RU6}7Sjc3pA`O*V*)p0b_gvvqQJX61f<|XP&9a{CKcz=G~J`X zSzCHBw`l-Bh19|Q-Ai3Q7^u-JHJ!MEUY=u8T1qQ7GkP9U zi<)ZDxi)~_7{yd)FP?n%W5aZtTk>L=!@EV-=C63G1L5#@jdLxy-Oqk?^MTP;dF`$@(FTv+}S)4X0<<{3jX65eG|yLH)XKa$rk z4})_qwI(~YS{I7jg&7_X_%CO_N*(Xz{Uq{*#($L$#$Z}Z!42Sc1sGe}cQjw^5wSnh}uyXjf8)5dABH4uhj@Kq0q z`$Ig+tcUaE-n3r5JXe`TETM&LJyhm&*3=DC5DXscEL11%e+z1vZ&< z#oS2CzfA(ZS>A)6F?Xd@ifuHHc*)URZ*-cb@LB*# zdGyF!ZomYrbZ2!X)^h8+Cl;!__?wgN;3-OalP%zS6(-<@`^YE+sUbMT-r_OwJ~qqD z?$361DJF9i5D?Srue7N%IAkvGH0CH6_3*le=fxzM-BqK`Ug|2GwK|nUO1M5b^tAJ~ z-)wh=)~AatvuWClzx4hZ$~d*%v;LTyp*da-6kTnyUJEVzS#1kmEaw+a29&!NuP(X1 zGjOKG(V1_hqCfHkUDk{@#MhVa2#L)dRbS708@r+S3u&n)b0=e}MXlrRsL%ZaLjyERMO*#kEyy2e*sDunLu;csg0vk>R^< zC2b>$@t?H)S|YzAxBX1}oRbo1B;eK^!wi3+I;x9^`QgE=0R1k5$i#4ql1qm}lBNt< z`RRvp^fawVXABwev!K44D*Xj+UK@4=Z>;p&KmX&~0oP@=#QTvr7ln^~V=2G7IWML* zm#L``T948nGul@!Zb>-{!ECTY&Ahh5?|6>n!h}?7?LFu86q9A&m}B)Tj_SI|iGCI- z6-~g|`~Da&(OF*;aDKY4esr)a(`ZhQItjm7D$}}fhK+uhyJeoKEfdA<2D2R9h|jxQ z1mF$bpA<`Llb7g6)J!pBHkosfNL1l2^0iVhSMe2@Un~|T&64!%$zyh@<*RXr9Wq!(VXrNrW;46Mv(^Gi_rQ}Bo#7Q$=TtQIe5!CIYfYRc3W{Q-=Uid)M1Ou zgNoGhYn2taeo;eKJpU(=_?au$$J6+b!G3;!F0o9x|97}i%p{vUt+14)<1+PqKm4`` zr_`?P>;2pKseKcjOI7r>X|=YaDC{~OiyukLL;`qlf4cGVHj~N;vu#`|+rfs#ZYD+S z6j0^H)4Ys&z**%w@6Q&SRWBn1OHsz&knb3vIDV}%7YEMho^xDI4(8Ce_te5vsC9F`;Q~ck&Hcj83j(p>J^~5$%hIz1m=gXoG?T5V z4js%d0tci|h6{MEk)>l0yGmXrM~J|r80W*dCsiLMo0T_U!;K7ClY?C;XXThP{0@Ai zR=9lAF{mrJkX}4>BA-ZNYpFe>uEw$as-?zWZi1Cen_uB2eoND@zt}x$Jv4UNx_Qdz zpu(>EkW+#dCn}E{Xes#$VZ-HVlygp3smq6Fqt_wJB){zAXUgj7DYpT+jty4z4}gsx z6c8Qng(V7Tw&knx@LELH1yvIhaE7%T)eUO}{NIM$$Hj-U(4;v?zLyS6cP&g$FMc%h zT?x(4CA!JUP#1p`PbAw7-AR5u_)+~ZcX*o((&sU>Ue^4eaUKj7R9VM6%Ps3cv1!DKi9r?d* zj4Z#Cs&}kDb(ep|BAz!cLd&LEYL`Ufm7w4vf$3I(+3ZRs3QhEs4pP4dHQyBRWnXE& zpRb}+1=A3K{>5;kgTx4~LqjmO8tC5uW~6AC2MkCy7+FE|uLeC8`oAyzpCJBEBmRGC c8n=6E0@B?vz@U^!Nq0y$44pIY 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 NeyIK+|DM^q{{wI=gKz)< literal 331443 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�RYnt5C)$ldjs#Q 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 diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png index c8a0b2a25288014c0704a8b2c6e5dd9b0837cc4d..95d13de016c50adba90f2c7c7cd635453462c743 100644 GIT binary patch delta 548 zcmV+<0^9wc2)qQ4BYy$|NklTI|{! zsO%@+d-N9FxdHAM73=FQCO>)NR92;6``Q2}t~h85TH~6UrHZm(h8HXG@9XeOmu!Fe zSHOW6E=L-J^gT9c5wu(aBkKa}J@Xa2M&Zd>s@vgOTZl)`TwKo+62*oFi%WM*wZf5C z9_R87;U$Xe4}T52w`vN5278(M`LVz6e_AFWK=+4T8tN?W4mp+BS!>uMOg*U(4(RIsEC#g=! zQ$O45R8-Z5q25-UY7R2`e1upmMkbSC&59t$n-uA+Q-9rMpQZDr;n*I{;M#qfxpG^8}P>q2>HEM;kSV4xi?o%xfxRxc$VPAE0j^ mzQD<={v8yUs=I&xZ}SZ?Ji0oR_DVPa00005VX7yV(M&^xArEM*9@Vd-W zhmv6>*siS-oP`2pDtT}!i3@!zhB9l+`}XsKVSBz}jei6A1kY~a5snf>VlsU*5G5J5 zohsCyouL_79NH&9tCr|Ii?p=_dM%4o9fOf^37=l3H>|hj@pGmHuKgjS{$(Eiz9@Kx zgH|P>bf*UP6LFaIEYt#vnop8AQ=>xvZ~`+TLuC;0Laqi~eF;k7K-3v#UQtB>-VShR z>YPEko_|Nj4-y=^d3;3!wJHKa=FX&36Z8xu=2L{j^N{J4!wgCTDz2MC)o20@ai580!`iVJ>a#_eRj$+l!-)gE-VC zBM=BY;FFOXSJ-(Vs7^;ti#T1Q##?9O$lkyr7Jp~(VYdjDWw74J(Gy5$dQFG>W4BRQ zScsOE7Hr$3#gT(?RKGWLosW)uael37uZ@}a!}t`36TSrAacXcUkeF3OEvP_wc=!ki zgk;2HlPE4OhRfwbEEa<(ir8fp5FPFI^OLtae1`3H$7yXo{rLXB{guTxzle+6L>9b} zZGUE9GMV6ZyWw;?(cIh&K@bqSADjr?`rOMaEhv1gp)Tcl&$-2ZT&X<_-DU9OO%X*! zMJO*XhtKDO-EJps?xqGg@-Q-6%b~%~e0uZlHrDK{TFvBhi5OIVAfnbrP<{AaJc<%h z-|FvdZEiWGtj~2D+9gIWR=6y*YjCvC|9=fSHO=CvSEhE72qrFej&_y3LP%2n2RJX( zpFLHT>3M?#hTPh>X>F#j24<6?iO9{?hG756Q$$WK^x-EvHjxm#deSpFbjF*SUFKMm zQM_N!XXPmsps<-l;6XAve0_SX+aLP9-7AI1BTEzg4PYIH8K(4`vH$=807*qoLlNklWoUqHR^*Ry6wOA> zoEp%`|jtSbMCq4SstBx!^Ax-%YT0j(3ZLZ{Z%)hzv>3` zSKWaAsvFQ>bt>S@XGH`C2-tQ=hahy$Gdm4%$_NpwX3G#o0jlQ0&LX2zp4%yaW1bMO zE>=c86-Ml{B1*=UIt2$S{fG1$@W~JXY46x@{*r+mg*t3jW=#nj=gEj#>%y_~{#A3$ z0D}U6mq$uyY=1IQ*Jz^l22k5T-|1dQ7BURM6JL)61KSqK{QuaE3PwC8@wR!J736(j zL;6A)(^t9h`xSS8lUPN;#Qi-4^b7lU@7=m`hgu zf&hnwizq&+;iq4jR~U#1`+dNK!4e$(M6$Yol2aP?AJb{1FMKmVlR7Nfs$$;?5t0aG z9@Oys5Pu0hY`{0=Iu2CoST|ROZkSkk zTq17(oAzj!I8?;YFp} zkD#C+-nNoXp&zQ7=pixnGhjHQ$4TfO~&Y^O3y3<(vn=oJ~4YYo1_ z1(QX(te##hN3t9|Yn=PBe_k~x&8UccT=Kxh#Kd^u3JVK;;BG0>!TNUy5U8g_9iOIP z;S>v6IS6pI&iD7F8h0%9c6$$5S$|o`&d%m=1qB62OiV;sSs4Zn9EiNUJlO4a-Y?kh zeMX0hh2u^WZ*5XLGKA~eb@x3sHWp5&lUp$%Ap!aM`3MgWM|yg?2af6Xbkijjb?GUc zaw%C}6p@^qjI^{g4#$*{k%9jG`}_7kt#>UTJ1r7kGw^V4_eP0}i$i5)C4UEvii*PF z!-wH;IC$Ijn+(&2DVjEa?B)Of002ov JPDHLkV1m7BxfK8a delta 2705 zcmV;C3U2kl3z!vCMm$V(6k^rHB{)JapxF-`p{ zdVJ%f$0(wSW{EkJS`KQKN*`lcGUwGP*6l`*2nq2dpPIp{o8A=wf0(zMF)fl2?0%q1%*Tm8h=CU`VLe1Mh_IVJt8IA z;6ol$l-t>;a-FIatmUPWrDR{t*`r_b=ZdQ#%Ye;xOLMX9ep96arPiy1227b?2zVrc z3m7)s;gVUIqTnJ>&0m#ijnSp;-5cbhf}WVvtuHN$^+$iSSACLm?)0Y{gxb^f5QIAi z$oO|Rg!GSp&VLXVKgU4@bQOt`L>`K++VM3-k%dsuMh{@ki~4tuerc(#GUuI|pFVg? ztT}AGJwS$m-#rsX2liXB&VitC2h}d38=w+cN#BVMnYqXu{@2;{hgK}CIkG+j4GkRt zm>XNxUf_M>Kagfs?z z)>NM7<+cHd&4oO;dWjf15=wsuw+SEt~ z>MA^d!2{waIHyBgmIS&TcpHw||aX3NO-J;J~@F&(zFFW>sCfzz`6Z zAma8MV`!8U|C((ALsJMeTCpmR3`lnvlF|o0G>PjRxPWCC-ykk9cDUzk?V$7ybz$9$ zCN$V3qDeRAJkbef&Rg->f0+&&jYBs1n?i=hvH^FG9OK|+wxbHva|)au)!L;{VtX%TIgy*f;C-UizbtD&U8CAFwkVPK z>lWZv;t9>6vq3~aCnbn*@Y759?j!|XYJV~diq>@R$EtjL4Q!sz4eu>u-5ld}`gD^e zT_j1zZ}l?l4j0Z_WONPCpwHbZOj&seM}E~3KyPrhIMsMM&5rGh_4xNZJ<6&D_!AJl zRs(+@ErFuIwvv9l@_`Lo4qUzGj1keSppA-b{?dPb0tyZ~Fm|BUb6-~F!p`pd~_Bvbp&8ouGw;Ql!p$X`mV05n>PA1ADE(9%*o)fjcieXiNpG@tQc{R5qb@U zod*SMFLvUM$=)rSpLr3V7LiPwZhzH`aP+JOiSO29J6FW%hTfal*MJ3^^RUBlv&B7Y#|LmN1i zs@3mVT6Q+NDUI>k2W2%J)_!5btT+QcFSg*@V_IbI0XFQiVPp)2@x#>EJm0I;++qn0 zPOioG40w$0&tTk87BpqTyeu1beD8*ngtHMb90vCQaW013yUDh*`1(fyg1hAyl*~I= z&UvcRQ{Y@96xp}8KNoO+AAc8C&CuhKB@L*xYCPVz`)6R+VK>x_0>R>)L=Blp#`$^* zK6)9iJt?C{n3mWskK|0AIE@0yz#J^%pU)YHO|l-Fm6eQ@{FpjgaXtx4i3#MFGDNf9 zU19mET2`>0C`BuPib&w_{2B+oTIPeCmkoIAbq5?GcX-Q5#S=BN3rFrCXtqwhTPm-gpe|J{rdG-^MVO0Hd(Rm z8*hM@Y?Wm!sawCL0w14*HVUHZOKL32wqj+X58g}=kdz^LtTxowjkrM!M)p(Vms$}Y z?v+Rcs7Ht&g|B|3$$!?W@b{-!yqeA9=SpBzqOJ)}Ai3V$xpT2*%^HM;h9V~?2PTur z^X%0pjo5X_f{OEMS+X4|W$Vrs?hGe&t6eD#+mKI+XpFkYPP|Wt!@tyHV3Zb-!3?qr zoJd&JNKzz?vLSfPy)H>b?9uLtfh=LVD@c9$Ny|?ZFAeke{*P3IN?=7qpyaWsyu3W5 zq@;MZRnc5QK>-#oUW_gzqsq$4g0HWy=er2EFvj#K1F6VNN1^FU6YJ{^UH zg&xf%C4VJh$dDn3h={mMD7!aq%2)!sx6#m4)d^?HEtd|ZF4Xi{u~wGvY}v_@SeUZ0 z5u0D}0mpiW-mqZ<3BEBNX7JH6e?QMqvsJeT(@hOBcOEI#qsxQ7L&<+}E3>)kC`5|0iYa37zo_CjTnUWYbVqTdpa?Vnv;=hw< zf9)!x_B^cB0d2ltw>m)~S97EK0 zVRwFQS=M4}d0y$wdet}YQIi20D|R10Wq&#Jj82=H67Z)NXX^tVp5%~y{4bvCTwT<>RKhAlNyhd+N~7_s>`?S6Gd{a-k=}dn*0yb^eQmNpX@OJ015yA LNkvXXu0mjf!$>(= diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png index 64308e22e765dae90f21aa474f182692d9da1777..6e6c85b6a01e6b882444ef9d8b0d790809604aa9 100644 GIT binary patch delta 2348 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 Ef;(sk5&!@I diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png index 0b78f6c08b649bff3de1d7cc34d61c6de7015e51..6f26f228f1ce9125c879ab7a8c07e9b8e199448c 100644 GIT binary patch delta 969 zcmV;)12+8k4c-TkBYy*>Nkls@k@ zMe3l%r{9=lbo+#YW%FFT_l3a|o3qmDzswH5t#j_A-1}Fy>Fn$?(NvgQt~gMSTd*-| z+ZB&_l0g zIa`itlCbxu;XePzMS3Goku+^sdP#I8N|M}WYsyP0J)(m z$5k#WR)3{G;jNRXL&+Hm0|NtecXu@tP&srIe4aH%G}KU++nBKTpy;LGnUUb;`Cc#=Xoou<0F zn$FHnB9RCc6{R#ScC+M}jB}{GaT@Qnc)mT$Dt{S^@9#7y&|sTvA6cKplV_rzzS!-8_HeyygEHe>)6R*^%k93K9!|6x}E+VbKS$< zFRjY;Z*Ll4#?&0p@Ao^v*49>1sT8qTYzRE#LNPkj&aDfdPIKynW9Qg@`I|L=rgVX( zQGZreMtyxfp-_lqGD$~A$Iv`|FmgssgSrGC_KSs0AfF+%-_?>huHKb2F;FXj+% r%%Qm==-O+^YUG`9V*Re1aL_*i3afAC5vDHv00000NkvXXu0mjfc}eZK delta 1768 zcmV2low-BYy_INkl$9}QPm&nHkA{_)KU^AHpcVvy1 z)*TQ{F4t5XS4ZlMr^9&3RZKY7&2ct;4LNjW(v1~;px9c-p;&Twq|%Jw5tXJJAdD-m zv@FZA`+nZ@?nV-#pwn;Wo!Q;z|31Ix`G5TW|K%_n3@#*T)r(lqvDmo`Te^`dUw3w9s2Af1mPM;jYcHgvT3t9 z^XY0);q{^l%6~VDN9chxTPCjPk@$rB9umIYSu=37ssiJq(yXL9^Sr3Udw1_r!f($P z70gC8BP4||WI3w!h`>wzqT8>k*x?{s}Gf zu4Nxtmcg>@ob44ABr;{)Q|?m-+Bu#Ue%ONI-wW#83De>Q?AmNb)!XAZ)WgsDJvL^= zs<4>!RDUiewV*&yjF!1NHX%|({T2%tDigIEEco3&#?akAH)2@<6R|MAfYZnPa+T(D z?MGErXq;7=SL}>pVA9FhxzT|A$0y*O5aGDM;I%)QQ1o{{obJnAty1qPiX7aYp~IR2GD^UQ!4i-3)VW^|nu@l3rO^aOPlw2kK9EZ z5`X8LU^Wo!JEm!HCbk7@Yz>VFt$IW4Je<$v4L}gl7Y6TAD{)i;$I?~s*G5-TBIjt(AG+3`DQVzYtaoF;v2%pG-5r3Rc zPIC92(E8z2myHV?Hofk{o=OXP`n)*y4ZRu7>@+Jwi52+h`pB3PBn&swGKwY`aH*)< zq(kOHT~Ij6%F0k*UmtvIHX9;L1P{L?LLNKa%LP22f1;27t!;Y8>^a9{TZ0!bmKpJ0 zTL24VWgP5MQQbhx3M`(yU&YJ&NPn=*tTb+SFJZAbIYd}mT8f5-2JG3h2Ze=&!ToY? z)?-pIVqn!JU-JY27%qyb8T_%HX9%AsT#S%6Yn&9>VdD+0cN43H*pgq1H%Dl({3iV=zo#vq=d$I z{i`x!BgUsM{RA!#gS?wV0uUP;i^j%AY~Q{eot>R%Zf^cDiDXaD@zJ5ryEy~`7&*P; zh4}cQha@Uf(>D}l216rPp8fAhA?b}8l3Z3!W`CcCX2hpGz=<;gZcWpnyu2I^hXd8s)ksQ8!rHZK=^;LC z`H%hG4>j9R!ATMZj#d37)p|#s#HTO49#Rk%>uddZ=LrTk-M|HJyLIcLadGJA70-b5J5#xGzU0xpf&-$@4n?cq>LKDk`lYeK%JbP=49~c`w ze{s_8Cz|G^Q`=DUJu9sF_PrtgBJSp$FT854oTF1XuVhWWVZExvs+gKvHzPUJkamHa=8M_eZZ+*NhGR^*0Wcs?N zw2m*&klEA0P^}=|lVQi*r*=Mn@yq%T5%AAAk6ih0g-CVvOMAQf+XL;!`5CE}6!~X$;k;LFgfhT4F0000< KMNUMnLSTaQVRKsm diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png index 02ccbb45acfef3ab6b40c242ea412e5d63af0fcc..7fe870d9965fe70801ba9b5aa561ef3e726d87b5 100644 GIT binary patch delta 2328 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 R{*OF~bU=ohwa=ij{{u=RJS+eJ literal 7741 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 diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png index e0d3b77d055c35ae81721dfba9f2d877ed56d53b..5ad80187a2b9d75d67946055753881cefd525c76 100644 GIT binary patch delta 1455 zcmV;g1yK5!6~GISBYy>lNklWoUqHR^*Ry6wOA> zoEp%`|jtSbMCq4SstBx!^Ax-%YT0j(3ZLZ{Z%)hzv>3` zSKWaAsvFQ>bt>S@XGH`C2-tQ=hahy$Gdm4%$_NpwX3G#o0jlQ0&LX2zp4%yaW1bMO zE>=c86-Ml{B1*=UIt2$S{fG1$@W~JXY46x@{*r+mg*t3jW=#nj=gEj#>%y_~{#A3$ z0D}U6mq$uyY=1IQ*Jz^l22k5T-|1dQ7BURM6JL)61KSqK{QuaE3PwC8@wR!J736(j zL;6A)(^t9h`xSS8lUPN;#Qi-4^b7lU@7=m`hgu zf&hnwizq&+;iq4jR~U#1`+dNK!4e$(M6$Yol2aP?AJb{1FMKmVlR7Nfs$$;?5t0aG z9@Oys5Pu0hY`{0=Iu2CoST|ROZkSkk zTq17(oAzj!I8?;YFp} zkD#C+-nNoXp&zQ7=pixnGhjHQ$4TfO~&Y^O3y3<(vn=oJ~4YYo1_ z1(QX(te##hN3t9|Yn=PBe_k~x&8UccT=Kxh#Kd^u3JVK;;BG0>!TNUy5U8g_9iOIP z;S>v6IS6pI&iD7F8h0%9c6$$5S$|o`&d%m=1qB62OiV;sSs4Zn9EiNUJlO4a-Y?kh zeMX0hh2u^WZ*5XLGKA~eb@x3sHWp5&lUp$%Ap!aM`3MgWM|yg?2af6Xbkijjb?GUc zaw%C}6p@^qjI^{g4#$*{k%9jG`}_7kt#>UTJ1r7kGw^V4_eP0}i$i5)C4UEvii*PF z!-wH;IC$Ijn+(&2DVjEa?B)Of002ov JPDHLkV1m7BxfK8a delta 2705 zcmV;C3U2kl3z!vCMm$V(6k^rHB{)JapxF-`p{ zdVJ%f$0(wSW{EkJS`KQKN*`lcGUwGP*6l`*2nq2dpPIp{o8A=wf0(zMF)fl2?0%q1%*Tm8h=CU`VLe1Mh_IVJt8IA z;6ol$l-t>;a-FIatmUPWrDR{t*`r_b=ZdQ#%Ye;xOLMX9ep96arPiy1227b?2zVrc z3m7)s;gVUIqTnJ>&0m#ijnSp;-5cbhf}WVvtuHN$^+$iSSACLm?)0Y{gxb^f5QIAi z$oO|Rg!GSp&VLXVKgU4@bQOt`L>`K++VM3-k%dsuMh{@ki~4tuerc(#GUuI|pFVg? ztT}AGJwS$m-#rsX2liXB&VitC2h}d38=w+cN#BVMnYqXu{@2;{hgK}CIkG+j4GkRt zm>XNxUf_M>Kagfs?z z)>NM7<+cHd&4oO;dWjf15=wsuw+SEt~ z>MA^d!2{waIHyBgmIS&TcpHw||aX3NO-J;J~@F&(zFFW>sCfzz`6Z zAma8MV`!8U|C((ALsJMeTCpmR3`lnvlF|o0G>PjRxPWCC-ykk9cDUzk?V$7ybz$9$ zCN$V3qDeRAJkbef&Rg->f0+&&jYBs1n?i=hvH^FG9OK|+wxbHva|)au)!L;{VtX%TIgy*f;C-UizbtD&U8CAFwkVPK z>lWZv;t9>6vq3~aCnbn*@Y759?j!|XYJV~diq>@R$EtjL4Q!sz4eu>u-5ld}`gD^e zT_j1zZ}l?l4j0Z_WONPCpwHbZOj&seM}E~3KyPrhIMsMM&5rGh_4xNZJ<6&D_!AJl zRs(+@ErFuIwvv9l@_`Lo4qUzGj1keSppA-b{?dPb0tyZ~Fm|BUb6-~F!p`pd~_Bvbp&8ouGw;Ql!p$X`mV05n>PA1ADE(9%*o)fjcieXiNpG@tQc{R5qb@U zod*SMFLvUM$=)rSpLr3V7LiPwZhzH`aP+JOiSO29J6FW%hTfal*MJ3^^RUBlv&B7Y#|LmN1i zs@3mVT6Q+NDUI>k2W2%J)_!5btT+QcFSg*@V_IbI0XFQiVPp)2@x#>EJm0I;++qn0 zPOioG40w$0&tTk87BpqTyeu1beD8*ngtHMb90vCQaW013yUDh*`1(fyg1hAyl*~I= z&UvcRQ{Y@96xp}8KNoO+AAc8C&CuhKB@L*xYCPVz`)6R+VK>x_0>R>)L=Blp#`$^* zK6)9iJt?C{n3mWskK|0AIE@0yz#J^%pU)YHO|l-Fm6eQ@{FpjgaXtx4i3#MFGDNf9 zU19mET2`>0C`BuPib&w_{2B+oTIPeCmkoIAbq5?GcX-Q5#S=BN3rFrCXtqwhTPm-gpe|J{rdG-^MVO0Hd(Rm z8*hM@Y?Wm!sawCL0w14*HVUHZOKL32wqj+X58g}=kdz^LtTxowjkrM!M)p(Vms$}Y z?v+Rcs7Ht&g|B|3$$!?W@b{-!yqeA9=SpBzqOJ)}Ai3V$xpT2*%^HM;h9V~?2PTur z^X%0pjo5X_f{OEMS+X4|W$Vrs?hGe&t6eD#+mKI+XpFkYPP|Wt!@tyHV3Zb-!3?qr zoJd&JNKzz?vLSfPy)H>b?9uLtfh=LVD@c9$Ny|?ZFAeke{*P3IN?=7qpyaWsyu3W5 zq@;MZRnc5QK>-#oUW_gzqsq$4g0HWy=er2EFvj#K1F6VNN1^FU6YJ{^UH zg&xf%C4VJh$dDn3h={mMD7!aq%2)!sx6#m4)d^?HEtd|ZF4Xi{u~wGvY}v_@SeUZ0 z5u0D}0mpiW-mqZ<3BEBNX7JH6e?QMqvsJeT(@hOBcOEI#qsxQ7L&<+}E3>)kC`5|0iYa37zo_CjTnUWYbVqTdpa?Vnv;=hw< zf9)!x_B^cB0d2ltw>m)~S97EK0 zVRwFQS=M4}d0y$wdet}YQIi20D|R10Wq&#Jj82=H67Z)NXX^tVp5%~y{4bvCTwT<>RKhAlNyhd+N~7_s>`?S6Gd{a-k=}dn*0yb^eQmNpX@OJ015yA LNkvXXu0mjf!$>(= diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png index 88ea9995566b4a378ad5dbb1af33567343999da1..0a94384d619884c1e08692ac2e54434601202c9e 100644 GIT binary patch literal 3342 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 literal 11924 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 a==cu|HXQ^Ofl^Qa0000dqZT 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 literal 11924 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 literal 19832 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 diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png index 3909a483d707efe6902c05154f05975bd33e0811..8c4973081f22d5f81b781442cb0eb6b18514317a 100644 GIT binary patch literal 3132 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 literal 6398 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

wfbU}SOG#?y4 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 WlWiA^*^0>k0000=2.2.2 <3.0.0" @@ -34,4 +34,5 @@ flutter: flutter_icons: android: true ios: true - image_path: "assets/icon.png" + image_path_android: "assets/android_icon.png" + image_path_ios: "assets/ios_icon.png" From 08d07e4425c293ca922789a55e44f7887d95e6d6 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Thu, 31 Dec 2020 20:19:59 +0530 Subject: [PATCH 0718/1140] feat: review fixes --- example/lib/group_info_screen.dart | 5 +++-- lib/src/channel_file_display_screen.dart | 2 +- lib/src/channel_media_display_screen.dart | 2 +- lib/src/image_footer.dart | 4 +++- 4 files changed, 8 insertions(+), 5 deletions(-) diff --git a/example/lib/group_info_screen.dart b/example/lib/group_info_screen.dart index 31653db8..87064472 100644 --- a/example/lib/group_info_screen.dart +++ b/example/lib/group_info_screen.dart @@ -129,7 +129,7 @@ class _GroupInfoScreenState extends State { child: Padding( padding: const EdgeInsets.all(8.0), child: StreamSvgIcon.userAdd( - color: StreamChatTheme.of(context).accentColor), + color: StreamChatTheme.of(context).colorTheme.accentBlue), ), ), ), @@ -356,7 +356,8 @@ class _GroupInfoScreenState extends State { padding: const EdgeInsets.only(right: 16.0, left: 8.0), child: InkWell( child: StreamSvgIcon.check( - color: StreamChatTheme.of(context).accentColor, + color: + StreamChatTheme.of(context).colorTheme.accentBlue, size: 24.0, ), onTap: () { diff --git a/lib/src/channel_file_display_screen.dart b/lib/src/channel_file_display_screen.dart index 0cd3d854..79645f73 100644 --- a/lib/src/channel_file_display_screen.dart +++ b/lib/src/channel_file_display_screen.dart @@ -77,7 +77,7 @@ class _ChannelFileDisplayScreenState extends State { ), ), ), - backgroundColor: StreamChatTheme.of(context).primaryColor, + backgroundColor: StreamChatTheme.of(context).colorTheme.white, ), body: _buildMediaGrid(), ); diff --git a/lib/src/channel_media_display_screen.dart b/lib/src/channel_media_display_screen.dart index ea6dabff..506a46b9 100644 --- a/lib/src/channel_media_display_screen.dart +++ b/lib/src/channel_media_display_screen.dart @@ -79,7 +79,7 @@ class _ChannelMediaDisplayScreenState extends State { ), ), ), - backgroundColor: StreamChatTheme.of(context).primaryColor, + backgroundColor: StreamChatTheme.of(context).colorTheme.white, ), body: _buildMediaGrid(), ); diff --git a/lib/src/image_footer.dart b/lib/src/image_footer.dart index 128acbf7..c17a5bcf 100644 --- a/lib/src/image_footer.dart +++ b/lib/src/image_footer.dart @@ -621,7 +621,9 @@ class _ImageFooterState extends State { icon: Transform.rotate( angle: -pi / 2, child: StreamSvgIcon.Icon_send_message( - color: StreamChatTheme.of(context).accentColor, + color: StreamChatTheme.of(context) + .colorTheme + .accentBlue, ), ), ), From 7c8d5a643f7ef41c0b62efeb5d9c9271256aa631 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Thu, 31 Dec 2020 20:27:51 +0530 Subject: [PATCH 0719/1140] feat: fixed overflow --- lib/src/channel_bottom_sheet.dart | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/lib/src/channel_bottom_sheet.dart b/lib/src/channel_bottom_sheet.dart index 130738d8..d2c7eb04 100644 --- a/lib/src/channel_bottom_sheet.dart +++ b/lib/src/channel_bottom_sheet.dart @@ -33,25 +33,29 @@ class _ChannelBottomSheetState extends State { topRight: Radius.circular(16.0), ), ), - child: Column( - mainAxisSize: MainAxisSize.min, + child: ListView( children: [ SizedBox( height: 24.0, ), - Padding( - padding: const EdgeInsets.symmetric(horizontal: 16.0), - child: ChannelName( - textStyle: StreamChatTheme.of(context).textTheme.headlineBold, + Center( + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 16.0), + child: ChannelName( + textStyle: StreamChatTheme.of(context).textTheme.headlineBold, + ), ), ), SizedBox( height: 5.0, ), - ChannelInfo( - showTypingIndicator: false, - channel: StreamChannel.of(context).channel, - textStyle: StreamChatTheme.of(context).channelPreviewTheme.subtitle, + Center( + child: ChannelInfo( + showTypingIndicator: false, + channel: StreamChannel.of(context).channel, + textStyle: + StreamChatTheme.of(context).channelPreviewTheme.subtitle, + ), ), SizedBox( height: 17.0, From 7f2dadb60d5a1f83aa954787a9fec09f1b3819d1 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Thu, 31 Dec 2020 16:25:11 +0100 Subject: [PATCH 0720/1140] update unread count --- lib/src/message_widget.dart | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/lib/src/message_widget.dart b/lib/src/message_widget.dart index 61c6bf5c..5c175512 100644 --- a/lib/src/message_widget.dart +++ b/lib/src/message_widget.dart @@ -813,12 +813,13 @@ class _MessageWidgetState extends State { if (isMessageRead) { child = Row( children: [ - Text( - widget.readList.length.toString(), - style: style.copyWith( - color: StreamChatTheme.of(context).colorTheme.accentBlue, + if (StreamChannel.of(context).channel.memberCount > 2) + Text( + widget.readList.length.toString(), + style: style.copyWith( + color: StreamChatTheme.of(context).colorTheme.accentBlue, + ), ), - ), SizedBox(width: 2), child, ], From 0fea3ab64af3f41de443e501ea6f004218d279e3 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Thu, 31 Dec 2020 16:31:39 +0100 Subject: [PATCH 0721/1140] fix preview read indicator --- lib/src/channel_preview.dart | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/lib/src/channel_preview.dart b/lib/src/channel_preview.dart index c0c6f558..7f976688 100644 --- a/lib/src/channel_preview.dart +++ b/lib/src/channel_preview.dart @@ -130,11 +130,14 @@ class ChannelPreview extends StatelessWidget { .lastMessageAt .fontSize, isMessageRead: channel.state.read - .where((element) => element.lastRead + ?.where((element) => + element.user.id != + channel.client.state.user.id) + ?.where((element) => element.lastRead .isAfter(channel .state.lastMessage.createdAt)) - .length == - ((channel.memberCount ?? 0) - 1), + ?.isNotEmpty == + true, ), ); } From 35adbde641f24202ee13f39b867aaeb3c192823d Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Thu, 31 Dec 2020 16:36:53 +0100 Subject: [PATCH 0722/1140] fix shimmer size --- lib/src/channel_list_view.dart | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/src/channel_list_view.dart b/lib/src/channel_list_view.dart index 273a112a..1988b9e1 100644 --- a/lib/src/channel_list_view.dart +++ b/lib/src/channel_list_view.dart @@ -380,6 +380,10 @@ class _ChannelListViewState extends State width: 40, ), ), + contentPadding: const EdgeInsets.only( + left: 8, + right: 8, + ), title: Align( alignment: Alignment.centerLeft, child: Container( @@ -394,6 +398,7 @@ class _ChannelListViewState extends State ), ), subtitle: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Align( alignment: Alignment.centerLeft, From fe38ba8a5614cef0f5861d6fbd159b0ae6466454 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Thu, 31 Dec 2020 21:14:11 +0530 Subject: [PATCH 0723/1140] fix: review fixes --- example/lib/chat_info_screen.dart | 15 +- example/lib/group_info_screen.dart | 250 +++++++++++++++++++---------- example/lib/main.dart | 2 +- lib/src/option_list_tile.dart | 8 +- 4 files changed, 178 insertions(+), 97 deletions(-) diff --git a/example/lib/chat_info_screen.dart b/example/lib/chat_info_screen.dart index 529550ca..125c510f 100644 --- a/example/lib/chat_info_screen.dart +++ b/example/lib/chat_info_screen.dart @@ -260,13 +260,13 @@ class _ChatInfoScreenState extends State { return OptionListTile( title: 'Delete Conversation', leading: StreamSvgIcon.delete( - color: Colors.red, + color: StreamChatTheme.of(context).colorTheme.accentRed, size: 24.0, ), onTap: () { _showDeleteDialog(); }, - titleColor: Colors.red, + titleColor: StreamChatTheme.of(context).colorTheme.accentRed, ); } @@ -278,7 +278,7 @@ class _ChatInfoScreenState extends State { question: 'Are you sure you want to delete this conversation?', cancelText: 'CANCEL', icon: StreamSvgIcon.delete( - color: Colors.red, + color: StreamChatTheme.of(context).colorTheme.accentRed, ), ); var channel = StreamChannel.of(context).channel; @@ -416,14 +416,14 @@ class __SharedGroupsScreenState extends State<_SharedGroupsScreen> { children: [ StreamSvgIcon.message( size: 136.0, - color: Color(0xffdbdbdb), + color: StreamChatTheme.of(context).colorTheme.greyGainsboro, ), SizedBox(height: 16.0), Text( 'No Shared Groups', style: TextStyle( fontSize: 14.0, - color: Color(0xff000000), + color: StreamChatTheme.of(context).colorTheme.black, ), ), SizedBox(height: 8.0), @@ -432,7 +432,10 @@ class __SharedGroupsScreenState extends State<_SharedGroupsScreen> { textAlign: TextAlign.center, style: TextStyle( fontSize: 14.0, - color: Color(0xff000000).withOpacity(0.5), + color: StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(0.5), ), ), ], diff --git a/example/lib/group_info_screen.dart b/example/lib/group_info_screen.dart index 87064472..304619d6 100644 --- a/example/lib/group_info_screen.dart +++ b/example/lib/group_info_screen.dart @@ -70,11 +70,11 @@ class _GroupInfoScreenState extends State { var channel = StreamChannel.of(context); return Scaffold( - backgroundColor: Color(0xffdbdbdb), + backgroundColor: StreamChatTheme.of(context).colorTheme.greyGainsboro, appBar: AppBar( elevation: 1.0, toolbarHeight: 56.0, - backgroundColor: Colors.white, + backgroundColor: StreamChatTheme.of(context).colorTheme.white, leading: InkWell( onTap: () { Navigator.pop(context); @@ -96,7 +96,7 @@ class _GroupInfoScreenState extends State { ?.map((e) => e.user) ?.toList()), style: TextStyle( - color: Colors.black, + color: StreamChatTheme.of(context).colorTheme.black, fontSize: 16, ), maxLines: 1, @@ -112,7 +112,10 @@ class _GroupInfoScreenState extends State { return Text( '${channel.channel.memberCount} Members, ${snapshot?.data?.members?.where((e) => e.user.online)?.length ?? 0} Online', style: TextStyle( - color: Colors.black.withOpacity(0.5), + color: StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(0.5), fontSize: 12.0, ), ); @@ -140,7 +143,7 @@ class _GroupInfoScreenState extends State { _buildMembers(), Container( height: 8.0, - color: Color(0xffdbdbdb), + color: StreamChatTheme.of(context).colorTheme.greyGainsboro, ), _buildNameTile(), _buildOptionListTiles(), @@ -213,7 +216,10 @@ class _GroupInfoScreenState extends State { _getLastSeen( snapshot.data.members[position].user), style: TextStyle( - color: Colors.black.withOpacity(0.5)), + color: StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(0.5)), ), ], ), @@ -226,20 +232,25 @@ class _GroupInfoScreenState extends State { ? 'Owner' : '', style: TextStyle( - color: Colors.black.withOpacity(0.5)), + color: StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(0.5)), ), ), ], ), Container( height: 1.0, - color: Color(0xffdbdbdb), + color: StreamChatTheme.of(context) + .colorTheme + .greyGainsboro, ), ], ), ), ), - color: Colors.white, + color: StreamChatTheme.of(context).colorTheme.white, ); }, ), @@ -262,7 +273,9 @@ class _GroupInfoScreenState extends State { padding: const EdgeInsets.symmetric( horizontal: 21.0, vertical: 12.0), child: StreamSvgIcon.down( - color: Color(0xff7a7a7a), + color: StreamChatTheme.of(context) + .colorTheme + .grey, ), ), Expanded( @@ -272,8 +285,10 @@ class _GroupInfoScreenState extends State { children: [ Text( '${snapshot.data.members.length - groupMemberListLength} more', - style: - TextStyle(color: Color(0xff7a7a7a)), + style: TextStyle( + color: StreamChatTheme.of(context) + .colorTheme + .grey), ), ], ), @@ -283,7 +298,9 @@ class _GroupInfoScreenState extends State { ), Container( height: 1.0, - color: Color(0xffdbdbdb), + color: StreamChatTheme.of(context) + .colorTheme + .greyGainsboro, ), ], ), @@ -302,7 +319,7 @@ class _GroupInfoScreenState extends State { var channelName = channel.extraData['name'] ?? ''; return Material( - color: Colors.white, + color: StreamChatTheme.of(context).colorTheme.white, child: Container( height: 56.0, alignment: Alignment.center, @@ -313,7 +330,11 @@ class _GroupInfoScreenState extends State { child: Text( 'NAME', style: TextStyle( - color: Colors.black.withOpacity(0.5), fontSize: 12.0), + color: StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(0.5), + fontSize: 12.0), ), ), SizedBox( @@ -323,12 +344,15 @@ class _GroupInfoScreenState extends State { child: TextField( focusNode: _focusNode, controller: _nameController, - cursorColor: Colors.black, + cursorColor: StreamChatTheme.of(context).colorTheme.black, decoration: InputDecoration.collapsed( hintText: 'Add a group name', hintStyle: TextStyle( fontWeight: FontWeight.bold, - color: Colors.black.withOpacity(0.5), + color: StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(0.5), ), ), style: TextStyle( @@ -395,7 +419,7 @@ class _GroupInfoScreenState extends State { // title: 'Notifications', // leading: StreamSvgIcon.Icon_notification( // size: 24.0, - // color: Colors.black.withOpacity(0.5), + // color: StreamChatTheme.of(context).colorTheme.black.withOpacity(0.5), // ), // trailing: CupertinoSwitch( // value: true, @@ -407,10 +431,16 @@ class _GroupInfoScreenState extends State { stream: StreamChannel.of(context).channel.isMutedStream, builder: (context, snapshot) { return OptionListTile( + tileColor: StreamChatTheme.of(context).colorTheme.white, + separatorColor: + StreamChatTheme.of(context).colorTheme.greyGainsboro, title: 'Mute group', leading: StreamSvgIcon.mute( size: 23.0, - color: Colors.black.withOpacity(0.5), + color: StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(0.5), ), trailing: snapshot.data == null ? CircularProgressIndicator() @@ -428,10 +458,13 @@ class _GroupInfoScreenState extends State { ); }), OptionListTile( + tileColor: StreamChatTheme.of(context).colorTheme.white, + separatorColor: StreamChatTheme.of(context).colorTheme.greyGainsboro, title: 'Photos & Videos', leading: StreamSvgIcon.pictures( size: 32.0, - color: Colors.black.withOpacity(0.5), + color: + StreamChatTheme.of(context).colorTheme.black.withOpacity(0.5), ), trailing: StreamSvgIcon.right(), onTap: () { @@ -459,10 +492,13 @@ class _GroupInfoScreenState extends State { }, ), OptionListTile( + tileColor: StreamChatTheme.of(context).colorTheme.white, + separatorColor: StreamChatTheme.of(context).colorTheme.greyGainsboro, title: 'Files', leading: StreamSvgIcon.files( size: 32.0, - color: Colors.black.withOpacity(0.5), + color: + StreamChatTheme.of(context).colorTheme.black.withOpacity(0.5), ), trailing: StreamSvgIcon.right(), onTap: () { @@ -491,10 +527,14 @@ class _GroupInfoScreenState extends State { ), if (!channel.channel.isDistinct) OptionListTile( + tileColor: StreamChatTheme.of(context).colorTheme.white, + separatorColor: + StreamChatTheme.of(context).colorTheme.greyGainsboro, title: 'Leave Group', leading: StreamSvgIcon.userRemove( size: 24.0, - color: Colors.black.withOpacity(0.5), + color: + StreamChatTheme.of(context).colorTheme.black.withOpacity(0.5), ), trailing: Container( height: 24.0, @@ -583,7 +623,9 @@ class _GroupInfoScreenState extends State { padding: const EdgeInsets.all(24), child: StreamSvgIcon.search( size: 96, - color: Colors.grey, + color: StreamChatTheme.of(context) + .colorTheme + .grey, ), ), Text( @@ -624,7 +666,7 @@ class _GroupInfoScreenState extends State { Expanded( child: TextField( controller: _searchController, - cursorColor: Colors.black, + cursorColor: StreamChatTheme.of(context).colorTheme.black, autofocus: true, decoration: InputDecoration( isDense: true, @@ -633,19 +675,25 @@ class _GroupInfoScreenState extends State { padding: const EdgeInsets.symmetric( vertical: 2.0, horizontal: 6.0), child: StreamSvgIcon.search( - color: Colors.black, + color: StreamChatTheme.of(context).colorTheme.black, ), ), hintText: 'Search', border: OutlineInputBorder( borderRadius: BorderRadius.circular(32.0), - borderSide: - BorderSide(color: Colors.black.withOpacity(0.08)), + borderSide: BorderSide( + color: StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(0.08)), ), focusedBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(32.0), - borderSide: - BorderSide(color: Colors.black.withOpacity(0.08)), + borderSide: BorderSide( + color: StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(0.08)), ), contentPadding: EdgeInsets.zero, ), @@ -656,7 +704,10 @@ class _GroupInfoScreenState extends State { ), IconButton( icon: StreamSvgIcon.close_small( - color: Colors.black.withOpacity(0.5), + color: StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(0.5), ), onPressed: () { Navigator.pop(context); @@ -679,6 +730,7 @@ class _GroupInfoScreenState extends State { return StreamChannel( channel: channel, child: Material( + color: StreamChatTheme.of(context).colorTheme.white, child: Column( mainAxisSize: MainAxisSize.min, children: [ @@ -713,37 +765,41 @@ class _GroupInfoScreenState extends State { ), if (StreamChat.of(context).user.id != user.id) _buildModalListTile( - StreamSvgIcon.user( - color: Color(0xff7a7a7a), - size: 24.0, - ), - 'View info', () async { - var client = StreamChat.of(context).client; + context, + StreamSvgIcon.user( + color: StreamChatTheme.of(context).colorTheme.grey, + size: 24.0, + ), + 'View info', + () async { + var client = StreamChat.of(context).client; - var c = client.channel('messaging', extraData: { - 'members': [ - user.id, - StreamChat.of(context).user.id, - ], - }); + var c = client.channel('messaging', extraData: { + 'members': [ + user.id, + StreamChat.of(context).user.id, + ], + }); - await c.watch(); + await c.watch(); - await Navigator.push( - context, - MaterialPageRoute( - builder: (context) => StreamChannel( - channel: c, - child: ChatInfoScreen( - user: user, + await Navigator.push( + context, + MaterialPageRoute( + builder: (context) => StreamChannel( + channel: c, + child: ChatInfoScreen( + user: user, + ), ), ), - ), - ); - }), + ); + }, + ), _buildModalListTile( + context, StreamSvgIcon.message( - color: Color(0xff7a7a7a), + color: StreamChatTheme.of(context).colorTheme.grey, size: 24.0, ), 'Message', @@ -774,8 +830,9 @@ class _GroupInfoScreenState extends State { StreamChat.of(context).user.id != user.id && isUserAdmin) _buildModalListTile( + context, StreamSvgIcon.Icon_user_settings( - color: Color(0xff7a7a7a), + color: StreamChatTheme.of(context).colorTheme.grey, size: 24.0, ), 'Make Owner', () { @@ -785,8 +842,9 @@ class _GroupInfoScreenState extends State { StreamChat.of(context).user.id != user.id && isUserAdmin) _buildModalListTile( + context, StreamSvgIcon.userRemove( - color: Colors.red, + color: StreamChatTheme.of(context).colorTheme.accentRed, size: 24.0, ), 'Remove From Group', () async { @@ -795,10 +853,11 @@ class _GroupInfoScreenState extends State { _memberQueryFuture = channel.queryMembers( filter: {}, ); - }, color: Colors.red), + }, color: StreamChatTheme.of(context).colorTheme.accentRed), _buildModalListTile( + context, StreamSvgIcon.close_small( - color: Color(0xff7a7a7a), + color: StreamChatTheme.of(context).colorTheme.grey, size: 24.0, ), 'Cancel', () { @@ -829,12 +888,20 @@ class _GroupInfoScreenState extends State { if (otherMember.online) { alternativeWidget = Text( 'Online', - style: TextStyle(color: Colors.black.withOpacity(0.5)), + style: TextStyle( + color: StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(0.5)), ); } else { alternativeWidget = Text( 'Last seen ${Jiffy(otherMember.lastActive).fromNow()}', - style: TextStyle(color: Colors.black.withOpacity(0.5)), + style: TextStyle( + color: StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(0.5)), ); } } @@ -856,43 +923,50 @@ class _GroupInfoScreenState extends State { color: Color(0xff20E070), ), ), - color: Colors.white, + color: StreamChatTheme.of(context).colorTheme.white, ), alternativeWidget, ], ); } - Widget _buildModalListTile(Widget leading, String title, VoidCallback onTap, - {Color color = Colors.black}) { + Widget _buildModalListTile( + BuildContext context, Widget leading, String title, VoidCallback onTap, + {Color color}) { + color ??= StreamChatTheme.of(context).colorTheme.black; + return Material( - child: InkWell( - onTap: onTap, - child: Column( - children: [ - Container( - height: 1.0, - color: Color(0xffdbdbdb), - ), - Container( - height: 64.0, - child: Row( - children: [ - Padding( - padding: const EdgeInsets.all(16.0), - child: leading, - ), - Expanded( - child: Text( - title, - style: TextStyle(color: color, fontWeight: FontWeight.bold), - )) - ], + color: StreamChatTheme.of(context).colorTheme.white, + child: InkWell( + onTap: onTap, + child: Column( + children: [ + Container( + height: 1.0, + color: StreamChatTheme.of(context).colorTheme.greyGainsboro, ), - ), - ], + Container( + height: 64.0, + child: Row( + children: [ + Padding( + padding: const EdgeInsets.all(16.0), + child: leading, + ), + Expanded( + child: Text( + title, + style: + TextStyle(color: color, fontWeight: FontWeight.bold), + ), + ) + ], + ), + ), + ], + ), ), - )); + ); } String _getChannelName(double width, {List members}) { diff --git a/example/lib/main.dart b/example/lib/main.dart index 57f50305..c2bb1a74 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -63,7 +63,7 @@ class MyApp extends StatelessWidget { debugShowCheckedModeBanner: false, theme: ThemeData.light(), darkTheme: ThemeData.dark(), - themeMode: ThemeMode.system, + themeMode: ThemeMode.dark, onGenerateRoute: AppRoutes.generateRoute, initialRoute: client.state.user == null ? Routes.CHOOSE_USER : Routes.HOME, diff --git a/lib/src/option_list_tile.dart b/lib/src/option_list_tile.dart index 382db945..c8aff92e 100644 --- a/lib/src/option_list_tile.dart +++ b/lib/src/option_list_tile.dart @@ -7,6 +7,8 @@ class OptionListTile extends StatelessWidget { final Widget trailing; final VoidCallback onTap; final Color titleColor; + final Color tileColor; + final Color separatorColor; OptionListTile({ this.title, @@ -14,6 +16,8 @@ class OptionListTile extends StatelessWidget { this.trailing, this.onTap, this.titleColor, + this.tileColor, + this.separatorColor, }); @override @@ -21,11 +25,11 @@ class OptionListTile extends StatelessWidget { return Column( children: [ Container( - color: Color(0xffe6e6e6), + color: separatorColor ?? Color(0xffe6e6e6), height: 2.0, ), Material( - color: Colors.white, + color: tileColor ?? Colors.white, child: Container( height: 56.0, child: InkWell( From 0ff6b437dd1cfb5352692aff49e64f2be5e622e5 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Thu, 31 Dec 2020 21:23:00 +0530 Subject: [PATCH 0724/1140] feat: Converted completely to dark theme --- example/lib/group_info_screen.dart | 4 +++- lib/src/channel_file_display_screen.dart | 17 +++++++++++------ lib/src/channel_media_display_screen.dart | 18 ++++++++++++------ 3 files changed, 26 insertions(+), 13 deletions(-) diff --git a/example/lib/group_info_screen.dart b/example/lib/group_info_screen.dart index 304619d6..33102de9 100644 --- a/example/lib/group_info_screen.dart +++ b/example/lib/group_info_screen.dart @@ -81,7 +81,9 @@ class _GroupInfoScreenState extends State { }, child: Padding( padding: const EdgeInsets.only(left: 12.0), - child: StreamSvgIcon.left(), + child: StreamSvgIcon.left( + color: StreamChatTheme.of(context).colorTheme.black, + ), ), ), leadingWidth: 36.0, diff --git a/lib/src/channel_file_display_screen.dart b/lib/src/channel_file_display_screen.dart index 79645f73..6feac224 100644 --- a/lib/src/channel_file_display_screen.dart +++ b/lib/src/channel_file_display_screen.dart @@ -53,14 +53,16 @@ class _ChannelFileDisplayScreenState extends State { @override Widget build(BuildContext context) { return Scaffold( - backgroundColor: Colors.white, + backgroundColor: StreamChatTheme.of(context).colorTheme.white, appBar: AppBar( brightness: Theme.of(context).brightness, elevation: 1, centerTitle: true, title: Text( 'Files', - style: TextStyle(color: Colors.black, fontSize: 16.0), + style: TextStyle( + color: StreamChatTheme.of(context).colorTheme.black, + fontSize: 16.0), ), leading: Center( child: InkWell( @@ -69,7 +71,7 @@ class _ChannelFileDisplayScreenState extends State { }, child: Container( child: StreamSvgIcon.left( - color: Colors.black, + color: StreamChatTheme.of(context).colorTheme.black, size: 24.0, ), width: 24.0, @@ -104,14 +106,14 @@ class _ChannelFileDisplayScreenState extends State { children: [ StreamSvgIcon.files( size: 136.0, - color: Color(0xffdbdbdb), + color: StreamChatTheme.of(context).colorTheme.greyGainsboro, ), SizedBox(height: 16.0), Text( 'No Files', style: TextStyle( fontSize: 14.0, - color: Color(0xff000000), + color: StreamChatTheme.of(context).colorTheme.black, ), ), SizedBox(height: 8.0), @@ -120,7 +122,10 @@ class _ChannelFileDisplayScreenState extends State { textAlign: TextAlign.center, style: TextStyle( fontSize: 14.0, - color: Color(0xff000000).withOpacity(0.5), + color: StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(0.5), ), ), ], diff --git a/lib/src/channel_media_display_screen.dart b/lib/src/channel_media_display_screen.dart index 506a46b9..09d2a8a8 100644 --- a/lib/src/channel_media_display_screen.dart +++ b/lib/src/channel_media_display_screen.dart @@ -55,14 +55,17 @@ class _ChannelMediaDisplayScreenState extends State { @override Widget build(BuildContext context) { return Scaffold( - backgroundColor: Colors.white, + backgroundColor: StreamChatTheme.of(context).colorTheme.white, appBar: AppBar( brightness: Theme.of(context).brightness, elevation: 1, centerTitle: true, title: Text( 'Photos & Videos', - style: TextStyle(color: Colors.black, fontSize: 16.0), + style: TextStyle( + color: StreamChatTheme.of(context).colorTheme.black, + fontSize: 16.0, + ), ), leading: Center( child: InkWell( @@ -71,7 +74,7 @@ class _ChannelMediaDisplayScreenState extends State { }, child: Container( child: StreamSvgIcon.left( - color: Colors.black, + color: StreamChatTheme.of(context).colorTheme.black, size: 24.0, ), width: 24.0, @@ -106,14 +109,14 @@ class _ChannelMediaDisplayScreenState extends State { children: [ StreamSvgIcon.pictures( size: 136.0, - color: Color(0xffdbdbdb), + color: StreamChatTheme.of(context).colorTheme.greyGainsboro, ), SizedBox(height: 16.0), Text( 'No Media', style: TextStyle( fontSize: 14.0, - color: Color(0xff000000), + color: StreamChatTheme.of(context).colorTheme.black, ), ), SizedBox(height: 8.0), @@ -122,7 +125,10 @@ class _ChannelMediaDisplayScreenState extends State { textAlign: TextAlign.center, style: TextStyle( fontSize: 14.0, - color: Color(0xff000000).withOpacity(0.5), + color: StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(0.5), ), ), ], From 0afae55f2eb82b0e8f99332bae1e39ee08cdc752 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Thu, 31 Dec 2020 17:18:30 +0100 Subject: [PATCH 0725/1140] fix light theme on ios --- example/ios/Runner.xcodeproj/project.pbxproj | 2 +- example/ios/Runner/Info.plist | 2 - example/lib/main.dart | 5 +- example/pubspec.yaml | 2 +- lib/src/message_list_view.dart | 467 +++++++++---------- 5 files changed, 233 insertions(+), 245 deletions(-) diff --git a/example/ios/Runner.xcodeproj/project.pbxproj b/example/ios/Runner.xcodeproj/project.pbxproj index a08a18f6..1e7527eb 100644 --- a/example/ios/Runner.xcodeproj/project.pbxproj +++ b/example/ios/Runner.xcodeproj/project.pbxproj @@ -842,4 +842,4 @@ /* End XCConfigurationList section */ }; rootObject = 97C146E61CF9000F007C117D /* Project object */; -} \ No newline at end of file +} diff --git a/example/ios/Runner/Info.plist b/example/ios/Runner/Info.plist index 53d6d58a..7e63f46d 100644 --- a/example/ios/Runner/Info.plist +++ b/example/ios/Runner/Info.plist @@ -58,8 +58,6 @@ remote-notification - UIUserInterfaceStyle - Light UIViewControllerBasedStatusBarAppearance diff --git a/example/lib/main.dart b/example/lib/main.dart index 8d436614..ca3bedd2 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -59,7 +59,10 @@ class MyApp extends StatelessWidget { debugShowCheckedModeBanner: false, theme: ThemeData.light(), darkTheme: ThemeData.dark(), - themeMode: ThemeMode.system, + themeMode: + WidgetsBinding.instance.window.platformBrightness == Brightness.light + ? ThemeMode.light + : ThemeMode.dark, onGenerateRoute: AppRoutes.generateRoute, initialRoute: client.state.user == null ? Routes.CHOOSE_USER : Routes.HOME, diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 911d26d2..4f76c695 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -1,6 +1,6 @@ name: example description: A new Flutter project. -version: 1.0.105+108 +version: 1.0.106+109 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 a85beb0a..40680991 100644 --- a/lib/src/message_list_view.dart +++ b/lib/src/message_list_view.dart @@ -173,10 +173,10 @@ class _MessageListViewState extends State { bool _showScrollToBottom = false; ItemPositionsListener _itemPositionListener; int _messageListLength; + StreamChannelState streamChannel; int get _initialIndex { if (widget.initialScrollIndex != null) return widget.initialScrollIndex; - final streamChannel = StreamChannel.of(context); if (streamChannel.initialMessageId != null) { final messages = streamChannel.channel.state.messages; final totalMessages = messages.length; @@ -196,11 +196,10 @@ class _MessageListViewState extends State { } bool _isInitialMessage(String id) { - final streamChannel = StreamChannel.of(context); return streamChannel.initialMessageId == id; } - bool get _upToDate => StreamChannel.of(context).channel.state.isUpToDate; + bool get _upToDate => streamChannel.channel.state.isUpToDate; bool _topPaginationActive = false; bool _bottomPaginationActive = false; @@ -216,270 +215,259 @@ class _MessageListViewState extends State { @override Widget build(BuildContext context) { - final streamChannel = StreamChannel.of(context); - final messagesStream = widget.parentMessage != null ? streamChannel.channel.state.threadsStream .where((threads) => threads.containsKey(widget.parentMessage.id)) .map((threads) => threads[widget.parentMessage.id]) : streamChannel.channel.state?.messagesStream; - return WillPopScope( - onWillPop: () async { - if (!_upToDate) { - await streamChannel.reloadChannel(); - } - return true; - }, - child: StreamBuilder>( - stream: messagesStream?.map((messages) => messages - ?.where((e) => - !e.isDeleted || - (e.isDeleted && - e.user.id == streamChannel.channel.client.state.user.id)) - ?.toList()), - builder: (context, snapshot) { - if (!snapshot.hasData) { + return StreamBuilder>( + stream: messagesStream?.map((messages) => messages + ?.where((e) => + !e.isDeleted || + (e.isDeleted && + e.user.id == streamChannel.channel.client.state.user.id)) + ?.toList()), + builder: (context, snapshot) { + if (!snapshot.hasData) { + return Center( + child: const CircularProgressIndicator(), + ); + } + + final messageList = snapshot.data?.reversed?.toList() ?? []; + if (messageList.isEmpty) { + if (_upToDate) { return Center( - child: const CircularProgressIndicator(), + child: Text( + 'No chats here yet...', + style: StreamChatTheme.of(context) + .textTheme + .footnote + .copyWith( + color: StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(.5)), + ), ); } + } else { + messages = messageList; + } - final messageList = snapshot.data?.reversed?.toList() ?? []; - if (messageList.isEmpty) { - if (_upToDate) { - return Center( - child: Text( - 'No chats here yet...', - style: StreamChatTheme.of(context) - .textTheme - .footnote - .copyWith( - color: StreamChatTheme.of(context) - .colorTheme - .black - .withOpacity(.5)), - ), - ); - } - } else { - messages = messageList; - } + final newMessagesListLength = messages.length; - final newMessagesListLength = messages.length; - - if (_messageListLength != null) { - if (_bottomPaginationActive || (_inBetweenList && _upToDate)) { - if (_itemPositionListener.itemPositions.value?.isNotEmpty == - true) { - final first = _itemPositionListener.itemPositions.value.first; - final diff = newMessagesListLength - _messageListLength; - if (diff > 0) { - initialIndex = first.index + diff; - initialAlignment = first.itemLeadingEdge; - } + if (_messageListLength != null) { + if (_bottomPaginationActive || (_inBetweenList && _upToDate)) { + if (_itemPositionListener.itemPositions.value?.isNotEmpty == + true) { + final first = _itemPositionListener.itemPositions.value.first; + final diff = newMessagesListLength - _messageListLength; + if (diff > 0) { + initialIndex = first.index + diff; + initialAlignment = first.itemLeadingEdge; } - } else if (!_topPaginationActive && _upToDate) { - // Reset the index in-case we send any new message - initialIndex = 0; - initialAlignment = 0; } + } else if (!_topPaginationActive && _upToDate) { + // Reset the index in-case we send any new message + initialIndex = 0; + initialAlignment = 0; } + } - _messageListLength = newMessagesListLength; + _messageListLength = newMessagesListLength; - return Stack( - alignment: Alignment.center, - children: [ - LazyLoadScrollView( - onStartOfPage: () async { - _inBetweenList = false; - if (!_upToDate) { - _topPaginationActive = false; - _bottomPaginationActive = true; - return _paginateData( - streamChannel, - QueryDirection.bottom, - ); - } - }, - onEndOfPage: () async { - _inBetweenList = false; - _topPaginationActive = true; - _bottomPaginationActive = false; + return Stack( + alignment: Alignment.center, + children: [ + LazyLoadScrollView( + onStartOfPage: () async { + _inBetweenList = false; + if (!_upToDate) { + _topPaginationActive = false; + _bottomPaginationActive = true; return _paginateData( streamChannel, - QueryDirection.top, + QueryDirection.bottom, ); - }, - onInBetweenOfPage: () { - _inBetweenList = true; - }, - child: ScrollablePositionedList.builder( - key: ValueKey(initialIndex + initialAlignment), - itemPositionsListener: _itemPositionListener, - addAutomaticKeepAlives: true, - initialScrollIndex: initialIndex ?? 0, - initialAlignment: initialAlignment ?? 0, - physics: widget.scrollPhysics, - itemScrollController: _scrollController, - reverse: true, - itemCount: messages.length + - 2 + - (widget.parentMessage != null ? 1 : 0), - itemBuilder: (context, i) { - if (i == messages.length + 2) { - if (widget.parentMessageBuilder != null) { - return widget.parentMessageBuilder( - context, - widget.parentMessage, - ); - } else { - return Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - buildParentMessage(widget.parentMessage), - Container( - decoration: BoxDecoration( - gradient: LinearGradient( - begin: Alignment.topCenter, - end: Alignment.bottomCenter, - colors: [ - StreamChatTheme.of(context) - .colorTheme - .whiteSmoke, - StreamChatTheme.of(context) - .colorTheme - .whiteSnow, - ], - ), - ), - child: Padding( - padding: const EdgeInsets.all(8.0), - child: Text( - '${widget.parentMessage.replyCount} ${widget.parentMessage.replyCount == 1 ? 'Reply' : 'Replies'}', - textAlign: TextAlign.center, - style: StreamChatTheme.of(context) - .channelTheme - .channelHeaderTheme - .lastMessageAt, - ), - ), - ), - ], - ); - } - } - if (i == messages.length + 1) { - return _buildLoadingIndicator( - streamChannel, - QueryDirection.top, - ); - } - if (i == 0) { - return _buildLoadingIndicator( - streamChannel, - QueryDirection.bottom, - ); - } - final message = messages[i - 1]; - final nextMessage = (i - 1) > 0 ? messages[i - 2] : null; - - Widget messageWidget; - - if (i == 1) { - messageWidget = _buildBottomMessage( + } + }, + onEndOfPage: () async { + _inBetweenList = false; + _topPaginationActive = true; + _bottomPaginationActive = false; + return _paginateData( + streamChannel, + QueryDirection.top, + ); + }, + onInBetweenOfPage: () { + _inBetweenList = true; + }, + child: ScrollablePositionedList.builder( + key: ValueKey(initialIndex + initialAlignment), + itemPositionsListener: _itemPositionListener, + addAutomaticKeepAlives: true, + initialScrollIndex: initialIndex ?? 0, + initialAlignment: initialAlignment ?? 0, + physics: widget.scrollPhysics, + itemScrollController: _scrollController, + reverse: true, + itemCount: messages.length + + 2 + + (widget.parentMessage != null ? 1 : 0), + itemBuilder: (context, i) { + if (i == messages.length + 2) { + if (widget.parentMessageBuilder != null) { + return widget.parentMessageBuilder( context, - message, - messages, - streamChannel, - ); - } else if (i == messages.length - 1) { - messageWidget = _buildTopMessage( - context, - message, - messages, - streamChannel, + widget.parentMessage, ); } else { - if (widget.messageBuilder != null) { - messageWidget = Builder( - key: ValueKey('MESSAGE-${message.id}'), - builder: (_) => widget.messageBuilder( - context, - MessageDetails( - context, - message, - messages, - i, - ), - messages), - ); - } else { - 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(), - ), + buildParentMessage(widget.parentMessage), + Container( + decoration: BoxDecoration( + gradient: LinearGradient( + begin: Alignment.topCenter, + end: Alignment.bottomCenter, + colors: [ + StreamChatTheme.of(context) + .colorTheme + .whiteSmoke, + StreamChatTheme.of(context) + .colorTheme + .whiteSnow, + ], + ), + ), + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Text( + '${widget.parentMessage.replyCount} ${widget.parentMessage.replyCount == 1 ? 'Reply' : 'Replies'}', + textAlign: TextAlign.center, + style: StreamChatTheme.of(context) + .channelTheme + .channelHeaderTheme + .lastMessageAt, + ), + ), ), ], ); } + } + if (i == messages.length + 1) { + return _buildLoadingIndicator( + streamChannel, + QueryDirection.top, + ); + } + if (i == 0) { + return _buildLoadingIndicator( + streamChannel, + QueryDirection.bottom, + ); + } + final message = messages[i - 1]; + final nextMessage = (i - 1) > 0 ? messages[i - 2] : null; - return messageWidget; - }, - ), + Widget messageWidget; + + if (i == 1) { + messageWidget = _buildBottomMessage( + context, + message, + messages, + streamChannel, + ); + } else if (i == messages.length - 1) { + messageWidget = _buildTopMessage( + context, + message, + messages, + streamChannel, + ); + } else { + if (widget.messageBuilder != null) { + messageWidget = Builder( + key: ValueKey('MESSAGE-${message.id}'), + builder: (_) => widget.messageBuilder( + context, + MessageDetails( + context, + message, + messages, + i, + ), + messages), + ); + } else { + 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; + }, ), - if (widget.showScrollToBottom) _buildScrollToBottom(), - Positioned( - top: 20.0, - child: ValueListenableBuilder>( - valueListenable: _itemPositionListener.itemPositions, - builder: (context, values, _) { - final items = _itemPositionListener.itemPositions?.value; - if (items.isEmpty || messages.isEmpty) { - return SizedBox(); - } + ), + if (widget.showScrollToBottom) _buildScrollToBottom(), + Positioned( + top: 20.0, + child: ValueListenableBuilder>( + valueListenable: _itemPositionListener.itemPositions, + builder: (context, values, _) { + final items = _itemPositionListener.itemPositions?.value; + if (items.isEmpty || messages.isEmpty) { + return SizedBox(); + } - var index = _getTopElement(values).index; + var index = _getTopElement(values).index; - if (index > messages.length) { - return SizedBox(); - } + if (index > messages.length) { + return SizedBox(); + } - if (index == messages.length) { - index = max(index - 1, 0); - } + if (index == messages.length) { + index = max(index - 1, 0); + } - return widget.dateDividerBuilder != null - ? widget.dateDividerBuilder( - messages[index].createdAt.toLocal(), - ) - : DateDivider( - dateTime: messages[index].createdAt.toLocal(), - ); - }, - ), + return widget.dateDividerBuilder != null + ? widget.dateDividerBuilder( + messages[index].createdAt.toLocal(), + ) + : DateDivider( + dateTime: messages[index].createdAt.toLocal(), + ); + }, ), - ], - ); - }), - ); + ), + ], + ); + }); } Future _paginateData( @@ -499,7 +487,6 @@ class _MessageListViewState extends State { } Widget _buildScrollToBottom() { - final streamChannel = StreamChannel.of(context); return StreamBuilder>( stream: Rx.combineLatest2( streamChannel.channel.state.isUpToDateStream, @@ -744,7 +731,7 @@ class _MessageListViewState extends State { final isNextUser = index - 2 >= 0 && message.user.id == messages[index - 2]?.user?.id; - final channel = StreamChannel.of(context).channel; + final channel = streamChannel.channel; final readList = channel.state?.read ?.where((element) => element.user.id != userId) ?.where((read) => @@ -836,7 +823,7 @@ class _MessageListViewState extends State { _itemPositionListener = widget.itemPositionListener ?? ItemPositionsListener.create(); - final streamChannel = StreamChannel.of(context); + streamChannel = StreamChannel.of(context); initialIndex = _initialIndex; initialAlignment = _initialAlignment; @@ -879,16 +866,13 @@ class _MessageListViewState extends State { context, MaterialPageRoute(builder: (_) { return StreamBuilder( - stream: StreamChannel.of(context) - .channel - .state - .messagesStream - .map((messages) => + stream: streamChannel.channel.state.messagesStream.map( + (messages) => messages.firstWhere((m) => m.id == message.id)), initialData: message, builder: (_, snapshot) { return StreamChannel( - channel: StreamChannel.of(context).channel, + channel: streamChannel.channel, child: widget.threadBuilder(context, snapshot.data), ); }); @@ -900,6 +884,9 @@ class _MessageListViewState extends State { @override void dispose() { + if (!_upToDate) { + streamChannel.reloadChannel(); + } _messageNewListener?.cancel(); super.dispose(); } From e6c22cef8219316383bf3bebb8250c9d15bd4f66 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Fri, 1 Jan 2021 12:27:40 +0530 Subject: [PATCH 0726/1140] Fix themeMode --- example/lib/main.dart | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/example/lib/main.dart b/example/lib/main.dart index ca3bedd2..8d436614 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -59,10 +59,7 @@ class MyApp extends StatelessWidget { debugShowCheckedModeBanner: false, theme: ThemeData.light(), darkTheme: ThemeData.dark(), - themeMode: - WidgetsBinding.instance.window.platformBrightness == Brightness.light - ? ThemeMode.light - : ThemeMode.dark, + themeMode: ThemeMode.system, onGenerateRoute: AppRoutes.generateRoute, initialRoute: client.state.user == null ? Routes.CHOOSE_USER : Routes.HOME, From dc643c0f71d5d76472a12050ab75f4e67f8c58f2 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Fri, 1 Jan 2021 14:04:33 +0530 Subject: [PATCH 0727/1140] feat: Fixed conflicts, added group info screen --- example/lib/main.dart | 28 ++++++++++++++++++++++++++++ lib/src/channel_list_view.dart | 23 ++++++----------------- lib/src/option_list_tile.dart | 12 +++--------- 3 files changed, 37 insertions(+), 26 deletions(-) diff --git a/example/lib/main.dart b/example/lib/main.dart index c2bb1a74..c958efb8 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -398,6 +398,34 @@ class _ChannelListPageState extends State { limit: 20, ), channelWidget: ChannelPage(), + onViewInfoTap: (channel) { + if (channel.memberCount == 2 && + channel.isDistinct) { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => StreamChannel( + channel: channel, + child: ChatInfoScreen( + user: channel.state.members.first.user, + ), + ), + ), + ); + } else { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => StreamChannel( + channel: channel, + child: GroupInfoScreen(), + ), + ), + ); + } + + // TODO: Add group screen + }, ), ), ), diff --git a/lib/src/channel_list_view.dart b/lib/src/channel_list_view.dart index 831696f7..6c4e967e 100644 --- a/lib/src/channel_list_view.dart +++ b/lib/src/channel_list_view.dart @@ -22,6 +22,8 @@ typedef ChannelTapCallback = void Function(Channel, Widget); /// Builder used to create a custom [ChannelPreview] from a [Channel] typedef ChannelPreviewBuilder = Widget Function(BuildContext, Channel); +typedef ViewInfoCallback = void Function(Channel); + /// ![screenshot](https://raw.githubusercontent.com/GetStream/stream-chat-flutter/master/screenshots/channel_list_view.png) /// ![screenshot](https://raw.githubusercontent.com/GetStream/stream-chat-flutter/master/screenshots/channel_list_view_paint.png) /// @@ -77,6 +79,7 @@ class ChannelListView extends StatefulWidget { this.crossAxisCount = 1, this.padding, this.selectedChannels = const [], + this.onViewInfoTap, }) : super(key: key); /// The builder that will be used in case of error @@ -145,6 +148,8 @@ class ChannelListView extends StatefulWidget { final List selectedChannels; + final ViewInfoCallback onViewInfoTap; + @override _ChannelListViewState createState() => _ChannelListViewState(); } @@ -579,23 +584,7 @@ class _ChannelListViewState extends State return StreamChannel( child: ChannelBottomSheet( onViewInfoTap: () { - if (channel.memberCount == 2 && - channel.isDistinct) { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => StreamChannel( - channel: channel, - child: ChatInfoScreen( - user: - channel.state.members.first.user, - ), - ), - ), - ); - } - - // TODO: Add group screen + widget.onViewInfoTap(channel); }, ), channel: channel, diff --git a/lib/src/option_list_tile.dart b/lib/src/option_list_tile.dart index 5a9641f7..a18c2ab1 100644 --- a/lib/src/option_list_tile.dart +++ b/lib/src/option_list_tile.dart @@ -26,18 +26,12 @@ class OptionListTile extends StatelessWidget { return Column( children: [ Container( - color: separatorColor ?? Color(0xffe6e6e6), + color: separatorColor ?? + StreamChatTheme.of(context).colorTheme.greyGainsboro, height: 2.0, ), Material( - color: tileColor ?? Colors.white, - child: Container( - height: 56.0, - color: StreamChatTheme.of(context).colorTheme.greyGainsboro, - height: 1.0, - ), - Material( - color: StreamChatTheme.of(context).colorTheme.white, + color: tileColor ?? StreamChatTheme.of(context).colorTheme.white, child: Container( height: 63.0, child: InkWell( From b11543ea7f8d05491edaf18d59c71cf1107ed763 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Fri, 1 Jan 2021 15:11:22 +0530 Subject: [PATCH 0728/1140] rfac: Changed over group info screen to use streams --- example/lib/group_info_screen.dart | 489 ++++++++++++++--------------- example/lib/main.dart | 2 - 2 files changed, 237 insertions(+), 254 deletions(-) diff --git a/example/lib/group_info_screen.dart b/example/lib/group_info_screen.dart index 33102de9..fd866578 100644 --- a/example/lib/group_info_screen.dart +++ b/example/lib/group_info_screen.dart @@ -16,12 +16,9 @@ class GroupInfoScreen extends StatefulWidget { } class _GroupInfoScreenState extends State { - Future _memberQueryFuture; TextEditingController _nameController; - bool _userSearchMode = false; TextEditingController _searchController; - bool _loading = false; String _userNameQuery = ''; Timer _debounce; @@ -29,9 +26,6 @@ class _GroupInfoScreenState extends State { final FocusNode _focusNode = FocusNode(); - bool namedChanged = false; - String changedName = ''; - int groupMemberListLength; void _userNameListener() { @@ -52,10 +46,6 @@ class _GroupInfoScreenState extends State { void initState() { super.initState(); var channel = StreamChannel.of(context); - - _memberQueryFuture = channel.channel.queryMembers( - filter: {}, - ); _nameController = TextEditingController.fromValue( TextEditingValue(text: channel.channel.extraData['name'] ?? '')); _searchController = TextEditingController()..addListener(_userNameListener); @@ -69,50 +59,59 @@ class _GroupInfoScreenState extends State { Widget build(BuildContext context) { var channel = StreamChannel.of(context); - return Scaffold( - backgroundColor: StreamChatTheme.of(context).colorTheme.greyGainsboro, - appBar: AppBar( - elevation: 1.0, - toolbarHeight: 56.0, - backgroundColor: StreamChatTheme.of(context).colorTheme.white, - leading: InkWell( - onTap: () { - Navigator.pop(context); - }, - child: Padding( - padding: const EdgeInsets.only(left: 12.0), - child: StreamSvgIcon.left( - color: StreamChatTheme.of(context).colorTheme.black, - ), - ), - ), - leadingWidth: 36.0, - title: Column( - children: [ - FutureBuilder( - future: _memberQueryFuture, - builder: (context, snapshot) { - return Text( - _getChannelName(MediaQuery.of(context).size.width, - members: snapshot.data?.members - ?.map((e) => e.user) - ?.toList()), - style: TextStyle( - color: StreamChatTheme.of(context).colorTheme.black, - fontSize: 16, - ), - maxLines: 1, - overflow: TextOverflow.ellipsis, - ); - }), - SizedBox( - height: 3.0, - ), - FutureBuilder( - future: _memberQueryFuture, - builder: (context, snapshot) { - return Text( - '${channel.channel.memberCount} Members, ${snapshot?.data?.members?.where((e) => e.user.online)?.length ?? 0} Online', + return StreamBuilder>( + stream: channel.channel.state.membersStream, + builder: (context, snapshot) { + if (!snapshot.hasData) { + return Container( + color: StreamChatTheme.of(context).colorTheme.greyGainsboro, + child: Center(child: CircularProgressIndicator()), + ); + } + + return Scaffold( + backgroundColor: + StreamChatTheme.of(context).colorTheme.greyGainsboro, + appBar: AppBar( + elevation: 1.0, + toolbarHeight: 56.0, + backgroundColor: StreamChatTheme.of(context).colorTheme.white, + leading: InkWell( + onTap: () { + Navigator.pop(context); + }, + child: Padding( + padding: const EdgeInsets.only(left: 12.0), + child: StreamSvgIcon.left( + color: StreamChatTheme.of(context).colorTheme.black, + ), + ), + ), + leadingWidth: 36.0, + title: Column( + children: [ + StreamBuilder( + stream: channel.channelStateStream, + builder: (context, state) { + return Text( + _getChannelName( + 2 * MediaQuery.of(context).size.width / 3, + members: snapshot.data, + extraData: state.data.channel.extraData, + maxFontSize: 16.0), + style: TextStyle( + color: StreamChatTheme.of(context).colorTheme.black, + fontSize: 16, + ), + maxLines: 1, + overflow: TextOverflow.ellipsis, + ); + }), + SizedBox( + height: 3.0, + ), + Text( + '${channel.channel.memberCount} Members, ${snapshot?.data?.where((e) => e.user.online)?.length ?? 0} Online', style: TextStyle( color: StreamChatTheme.of(context) .colorTheme @@ -120,199 +119,178 @@ class _GroupInfoScreenState extends State { .withOpacity(0.5), fontSize: 12.0, ), - ); - }), - ], - ), - centerTitle: true, - actions: [ - StreamNeumorphicButton( - child: InkWell( - onTap: () { - _buildAddUserModal(context); - }, - child: Padding( - padding: const EdgeInsets.all(8.0), - child: StreamSvgIcon.userAdd( - color: StreamChatTheme.of(context).colorTheme.accentBlue), + ), + ], ), - ), - ), - ], - ), - body: ListView( - children: [ - _buildMembers(), - Container( - height: 8.0, - color: StreamChatTheme.of(context).colorTheme.greyGainsboro, - ), - _buildNameTile(), - _buildOptionListTiles(), - ], - ), - ); - } - - Widget _buildMembers() { - var channel = StreamChannel.of(context); - - return FutureBuilder( - builder: (context, snapshot) { - if (snapshot.data == null) { - return Center( - child: Padding( - padding: const EdgeInsets.all(8.0), - child: CircularProgressIndicator(), - ), - ); - } - - groupMemberListLength ??= - snapshot.data.members.length > 6 ? 6 : snapshot.data.members.length; - - return Column( - children: [ - ListView.builder( - shrinkWrap: true, - physics: NeverScrollableScrollPhysics(), - itemCount: groupMemberListLength, - itemBuilder: (context, position) { - return Material( + centerTitle: true, + actions: [ + StreamNeumorphicButton( child: InkWell( onTap: () { - var userMember = snapshot.data.members.firstWhere( - (e) => e.user.id == StreamChat.of(context).user.id); - _showUserInfoModal(snapshot.data.members[position].user, - userMember.role == 'owner'); + _buildAddUserModal(context); }, - child: Container( - height: 65.0, - child: Column( + child: Padding( + padding: const EdgeInsets.all(8.0), + child: StreamSvgIcon.userAdd( + color: StreamChatTheme.of(context) + .colorTheme + .accentBlue), + ), + ), + ), + ], + ), + body: ListView( + children: [ + _buildMembers(snapshot.data), + Container( + height: 8.0, + color: StreamChatTheme.of(context).colorTheme.greyGainsboro, + ), + _buildNameTile(), + _buildOptionListTiles(), + ], + ), + ); + }); + } + + Widget _buildMembers(List members) { + groupMemberListLength ??= members.length > 6 ? 6 : members.length; + + return Column( + children: [ + ListView.builder( + shrinkWrap: true, + physics: NeverScrollableScrollPhysics(), + itemCount: groupMemberListLength, + itemBuilder: (context, position) { + return Material( + child: InkWell( + onTap: () { + var userMember = members.firstWhere( + (e) => e.user.id == StreamChat.of(context).user.id); + _showUserInfoModal( + members[position].user, userMember.role == 'owner'); + }, + child: Container( + height: 65.0, + child: Column( + children: [ + Row( children: [ - Row( - children: [ - Padding( - padding: const EdgeInsets.symmetric( - horizontal: 8.0, vertical: 12.0), - child: UserAvatar( - user: snapshot.data.members[position].user, - constraints: BoxConstraints( - maxHeight: 40.0, maxWidth: 40.0), + Padding( + padding: const EdgeInsets.symmetric( + horizontal: 8.0, vertical: 12.0), + child: UserAvatar( + user: members[position].user, + constraints: BoxConstraints( + maxHeight: 40.0, maxWidth: 40.0), + ), + ), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + members[position].user.name, + style: TextStyle(fontWeight: FontWeight.bold), ), - ), - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text( - snapshot.data.members[position].user.name, - style: TextStyle( - fontWeight: FontWeight.bold), - ), - SizedBox( - height: 1.0, - ), - Text( - _getLastSeen( - snapshot.data.members[position].user), - style: TextStyle( - color: StreamChatTheme.of(context) - .colorTheme - .black - .withOpacity(0.5)), - ), - ], + SizedBox( + height: 1.0, ), - ), - Padding( - padding: const EdgeInsets.all(8.0), - child: Text( - snapshot.data.members[position].role == - 'owner' - ? 'Owner' - : '', + Text( + _getLastSeen(members[position].user), style: TextStyle( color: StreamChatTheme.of(context) .colorTheme .black .withOpacity(0.5)), ), - ), - ], + ], + ), ), - Container( - height: 1.0, - color: StreamChatTheme.of(context) - .colorTheme - .greyGainsboro, + Padding( + padding: const EdgeInsets.all(8.0), + child: Text( + members[position].role == 'owner' ? 'Owner' : '', + style: TextStyle( + color: StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(0.5)), + ), + ), + ], + ), + Container( + height: 1.0, + color: StreamChatTheme.of(context) + .colorTheme + .greyGainsboro, + ), + ], + ), + ), + ), + color: StreamChatTheme.of(context).colorTheme.whiteSnow, + ); + }, + ), + if (groupMemberListLength != members.length) + InkWell( + onTap: () { + setState(() { + groupMemberListLength = members.length; + }); + }, + child: Material( + color: StreamChatTheme.of(context).colorTheme.whiteSnow, + child: Container( + height: 65.0, + child: Column( + children: [ + Expanded( + child: Row( + children: [ + Padding( + padding: const EdgeInsets.symmetric( + horizontal: 21.0, vertical: 12.0), + child: StreamSvgIcon.down( + color: + StreamChatTheme.of(context).colorTheme.white, + ), + ), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + '${members.length - groupMemberListLength} more', + style: TextStyle( + color: StreamChatTheme.of(context) + .colorTheme + .grey), + ), + ], + ), ), ], ), ), - ), - color: StreamChatTheme.of(context).colorTheme.white, - ); - }, - ), - if (groupMemberListLength != snapshot.data.members.length) - InkWell( - onTap: () { - setState(() { - groupMemberListLength = snapshot.data.members.length; - }); - }, - child: Material( - child: Container( - height: 65.0, - child: Column( - children: [ - Expanded( - child: Row( - children: [ - Padding( - padding: const EdgeInsets.symmetric( - horizontal: 21.0, vertical: 12.0), - child: StreamSvgIcon.down( - color: StreamChatTheme.of(context) - .colorTheme - .grey, - ), - ), - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text( - '${snapshot.data.members.length - groupMemberListLength} more', - style: TextStyle( - color: StreamChatTheme.of(context) - .colorTheme - .grey), - ), - ], - ), - ), - ], - ), - ), - Container( - height: 1.0, - color: StreamChatTheme.of(context) - .colorTheme - .greyGainsboro, - ), - ], + Container( + height: 1.0, + color: + StreamChatTheme.of(context).colorTheme.greyGainsboro, ), - ), + ], ), ), - ], - ); - }, - future: _memberQueryFuture, + ), + ), + ], ); } @@ -321,7 +299,7 @@ class _GroupInfoScreenState extends State { var channelName = channel.extraData['name'] ?? ''; return Material( - color: StreamChatTheme.of(context).colorTheme.white, + color: StreamChatTheme.of(context).colorTheme.whiteSnow, child: Container( height: 56.0, alignment: Alignment.center, @@ -389,12 +367,6 @@ class _GroupInfoScreenState extends State { onTap: () { StreamChannel.of(context).channel.update({ 'name': _nameController.text.trim(), - }).then((value) { - setState(() { - _focusNode.unfocus(); - namedChanged = true; - changedName = _nameController.text.trim(); - }); }).catchError((err) { setState(() { _nameController.text = channelName; @@ -433,7 +405,7 @@ class _GroupInfoScreenState extends State { stream: StreamChannel.of(context).channel.isMutedStream, builder: (context, snapshot) { return OptionListTile( - tileColor: StreamChatTheme.of(context).colorTheme.white, + tileColor: StreamChatTheme.of(context).colorTheme.whiteSnow, separatorColor: StreamChatTheme.of(context).colorTheme.greyGainsboro, title: 'Mute group', @@ -460,7 +432,7 @@ class _GroupInfoScreenState extends State { ); }), OptionListTile( - tileColor: StreamChatTheme.of(context).colorTheme.white, + tileColor: StreamChatTheme.of(context).colorTheme.whiteSnow, separatorColor: StreamChatTheme.of(context).colorTheme.greyGainsboro, title: 'Photos & Videos', leading: StreamSvgIcon.pictures( @@ -494,7 +466,7 @@ class _GroupInfoScreenState extends State { }, ), OptionListTile( - tileColor: StreamChatTheme.of(context).colorTheme.white, + tileColor: StreamChatTheme.of(context).colorTheme.whiteSnow, separatorColor: StreamChatTheme.of(context).colorTheme.greyGainsboro, title: 'Files', leading: StreamSvgIcon.files( @@ -529,7 +501,7 @@ class _GroupInfoScreenState extends State { ), if (!channel.channel.isDistinct) OptionListTile( - tileColor: StreamChatTheme.of(context).colorTheme.white, + tileColor: StreamChatTheme.of(context).colorTheme.whiteSnow, separatorColor: StreamChatTheme.of(context).colorTheme.greyGainsboro, title: 'Leave Group', @@ -582,9 +554,6 @@ class _GroupInfoScreenState extends State { await channel.addMembers([user.id]); Navigator.pop(context); - _memberQueryFuture = channel.queryMembers( - filter: {}, - ); setState(() {}); }, crossAxisCount: 4, @@ -852,9 +821,6 @@ class _GroupInfoScreenState extends State { 'Remove From Group', () async { await channel.removeMembers([user.id]); Navigator.pop(context); - _memberQueryFuture = channel.queryMembers( - filter: {}, - ); }, color: StreamChatTheme.of(context).colorTheme.accentRed), _buildModalListTile( context, @@ -971,17 +937,36 @@ class _GroupInfoScreenState extends State { ); } - String _getChannelName(double width, {List members}) { - if (namedChanged) { - return changedName; - } + String _getChannelName(double width, + {List members, Map extraData, double maxFontSize}) { + String title; + var client = StreamChat.of(context); + if (extraData['name'] == null) { + final otherMembers = + members.where((member) => member.user.id != client.user.id); + if (otherMembers.isNotEmpty) { + final maxWidth = width; + final maxChars = maxWidth / maxFontSize; + var currentChars = 0; + final currentMembers = []; + otherMembers.forEach((element) { + final newLength = currentChars + element.user.name.length; + if (newLength < maxChars) { + currentChars = newLength; + currentMembers.add(element); + } + }); - if (StreamChannel.of(context).channel.extraData['name'] == null && - members != null) { - return '${members[0].name} & ${members.length - 1} others'; + final exceedingMembers = otherMembers.length - currentMembers.length; + title = + '${currentMembers.map((e) => e.user.name).join(', ')} ${exceedingMembers > 0 ? '+ $exceedingMembers' : ''}'; + } else { + title = 'No title'; + } + } else { + title = extraData['name']; } - - return StreamChannel.of(context).channel.extraData['name'] ?? ''; + return title; } String _getLastSeen(User user) { diff --git a/example/lib/main.dart b/example/lib/main.dart index c958efb8..69300312 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -423,8 +423,6 @@ class _ChannelListPageState extends State { ), ); } - - // TODO: Add group screen }, ), ), From e837b9b0e567f21e63b0b0de945551b14e607d31 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Fri, 1 Jan 2021 18:35:25 +0530 Subject: [PATCH 0729/1140] feat: Fixed issues with alignment in group info screen and dark theme --- example/lib/chat_info_screen.dart | 78 ++++++++++----- example/lib/group_info_screen.dart | 147 ++++++++++++++++------------- lib/src/channel_bottom_sheet.dart | 28 ++++-- lib/src/image_footer.dart | 42 +++++---- lib/src/option_list_tile.dart | 26 ++--- 5 files changed, 198 insertions(+), 123 deletions(-) diff --git a/example/lib/chat_info_screen.dart b/example/lib/chat_info_screen.dart index 125c510f..d992e73b 100644 --- a/example/lib/chat_info_screen.dart +++ b/example/lib/chat_info_screen.dart @@ -76,6 +76,7 @@ class _ChatInfoScreenState extends State { SizedBox(height: 15.0), OptionListTile( title: '@${widget.user.id}', + tileColor: StreamChatTheme.of(context).colorTheme.whiteSnow, trailing: Padding( padding: const EdgeInsets.symmetric(horizontal: 8.0), child: Text( @@ -131,13 +132,18 @@ class _ChatInfoScreenState extends State { stream: StreamChannel.of(context).channel.isMutedStream, builder: (context, snapshot) { return OptionListTile( + tileColor: StreamChatTheme.of(context).colorTheme.whiteSnow, title: 'Mute user', - leading: StreamSvgIcon.mute( - size: 23.0, - color: StreamChatTheme.of(context) - .colorTheme - .black - .withOpacity(0.5), + titleTextStyle: StreamChatTheme.of(context).textTheme.body, + leading: Padding( + padding: const EdgeInsets.symmetric(horizontal: 16.0), + child: StreamSvgIcon.mute( + size: 24.0, + color: StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(0.5), + ), ), trailing: snapshot.data == null ? CircularProgressIndicator() @@ -174,10 +180,15 @@ class _ChatInfoScreenState extends State { // ), OptionListTile( title: 'Photos & Videos', - leading: StreamSvgIcon.pictures( - size: 32.0, - color: - StreamChatTheme.of(context).colorTheme.black.withOpacity(0.5), + tileColor: StreamChatTheme.of(context).colorTheme.whiteSnow, + titleTextStyle: StreamChatTheme.of(context).textTheme.body, + leading: Padding( + padding: const EdgeInsets.symmetric(horizontal: 12.0), + child: StreamSvgIcon.pictures( + size: 32.0, + color: + StreamChatTheme.of(context).colorTheme.black.withOpacity(0.5), + ), ), trailing: StreamSvgIcon.right(), onTap: () { @@ -206,12 +217,19 @@ class _ChatInfoScreenState extends State { ), OptionListTile( title: 'Files', - leading: StreamSvgIcon.files( - size: 32.0, - color: - StreamChatTheme.of(context).colorTheme.black.withOpacity(0.5), + tileColor: StreamChatTheme.of(context).colorTheme.whiteSnow, + titleTextStyle: StreamChatTheme.of(context).textTheme.body, + leading: Padding( + padding: const EdgeInsets.symmetric(horizontal: 12.0), + child: StreamSvgIcon.files( + size: 32.0, + color: + StreamChatTheme.of(context).colorTheme.black.withOpacity(0.5), + ), + ), + trailing: StreamSvgIcon.right( + color: StreamChatTheme.of(context).colorTheme.grey, ), - trailing: StreamSvgIcon.right(), onTap: () { final channel = StreamChannel.of(context).channel; @@ -238,12 +256,19 @@ class _ChatInfoScreenState extends State { ), OptionListTile( title: 'Shared groups', - leading: StreamSvgIcon.Icon_group( - size: 24.0, - color: - StreamChatTheme.of(context).colorTheme.black.withOpacity(0.5), + tileColor: StreamChatTheme.of(context).colorTheme.whiteSnow, + titleTextStyle: StreamChatTheme.of(context).textTheme.body, + leading: Padding( + padding: const EdgeInsets.symmetric(horizontal: 16.0), + child: StreamSvgIcon.Icon_group( + size: 24.0, + color: + StreamChatTheme.of(context).colorTheme.black.withOpacity(0.5), + ), + ), + trailing: StreamSvgIcon.right( + color: StreamChatTheme.of(context).colorTheme.grey, ), - trailing: StreamSvgIcon.right(), onTap: () { Navigator.push( context, @@ -259,9 +284,16 @@ class _ChatInfoScreenState extends State { Widget _buildDeleteListTile() { return OptionListTile( title: 'Delete Conversation', - leading: StreamSvgIcon.delete( - color: StreamChatTheme.of(context).colorTheme.accentRed, - size: 24.0, + tileColor: StreamChatTheme.of(context).colorTheme.whiteSnow, + titleTextStyle: StreamChatTheme.of(context).textTheme.body.copyWith( + color: StreamChatTheme.of(context).colorTheme.accentRed, + ), + leading: Padding( + padding: const EdgeInsets.symmetric(horizontal: 16.0), + child: StreamSvgIcon.delete( + color: StreamChatTheme.of(context).colorTheme.accentRed, + size: 24.0, + ), ), onTap: () { _showDeleteDialog(); diff --git a/example/lib/group_info_screen.dart b/example/lib/group_info_screen.dart index fd866578..c044a23d 100644 --- a/example/lib/group_info_screen.dart +++ b/example/lib/group_info_screen.dart @@ -70,8 +70,7 @@ class _GroupInfoScreenState extends State { } return Scaffold( - backgroundColor: - StreamChatTheme.of(context).colorTheme.greyGainsboro, + backgroundColor: StreamChatTheme.of(context).colorTheme.whiteSnow, appBar: AppBar( elevation: 1.0, toolbarHeight: 56.0, @@ -259,7 +258,7 @@ class _GroupInfoScreenState extends State { horizontal: 21.0, vertical: 12.0), child: StreamSvgIcon.down( color: - StreamChatTheme.of(context).colorTheme.white, + StreamChatTheme.of(context).colorTheme.grey, ), ), Expanded( @@ -306,19 +305,18 @@ class _GroupInfoScreenState extends State { child: Row( children: [ Padding( - padding: const EdgeInsets.all(8.0), + padding: const EdgeInsets.all(7.0), child: Text( 'NAME', - style: TextStyle( + style: StreamChatTheme.of(context).textTheme.footnote.copyWith( color: StreamChatTheme.of(context) .colorTheme .black - .withOpacity(0.5), - fontSize: 12.0), + .withOpacity(0.5)), ), ), SizedBox( - width: 9.0, + width: 7.0, ), Expanded( child: TextField( @@ -326,15 +324,15 @@ class _GroupInfoScreenState extends State { controller: _nameController, cursorColor: StreamChatTheme.of(context).colorTheme.black, decoration: InputDecoration.collapsed( - hintText: 'Add a group name', - hintStyle: TextStyle( - fontWeight: FontWeight.bold, - color: StreamChatTheme.of(context) - .colorTheme - .black - .withOpacity(0.5), - ), - ), + hintText: 'Add a group name', + hintStyle: StreamChatTheme.of(context) + .textTheme + .bodyBold + .copyWith( + color: StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(0.5))), style: TextStyle( fontWeight: FontWeight.bold, height: 0.82, @@ -409,12 +407,16 @@ class _GroupInfoScreenState extends State { separatorColor: StreamChatTheme.of(context).colorTheme.greyGainsboro, title: 'Mute group', - leading: StreamSvgIcon.mute( - size: 23.0, - color: StreamChatTheme.of(context) - .colorTheme - .black - .withOpacity(0.5), + titleTextStyle: StreamChatTheme.of(context).textTheme.body, + leading: Padding( + padding: const EdgeInsets.symmetric(horizontal: 16.0), + child: StreamSvgIcon.mute( + size: 24.0, + color: StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(0.5), + ), ), trailing: snapshot.data == null ? CircularProgressIndicator() @@ -435,12 +437,18 @@ class _GroupInfoScreenState extends State { tileColor: StreamChatTheme.of(context).colorTheme.whiteSnow, separatorColor: StreamChatTheme.of(context).colorTheme.greyGainsboro, title: 'Photos & Videos', - leading: StreamSvgIcon.pictures( - size: 32.0, - color: - StreamChatTheme.of(context).colorTheme.black.withOpacity(0.5), + titleTextStyle: StreamChatTheme.of(context).textTheme.body, + leading: Padding( + padding: const EdgeInsets.symmetric(horizontal: 12.0), + child: StreamSvgIcon.pictures( + size: 32.0, + color: + StreamChatTheme.of(context).colorTheme.black.withOpacity(0.5), + ), + ), + trailing: StreamSvgIcon.right( + color: StreamChatTheme.of(context).colorTheme.grey, ), - trailing: StreamSvgIcon.right(), onTap: () { var channel = StreamChannel.of(context).channel; @@ -469,12 +477,18 @@ class _GroupInfoScreenState extends State { tileColor: StreamChatTheme.of(context).colorTheme.whiteSnow, separatorColor: StreamChatTheme.of(context).colorTheme.greyGainsboro, title: 'Files', - leading: StreamSvgIcon.files( - size: 32.0, - color: - StreamChatTheme.of(context).colorTheme.black.withOpacity(0.5), + titleTextStyle: StreamChatTheme.of(context).textTheme.body, + leading: Padding( + padding: const EdgeInsets.symmetric(horizontal: 12.0), + child: StreamSvgIcon.files( + size: 32.0, + color: + StreamChatTheme.of(context).colorTheme.black.withOpacity(0.5), + ), + ), + trailing: StreamSvgIcon.right( + color: StreamChatTheme.of(context).colorTheme.grey, ), - trailing: StreamSvgIcon.right(), onTap: () { var channel = StreamChannel.of(context).channel; @@ -505,10 +519,16 @@ class _GroupInfoScreenState extends State { separatorColor: StreamChatTheme.of(context).colorTheme.greyGainsboro, title: 'Leave Group', - leading: StreamSvgIcon.userRemove( - size: 24.0, - color: - StreamChatTheme.of(context).colorTheme.black.withOpacity(0.5), + titleTextStyle: StreamChatTheme.of(context).textTheme.body, + leading: Padding( + padding: const EdgeInsets.symmetric(horizontal: 16.0), + child: StreamSvgIcon.userRemove( + size: 24.0, + color: StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(0.5), + ), ), trailing: Container( height: 24.0, @@ -767,36 +787,37 @@ class _GroupInfoScreenState extends State { ); }, ), - _buildModalListTile( - context, - StreamSvgIcon.message( - color: StreamChatTheme.of(context).colorTheme.grey, - size: 24.0, - ), - 'Message', - () async { - var client = StreamChat.of(context).client; + if (StreamChat.of(context).user.id != user.id) + _buildModalListTile( + context, + StreamSvgIcon.message( + color: StreamChatTheme.of(context).colorTheme.grey, + size: 24.0, + ), + 'Message', + () async { + var client = StreamChat.of(context).client; - var c = client.channel('messaging', extraData: { - 'members': [ - user.id, - StreamChat.of(context).user.id, - ], - }); + var c = client.channel('messaging', extraData: { + 'members': [ + user.id, + StreamChat.of(context).user.id, + ], + }); - await c.watch(); + await c.watch(); - await Navigator.push( - context, - MaterialPageRoute( - builder: (context) => StreamChannel( - channel: c, - child: ChannelPage(), + await Navigator.push( + context, + MaterialPageRoute( + builder: (context) => StreamChannel( + channel: c, + child: ChannelPage(), + ), ), - ), - ); - }, - ), + ); + }, + ), if (!channel.isDistinct && StreamChat.of(context).user.id != user.id && isUserAdmin) diff --git a/lib/src/channel_bottom_sheet.dart b/lib/src/channel_bottom_sheet.dart index d2c7eb04..3e9f6ec3 100644 --- a/lib/src/channel_bottom_sheet.dart +++ b/lib/src/channel_bottom_sheet.dart @@ -129,16 +129,22 @@ class _ChannelBottomSheetState extends State { height: 24.0, ), OptionListTile( - leading: StreamSvgIcon.user( - color: StreamChatTheme.of(context).colorTheme.grey, + leading: Padding( + padding: const EdgeInsets.symmetric(horizontal: 16.0), + child: StreamSvgIcon.user( + color: StreamChatTheme.of(context).colorTheme.grey, + ), ), title: 'View Info', onTap: widget.onViewInfoTap, ), if (!channel.isDistinct) OptionListTile( - leading: StreamSvgIcon.userRemove( - color: StreamChatTheme.of(context).colorTheme.grey, + leading: Padding( + padding: const EdgeInsets.symmetric(horizontal: 16.0), + child: StreamSvgIcon.userRemove( + color: StreamChatTheme.of(context).colorTheme.grey, + ), ), title: 'Leave Group', onTap: () async { @@ -147,8 +153,11 @@ class _ChannelBottomSheetState extends State { ), if (isOwner) OptionListTile( - leading: StreamSvgIcon.delete( - color: StreamChatTheme.of(context).colorTheme.accentRed, + leading: Padding( + padding: const EdgeInsets.symmetric(horizontal: 16.0), + child: StreamSvgIcon.delete( + color: StreamChatTheme.of(context).colorTheme.accentRed, + ), ), title: 'Delete Conversation', titleColor: StreamChatTheme.of(context).colorTheme.accentRed, @@ -157,8 +166,11 @@ class _ChannelBottomSheetState extends State { }, ), OptionListTile( - leading: StreamSvgIcon.close_small( - color: StreamChatTheme.of(context).colorTheme.grey, + leading: Padding( + padding: const EdgeInsets.symmetric(horizontal: 16.0), + child: StreamSvgIcon.close_small( + color: StreamChatTheme.of(context).colorTheme.grey, + ), ), title: 'Cancel', onTap: () { diff --git a/lib/src/image_footer.dart b/lib/src/image_footer.dart index c17a5bcf..11e62302 100644 --- a/lib/src/image_footer.dart +++ b/lib/src/image_footer.dart @@ -112,13 +112,14 @@ class _ImageFooterState extends State { context: context, removeTop: true, child: BottomAppBar( + color: StreamChatTheme.of(context).colorTheme.white, child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ IconButton( icon: StreamSvgIcon.icon_SHARE( size: 24.0, - color: Colors.black, + color: StreamChatTheme.of(context).colorTheme.black, ), onPressed: () { _buildShareModal(context); @@ -134,11 +135,8 @@ class _ImageFooterState extends State { children: [ Text( '${widget.currentPage + 1} of ${widget.totalPages}', - style: TextStyle( - fontSize: 16.0, - fontWeight: FontWeight.w700, - color: Colors.black, - ), + style: + StreamChatTheme.of(context).textTheme.headlineBold, ), ], ), @@ -146,7 +144,7 @@ class _ImageFooterState extends State { ), IconButton( icon: StreamSvgIcon.Icon_grid( - color: Colors.black, + color: StreamChatTheme.of(context).colorTheme.black, ), onPressed: () { _buildPhotosModal(context); @@ -337,7 +335,10 @@ class _ImageFooterState extends State { padding: const EdgeInsets.all(24), child: StreamSvgIcon.search( size: 96, - color: Colors.grey, + color: + StreamChatTheme.of(context) + .colorTheme + .grey, ), ), Text( @@ -436,32 +437,41 @@ class _ImageFooterState extends State { ), child: TextField( controller: _searchController, - cursorColor: Colors.black, + cursorColor: StreamChatTheme.of(context).colorTheme.black, autofocus: true, decoration: InputDecoration( prefixIconConstraints: BoxConstraints.tight(Size(40, 24)), prefixIcon: Padding( padding: const EdgeInsets.only(left: 8, right: 8), child: StreamSvgIcon.search( - color: Colors.black, + color: StreamChatTheme.of(context).colorTheme.black, size: 24, ), ), hintText: 'Search', hintStyle: TextStyle( - color: Colors.black.withOpacity(0.5), + color: StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(0.5), fontSize: 14, ), enabledBorder: OutlineInputBorder( borderSide: BorderSide( - color: Colors.black.withOpacity(0.08), + color: StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(0.08), ), borderRadius: BorderRadius.circular(24), ), focusedBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(24.0), borderSide: BorderSide( - color: Colors.black.withOpacity(0.08), + color: StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(0.08), ), ), contentPadding: EdgeInsets.zero, @@ -500,7 +510,7 @@ class _ImageFooterState extends State { padding: const EdgeInsets.symmetric(horizontal: 6.0), child: IconButton( icon: StreamSvgIcon.search( - color: Colors.black, + color: StreamChatTheme.of(context).colorTheme.black, ), iconSize: 24.0, onPressed: () { @@ -517,7 +527,7 @@ class _ImageFooterState extends State { style: TextStyle( fontSize: 16.0, fontWeight: FontWeight.w700, - color: Colors.black, + color: StreamChatTheme.of(context).colorTheme.black, ), ), ), @@ -525,7 +535,7 @@ class _ImageFooterState extends State { padding: const EdgeInsets.symmetric(horizontal: 6.0), child: IconButton( icon: StreamSvgIcon.share_arrow( - color: Colors.black, + color: StreamChatTheme.of(context).colorTheme.black, ), onPressed: () async { final attachment = widget.mediaAttachments[widget.currentPage]; diff --git a/lib/src/option_list_tile.dart b/lib/src/option_list_tile.dart index a18c2ab1..eb6e0ab7 100644 --- a/lib/src/option_list_tile.dart +++ b/lib/src/option_list_tile.dart @@ -4,12 +4,13 @@ import 'package:stream_chat_flutter/src/stream_svg_icon.dart'; class OptionListTile extends StatelessWidget { final String title; - final StreamSvgIcon leading; + final Widget leading; final Widget trailing; final VoidCallback onTap; final Color titleColor; final Color tileColor; final Color separatorColor; + final TextStyle titleTextStyle; OptionListTile({ this.title, @@ -19,6 +20,7 @@ class OptionListTile extends StatelessWidget { this.titleColor, this.tileColor, this.separatorColor, + this.titleTextStyle, }); @override @@ -38,10 +40,7 @@ class OptionListTile extends StatelessWidget { onTap: onTap, child: Row( children: [ - if (leading != null) - Expanded( - child: Center(child: leading), - ), + if (leading != null) Center(child: leading), if (leading == null) SizedBox( width: 16.0, @@ -50,14 +49,15 @@ class OptionListTile extends StatelessWidget { flex: 4, child: Text( title, - style: titleColor == null - ? StreamChatTheme.of(context).textTheme.bodyBold - : StreamChatTheme.of(context) - .textTheme - .bodyBold - .copyWith( - color: titleColor, - ), + style: titleTextStyle ?? + (titleColor == null + ? StreamChatTheme.of(context).textTheme.bodyBold + : StreamChatTheme.of(context) + .textTheme + .bodyBold + .copyWith( + color: titleColor, + )), ), ), Expanded( From 4e265f4a8de0ed9b6c5cdbff9b28827e2c7d35bb Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Fri, 1 Jan 2021 18:49:36 +0530 Subject: [PATCH 0730/1140] fix: Fixed remove user bug --- example/lib/group_info_screen.dart | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/example/lib/group_info_screen.dart b/example/lib/group_info_screen.dart index c044a23d..84aa9c3a 100644 --- a/example/lib/group_info_screen.dart +++ b/example/lib/group_info_screen.dart @@ -26,7 +26,7 @@ class _GroupInfoScreenState extends State { final FocusNode _focusNode = FocusNode(); - int groupMemberListLength; + bool listExpanded = false; void _userNameListener() { if (_searchController.text == _userNameQuery) { @@ -155,7 +155,13 @@ class _GroupInfoScreenState extends State { } Widget _buildMembers(List members) { - groupMemberListLength ??= members.length > 6 ? 6 : members.length; + int groupMemberListLength; + + if (listExpanded) { + groupMemberListLength = members.length; + } else { + groupMemberListLength = members.length > 6 ? 6 : members.length; + } return Column( children: [ @@ -241,7 +247,7 @@ class _GroupInfoScreenState extends State { InkWell( onTap: () { setState(() { - groupMemberListLength = members.length; + listExpanded = true; }); }, child: Material( From 00e211f9fe1967f1c271ea701f330b575e33f0cc Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Fri, 1 Jan 2021 18:59:38 +0530 Subject: [PATCH 0731/1140] fix: Fixed separator width --- lib/src/option_list_tile.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/option_list_tile.dart b/lib/src/option_list_tile.dart index eb6e0ab7..1b87c9d7 100644 --- a/lib/src/option_list_tile.dart +++ b/lib/src/option_list_tile.dart @@ -30,7 +30,7 @@ class OptionListTile extends StatelessWidget { Container( color: separatorColor ?? StreamChatTheme.of(context).colorTheme.greyGainsboro, - height: 2.0, + height: 1.0, ), Material( color: tileColor ?? StreamChatTheme.of(context).colorTheme.white, From 7cf0e00b15b629c69eb375ff7165b35d87e864b9 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Sat, 2 Jan 2021 14:14:04 +0530 Subject: [PATCH 0732/1140] fix: added todo --- example/lib/group_info_screen.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/example/lib/group_info_screen.dart b/example/lib/group_info_screen.dart index 84aa9c3a..056f17c6 100644 --- a/example/lib/group_info_screen.dart +++ b/example/lib/group_info_screen.dart @@ -834,7 +834,7 @@ class _GroupInfoScreenState extends State { size: 24.0, ), 'Make Owner', () { - // TODO: I have no clue how to make someone an owner + // TODO: Add make owner implementation (Remaining from backend) }), if (!channel.isDistinct && StreamChat.of(context).user.id != user.id && From a2b3f34a0fd39bae4f49b462eb71c56b8c66ef6a Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Mon, 4 Jan 2021 12:52:53 +0530 Subject: [PATCH 0733/1140] [Message Input] Fix replyToMessage cleared bug Signed-off-by: Sahil Kumar --- example/lib/main.dart | 9 ++++++--- lib/src/message_input.dart | 29 +++++++++-------------------- 2 files changed, 15 insertions(+), 23 deletions(-) diff --git a/example/lib/main.dart b/example/lib/main.dart index 17f497a4..aff84600 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -434,7 +434,7 @@ class ChannelPage extends StatefulWidget { } class _ChannelPageState extends State { - Message _replyMessage; + Message _replyToMessage; FocusNode _focusNode; @override @@ -450,7 +450,7 @@ class _ChannelPageState extends State { } void _reply(Message message) { - setState(() => _replyMessage = message); + setState(() => _replyToMessage = message); _focusNode.requestFocus(); } @@ -502,7 +502,10 @@ class _ChannelPageState extends State { ), MessageInput( focusNode: _focusNode, - replyToMessage: _replyMessage, + replyToMessage: _replyToMessage, + onReplyToMessageCleared: () { + setState(() => _replyToMessage = null); + }, ), ], ), diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index d014e390..95a4e497 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -111,6 +111,7 @@ class MessageInput extends StatefulWidget { this.attachmentThumbnailBuilders, this.focusNode, this.replyToMessage, + this.onReplyToMessageCleared, }) : super(key: key); /// Message to edit @@ -162,6 +163,9 @@ class MessageInput extends StatefulWidget { /// final Message replyToMessage; + /// + final VoidCallback onReplyToMessageCleared; + @override MessageInputState createState() => MessageInputState(); @@ -203,9 +207,7 @@ class MessageInputState extends State { /// The editing controller passed to the input TextField TextEditingController textEditingController; - Message _replyToMessage; - - bool get _hasReplyToMessage => _replyToMessage != null; + bool get _hasReplyToMessage => widget.replyToMessage != null; @override Widget build(BuildContext context) { @@ -242,9 +244,7 @@ class MessageInputState extends State { IconButton( visualDensity: VisualDensity.compact, icon: StreamSvgIcon.close_small(), - onPressed: () { - setState(() => _replyToMessage = null); - }, + onPressed: widget.onReplyToMessageCleared, ), ], ), @@ -1353,7 +1353,7 @@ class MessageInputState extends State { if (!_hasReplyToMessage) { return Offstage(); } - final containsUrl = _replyToMessage.attachments + final containsUrl = widget.replyToMessage.attachments ?.any((element) => element.ogScrapeUrl != null) == true; return Transform( @@ -1362,7 +1362,7 @@ class MessageInputState extends State { child: ReplyToMessageWidget( reverse: true, showBorder: !containsUrl, - message: _replyToMessage, + message: widget.replyToMessage, messageTheme: StreamChatTheme.of(context).otherMessageTheme, ), ); @@ -2015,7 +2015,7 @@ class MessageInputState extends State { textEditingController.clear(); _attachments.clear(); - _replyToMessage = null; + widget.onReplyToMessageCleared(); setState(() { _messageIsPresent = false; @@ -2091,9 +2091,6 @@ class MessageInputState extends State { @override void initState() { super.initState(); - - _replyToMessage = widget.replyToMessage; - _focusNode = widget.focusNode ?? FocusNode(); _emojiNames = Emoji.all().map((e) => e.name); @@ -2155,14 +2152,6 @@ class MessageInputState extends State { } super.didChangeDependencies(); } - - @override - void didUpdateWidget(MessageInput oldWidget) { - super.didUpdateWidget(oldWidget); - if (widget.replyToMessage?.id != _replyToMessage?.id) { - _replyToMessage = widget.replyToMessage; - } - } } class _SendingAttachment { From 380b9373a464ce574b60b62d48a65e4667363b43 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Mon, 4 Jan 2021 12:53:21 +0530 Subject: [PATCH 0734/1140] minor improvements Signed-off-by: Sahil Kumar --- lib/src/lazy_load_scroll_view.dart | 2 +- lib/src/media_list_view.dart | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/lib/src/lazy_load_scroll_view.dart b/lib/src/lazy_load_scroll_view.dart index 2bc82a55..bc1f4d1b 100644 --- a/lib/src/lazy_load_scroll_view.dart +++ b/lib/src/lazy_load_scroll_view.dart @@ -31,7 +31,7 @@ class LazyLoadScrollView extends StatefulWidget { final bool isLoading; /// Initiates a LazyLoadScrollView widget - LazyLoadScrollView({ + const LazyLoadScrollView({ Key key, @required this.child, this.onStartOfPage, diff --git a/lib/src/media_list_view.dart b/lib/src/media_list_view.dart index 08ebfcc7..4a954857 100644 --- a/lib/src/media_list_view.dart +++ b/lib/src/media_list_view.dart @@ -29,6 +29,7 @@ class MediaListView extends StatefulWidget { this.selectedIds = const [], this.onSelect, }) : super(key: key); + @override _MediaListViewState createState() => _MediaListViewState(); } @@ -42,9 +43,7 @@ class _MediaListViewState extends State { @override Widget build(BuildContext context) { return LazyLoadScrollView( - onEndOfPage: () { - _getMedia(); - }, + onEndOfPage: () async => _getMedia(), child: GridView.builder( itemCount: _media.length, controller: _scrollController, From 8fa8c9dc6b52b73b655a113363e4a1947a27d8ea Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Mon, 4 Jan 2021 13:48:29 +0530 Subject: [PATCH 0735/1140] Rename replyToMessage -> quotedMessage Signed-off-by: Sahil Kumar --- example/lib/main.dart | 10 +++++----- lib/src/message_input.dart | 28 ++++++++++++++-------------- lib/src/message_widget.dart | 12 ++++++------ lib/src/reply_message_widget.dart | 4 ++-- 4 files changed, 27 insertions(+), 27 deletions(-) diff --git a/example/lib/main.dart b/example/lib/main.dart index aff84600..70cd513a 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -434,7 +434,7 @@ class ChannelPage extends StatefulWidget { } class _ChannelPageState extends State { - Message _replyToMessage; + Message _quotedMessage; FocusNode _focusNode; @override @@ -450,7 +450,7 @@ class _ChannelPageState extends State { } void _reply(Message message) { - setState(() => _replyToMessage = message); + setState(() => _quotedMessage = message); _focusNode.requestFocus(); } @@ -502,9 +502,9 @@ class _ChannelPageState extends State { ), MessageInput( focusNode: _focusNode, - replyToMessage: _replyToMessage, - onReplyToMessageCleared: () { - setState(() => _replyToMessage = null); + quotedMessage: _quotedMessage, + onQuotedMessageCleared: () { + setState(() => _quotedMessage = null); }, ), ], diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 95a4e497..a24bda9d 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -110,8 +110,8 @@ class MessageInput extends StatefulWidget { this.actionsLocation = ActionsLocation.left, this.attachmentThumbnailBuilders, this.focusNode, - this.replyToMessage, - this.onReplyToMessageCleared, + this.quotedMessage, + this.onQuotedMessageCleared, }) : super(key: key); /// Message to edit @@ -161,10 +161,10 @@ class MessageInput extends StatefulWidget { final FocusNode focusNode; /// - final Message replyToMessage; + final Message quotedMessage; /// - final VoidCallback onReplyToMessageCleared; + final VoidCallback onQuotedMessageCleared; @override MessageInputState createState() => MessageInputState(); @@ -207,7 +207,7 @@ class MessageInputState extends State { /// The editing controller passed to the input TextField TextEditingController textEditingController; - bool get _hasReplyToMessage => widget.replyToMessage != null; + bool get _hasQuotedMessage => widget.quotedMessage != null; @override Widget build(BuildContext context) { @@ -226,7 +226,7 @@ class MessageInputState extends State { child: Column( mainAxisSize: MainAxisSize.min, children: [ - if (_hasReplyToMessage) + if (_hasQuotedMessage) Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ @@ -244,7 +244,7 @@ class MessageInputState extends State { IconButton( visualDensity: VisualDensity.compact, icon: StreamSvgIcon.close_small(), - onPressed: widget.onReplyToMessageCleared, + onPressed: widget.onQuotedMessageCleared, ), ], ), @@ -1350,19 +1350,19 @@ class MessageInputState extends State { } Widget _buildReplyToMessage() { - if (!_hasReplyToMessage) { + if (!_hasQuotedMessage) { return Offstage(); } - final containsUrl = widget.replyToMessage.attachments + final containsUrl = widget.quotedMessage.attachments ?.any((element) => element.ogScrapeUrl != null) == true; return Transform( transform: Matrix4.rotationY(pi), alignment: Alignment.center, - child: ReplyToMessageWidget( + child: QuotedMessageWidget( reverse: true, showBorder: !containsUrl, - message: widget.replyToMessage, + message: widget.quotedMessage, messageTheme: StreamChatTheme.of(context).otherMessageTheme, ), ); @@ -2015,7 +2015,7 @@ class MessageInputState extends State { textEditingController.clear(); _attachments.clear(); - widget.onReplyToMessageCleared(); + widget.onQuotedMessageCleared(); setState(() { _messageIsPresent = false; @@ -2047,9 +2047,9 @@ class MessageInputState extends State { ); } - if (widget.replyToMessage != null) { + if (widget.quotedMessage != null) { message = message.copyWith( - replyToMessageId: widget.replyToMessage.id, + quotedMessageId: widget.quotedMessage.id, ); } diff --git a/lib/src/message_widget.dart b/lib/src/message_widget.dart index 36364416..c0fea794 100644 --- a/lib/src/message_widget.dart +++ b/lib/src/message_widget.dart @@ -241,7 +241,7 @@ class _MessageWidgetState extends State { bool get showInChannel => widget.showInChannelIndicator && widget.message?.showInChannel == true; - bool get _hasReplyToMessage => widget.message?.replyToMessage != null; + bool get _hasQuotedMessage => widget.message?.quotedMessage != null; bool get isSendFailed => widget.message.status == MessageSendingStatus.FAILED; @@ -397,11 +397,11 @@ class _MessageWidgetState extends State { mainAxisSize: MainAxisSize.min, children: [ - if (_hasReplyToMessage) - ReplyToMessageWidget( + if (_hasQuotedMessage) + QuotedMessageWidget( message: widget .message - .replyToMessage, + .quotedMessage, messageTheme: isMyMessage ? StreamChatTheme.of( context) @@ -919,7 +919,7 @@ class _MessageWidgetState extends State { if (widget.message.attachments ?.any((element) => element.ogScrapeUrl != null) == true && - !_hasReplyToMessage) + !_hasQuotedMessage) _buildUrlAttachment(), ], ), @@ -931,7 +931,7 @@ class _MessageWidgetState extends State { widget.message.text.characters.every((c) => Emoji.byChar(c) != null); Color _getBackgroundColor() { - if (_hasReplyToMessage) { + if (_hasQuotedMessage) { return widget.messageTheme.messageBackgroundColor; } diff --git a/lib/src/reply_message_widget.dart b/lib/src/reply_message_widget.dart index 1a4348f3..40b78cfa 100644 --- a/lib/src/reply_message_widget.dart +++ b/lib/src/reply_message_widget.dart @@ -63,7 +63,7 @@ class _VideoAttachmentThumbnailState extends State<_VideoAttachmentThumbnail> { } /// -class ReplyToMessageWidget extends StatelessWidget { +class QuotedMessageWidget extends StatelessWidget { /// The message final Message message; @@ -84,7 +84,7 @@ class ReplyToMessageWidget extends StatelessWidget { attachmentThumbnailBuilders; /// - ReplyToMessageWidget({ + QuotedMessageWidget({ Key key, @required this.message, @required this.messageTheme, From 032555831c7e7621710029b1b70e49d2a477ac00 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Mon, 4 Jan 2021 13:52:05 +0530 Subject: [PATCH 0736/1140] Revert "testing changes, remove them when pushed" This reverts commit a27efad0 Signed-off-by: Sahil Kumar --- example/lib/choose_user_page.dart | 4 ++-- example/lib/main.dart | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/example/lib/choose_user_page.dart b/example/lib/choose_user_page.dart index ca28b1b3..55bfa36c 100644 --- a/example/lib/choose_user_page.dart +++ b/example/lib/choose_user_page.dart @@ -11,13 +11,13 @@ import 'routes/routes.dart'; const kStreamApiKey = 'STREAM_API_KEY'; const kStreamUserId = 'STREAM_USER_ID'; const kStreamToken = 'STREAM_TOKEN'; -const kDefaultStreamApiKey = 'hg4yvnb2g6pu'; +const kDefaultStreamApiKey = 'uj7qrdbfrzvg'; class ChooseUserPage extends StatelessWidget { @override Widget build(BuildContext context) { final users = { - 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoidmlzaGFsIn0.va4qzf2KTQctOJfqdtzcdETAMKgazshuJnYJCPmmaKY': + 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoidmlzaGFsIn0.lCz-idDgaZ-xszjnuB_hTfeIOhTFmJtTB2fEjhwrcCI': User( id: 'vishal', extraData: { diff --git a/example/lib/main.dart b/example/lib/main.dart index 70cd513a..f4b183c6 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -22,7 +22,6 @@ void main() async { final client = Client( apiKey ?? kDefaultStreamApiKey, - baseURL: 'https://chat-proxy-oregon.stream-io-api.com', logLevel: Level.INFO, showLocalNotification: (!kIsWeb && Platform.isAndroid) ? showLocalNotification : null, From 94555a756560cde9bce8644237aff5b6c48b415d Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Mon, 4 Jan 2021 14:17:57 +0530 Subject: [PATCH 0737/1140] del: Removed share media modal --- lib/src/image_footer.dart | 315 ++------------------------------------ 1 file changed, 14 insertions(+), 301 deletions(-) diff --git a/lib/src/image_footer.dart b/lib/src/image_footer.dart index 11e62302..3a6cfbcc 100644 --- a/lib/src/image_footer.dart +++ b/lib/src/image_footer.dart @@ -12,7 +12,6 @@ import 'package:flutter/material.dart'; import 'package:image_gallery_saver/image_gallery_saver.dart'; import 'package:path_provider/path_provider.dart'; import 'package:stream_chat/stream_chat.dart'; -import 'package:stream_chat_flutter/src/stream_chat.dart'; import 'package:stream_chat_flutter/src/stream_chat_theme.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; @@ -121,8 +120,20 @@ class _ImageFooterState extends State { size: 24.0, color: StreamChatTheme.of(context).colorTheme.black, ), - onPressed: () { - _buildShareModal(context); + onPressed: () async { + final attachment = + widget.mediaAttachments[widget.currentPage]; + var url = attachment.imageUrl ?? + attachment.assetUrl ?? + attachment.thumbUrl; + var type = attachment.type == 'image' + ? 'jpg' + : url?.split('?')?.first?.split('.')?.last ?? 'jpg'; + var request = await HttpClient().getUrl(Uri.parse(url)); + var response = await request.close(); + var bytes = + await consolidateHttpClientResponseBytes(response); + await Share.file('File', 'image.$type', bytes, 'image/$type'); }, ), InkWell( @@ -258,304 +269,6 @@ class _ImageFooterState extends State { ); } - void _buildShareModal(context) async { - final result = await showDialog( - context: context, - builder: (context) { - return StatefulBuilder(builder: (context, modalSetState) { - modalSetStateCallback = modalSetState; - return Padding( - padding: EdgeInsets.only( - top: _userSearchMode || _messageFocusNode.hasFocus - ? 16.0 - : MediaQuery.of(context).size.height / 2, - left: 8.0, - right: 8.0), - child: Material( - borderRadius: BorderRadius.only( - topLeft: Radius.circular(16.0), - topRight: Radius.circular(16.0), - ), - clipBehavior: Clip.antiAlias, - child: Scaffold( - body: UsersBloc( - child: Column( - children: [ - _buildTextInputSection(modalSetState), - Expanded( - child: ChannelsBloc( - child: ChannelListView( - selectedChannels: _selectedChannels, - onChannelTap: (channel, _) { - _searchController.clear(); - if (!_selectedChannels.contains(channel)) { - modalSetState(() { - _selectedChannels.add(channel); - }); - } else { - modalSetState(() { - _selectedChannels.remove(channel); - }); - } - }, - padding: const EdgeInsets.symmetric(vertical: 8), - crossAxisCount: 4, - pagination: PaginationParams( - limit: 25, - ), - filter: { - if (_channelNameQuery?.trim()?.isNotEmpty == true) - 'name': { - r'$autocomplete': _channelNameQuery, - }, - 'id': { - r'$ne': StreamChat.of(context).user.id, - }, - }, - sort: [ - SortOption( - 'name', - direction: SortOption.ASC, - ), - ], - emptyBuilder: (_) { - return LayoutBuilder( - builder: (context, viewportConstraints) { - return SingleChildScrollView( - physics: AlwaysScrollableScrollPhysics(), - child: ConstrainedBox( - constraints: BoxConstraints( - minHeight: - viewportConstraints.maxHeight, - ), - child: Center( - child: Column( - children: [ - Padding( - padding: const EdgeInsets.all(24), - child: StreamSvgIcon.search( - size: 96, - color: - StreamChatTheme.of(context) - .colorTheme - .grey, - ), - ), - Text( - 'No chat matches these keywords...', - ), - ], - ), - ), - ), - ); - }, - ); - }, - ), - ), - ), - if (_selectedChannels.isNotEmpty) - _buildShareTextInputSection(modalSetState), - if (!_userSearchMode && _selectedChannels.isEmpty) - Align( - alignment: Alignment.bottomCenter, - child: Container( - color: StreamChatTheme.of(context).colorTheme.white, - height: 48.0, - child: Material( - color: - StreamChatTheme.of(context).colorTheme.white, - child: InkWell( - onTap: () async { - var url = widget - .mediaAttachments[widget.currentPage] - .imageUrl ?? - widget - .mediaAttachments[widget.currentPage] - .assetUrl ?? - widget - .mediaAttachments[widget.currentPage] - .thumbUrl; - - if (widget - .mediaAttachments[widget.currentPage] - .type == - 'video') { - await _saveVideo(url); - } else { - await _saveImage(url); - } - Navigator.pop(context); - }, - child: SizedBox.expand( - child: Center( - child: Text( - 'Save to Photos', - style: TextStyle( - color: StreamChatTheme.of(context) - .colorTheme - .accentBlue, - fontWeight: FontWeight.bold, - ), - ), - ), - ), - ), - ), - ), - ), - ], - ), - ), - ), - ), - ); - }); - }, - ); - if (result == null) { - _selectedChannels.clear(); - } - } - - Widget _buildTextInputSection(modalSetState) { - if (_userSearchMode) { - return Column( - children: [ - SizedBox(height: 16.0), - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - SizedBox(width: 8.0), - Expanded( - child: Container( - height: 36, - margin: const EdgeInsets.symmetric( - vertical: 8, - horizontal: 8, - ), - child: TextField( - controller: _searchController, - cursorColor: StreamChatTheme.of(context).colorTheme.black, - autofocus: true, - decoration: InputDecoration( - prefixIconConstraints: BoxConstraints.tight(Size(40, 24)), - prefixIcon: Padding( - padding: const EdgeInsets.only(left: 8, right: 8), - child: StreamSvgIcon.search( - color: StreamChatTheme.of(context).colorTheme.black, - size: 24, - ), - ), - hintText: 'Search', - hintStyle: TextStyle( - color: StreamChatTheme.of(context) - .colorTheme - .black - .withOpacity(0.5), - fontSize: 14, - ), - enabledBorder: OutlineInputBorder( - borderSide: BorderSide( - color: StreamChatTheme.of(context) - .colorTheme - .black - .withOpacity(0.08), - ), - borderRadius: BorderRadius.circular(24), - ), - focusedBorder: OutlineInputBorder( - borderRadius: BorderRadius.circular(24.0), - borderSide: BorderSide( - color: StreamChatTheme.of(context) - .colorTheme - .black - .withOpacity(0.08), - ), - ), - contentPadding: EdgeInsets.zero, - ), - ), - ), - ), - IconButton( - icon: StreamSvgIcon.close_small( - color: StreamChatTheme.of(context) - .colorTheme - .black - .withOpacity(0.5), - ), - splashRadius: 24, - onPressed: () { - modalSetState(() { - if (_searchController.text.isNotEmpty) { - _searchController.text = ''; - } else { - _userSearchMode = false; - } - }); - setState(() {}); - }, - ) - ], - ), - ], - ); - } - return Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Padding( - padding: const EdgeInsets.symmetric(horizontal: 6.0), - child: IconButton( - icon: StreamSvgIcon.search( - color: StreamChatTheme.of(context).colorTheme.black, - ), - iconSize: 24.0, - onPressed: () { - modalSetState(() { - _userSearchMode = true; - }); - }, - ), - ), - Padding( - padding: const EdgeInsets.all(16.0), - child: Text( - 'Select a Chat to Share', - style: TextStyle( - fontSize: 16.0, - fontWeight: FontWeight.w700, - color: StreamChatTheme.of(context).colorTheme.black, - ), - ), - ), - Padding( - padding: const EdgeInsets.symmetric(horizontal: 6.0), - child: IconButton( - icon: StreamSvgIcon.share_arrow( - color: StreamChatTheme.of(context).colorTheme.black, - ), - onPressed: () async { - final attachment = widget.mediaAttachments[widget.currentPage]; - var url = attachment.imageUrl ?? - attachment.assetUrl ?? - attachment.thumbUrl; - var type = attachment.type == 'image' - ? 'jpg' - : url?.split('?')?.first?.split('.')?.last ?? 'jpg'; - var request = await HttpClient().getUrl(Uri.parse(url)); - var response = await request.close(); - var bytes = await consolidateHttpClientResponseBytes(response); - await Share.file('File', 'image.$type', bytes, 'image/$type'); - }, - ), - ), - ], - ); - } - Widget _buildShareTextInputSection(modalSetState) { return Align( alignment: Alignment.bottomCenter, From 54efd6f3de3de6ae9c88853d234195170a41db0a Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Mon, 4 Jan 2021 14:29:18 +0530 Subject: [PATCH 0738/1140] fix: fix channel null error --- example/lib/group_info_screen.dart | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/example/lib/group_info_screen.dart b/example/lib/group_info_screen.dart index 056f17c6..1cba6fa7 100644 --- a/example/lib/group_info_screen.dart +++ b/example/lib/group_info_screen.dart @@ -92,6 +92,10 @@ class _GroupInfoScreenState extends State { StreamBuilder( stream: channel.channelStateStream, builder: (context, state) { + if (!state.hasData) { + return CircularProgressIndicator(); + } + return Text( _getChannelName( 2 * MediaQuery.of(context).size.width / 3, From 43446713c8200a2086d6120ae6fa53b05304dffb Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Mon, 4 Jan 2021 14:29:55 +0530 Subject: [PATCH 0739/1140] fix: fixed null error --- example/lib/group_info_screen.dart | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/example/lib/group_info_screen.dart b/example/lib/group_info_screen.dart index 1cba6fa7..0aa0cfb0 100644 --- a/example/lib/group_info_screen.dart +++ b/example/lib/group_info_screen.dart @@ -93,7 +93,16 @@ class _GroupInfoScreenState extends State { stream: channel.channelStateStream, builder: (context, state) { if (!state.hasData) { - return CircularProgressIndicator(); + return Text( + 'Loading...', + style: TextStyle( + color: + StreamChatTheme.of(context).colorTheme.black, + fontSize: 16, + ), + maxLines: 1, + overflow: TextOverflow.ellipsis, + ); } return Text( From 33810de18f1abc808c483c91b16a791a22859798 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Mon, 4 Jan 2021 15:49:24 +0530 Subject: [PATCH 0740/1140] Refactoring, UI fixes Signed-off-by: Sahil Kumar --- lib/src/message_input.dart | 6 +- lib/src/message_widget.dart | 67 +++++++------ ...widget.dart => quoted_message_widget.dart} | 98 ++++++++++--------- 3 files changed, 90 insertions(+), 81 deletions(-) rename lib/src/{reply_message_widget.dart => quoted_message_widget.dart} (83%) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index a24bda9d..72c5f70d 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -25,7 +25,7 @@ import 'package:video_compress/video_compress.dart'; import 'extension.dart'; import '../stream_chat_flutter.dart'; -import 'reply_message_widget.dart'; +import 'quoted_message_widget.dart'; import 'stream_channel.dart'; typedef FileUploader = Future Function(PlatformFile, Channel); @@ -2015,7 +2015,9 @@ class MessageInputState extends State { textEditingController.clear(); _attachments.clear(); - widget.onQuotedMessageCleared(); + if (widget.onQuotedMessageCleared != null) { + widget.onQuotedMessageCleared(); + } setState(() { _messageIsPresent = false; diff --git a/lib/src/message_widget.dart b/lib/src/message_widget.dart index c0fea794..1c49a9ca 100644 --- a/lib/src/message_widget.dart +++ b/lib/src/message_widget.dart @@ -11,7 +11,7 @@ import 'package:jiffy/jiffy.dart'; import 'package:stream_chat_flutter/src/message_actions_modal.dart'; import 'package:stream_chat_flutter/src/message_reactions_modal.dart'; import 'package:stream_chat_flutter/src/reaction_bubble.dart'; -import 'package:stream_chat_flutter/src/reply_message_widget.dart'; +import 'package:stream_chat_flutter/src/quoted_message_widget.dart'; import 'package:stream_chat_flutter/src/url_attachment.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; @@ -356,37 +356,39 @@ class _MessageWidgetState extends State { widget.messageTheme, ), ) - : GestureDetector( - onLongPress: () => - onLongPress(context), - child: Material( - clipBehavior: - Clip.antiAlias, - shape: widget.shape ?? - RoundedRectangleBorder( - side: isOnlyEmoji - ? BorderSide.none - : widget.borderSide ?? - BorderSide( - color: Theme.of(context).brightness == - Brightness - .dark - ? StreamChatTheme.of(context) - .colorTheme - .white - .withAlpha( - 24) - : StreamChatTheme.of(context) - .colorTheme - .black - .withAlpha(24), - ), - borderRadius: widget - .borderRadiusGeometry ?? - BorderRadius.zero, - ), - color: - _getBackgroundColor(), + : Material( + clipBehavior: Clip.antiAlias, + shape: widget.shape ?? + RoundedRectangleBorder( + side: isOnlyEmoji + ? BorderSide.none + : widget.borderSide ?? + BorderSide( + color: Theme.of(context) + .brightness == + Brightness + .dark + ? StreamChatTheme.of( + context) + .colorTheme + .white + .withAlpha( + 24) + : StreamChatTheme.of( + context) + .colorTheme + .black + .withAlpha( + 24), + ), + borderRadius: widget + .borderRadiusGeometry ?? + BorderRadius.zero, + ), + color: _getBackgroundColor(), + child: InkWell( + onLongPress: () => + onLongPress(context), child: Padding( padding: EdgeInsets.all( hasFiles ? 2.0 : 0.0), @@ -399,6 +401,7 @@ class _MessageWidgetState extends State { children: [ if (_hasQuotedMessage) QuotedMessageWidget( + onTap: () {}, message: widget .message .quotedMessage, diff --git a/lib/src/reply_message_widget.dart b/lib/src/quoted_message_widget.dart similarity index 83% rename from lib/src/reply_message_widget.dart rename to lib/src/quoted_message_widget.dart index 40b78cfa..7c5dd512 100644 --- a/lib/src/reply_message_widget.dart +++ b/lib/src/quoted_message_widget.dart @@ -12,8 +12,9 @@ import 'message_text.dart'; import 'stream_chat_theme.dart'; import 'user_avatar.dart'; import 'utils.dart'; +import 'extension.dart'; -typedef ReplyMessageAttachmentThumbnailBuilder = Widget Function( +typedef QuotedMessageAttachmentThumbnailBuilder = Widget Function( BuildContext, Attachment, ); @@ -80,9 +81,11 @@ class QuotedMessageWidget extends StatelessWidget { final int textLimit; /// Map that defines a thumbnail builder for an attachment type - final Map + final Map attachmentThumbnailBuilders; + final GestureTapCallback onTap; + /// QuotedMessageWidget({ Key key, @@ -92,6 +95,7 @@ class QuotedMessageWidget extends StatelessWidget { this.showBorder = false, this.textLimit = 170, this.attachmentThumbnailBuilders, + this.onTap, }) : super(key: key); bool get _hasAttachments => message.attachments?.isNotEmpty == true; @@ -104,32 +108,54 @@ class QuotedMessageWidget extends StatelessWidget { @override Widget build(BuildContext context) { - return Padding( - padding: const EdgeInsets.only(top: 8, bottom: 6, right: 4, left: 8), - child: Row( - crossAxisAlignment: CrossAxisAlignment.end, - mainAxisSize: MainAxisSize.min, - children: [ - Flexible(child: _buildMessage(context)), - SizedBox(width: 4), - _buildUserAvatar(), - ], + return InkWell( + onTap: onTap, + child: Padding( + padding: const EdgeInsets.only(top: 8, bottom: 6, right: 4, left: 8), + child: Row( + crossAxisAlignment: CrossAxisAlignment.end, + mainAxisSize: MainAxisSize.min, + children: [ + Flexible(child: _buildMessage(context)), + SizedBox(width: 4), + _buildUserAvatar(), + ], + ), ), ); } Widget _buildMessage(BuildContext context) { + final isOnlyEmoji = + message.text.characters.every((c) => Emoji.byChar(c) != null); + var msg = _hasAttachments && !_containsText + ? message.copyWith(text: message.attachments.last?.title ?? '') + : message; + if (msg.text.length > textLimit) { + msg = msg.copyWith(text: '${msg.text.substring(0, textLimit - 3)}...'); + } + final children = [ - if (_hasAttachments) ...[ - _parseAttachments(context), - SizedBox(width: 8), - ], - Flexible(child: _buildTextMessage()), - ]; + if (_hasAttachments) _parseAttachments(context), + if (msg.text.isNotEmpty) + Flexible( + child: Transform( + transform: Matrix4.rotationY(reverse ? pi : 0), + alignment: Alignment.center, + child: MessageText( + message: msg, + messageTheme: isOnlyEmoji && _containsText + ? messageTheme.copyWith( + messageText: messageTheme.messageText.copyWith( + fontSize: 24, + )) + : messageTheme, + ), + ), + ), + ].insertBetween(const SizedBox(width: 8)); + return Container( - constraints: BoxConstraints( - minHeight: 48.0, - ), decoration: BoxDecoration( color: _getBackgroundColor(context), border: showBorder @@ -146,6 +172,7 @@ class QuotedMessageWidget extends StatelessWidget { padding: const EdgeInsets.all(8), child: Row( mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, mainAxisAlignment: reverse ? MainAxisAlignment.end : MainAxisAlignment.start, children: reverse ? children.reversed.toList() : children, @@ -153,30 +180,6 @@ class QuotedMessageWidget extends StatelessWidget { ); } - Widget _buildTextMessage() { - final isOnlyEmoji = - message.text.characters.every((c) => Emoji.byChar(c) != null); - var msg = _hasAttachments && !_containsText - ? message.copyWith(text: message.attachments.last?.title ?? '') - : message; - if (msg.text.length > textLimit) { - msg = msg.copyWith(text: '${msg.text.substring(0, textLimit - 3)}...'); - } - return Transform( - transform: Matrix4.rotationY(reverse ? pi : 0), - alignment: Alignment.center, - child: MessageText( - message: msg, - messageTheme: isOnlyEmoji && _containsText - ? messageTheme.copyWith( - messageText: messageTheme.messageText.copyWith( - fontSize: 24, - )) - : messageTheme, - ), - ); - } - Widget _buildUrlAttachment(Attachment attachment) { final size = Size(32, 32); if (attachment.thumbUrl != null) { @@ -208,7 +211,7 @@ class QuotedMessageWidget extends StatelessWidget { ); child = _buildUrlAttachment(attachment); } else { - ReplyMessageAttachmentThumbnailBuilder attachmentBuilder; + QuotedMessageAttachmentThumbnailBuilder attachmentBuilder; attachment = message.attachments.last; if (attachmentThumbnailBuilders?.containsKey(attachment?.type) == true) { attachmentBuilder = attachmentThumbnailBuilders[attachment?.type]; @@ -219,6 +222,7 @@ class QuotedMessageWidget extends StatelessWidget { } child = attachmentBuilder(context, attachment); } + child = AbsorbPointer(child: child); return Transform( transform: Matrix4.rotationY(reverse ? pi : 0), alignment: Alignment.center, @@ -258,7 +262,7 @@ class QuotedMessageWidget extends StatelessWidget { ); } - Map + Map get _defaultAttachmentBuilder { return { 'image': (_, attachment) { From 95d91f3959f25865011bd41c746cbde7c5ab269a Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Mon, 4 Jan 2021 16:00:20 +0530 Subject: [PATCH 0741/1140] feat: Added show in chat --- example/lib/chat_info_screen.dart | 31 ++++++++++++++++++++++- example/lib/group_info_screen.dart | 25 ++++++++++++++++++ example/lib/main.dart | 21 +++++++++++++++ lib/src/channel_media_display_screen.dart | 4 +++ lib/src/full_screen_media.dart | 9 +++++++ lib/src/giphy_attachment.dart | 3 +++ lib/src/image_actions_modal.dart | 14 ++++++---- lib/src/image_attachment.dart | 3 +++ lib/src/image_header.dart | 5 ++++ lib/src/message_list_view.dart | 5 ++++ lib/src/message_widget.dart | 6 +++++ lib/src/video_attachment.dart | 3 +++ 12 files changed, 123 insertions(+), 6 deletions(-) diff --git a/example/lib/chat_info_screen.dart b/example/lib/chat_info_screen.dart index d992e73b..535c999b 100644 --- a/example/lib/chat_info_screen.dart +++ b/example/lib/chat_info_screen.dart @@ -5,6 +5,9 @@ import 'package:jiffy/jiffy.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; +import 'main.dart'; +import 'routes/routes.dart'; + /// Detail screen for a 1:1 chat correspondence class ChatInfoScreen extends StatefulWidget { /// User in consideration @@ -190,7 +193,9 @@ class _ChatInfoScreenState extends State { StreamChatTheme.of(context).colorTheme.black.withOpacity(0.5), ), ), - trailing: StreamSvgIcon.right(), + trailing: StreamSvgIcon.right( + color: StreamChatTheme.of(context).colorTheme.grey, + ), onTap: () { final channel = StreamChannel.of(context).channel; @@ -208,6 +213,30 @@ class _ChatInfoScreenState extends State { ), ], paginationParams: PaginationParams(limit: 20), + onShowMessage: (m, c) async { + final client = StreamChat.of(context).client; + final message = m; + final channel = client.channel( + c.type, + id: c.id, + ); + if (channel.state == null) { + await channel.watch(); + } + Navigator.pop(context); + Navigator.pop(context); + Navigator.pop(context); + Navigator.pop(context); + Navigator.pop(context); + Navigator.pushNamed( + context, + Routes.CHANNEL_PAGE, + arguments: ChannelPageArgs( + channel: channel, + initialMessage: message, + ), + ); + }, ), ), ), diff --git a/example/lib/group_info_screen.dart b/example/lib/group_info_screen.dart index 0aa0cfb0..a8fb52e4 100644 --- a/example/lib/group_info_screen.dart +++ b/example/lib/group_info_screen.dart @@ -9,6 +9,7 @@ import 'package:stream_chat_flutter/stream_chat_flutter.dart'; import 'chat_info_screen.dart'; import 'main.dart'; +import 'routes/routes.dart'; class GroupInfoScreen extends StatefulWidget { @override @@ -485,6 +486,30 @@ class _GroupInfoScreenState extends State { ), ], paginationParams: PaginationParams(limit: 20), + onShowMessage: (m, c) async { + final client = StreamChat.of(context).client; + final message = m; + final channel = client.channel( + c.type, + id: c.id, + ); + if (channel.state == null) { + await channel.watch(); + } + Navigator.pop(context); + Navigator.pop(context); + Navigator.pop(context); + Navigator.pop(context); + Navigator.pop(context); + Navigator.pushNamed( + context, + Routes.CHANNEL_PAGE, + arguments: ChannelPageArgs( + channel: channel, + initialMessage: message, + ), + ); + }, ), ), ), diff --git a/example/lib/main.dart b/example/lib/main.dart index 69300312..cc01cec4 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -517,6 +517,27 @@ class ChannelPage extends StatelessWidget { parent: parentMessage, ); }, + onShowMessage: (m, c) async { + final client = StreamChat.of(context).client; + final message = m; + final channel = client.channel( + c.type, + id: c.id, + ); + if (channel.state == null) { + await channel.watch(); + } + Navigator.pop(context); + Navigator.pop(context); + Navigator.pushReplacementNamed( + context, + Routes.CHANNEL_PAGE, + arguments: ChannelPageArgs( + channel: channel, + initialMessage: message, + ), + ); + }, ), Positioned( bottom: 0, diff --git a/lib/src/channel_media_display_screen.dart b/lib/src/channel_media_display_screen.dart index 09d2a8a8..1f8e9257 100644 --- a/lib/src/channel_media_display_screen.dart +++ b/lib/src/channel_media_display_screen.dart @@ -20,10 +20,13 @@ class ChannelMediaDisplayScreen extends StatefulWidget { /// The builder used when the file list is empty. final WidgetBuilder emptyBuilder; + final ShowMessageCallback onShowMessage; + const ChannelMediaDisplayScreen({ this.sortOptions, this.paginationParams, this.emptyBuilder, + this.onShowMessage, }); @override @@ -191,6 +194,7 @@ class _ChannelMediaDisplayScreenState extends State { message: media[position].message, sentAt: media[position].message.createdAt, userName: media[position].message.user.name, + onShowMessage: widget.onShowMessage, ), ), ), diff --git a/lib/src/full_screen_media.dart b/lib/src/full_screen_media.dart index 7e3f3d7d..e164eec8 100644 --- a/lib/src/full_screen_media.dart +++ b/lib/src/full_screen_media.dart @@ -6,9 +6,12 @@ import 'package:photo_view/photo_view.dart'; import 'package:stream_chat_flutter/src/image_footer.dart'; import 'package:stream_chat_flutter/src/image_header.dart'; import 'package:video_player/video_player.dart'; +import 'stream_channel.dart'; import '../stream_chat_flutter.dart'; +typedef ShowMessageCallback = void Function(Message message, Channel channel); + /// A full screen image widget class FullScreenMedia extends StatefulWidget { /// The url of the image @@ -18,6 +21,7 @@ class FullScreenMedia extends StatefulWidget { final int startIndex; final String userName; final DateTime sentAt; + final ShowMessageCallback onShowMessage; /// Instantiate a new FullScreenImage const FullScreenMedia({ @@ -27,6 +31,7 @@ class FullScreenMedia extends StatefulWidget { this.startIndex = 0, this.userName = '', this.sentAt, + this.onShowMessage, }) : super(key: key); @override @@ -167,6 +172,10 @@ class _FullScreenMediaState extends State message: widget.message, urls: widget.mediaAttachments, currentIndex: _currentPage, + onShowMessage: () { + widget.onShowMessage( + widget.message, StreamChannel.of(context).channel); + }, ), ImageFooter( currentPage: _currentPage, diff --git a/lib/src/giphy_attachment.dart b/lib/src/giphy_attachment.dart index cc1a319f..379fe182 100644 --- a/lib/src/giphy_attachment.dart +++ b/lib/src/giphy_attachment.dart @@ -12,6 +12,7 @@ class GiphyAttachment extends StatelessWidget { final MessageTheme messageTheme; final Message message; final Size size; + final ShowMessageCallback onShowMessage; const GiphyAttachment({ Key key, @@ -19,6 +20,7 @@ class GiphyAttachment extends StatelessWidget { this.messageTheme, this.message, this.size, + this.onShowMessage, }) : super(key: key); @override @@ -75,6 +77,7 @@ class GiphyAttachment extends StatelessWidget { userName: message.user.name, sentAt: message.createdAt, message: message, + onShowMessage: onShowMessage, ), ); })); diff --git a/lib/src/image_actions_modal.dart b/lib/src/image_actions_modal.dart index 168581c0..0001df6f 100644 --- a/lib/src/image_actions_modal.dart +++ b/lib/src/image_actions_modal.dart @@ -15,9 +15,15 @@ class ImageActionsModal extends StatelessWidget { final String sentAt; final List urls; final currentIndex; + final VoidCallback onShowMessage; ImageActionsModal( - {this.message, this.userName, this.sentAt, this.urls, this.currentIndex}); + {this.message, + this.userName, + this.sentAt, + this.urls, + this.currentIndex, + this.onShowMessage}); @override Widget build(BuildContext context) { @@ -134,10 +140,8 @@ class ImageActionsModal extends StatelessWidget { size: 24.0, color: StreamChatTheme.of(context).colorTheme.black, - ), () { - Navigator.pop(context); - Navigator.pop(context); - }), + ), + onShowMessage), _buildButton( context, 'Save ${urls[currentIndex].type == 'video' ? 'Video' : 'Image'}', diff --git a/lib/src/image_attachment.dart b/lib/src/image_attachment.dart index 3210949b..f9e3290b 100644 --- a/lib/src/image_attachment.dart +++ b/lib/src/image_attachment.dart @@ -13,6 +13,7 @@ class ImageAttachment extends StatelessWidget { final MessageTheme messageTheme; final Size size; final bool showTitle; + final ShowMessageCallback onShowMessage; const ImageAttachment({ Key key, @@ -21,6 +22,7 @@ class ImageAttachment extends StatelessWidget { @required this.size, this.messageTheme, this.showTitle = true, + this.onShowMessage, }) : super(key: key); @override @@ -56,6 +58,7 @@ class ImageAttachment extends StatelessWidget { userName: message.user.name, sentAt: message.createdAt, message: message, + onShowMessage: onShowMessage, ), ); }, diff --git a/lib/src/image_header.dart b/lib/src/image_header.dart index a9f1173f..6139bc7c 100644 --- a/lib/src/image_header.dart +++ b/lib/src/image_header.dart @@ -13,6 +13,9 @@ class ImageHeader extends StatelessWidget implements PreferredSizeWidget { /// By default it calls [Navigator.pop] final VoidCallback onBackPressed; + /// Callback to call when pressing the show message button. + final VoidCallback onShowMessage; + /// Callback to call when the header is tapped. final VoidCallback onTitleTap; @@ -35,6 +38,7 @@ class ImageHeader extends StatelessWidget implements PreferredSizeWidget { this.currentIndex, this.showBackButton = true, this.onBackPressed, + this.onShowMessage, this.onTitleTap, this.onImageTap, this.userName = '', @@ -111,6 +115,7 @@ class ImageHeader extends StatelessWidget implements PreferredSizeWidget { message: message, urls: urls, currentIndex: currentIndex, + onShowMessage: onShowMessage, ), ); }); diff --git a/lib/src/message_list_view.dart b/lib/src/message_list_view.dart index 40680991..1bcce91f 100644 --- a/lib/src/message_list_view.dart +++ b/lib/src/message_list_view.dart @@ -116,6 +116,7 @@ class MessageListView extends StatefulWidget { this.scrollController, this.itemPositionListener, this.highlightInitialMessage = false, + this.onShowMessage, }) : super(key: key); /// Function used to build a custom message widget @@ -162,6 +163,8 @@ class MessageListView extends StatefulWidget { /// Also See [StreamChannel] final bool highlightInitialMessage; + final ShowMessageCallback onShowMessage; + @override _MessageListViewState createState() => _MessageListViewState(); } @@ -711,6 +714,7 @@ class _MessageListViewState extends State { messageTheme: isMyMessage ? StreamChatTheme.of(context).ownMessageTheme : StreamChatTheme.of(context).otherMessageTheme, + onShowMessage: widget.onShowMessage, ); } @@ -788,6 +792,7 @@ class _MessageListViewState extends State { : StreamChatTheme.of(context).otherMessageTheme, readList: readList, allRead: allRead, + onShowMessage: widget.onShowMessage, ); if (!initialMessageHighlightComplete && diff --git a/lib/src/message_widget.dart b/lib/src/message_widget.dart index 5c175512..474c3bcf 100644 --- a/lib/src/message_widget.dart +++ b/lib/src/message_widget.dart @@ -119,6 +119,8 @@ class MessageWidget extends StatefulWidget { final List readList; + final ShowMessageCallback onShowMessage; + /// If true show the users username next to the timestamp of the message final bool showUsername; final bool showTimestamp; @@ -157,6 +159,7 @@ class MessageWidget extends StatefulWidget { this.onUserAvatarTap, this.onLinkTap, this.onMessageActions, + this.onShowMessage, this.editMessageInputBuilder, this.textBuilder, Map customAttachmentBuilders, @@ -179,6 +182,7 @@ class MessageWidget extends StatefulWidget { MediaQuery.of(context).size.width * 0.8, MediaQuery.of(context).size.height * 0.3, ), + onShowMessage: onShowMessage, ); }, 'video': (context, message, attachment) { @@ -190,6 +194,7 @@ class MessageWidget extends StatefulWidget { MediaQuery.of(context).size.height * 0.3, ), message: message, + onShowMessage: onShowMessage, ); }, 'giphy': (context, message, attachment) { @@ -201,6 +206,7 @@ class MessageWidget extends StatefulWidget { MediaQuery.of(context).size.width * 0.8, MediaQuery.of(context).size.height * 0.3, ), + onShowMessage: onShowMessage, ); }, 'file': (context, message, attachment) { diff --git a/lib/src/video_attachment.dart b/lib/src/video_attachment.dart index 21ede87a..83763aee 100644 --- a/lib/src/video_attachment.dart +++ b/lib/src/video_attachment.dart @@ -14,6 +14,7 @@ class VideoAttachment extends StatefulWidget { final MessageTheme messageTheme; final Size size; final Message message; + final ShowMessageCallback onShowMessage; VideoAttachment({ Key key, @@ -21,6 +22,7 @@ class VideoAttachment extends StatefulWidget { @required this.messageTheme, this.message, this.size, + this.onShowMessage, }) : super(key: key); @override @@ -95,6 +97,7 @@ class _VideoAttachmentState extends State { userName: widget.message.user.name, sentAt: widget.message.createdAt, message: widget.message, + onShowMessage: widget.onShowMessage, ), ), ), From 74cff7576b104fed196f38e6b5ddb64795b1bf9f Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Mon, 4 Jan 2021 16:22:08 +0530 Subject: [PATCH 0742/1140] fix: fixed onShowMessage not showing up for some aspects --- example/lib/chat_info_screen.dart | 13 ++++++++----- example/lib/group_info_screen.dart | 15 +++++++++------ lib/src/giphy_attachment.dart | 1 + lib/src/image_group.dart | 3 +++ lib/src/message_widget.dart | 1 + 5 files changed, 22 insertions(+), 11 deletions(-) diff --git a/example/lib/chat_info_screen.dart b/example/lib/chat_info_screen.dart index 535c999b..c96d982f 100644 --- a/example/lib/chat_info_screen.dart +++ b/example/lib/chat_info_screen.dart @@ -223,11 +223,14 @@ class _ChatInfoScreenState extends State { if (channel.state == null) { await channel.watch(); } - Navigator.pop(context); - Navigator.pop(context); - Navigator.pop(context); - Navigator.pop(context); - Navigator.pop(context); + await Navigator.pop(context); + await Future.delayed(Duration(milliseconds: 200)); + await Navigator.pop(context); + await Future.delayed(Duration(milliseconds: 200)); + await Navigator.pop(context); + await Future.delayed(Duration(milliseconds: 200)); + await Navigator.pop(context); + await Navigator.pop(context); Navigator.pushNamed( context, Routes.CHANNEL_PAGE, diff --git a/example/lib/group_info_screen.dart b/example/lib/group_info_screen.dart index a8fb52e4..ace7e2c8 100644 --- a/example/lib/group_info_screen.dart +++ b/example/lib/group_info_screen.dart @@ -496,12 +496,15 @@ class _GroupInfoScreenState extends State { if (channel.state == null) { await channel.watch(); } - Navigator.pop(context); - Navigator.pop(context); - Navigator.pop(context); - Navigator.pop(context); - Navigator.pop(context); - Navigator.pushNamed( + await Navigator.pop(context); + await Future.delayed(Duration(milliseconds: 200)); + await Navigator.pop(context); + await Future.delayed(Duration(milliseconds: 200)); + await Navigator.pop(context); + await Future.delayed(Duration(milliseconds: 200)); + await Navigator.pop(context); + await Navigator.pop(context); + await Navigator.pushNamed( context, Routes.CHANNEL_PAGE, arguments: ChannelPageArgs( diff --git a/lib/src/giphy_attachment.dart b/lib/src/giphy_attachment.dart index 379fe182..c879cd5b 100644 --- a/lib/src/giphy_attachment.dart +++ b/lib/src/giphy_attachment.dart @@ -330,6 +330,7 @@ class GiphyAttachment extends StatelessWidget { userName: message.user.name, sentAt: message.createdAt, message: message, + onShowMessage: onShowMessage, ), ); })); diff --git a/lib/src/image_group.dart b/lib/src/image_group.dart index e9b52f88..bb577a4b 100644 --- a/lib/src/image_group.dart +++ b/lib/src/image_group.dart @@ -10,11 +10,13 @@ class ImageGroup extends StatelessWidget { @required this.images, @required this.message, @required this.size, + this.onShowMessage, }) : super(key: key); final List images; final Message message; final Size size; + final ShowMessageCallback onShowMessage; @override Widget build(BuildContext context) { @@ -119,6 +121,7 @@ class ImageGroup extends StatelessWidget { userName: message.user.name, sentAt: message.createdAt, message: message, + onShowMessage: onShowMessage, ), ), ), diff --git a/lib/src/message_widget.dart b/lib/src/message_widget.dart index 474c3bcf..b19a8840 100644 --- a/lib/src/message_widget.dart +++ b/lib/src/message_widget.dart @@ -736,6 +736,7 @@ class _MessageWidgetState extends State { ), images: images, message: widget.message, + onShowMessage: widget.onShowMessage, ), ), ), From d54315cf775df8a79121bd638e976e00254b254b Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Mon, 4 Jan 2021 11:54:19 +0100 Subject: [PATCH 0743/1140] force one reaction --- lib/src/reaction_picker.dart | 10 +++++----- pubspec.yaml | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/src/reaction_picker.dart b/lib/src/reaction_picker.dart index 5892a66d..9344b386 100644 --- a/lib/src/reaction_picker.dart +++ b/lib/src/reaction_picker.dart @@ -136,11 +136,11 @@ class _ReactionPickerState extends State /// Add a reaction to the message void sendReaction(BuildContext context, String reactionType) { - StreamChannel.of(context) - .channel - .sendReaction(widget.message, reactionType, extraData: { - 'enforce_unique': true, - }); + StreamChannel.of(context).channel.sendReaction( + widget.message, + reactionType, + enforceUnique: true, + ); pop(); } diff --git a/pubspec.yaml b/pubspec.yaml index 12374291..db646293 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -28,7 +28,7 @@ dependencies: file_picker: ^2.0.12 image_picker: ^0.6.7+2 flutter_keyboard_visibility: ^3.3.0 - stream_chat: ^0.2.20 + stream_chat: ^0.2.21+2 mime: ^0.9.6+3 video_compress: ^2.1.1 visibility_detector: ^0.1.5 From fa50372f4203a2f0080376c2aa2b229284ce63f5 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Mon, 4 Jan 2021 11:55:30 +0100 Subject: [PATCH 0744/1140] update default reactions --- lib/src/stream_chat_theme.dart | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/src/stream_chat_theme.dart b/lib/src/stream_chat_theme.dart index 60e37b80..ec469f81 100644 --- a/lib/src/stream_chat_theme.dart +++ b/lib/src/stream_chat_theme.dart @@ -342,19 +342,19 @@ class StreamChatThemeData { assetName: 'Icon_love_reaction.svg', ), ReactionIcon( - type: 'thumbs_up', + type: 'like', assetName: 'Icon_thumbs_up_reaction.svg', ), ReactionIcon( - type: 'thumbs_down', + type: 'sad', assetName: 'Icon_thumbs_down_reaction.svg', ), ReactionIcon( - type: 'lol', + type: 'haha', assetName: 'Icon_LOL_reaction.svg', ), ReactionIcon( - type: 'wut', + type: 'wow', assetName: 'Icon_wut_reaction.svg', ), ], From d0c46569730f33cf0045e75ed398ce4212a2724f Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Mon, 4 Jan 2021 12:04:00 +0100 Subject: [PATCH 0745/1140] cleanup --- lib/src/channel_bottom_sheet.dart | 2 +- lib/src/image_footer.dart | 8 ++------ lib/src/media_list_view.dart | 11 +++-------- lib/src/message_widget.dart | 27 --------------------------- lib/src/stream_chat.dart | 1 - lib/src/stream_chat_theme.dart | 20 +------------------- 6 files changed, 7 insertions(+), 62 deletions(-) diff --git a/lib/src/channel_bottom_sheet.dart b/lib/src/channel_bottom_sheet.dart index d2c7eb04..4bfa3fd0 100644 --- a/lib/src/channel_bottom_sheet.dart +++ b/lib/src/channel_bottom_sheet.dart @@ -5,7 +5,7 @@ import 'channel_info.dart'; import 'option_list_tile.dart'; class ChannelBottomSheet extends StatefulWidget { - VoidCallback onViewInfoTap; + final VoidCallback onViewInfoTap; ChannelBottomSheet({this.onViewInfoTap}); diff --git a/lib/src/image_footer.dart b/lib/src/image_footer.dart index eff6110a..ec92693d 100644 --- a/lib/src/image_footer.dart +++ b/lib/src/image_footer.dart @@ -48,14 +48,10 @@ class ImageFooter extends StatefulWidget { this.message, this.videoPackages, this.mediaSelectedCallBack, - }) : preferredSize = Size.fromHeight(kToolbarHeight), - super(key: key); + }) : super(key: key); @override _ImageFooterState createState() => _ImageFooterState(); - - @override - final Size preferredSize; } class _ImageFooterState extends State { @@ -150,7 +146,7 @@ class _ImageFooterState extends State { ); } - Widget _buildPhotosModal(context) { + void _buildPhotosModal(context) { var videoAttachments = widget.mediaAttachments .where((element) => element.type == 'video') .toList(); diff --git a/lib/src/media_list_view.dart b/lib/src/media_list_view.dart index 08ebfcc7..9c3af69f 100644 --- a/lib/src/media_list_view.dart +++ b/lib/src/media_list_view.dart @@ -37,13 +37,12 @@ class _MediaListViewState extends State { final _media = []; final ScrollController _scrollController = ScrollController(); int _currentPage = 0; - bool _endPagination = false; @override Widget build(BuildContext context) { return LazyLoadScrollView( - onEndOfPage: () { - _getMedia(); + onEndOfPage: () async { + return _getMedia(); }, child: GridView.builder( itemCount: _media.length, @@ -161,11 +160,7 @@ class _MediaListViewState extends State { final media = await assetList.getAssetListPaged(_currentPage, 50); - if (media.isEmpty) { - setState(() { - _endPagination = true; - }); - } else { + if (!media.isEmpty) { setState(() { _media.addAll(media); }); diff --git a/lib/src/message_widget.dart b/lib/src/message_widget.dart index 5c175512..57e32c52 100644 --- a/lib/src/message_widget.dart +++ b/lib/src/message_widget.dart @@ -573,33 +573,6 @@ class _MessageWidgetState extends State { widget.message.attachments?.any((element) => element.type == 'giphy') == true; - Widget _buildReadIndicator() { - var padding = 0.0; - return Stack( - children: widget.readList.map((e) { - padding += 10.0; - return Positioned( - left: padding - 10, - bottom: 0, - top: 0, - child: Material( - color: StreamChatTheme.of(context).colorTheme.white, - clipBehavior: Clip.antiAlias, - shape: CircleBorder(), - child: Padding( - padding: const EdgeInsets.all(1.0), - child: UserAvatar( - user: e.user, - constraints: BoxConstraints.loose(Size.fromRadius(8)), - showOnlineStatus: false, - ), - ), - ), - ); - }).toList(), - ); - } - Widget _buildReactionIndicator( BuildContext context, ) { diff --git a/lib/src/stream_chat.dart b/lib/src/stream_chat.dart index 6866b0dd..521dc3c0 100644 --- a/lib/src/stream_chat.dart +++ b/lib/src/stream_chat.dart @@ -112,7 +112,6 @@ class StreamChatState extends State with WidgetsBindingObserver { inputBackground: themeData?.channelTheme?.inputBackground, messageInputButtonIconTheme: themeData?.channelTheme?.messageInputButtonIconTheme, - inputGradient: themeData?.channelTheme?.inputGradient, messageInputButtonTheme: themeData?.channelTheme?.messageInputButtonTheme, ), diff --git a/lib/src/stream_chat_theme.dart b/lib/src/stream_chat_theme.dart index ec469f81..02abd25c 100644 --- a/lib/src/stream_chat_theme.dart +++ b/lib/src/stream_chat_theme.dart @@ -92,12 +92,7 @@ class StreamChatThemeData { return defaultTheme.copyWith( primaryIconTheme: theme.primaryIconTheme, - channelTheme: defaultTheme.channelTheme.copyWith( - inputGradient: LinearGradient(colors: [ - theme.accentColor.withOpacity(.5), - theme.accentColor, - ]), - ), + channelTheme: defaultTheme.channelTheme, ownMessageTheme: defaultTheme.ownMessageTheme.copyWith( replies: defaultTheme.ownMessageTheme.replies.copyWith( color: theme.accentColor, @@ -168,8 +163,6 @@ class StreamChatThemeData { this.channelTheme.messageInputButtonIconTheme, messageInputButtonTheme: channelTheme.messageInputButtonTheme ?? this.channelTheme.messageInputButtonTheme, - inputGradient: - channelTheme.inputGradient ?? this.channelTheme.inputGradient, inputBackground: channelTheme.inputBackground ?? this.channelTheme.inputBackground, ) ?? @@ -273,10 +266,6 @@ class StreamChatThemeData { ), ), inputBackground: colorTheme.white.withAlpha(12), - inputGradient: LinearGradient(colors: [ - Color(0xFF00AEFF), - Color(0xFF0076FF), - ]), ), ownMessageTheme: MessageTheme( messageText: TextStyle( @@ -597,9 +586,6 @@ class ChannelTheme { /// Theme of the send button in [MessageInput] final ButtonThemeData messageInputButtonTheme; - /// Gradient of [MessageInput] - final Gradient inputGradient; - /// Background color of [MessageInput] final Color inputBackground; @@ -608,7 +594,6 @@ class ChannelTheme { this.messageInputButtonIconTheme, this.messageInputButtonTheme, this.inputBackground, - this.inputGradient, }); /// Creates a copy of [ChannelTheme] with specified attributes overridden. @@ -616,7 +601,6 @@ class ChannelTheme { ChannelHeaderTheme channelHeaderTheme, IconThemeData messageInputButtonIconTheme, ButtonThemeData messageInputButtonTheme, - Gradient inputGradient, Color inputBackground, }) => ChannelTheme( @@ -633,8 +617,6 @@ class ChannelTheme { messageInputButtonIconTheme ?? this.messageInputButtonIconTheme, messageInputButtonTheme: messageInputButtonTheme ?? this.messageInputButtonTheme, - inputGradient: inputGradient ?? this.inputGradient, - inputBackground: inputBackground ?? this.inputBackground, ); } From 041c1930c22c68d4a940c4fc1e4ddfe7d9ec679c Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Mon, 4 Jan 2021 12:08:14 +0100 Subject: [PATCH 0746/1140] fix longpress gesturedetector on message --- lib/src/message_widget.dart | 357 ++++++++++++++++++------------------ 1 file changed, 179 insertions(+), 178 deletions(-) diff --git a/lib/src/message_widget.dart b/lib/src/message_widget.dart index 57e32c52..6ef537f6 100644 --- a/lib/src/message_widget.dart +++ b/lib/src/message_widget.dart @@ -260,174 +260,181 @@ class _MessageWidgetState extends State { true; return Portal( - child: Padding( - padding: widget.padding ?? EdgeInsets.all(8), - child: Transform( - alignment: Alignment.center, - transform: Matrix4.rotationY(widget.reverse ? pi : 0), - child: FractionallySizedBox( - alignment: Alignment.centerLeft, - widthFactor: 0.75, - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisSize: MainAxisSize.min, - children: [ - Stack( - clipBehavior: Clip.none, - alignment: AlignmentDirectional.bottomStart, - children: [ - Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisSize: MainAxisSize.min, - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.end, - mainAxisSize: MainAxisSize.min, - children: [ - if (widget.showUserAvatar == DisplayWidget.show) - _buildUserAvatar(), - SizedBox(width: 6), - if (widget.showUserAvatar == DisplayWidget.hide) - SizedBox( - width: widget.messageTheme.avatarTheme - .constraints.maxWidth + - 8, - ), - Flexible( - child: PortalEntry( - portal: Container( - transform: - Matrix4.translationValues(-16, 2, 0), - child: _buildReactionIndicator(context), - constraints: - BoxConstraints(maxWidth: 22 * 6.0), + child: GestureDetector( + onLongPress: () => onLongPress(context), + child: Padding( + padding: widget.padding ?? EdgeInsets.all(8), + child: Transform( + alignment: Alignment.center, + transform: Matrix4.rotationY(widget.reverse ? pi : 0), + child: FractionallySizedBox( + alignment: Alignment.centerLeft, + widthFactor: 0.75, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + Stack( + clipBehavior: Clip.none, + alignment: AlignmentDirectional.bottomStart, + children: [ + Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.end, + mainAxisSize: MainAxisSize.min, + children: [ + if (widget.showUserAvatar == DisplayWidget.show) + _buildUserAvatar(), + SizedBox(width: 6), + if (widget.showUserAvatar == DisplayWidget.hide) + SizedBox( + width: widget.messageTheme.avatarTheme + .constraints.maxWidth + + 8, ), - portalAnchor: Alignment(-1.0, -1.0), - childAnchor: Alignment(1, -1.0), - child: Stack( - clipBehavior: Clip.none, - children: [ - Padding( - padding: widget.showReactions - ? EdgeInsets.only( - top: widget.message.reactionCounts - ?.isNotEmpty == - true - ? 18 - : 0, - ) - : EdgeInsets.zero, - child: (widget.message.isDeleted && - !isFailedState) - ? Transform( - alignment: Alignment.center, - transform: Matrix4.rotationY( - widget.reverse ? pi : 0), - child: DeletedMessage( - reverse: widget.reverse, - borderRadiusGeometry: - widget.borderRadiusGeometry, - borderSide: widget.borderSide, - shape: widget.shape, - messageTheme: - widget.messageTheme, - ), - ) - : Material( - clipBehavior: Clip.antiAlias, - shape: widget.shape ?? - RoundedRectangleBorder( - side: isOnlyEmoji - ? BorderSide.none - : widget.borderSide ?? - BorderSide( - color: Theme.of(context) - .brightness == - Brightness - .dark - ? StreamChatTheme.of( - context) - .colorTheme - .white - .withAlpha( - 24) - : StreamChatTheme.of( - context) - .colorTheme - .black - .withAlpha( - 24), - ), - borderRadius: widget - .borderRadiusGeometry ?? - BorderRadius.zero, + Flexible( + child: PortalEntry( + portal: Container( + transform: + Matrix4.translationValues(-16, 2, 0), + child: _buildReactionIndicator(context), + constraints: + BoxConstraints(maxWidth: 22 * 6.0), + ), + portalAnchor: Alignment(-1.0, -1.0), + childAnchor: Alignment(1, -1.0), + child: Stack( + clipBehavior: Clip.none, + children: [ + Padding( + padding: widget.showReactions + ? EdgeInsets.only( + top: widget + .message + .reactionCounts + ?.isNotEmpty == + true + ? 18 + : 0, + ) + : EdgeInsets.zero, + child: (widget.message.isDeleted && + !isFailedState) + ? Transform( + alignment: Alignment.center, + transform: Matrix4.rotationY( + widget.reverse ? pi : 0), + child: DeletedMessage( + reverse: widget.reverse, + borderRadiusGeometry: widget + .borderRadiusGeometry, + borderSide: widget.borderSide, + shape: widget.shape, + messageTheme: + widget.messageTheme, + ), + ) + : Material( + clipBehavior: Clip.antiAlias, + shape: widget.shape ?? + RoundedRectangleBorder( + side: isOnlyEmoji + ? BorderSide.none + : widget.borderSide ?? + BorderSide( + color: Theme.of(context) + .brightness == + Brightness + .dark + ? StreamChatTheme.of( + context) + .colorTheme + .white + .withAlpha( + 24) + : StreamChatTheme.of( + context) + .colorTheme + .black + .withAlpha( + 24), + ), + borderRadius: widget + .borderRadiusGeometry ?? + BorderRadius.zero, + ), + color: _getBackgroundColor(), + child: Padding( + padding: EdgeInsets.all( + hasFiles ? 2.0 : 0.0), + child: Column( + crossAxisAlignment: + CrossAxisAlignment + .start, + mainAxisSize: + MainAxisSize.min, + children: [ + ..._parseAttachments( + context), + if (widget.message.text + .trim() + .isNotEmpty && + !isGiphy) + _buildTextBubble( + context), + ], ), - color: _getBackgroundColor(), - child: Padding( - padding: EdgeInsets.all( - hasFiles ? 2.0 : 0.0), - child: Column( - crossAxisAlignment: - CrossAxisAlignment.start, - mainAxisSize: - MainAxisSize.min, - children: [ - ..._parseAttachments( - context), - if (widget.message.text - .trim() - .isNotEmpty && - !isGiphy) - _buildTextBubble(context), - ], ), ), - ), - ), - if (widget.showReactionPickerIndicator) - Positioned( - right: 0, - top: -6, - child: Transform( - transform: Matrix4.rotationY( - widget.reverse ? pi : 0), - child: CustomPaint( - painter: ReactionBubblePainter( - widget.messageTheme - .reactionsBackgroundColor, - widget.messageTheme - .reactionsBorderColor, + ), + if (widget.showReactionPickerIndicator) + Positioned( + right: 0, + top: -6, + child: Transform( + transform: Matrix4.rotationY( + widget.reverse ? pi : 0), + child: CustomPaint( + painter: ReactionBubblePainter( + widget.messageTheme + .reactionsBackgroundColor, + widget.messageTheme + .reactionsBorderColor, + ), ), ), ), - ), - ], + ], + ), ), ), - ), - ], - ), - if (showBottomRow) SizedBox(height: 20.0), - ], - ), - if (showBottomRow) _buildBottomRow(leftPadding), - if (isFailedState) - Positioned( - left: widget.reverse ? -3 : null, - right: widget.reverse ? null : -9, - bottom: showBottomRow ? 20 : 0, - child: Container( - decoration: BoxDecoration( - color: Colors.white, - shape: BoxShape.circle, + ], ), - child: StreamSvgIcon.error(size: 20), - ), + if (showBottomRow) SizedBox(height: 20.0), + ], ), - ], - ), - ], + if (showBottomRow) _buildBottomRow(leftPadding), + if (isFailedState) + Positioned( + left: widget.reverse ? -3 : null, + right: widget.reverse ? null : -9, + bottom: showBottomRow ? 20 : 0, + child: Container( + decoration: BoxDecoration( + color: Colors.white, + shape: BoxShape.circle, + ), + child: StreamSvgIcon.error(size: 20), + ), + ), + ], + ), + ], + ), ), ), ), @@ -739,23 +746,20 @@ class _MessageWidgetState extends State { }) { final attachmentShape = widget.attachmentShape ?? widget.shape ?? _getDefaultShape(context); - return GestureDetector( - onLongPress: () => onLongPress(context), - child: Material( - color: _getBackgroundColor(), - clipBehavior: Clip.antiAlias, - shape: attachmentShape, - child: Padding( - padding: widget.attachmentPadding, - child: Material( - clipBehavior: Clip.hardEdge, - shape: attachmentShape, - type: MaterialType.transparency, - child: Transform( - transform: Matrix4.rotationY(widget.reverse ? pi : 0), - alignment: Alignment.center, - child: attachmentWidget, - ), + return Material( + color: _getBackgroundColor(), + clipBehavior: Clip.antiAlias, + shape: attachmentShape, + child: Padding( + padding: widget.attachmentPadding, + child: Material( + clipBehavior: Clip.hardEdge, + shape: attachmentShape, + type: MaterialType.transparency, + child: Transform( + transform: Matrix4.rotationY(widget.reverse ? pi : 0), + alignment: Alignment.center, + child: attachmentWidget, ), ), ), @@ -854,10 +858,7 @@ class _MessageWidgetState extends State { ], ), ); - return GestureDetector( - onLongPress: () => onLongPress(context), - child: child, - ); + return child; } bool get isOnlyEmoji => From 523790b0274c6ce95f425d942e55480ffbbd2ddf Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Mon, 4 Jan 2021 16:45:17 +0530 Subject: [PATCH 0747/1140] fix: temp fix for navigation issues --- example/lib/chat_info_screen.dart | 8 -------- example/lib/group_info_screen.dart | 8 -------- example/lib/main.dart | 2 -- 3 files changed, 18 deletions(-) diff --git a/example/lib/chat_info_screen.dart b/example/lib/chat_info_screen.dart index c96d982f..50cb16f8 100644 --- a/example/lib/chat_info_screen.dart +++ b/example/lib/chat_info_screen.dart @@ -223,14 +223,6 @@ class _ChatInfoScreenState extends State { if (channel.state == null) { await channel.watch(); } - await Navigator.pop(context); - await Future.delayed(Duration(milliseconds: 200)); - await Navigator.pop(context); - await Future.delayed(Duration(milliseconds: 200)); - await Navigator.pop(context); - await Future.delayed(Duration(milliseconds: 200)); - await Navigator.pop(context); - await Navigator.pop(context); Navigator.pushNamed( context, Routes.CHANNEL_PAGE, diff --git a/example/lib/group_info_screen.dart b/example/lib/group_info_screen.dart index ace7e2c8..ffab48df 100644 --- a/example/lib/group_info_screen.dart +++ b/example/lib/group_info_screen.dart @@ -496,14 +496,6 @@ class _GroupInfoScreenState extends State { if (channel.state == null) { await channel.watch(); } - await Navigator.pop(context); - await Future.delayed(Duration(milliseconds: 200)); - await Navigator.pop(context); - await Future.delayed(Duration(milliseconds: 200)); - await Navigator.pop(context); - await Future.delayed(Duration(milliseconds: 200)); - await Navigator.pop(context); - await Navigator.pop(context); await Navigator.pushNamed( context, Routes.CHANNEL_PAGE, diff --git a/example/lib/main.dart b/example/lib/main.dart index cc01cec4..b7c30dce 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -527,8 +527,6 @@ class ChannelPage extends StatelessWidget { if (channel.state == null) { await channel.watch(); } - Navigator.pop(context); - Navigator.pop(context); Navigator.pushReplacementNamed( context, Routes.CHANNEL_PAGE, From eaa7d03bb426cd42d0a62a0e2ffa329ddfc55d3d Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Mon, 4 Jan 2021 16:59:13 +0530 Subject: [PATCH 0748/1140] fix: added back system theme --- 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 b7c30dce..74a6d808 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -63,7 +63,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 4ef7516b52b06efe4a90d16ef928f020e4d45124 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Mon, 4 Jan 2021 17:22:14 +0530 Subject: [PATCH 0749/1140] fix: chat_info_screen.dart --- example/lib/chat_info_screen.dart | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/example/lib/chat_info_screen.dart b/example/lib/chat_info_screen.dart index 50cb16f8..5eb0df7d 100644 --- a/example/lib/chat_info_screen.dart +++ b/example/lib/chat_info_screen.dart @@ -28,12 +28,14 @@ class _ChatInfoScreenState extends State { body: ListView( children: [ _buildUserHeader(), - SizedBox( + Container( height: 8.0, + color: StreamChatTheme.of(context).colorTheme.greyGainsboro, ), _buildOptionListTiles(), - SizedBox( + Container( height: 8.0, + color: StreamChatTheme.of(context).colorTheme.greyGainsboro, ), if ([ 'admin', @@ -139,7 +141,7 @@ class _ChatInfoScreenState extends State { title: 'Mute user', titleTextStyle: StreamChatTheme.of(context).textTheme.body, leading: Padding( - padding: const EdgeInsets.symmetric(horizontal: 16.0), + padding: const EdgeInsets.symmetric(horizontal: 22.0), child: StreamSvgIcon.mute( size: 24.0, color: StreamChatTheme.of(context) @@ -186,9 +188,9 @@ class _ChatInfoScreenState extends State { tileColor: StreamChatTheme.of(context).colorTheme.whiteSnow, titleTextStyle: StreamChatTheme.of(context).textTheme.body, leading: Padding( - padding: const EdgeInsets.symmetric(horizontal: 12.0), + padding: const EdgeInsets.symmetric(horizontal: 16.0), child: StreamSvgIcon.pictures( - size: 32.0, + size: 36.0, color: StreamChatTheme.of(context).colorTheme.black.withOpacity(0.5), ), @@ -244,7 +246,7 @@ class _ChatInfoScreenState extends State { tileColor: StreamChatTheme.of(context).colorTheme.whiteSnow, titleTextStyle: StreamChatTheme.of(context).textTheme.body, leading: Padding( - padding: const EdgeInsets.symmetric(horizontal: 12.0), + padding: const EdgeInsets.symmetric(horizontal: 18.0), child: StreamSvgIcon.files( size: 32.0, color: @@ -283,7 +285,7 @@ class _ChatInfoScreenState extends State { tileColor: StreamChatTheme.of(context).colorTheme.whiteSnow, titleTextStyle: StreamChatTheme.of(context).textTheme.body, leading: Padding( - padding: const EdgeInsets.symmetric(horizontal: 16.0), + padding: const EdgeInsets.symmetric(horizontal: 22.0), child: StreamSvgIcon.Icon_group( size: 24.0, color: @@ -313,7 +315,7 @@ class _ChatInfoScreenState extends State { color: StreamChatTheme.of(context).colorTheme.accentRed, ), leading: Padding( - padding: const EdgeInsets.symmetric(horizontal: 16.0), + padding: const EdgeInsets.symmetric(horizontal: 22.0), child: StreamSvgIcon.delete( color: StreamChatTheme.of(context).colorTheme.accentRed, size: 24.0, From fc2da1391598759e3a50a6a45eb616240882926f Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Mon, 4 Jan 2021 17:51:59 +0530 Subject: [PATCH 0750/1140] Handle onQuotedMessageTap Signed-off-by: Sahil Kumar --- lib/src/message_list_view.dart | 12 ++- lib/src/message_widget.dart | 172 +++++++++++++++++---------------- 2 files changed, 99 insertions(+), 85 deletions(-) diff --git a/lib/src/message_list_view.dart b/lib/src/message_list_view.dart index 7cd68eb3..169d9d45 100644 --- a/lib/src/message_list_view.dart +++ b/lib/src/message_list_view.dart @@ -181,7 +181,6 @@ class MessageListView extends StatefulWidget { class _MessageListViewState extends State { ItemScrollController _scrollController; bool _bottomWasVisible = false; - bool _topWasVisible = false; Function _onThreadTap; bool _showScrollToBottom = false; ItemPositionsListener _itemPositionListener; @@ -772,6 +771,17 @@ class _MessageListViewState extends State { bottom: index == 0 ? 30 : (isNextUser ? 2 : 7), top: 3, ), + onQuotedMessageTap: (quotedMessageId) { + if (messages.map((e) => e.id).contains(quotedMessageId)) { + final index = messages.indexWhere((m) => m.id == quotedMessageId); + _scrollController?.scrollTo( + index: index, + duration: const Duration(milliseconds: 350), + ); + } else { + streamChannel.loadChannelAtMessage(quotedMessageId); + } + }, showInChannelIndicator: widget.parentMessage == null, showThreadReplyIndicator: widget.parentMessage == null, showUsername: !isMyMessage && !isNextUser, diff --git a/lib/src/message_widget.dart b/lib/src/message_widget.dart index 1c49a9ca..3aa608ce 100644 --- a/lib/src/message_widget.dart +++ b/lib/src/message_widget.dart @@ -20,6 +20,7 @@ import 'message_text.dart'; import 'extension.dart'; typedef AttachmentBuilder = Widget Function(BuildContext, Message, Attachment); +typedef OnQuotedMessageTap = void Function(String); /// The display behaviour of a widget enum DisplayWidget { @@ -135,6 +136,9 @@ class MessageWidget extends StatefulWidget { /// Center user avatar with bottom of the message final bool translateUserAvatar; + /// Function called when quotedMessage is tapped + final OnQuotedMessageTap onQuotedMessageTap; + /// MessageWidget({ Key key, @@ -177,6 +181,7 @@ class MessageWidget extends StatefulWidget { ), this.attachmentPadding = EdgeInsets.zero, this.allRead = false, + this.onQuotedMessageTap, }) : attachmentBuilders = { 'image': (context, message, attachment) { return ImageAttachment( @@ -338,97 +343,81 @@ class _MessageWidgetState extends State { : 0, ) : EdgeInsets.zero, - child: - (widget.message.isDeleted && - !isFailedState) - ? Transform( - alignment: Alignment.center, - transform: Matrix4.rotationY( - widget.reverse ? pi : 0), - child: DeletedMessage( - reverse: widget.reverse, - borderRadiusGeometry: widget - .borderRadiusGeometry, - borderSide: - widget.borderSide, - shape: widget.shape, - messageTheme: - widget.messageTheme, - ), - ) - : Material( - clipBehavior: Clip.antiAlias, - shape: widget.shape ?? - RoundedRectangleBorder( - side: isOnlyEmoji - ? BorderSide.none - : widget.borderSide ?? - BorderSide( - color: Theme.of(context) - .brightness == - Brightness - .dark - ? StreamChatTheme.of( - context) - .colorTheme - .white - .withAlpha( - 24) - : StreamChatTheme.of( - context) - .colorTheme - .black - .withAlpha( - 24), - ), - borderRadius: widget - .borderRadiusGeometry ?? - BorderRadius.zero, - ), - color: _getBackgroundColor(), - child: InkWell( - onLongPress: () => - onLongPress(context), - child: Padding( - padding: EdgeInsets.all( - hasFiles ? 2.0 : 0.0), - child: Column( - crossAxisAlignment: - CrossAxisAlignment - .start, - mainAxisSize: - MainAxisSize.min, - children: [ - if (_hasQuotedMessage) - QuotedMessageWidget( - onTap: () {}, - message: widget - .message - .quotedMessage, - messageTheme: isMyMessage + child: (widget.message.isDeleted && + !isFailedState) + ? Transform( + alignment: Alignment.center, + transform: Matrix4.rotationY( + widget.reverse ? pi : 0), + child: DeletedMessage( + reverse: widget.reverse, + borderRadiusGeometry: + widget.borderRadiusGeometry, + borderSide: widget.borderSide, + shape: widget.shape, + messageTheme: + widget.messageTheme, + ), + ) + : Material( + clipBehavior: Clip.antiAlias, + shape: widget.shape ?? + RoundedRectangleBorder( + side: isOnlyEmoji + ? BorderSide.none + : widget.borderSide ?? + BorderSide( + color: Theme.of(context) + .brightness == + Brightness + .dark ? StreamChatTheme.of( context) - .otherMessageTheme + .colorTheme + .white + .withAlpha( + 24) : StreamChatTheme.of( context) - .ownMessageTheme, - reverse: widget - .reverse, + .colorTheme + .black + .withAlpha( + 24), ), - ..._parseAttachments( - context), - if (widget - .message.text - .trim() - .isNotEmpty && - !isGiphy) - _buildTextBubble( - context), - ], - ), - ), + borderRadius: widget + .borderRadiusGeometry ?? + BorderRadius.zero, + ), + color: _getBackgroundColor(), + child: InkWell( + onLongPress: () => + onLongPress(context), + child: Padding( + padding: EdgeInsets.all( + hasFiles ? 2.0 : 0.0), + child: Column( + crossAxisAlignment: + CrossAxisAlignment + .start, + mainAxisSize: + MainAxisSize.min, + children: [ + if (_hasQuotedMessage) + _buildQuotedMessage( + isMyMessage), + ..._parseAttachments( + context), + if (widget.message.text + .trim() + .isNotEmpty && + !isGiphy) + _buildTextBubble( + context), + ], ), ), + ), + ), ), if (widget.showReactionPickerIndicator) Positioned( @@ -480,6 +469,21 @@ class _MessageWidgetState extends State { ); } + Widget _buildQuotedMessage(bool isMyMessage) { + return QuotedMessageWidget( + onTap: () { + if (widget.onQuotedMessageTap != null) { + widget.onQuotedMessageTap(widget.message.quotedMessageId); + } + }, + message: widget.message.quotedMessage, + messageTheme: isMyMessage + ? StreamChatTheme.of(context).otherMessageTheme + : StreamChatTheme.of(context).ownMessageTheme, + reverse: widget.reverse, + ); + } + Widget _buildBottomRow(double leftPadding) { final deleted = widget.message.isDeleted; var children = []; From a298794e66470428b5f696dc4decb4f12527b033 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Mon, 4 Jan 2021 13:27:39 +0100 Subject: [PATCH 0751/1140] remove log --- lib/src/channel_media_display_screen.dart | 3 --- 1 file changed, 3 deletions(-) diff --git a/lib/src/channel_media_display_screen.dart b/lib/src/channel_media_display_screen.dart index 1f8e9257..cd5238bc 100644 --- a/lib/src/channel_media_display_screen.dart +++ b/lib/src/channel_media_display_screen.dart @@ -1,4 +1,3 @@ -import 'package:cached_network_image/cached_network_image.dart'; import 'package:flutter/material.dart'; import 'package:stream_chat_flutter/src/lazy_load_scroll_view.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; @@ -176,8 +175,6 @@ class _ChannelMediaDisplayScreenState extends State { SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 3), itemBuilder: (context, position) { var channel = StreamChannel.of(context).channel; - print('NAV'); - return Padding( padding: const EdgeInsets.all(1.0), child: InkWell( From 7f7b33bfd2e1687d504d835aad2ad6f4b2f791c5 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Mon, 4 Jan 2021 13:44:35 +0100 Subject: [PATCH 0752/1140] merge feature/new-ui --- example/lib/main.dart | 4 +--- example/pubspec.yaml | 2 +- lib/src/image_footer.dart | 8 ++++++-- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/example/lib/main.dart b/example/lib/main.dart index 74a6d808..b004271b 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -1,11 +1,9 @@ import 'dart:async'; import 'dart:io'; -import 'package:example/choose_user_page.dart'; import 'package:example/chat_info_screen.dart'; +import 'package:example/choose_user_page.dart'; import 'package:example/group_info_screen.dart'; -import 'package:example/new_chat_screen.dart'; -import 'package:example/new_group_chat_screen.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 4f76c695..67ff213d 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -1,6 +1,6 @@ name: example description: A new Flutter project. -version: 1.0.106+109 +version: 1.0.107+110 environment: sdk: ">=2.2.2 <3.0.0" diff --git a/lib/src/image_footer.dart b/lib/src/image_footer.dart index 46821ce2..3a6cfbcc 100644 --- a/lib/src/image_footer.dart +++ b/lib/src/image_footer.dart @@ -47,10 +47,14 @@ class ImageFooter extends StatefulWidget implements PreferredSizeWidget { this.message, this.videoPackages, this.mediaSelectedCallBack, - }) : super(key: key); + }) : preferredSize = Size.fromHeight(kToolbarHeight), + super(key: key); @override _ImageFooterState createState() => _ImageFooterState(); + + @override + final Size preferredSize; } class _ImageFooterState extends State { @@ -164,7 +168,7 @@ class _ImageFooterState extends State { ); } - void _buildPhotosModal(context) { + Widget _buildPhotosModal(context) { var videoAttachments = widget.mediaAttachments .where((element) => element.type == 'video') .toList(); From 8421faa450a73659ffe42cfdf2ec439fe420d820 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Mon, 4 Jan 2021 20:04:59 +0530 Subject: [PATCH 0753/1140] flutter format Signed-off-by: Sahil Kumar --- lib/src/message_widget.dart | 46 ++++++++++++++++++------------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/lib/src/message_widget.dart b/lib/src/message_widget.dart index 5cd0c441..597a60c6 100644 --- a/lib/src/message_widget.dart +++ b/lib/src/message_widget.dart @@ -400,30 +400,30 @@ class _MessageWidgetState extends State { ), color: _getBackgroundColor(), child: InkWell( - onLongPress: () => - onLongPress(context), - child: Padding( - padding: EdgeInsets.all( - hasFiles ? 2.0 : 0.0), - child: Column( - crossAxisAlignment: - CrossAxisAlignment - .start, - mainAxisSize: - MainAxisSize.min, - children: [ - if (_hasQuotedMessage) - _buildQuotedMessage( - isMyMessage), - ..._parseAttachments( - context), - if (widget.message.text - .trim() - .isNotEmpty && - !isGiphy) - _buildTextBubble( + onLongPress: () => + onLongPress(context), + child: Padding( + padding: EdgeInsets.all( + hasFiles ? 2.0 : 0.0), + child: Column( + crossAxisAlignment: + CrossAxisAlignment + .start, + mainAxisSize: + MainAxisSize.min, + children: [ + if (_hasQuotedMessage) + _buildQuotedMessage( + isMyMessage), + ..._parseAttachments( context), - ], + if (widget.message.text + .trim() + .isNotEmpty && + !isGiphy) + _buildTextBubble( + context), + ], ), ), ), From e2a07bbfa513eb32931ece7b9d42c664f96d1320 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Mon, 4 Jan 2021 20:20:19 +0530 Subject: [PATCH 0754/1140] fix tests Signed-off-by: Sahil Kumar --- test/src/message_reaction_modal_test.dart | 2 +- test/src/reaction_bubble_test.dart | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/test/src/message_reaction_modal_test.dart b/test/src/message_reaction_modal_test.dart index d1c2a49c..c023b20d 100644 --- a/test/src/message_reaction_modal_test.dart +++ b/test/src/message_reaction_modal_test.dart @@ -74,7 +74,7 @@ void main() { ), latestReactions: [ Reaction( - type: 'thumbs_up', + type: 'like', user: User(id: testUserId), ), Reaction( diff --git a/test/src/reaction_bubble_test.dart b/test/src/reaction_bubble_test.dart index 6518dc94..c0bc8cd1 100644 --- a/test/src/reaction_bubble_test.dart +++ b/test/src/reaction_bubble_test.dart @@ -31,7 +31,7 @@ void main() { ); testWidgets( - 'it should show a thumb up', + 'it should show a like', (WidgetTester tester) async { final client = MockClient(); final clientState = MockClientState(); @@ -50,7 +50,7 @@ void main() { child: ReactionBubble( reactions: [ Reaction( - type: 'thumbs_up', + type: 'like', user: User(id: 'test'), ), ], @@ -86,7 +86,7 @@ void main() { child: ReactionBubble( reactions: [ Reaction( - type: 'thumbs_up', + type: 'like', user: User(id: 'test'), ), Reaction( From 19c69c318295ea1ea30aa14d8b92214f64f0b70e Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Mon, 4 Jan 2021 17:29:09 +0100 Subject: [PATCH 0755/1140] shrinkwrap listview --- example/ios/Flutter/.last_build_id | 2 +- example/pubspec.yaml | 2 +- lib/src/channel_bottom_sheet.dart | 1 + 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/example/ios/Flutter/.last_build_id b/example/ios/Flutter/.last_build_id index f57e1e1f..e72273c3 100644 --- a/example/ios/Flutter/.last_build_id +++ b/example/ios/Flutter/.last_build_id @@ -1 +1 @@ -c770358a10272b4ee1cdc2eb432445f6 \ No newline at end of file +13a41b8138c4868054e44b5158f3bdd6 \ No newline at end of file diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 67ff213d..dbaf61b5 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -1,6 +1,6 @@ name: example description: A new Flutter project. -version: 1.0.107+110 +version: 1.0.108+111 environment: sdk: ">=2.2.2 <3.0.0" diff --git a/lib/src/channel_bottom_sheet.dart b/lib/src/channel_bottom_sheet.dart index 26f3a152..21f85430 100644 --- a/lib/src/channel_bottom_sheet.dart +++ b/lib/src/channel_bottom_sheet.dart @@ -34,6 +34,7 @@ class _ChannelBottomSheetState extends State { ), ), child: ListView( + shrinkWrap: true, children: [ SizedBox( height: 24.0, From ed6213e9386c19091ce50a7a8cf67192a39eec1c Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Tue, 5 Jan 2021 11:19:51 +0530 Subject: [PATCH 0756/1140] [MessageListView] fix onQuotedMessageTap Signed-off-by: Sahil Kumar --- lib/src/message_list_view.dart | 15 +- lib/src/message_widget.dart | 309 ++++++++++++++++----------------- 2 files changed, 166 insertions(+), 158 deletions(-) diff --git a/lib/src/message_list_view.dart b/lib/src/message_list_view.dart index 4ce150df..1d0d4e47 100644 --- a/lib/src/message_list_view.dart +++ b/lib/src/message_list_view.dart @@ -775,15 +775,24 @@ class _MessageListViewState extends State { bottom: index == 0 ? 30 : (isNextUser ? 2 : 7), top: 3, ), - onQuotedMessageTap: (quotedMessageId) { - if (messages.map((e) => e.id).contains(quotedMessageId)) { + onQuotedMessageTap: (quotedMessageId) async { + final scrollToIndex = () { final index = messages.indexWhere((m) => m.id == quotedMessageId); _scrollController?.scrollTo( index: index, duration: const Duration(milliseconds: 350), ); + }; + if (messages.map((e) => e.id).contains(quotedMessageId)) { + scrollToIndex(); } else { - streamChannel.loadChannelAtMessage(quotedMessageId); + streamChannel.loadChannelAtMessage(quotedMessageId).then((_) { + WidgetsBinding.instance.addPostFrameCallback((_) { + if (messages.map((e) => e.id).contains(quotedMessageId)) { + scrollToIndex(); + } + }); + }); } }, showInChannelIndicator: widget.parentMessage == null, diff --git a/lib/src/message_widget.dart b/lib/src/message_widget.dart index 597a60c6..0c108681 100644 --- a/lib/src/message_widget.dart +++ b/lib/src/message_widget.dart @@ -287,121 +287,119 @@ class _MessageWidgetState extends State { widget.message.attachments?.any((element) => element.type == 'file') == true; - final isMyMessage = - widget.message.user.id == StreamChat.of(context).user.id; - - return Portal( - child: GestureDetector( - onLongPress: () => onLongPress(context), - child: Padding( - padding: widget.padding ?? EdgeInsets.all(8), - child: Transform( - alignment: Alignment.center, - transform: Matrix4.rotationY(widget.reverse ? pi : 0), - child: FractionallySizedBox( - alignment: Alignment.centerLeft, - widthFactor: 0.75, - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisSize: MainAxisSize.min, - children: [ - Stack( - clipBehavior: Clip.none, - alignment: AlignmentDirectional.bottomStart, - children: [ - Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisSize: MainAxisSize.min, - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.end, - mainAxisSize: MainAxisSize.min, - children: [ - if (widget.showUserAvatar == DisplayWidget.show) - _buildUserAvatar(), - SizedBox(width: 6), - if (widget.showUserAvatar == DisplayWidget.hide) - SizedBox( - width: widget.messageTheme.avatarTheme - .constraints.maxWidth + - 8, - ), - Flexible( - child: PortalEntry( - portal: Container( - transform: - Matrix4.translationValues(-16, 2, 0), - child: _buildReactionIndicator(context), - constraints: - BoxConstraints(maxWidth: 22 * 6.0), + return Material( + type: MaterialType.transparency, + child: Portal( + child: InkWell( + onLongPress: () => onLongPress(context), + child: Padding( + padding: widget.padding ?? EdgeInsets.all(8), + child: Transform( + alignment: Alignment.center, + transform: Matrix4.rotationY(widget.reverse ? pi : 0), + child: FractionallySizedBox( + alignment: Alignment.centerLeft, + widthFactor: 0.75, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + Stack( + clipBehavior: Clip.none, + alignment: AlignmentDirectional.bottomStart, + children: [ + Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.end, + mainAxisSize: MainAxisSize.min, + children: [ + if (widget.showUserAvatar == DisplayWidget.show) + _buildUserAvatar(), + SizedBox(width: 6), + if (widget.showUserAvatar == DisplayWidget.hide) + SizedBox( + width: widget.messageTheme.avatarTheme + .constraints.maxWidth + + 8, ), - portalAnchor: Alignment(-1.0, -1.0), - childAnchor: Alignment(1, -1.0), - child: Stack( - clipBehavior: Clip.none, - children: [ - Padding( - padding: widget.showReactions - ? EdgeInsets.only( - top: widget - .message - .reactionCounts - ?.isNotEmpty == - true - ? 18 - : 0, - ) - : EdgeInsets.zero, - child: (widget.message.isDeleted && - !isFailedState) - ? Transform( - alignment: Alignment.center, - transform: Matrix4.rotationY( - widget.reverse ? pi : 0), - child: DeletedMessage( - reverse: widget.reverse, - borderRadiusGeometry: widget - .borderRadiusGeometry, - borderSide: widget.borderSide, - shape: widget.shape, - messageTheme: - widget.messageTheme, - ), - ) - : Material( - clipBehavior: Clip.antiAlias, - shape: widget.shape ?? - RoundedRectangleBorder( - side: isOnlyEmoji - ? BorderSide.none - : widget.borderSide ?? - BorderSide( - color: Theme.of(context) - .brightness == - Brightness - .dark - ? StreamChatTheme.of( - context) - .colorTheme - .white - .withAlpha( - 24) - : StreamChatTheme.of( - context) - .colorTheme - .black - .withAlpha( - 24), - ), - borderRadius: widget - .borderRadiusGeometry ?? - BorderRadius.zero, - ), - color: _getBackgroundColor(), - child: InkWell( - onLongPress: () => - onLongPress(context), + Flexible( + child: PortalEntry( + portal: Container( + transform: + Matrix4.translationValues(-16, 2, 0), + child: _buildReactionIndicator(context), + constraints: + BoxConstraints(maxWidth: 22 * 6.0), + ), + portalAnchor: Alignment(-1.0, -1.0), + childAnchor: Alignment(1, -1.0), + child: Stack( + clipBehavior: Clip.none, + children: [ + Padding( + padding: widget.showReactions + ? EdgeInsets.only( + top: widget + .message + .reactionCounts + ?.isNotEmpty == + true + ? 18 + : 0, + ) + : EdgeInsets.zero, + child: (widget.message.isDeleted && + !isFailedState) + ? Transform( + alignment: Alignment.center, + transform: Matrix4.rotationY( + widget.reverse ? pi : 0), + child: DeletedMessage( + reverse: widget.reverse, + borderRadiusGeometry: widget + .borderRadiusGeometry, + borderSide: + widget.borderSide, + shape: widget.shape, + messageTheme: + widget.messageTheme, + ), + ) + : Card( + clipBehavior: Clip.antiAlias, + elevation: 0.0, + shape: widget.shape ?? + RoundedRectangleBorder( + side: isOnlyEmoji + ? BorderSide.none + : widget.borderSide ?? + BorderSide( + color: Theme.of(context) + .brightness == + Brightness + .dark + ? StreamChatTheme.of( + context) + .colorTheme + .white + .withAlpha( + 24) + : StreamChatTheme.of( + context) + .colorTheme + .black + .withAlpha( + 24), + ), + borderRadius: widget + .borderRadiusGeometry ?? + BorderRadius.zero, + ), + color: _getBackgroundColor(), child: Padding( padding: EdgeInsets.all( hasFiles ? 2.0 : 0.0), @@ -413,8 +411,7 @@ class _MessageWidgetState extends State { MainAxisSize.min, children: [ if (_hasQuotedMessage) - _buildQuotedMessage( - isMyMessage), + _buildQuotedMessage(), ..._parseAttachments( context), if (widget.message.text @@ -427,51 +424,51 @@ class _MessageWidgetState extends State { ), ), ), - ), - ), - if (widget.showReactionPickerIndicator) - Positioned( - right: 0, - top: -6, - child: Transform( - transform: Matrix4.rotationY( - widget.reverse ? pi : 0), - child: CustomPaint( - painter: ReactionBubblePainter( - widget.messageTheme - .reactionsBackgroundColor, - widget.messageTheme - .reactionsBorderColor, + ), + if (widget.showReactionPickerIndicator) + Positioned( + right: 0, + top: -6, + child: Transform( + transform: Matrix4.rotationY( + widget.reverse ? pi : 0), + child: CustomPaint( + painter: ReactionBubblePainter( + widget.messageTheme + .reactionsBackgroundColor, + widget.messageTheme + .reactionsBorderColor, + ), ), ), ), - ), - ], + ], + ), ), ), - ), - ], - ), - if (showBottomRow) SizedBox(height: 20.0), - ], - ), - if (showBottomRow) _buildBottomRow(leftPadding), - if (isFailedState) - Positioned( - left: widget.reverse ? -3 : null, - right: widget.reverse ? null : -9, - bottom: showBottomRow ? 20 : 0, - child: Container( - decoration: BoxDecoration( - color: Colors.white, - shape: BoxShape.circle, + ], ), - child: StreamSvgIcon.error(size: 20), - ), + if (showBottomRow) SizedBox(height: 20.0), + ], ), - ], - ), - ], + if (showBottomRow) _buildBottomRow(leftPadding), + if (isFailedState) + Positioned( + left: widget.reverse ? -3 : null, + right: widget.reverse ? null : -9, + bottom: showBottomRow ? 20 : 0, + child: Container( + decoration: BoxDecoration( + color: Colors.white, + shape: BoxShape.circle, + ), + child: StreamSvgIcon.error(size: 20), + ), + ), + ], + ), + ], + ), ), ), ), @@ -480,7 +477,9 @@ class _MessageWidgetState extends State { ); } - Widget _buildQuotedMessage(bool isMyMessage) { + Widget _buildQuotedMessage() { + final isMyMessage = + widget.message.user.id == StreamChat.of(context).user.id; return QuotedMessageWidget( onTap: () { if (widget.onQuotedMessageTap != null) { From a317e620a0d4484102234b6f6cca688e37684cef Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Tue, 5 Jan 2021 12:06:09 +0530 Subject: [PATCH 0757/1140] [MessageActionsModal] Fix reaction picker alignment for quotedMessage Signed-off-by: Sahil Kumar --- lib/src/message_actions_modal.dart | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/lib/src/message_actions_modal.dart b/lib/src/message_actions_modal.dart index 050b5995..f0e228c9 100644 --- a/lib/src/message_actions_modal.dart +++ b/lib/src/message_actions_modal.dart @@ -55,17 +55,25 @@ class MessageActionsModal extends StatelessWidget { final user = StreamChat.of(context).user; final roughMaxSize = 2 * size.width / 3; + var messageTextLength = message.text.length; + if (message.quotedMessage != null) { + var quotedMessageLength = message.quotedMessage.text.length + 40; + if (message.quotedMessage.attachments?.isNotEmpty == true) { + quotedMessageLength += 40; + } + if (quotedMessageLength > messageTextLength) { + messageTextLength = quotedMessageLength; + } + } final roughSentenceSize = - message.text.length * messageTheme.messageText.fontSize * 1.2; + messageTextLength * messageTheme.messageText.fontSize * 1.2; final divFactor = message.attachments?.isNotEmpty == true ? 1 : (roughSentenceSize == 0 ? 1 : (roughSentenceSize / roughMaxSize)); return GestureDetector( behavior: HitTestBehavior.translucent, - onTap: () { - Navigator.pop(context); - }, + onTap: () => Navigator.pop(context), child: Stack( children: [ Positioned.fill( From 61a1eecc52a643310ed879441090decca7606924 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Tue, 5 Jan 2021 12:22:19 +0530 Subject: [PATCH 0758/1140] [MessageWidget] Disable onLongPress for deleted message Signed-off-by: Sahil Kumar --- lib/src/message_widget.dart | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/src/message_widget.dart b/lib/src/message_widget.dart index 0c108681..bc6646c5 100644 --- a/lib/src/message_widget.dart +++ b/lib/src/message_widget.dart @@ -291,7 +291,9 @@ class _MessageWidgetState extends State { type: MaterialType.transparency, child: Portal( child: InkWell( - onLongPress: () => onLongPress(context), + onLongPress: widget.message.isDeleted && !isFailedState + ? null + : () => onLongPress(context), child: Padding( padding: widget.padding ?? EdgeInsets.all(8), child: Transform( From dc801ca91debd627ead0374ae61c05b29422e1b8 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Tue, 5 Jan 2021 13:02:17 +0530 Subject: [PATCH 0759/1140] minor ui fixes Signed-off-by: Sahil Kumar --- lib/src/message_actions_modal.dart | 41 ++++++++++------------------- lib/src/message_input.dart | 42 ++++++++++++++++-------------- lib/src/stream_svg_icon.dart | 4 +-- 3 files changed, 39 insertions(+), 48 deletions(-) diff --git a/lib/src/message_actions_modal.dart b/lib/src/message_actions_modal.dart index f0e228c9..6294ef6a 100644 --- a/lib/src/message_actions_modal.dart +++ b/lib/src/message_actions_modal.dart @@ -313,8 +313,8 @@ class MessageActionsModal extends StatelessWidget { backgroundColor: StreamChatTheme.of(context).colorTheme.white, shape: RoundedRectangleBorder( borderRadius: BorderRadius.only( - topLeft: Radius.circular(32), - topRight: Radius.circular(32), + topLeft: Radius.circular(16), + topRight: Radius.circular(16), ), ), builder: (context) { @@ -326,39 +326,26 @@ class MessageActionsModal extends StatelessWidget { mainAxisSize: MainAxisSize.min, children: [ Padding( - padding: const EdgeInsets.only( - top: 16.0, - left: 16.0, - right: 16.0, - ), + padding: const EdgeInsets.fromLTRB(8, 8, 8, 0), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - IconButton( - icon: StreamSvgIcon.edit( - size: 22, - color: - StreamChatTheme.of(context).primaryIconTheme.color, + Padding( + padding: const EdgeInsets.all(8.0), + child: StreamSvgIcon.edit( + color: StreamChatTheme.of(context) + .colorTheme + .greyGainsboro, ), - onPressed: () {}, ), Text( - 'Edit message', - style: Theme.of(context) - .textTheme - .headline6 - .copyWith(fontWeight: FontWeight.bold), + 'Edit Message', + style: TextStyle(fontWeight: FontWeight.bold), ), IconButton( - icon: Icon( - Icons.cancel_outlined, - size: 22, - color: - StreamChatTheme.of(context).primaryIconTheme.color, - ), - onPressed: () { - Navigator.of(context).pop(); - }, + visualDensity: VisualDensity.compact, + icon: StreamSvgIcon.close_small(), + onPressed: Navigator.of(context).pop, ), ], ), diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 72c5f70d..52d91d45 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -227,26 +227,30 @@ class MessageInputState extends State { mainAxisSize: MainAxisSize.min, children: [ if (_hasQuotedMessage) - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Padding( - padding: const EdgeInsets.all(8.0), - child: StreamSvgIcon.reply( - color: - StreamChatTheme.of(context).colorTheme.greyGainsboro, + Padding( + padding: const EdgeInsets.fromLTRB(8, 8, 8, 0), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Padding( + padding: const EdgeInsets.all(8.0), + child: StreamSvgIcon.reply( + color: StreamChatTheme.of(context) + .colorTheme + .greyGainsboro, + ), ), - ), - Text( - 'Reply to Message', - style: TextStyle(fontWeight: FontWeight.bold), - ), - IconButton( - visualDensity: VisualDensity.compact, - icon: StreamSvgIcon.close_small(), - onPressed: widget.onQuotedMessageCleared, - ), - ], + Text( + 'Reply to Message', + style: TextStyle(fontWeight: FontWeight.bold), + ), + IconButton( + visualDensity: VisualDensity.compact, + icon: StreamSvgIcon.close_small(), + onPressed: widget.onQuotedMessageCleared, + ), + ], + ), ), Padding( padding: const EdgeInsets.all(8.0), diff --git a/lib/src/stream_svg_icon.dart b/lib/src/stream_svg_icon.dart index d00448bd..e7ef46c3 100644 --- a/lib/src/stream_svg_icon.dart +++ b/lib/src/stream_svg_icon.dart @@ -10,9 +10,9 @@ class StreamSvgIcon extends StatelessWidget { const StreamSvgIcon({ this.assetName, - this.width, - this.height, this.color, + this.width = 24, + this.height = 24, }); @override From b8c05d791f8be02356e93cb460dc68e859ad9f1b Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Tue, 5 Jan 2021 10:28:40 +0100 Subject: [PATCH 0760/1140] change default scroll physics --- example/ios/Flutter/.last_build_id | 2 +- example/ios/Podfile.lock | 4 ++-- example/pubspec.yaml | 2 +- lib/src/message_list_view.dart | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/example/ios/Flutter/.last_build_id b/example/ios/Flutter/.last_build_id index e72273c3..f57e1e1f 100644 --- a/example/ios/Flutter/.last_build_id +++ b/example/ios/Flutter/.last_build_id @@ -1 +1 @@ -13a41b8138c4868054e44b5158f3bdd6 \ No newline at end of file +c770358a10272b4ee1cdc2eb432445f6 \ No newline at end of file diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock index 2d9d0784..f266b656 100644 --- a/example/ios/Podfile.lock +++ b/example/ios/Podfile.lock @@ -40,7 +40,7 @@ PODS: - Firebase/Messaging (6.33.0): - Firebase/CoreOnly - FirebaseMessaging (~> 4.7.0) - - firebase_core (0.5.2): + - firebase_core (0.5.3): - Firebase/CoreOnly (~> 6.33.0) - Flutter - firebase_messaging (7.0.3): @@ -258,7 +258,7 @@ SPEC CHECKSUMS: esys_flutter_share: 403498dab005b36ce1f8d7aff377e81f0621b0b4 file_picker: 3e6c3790de664ccf9b882732d9db5eaf6b8d4eb1 Firebase: 8db6f2d1b2c5e2984efba4949a145875a8f65fe5 - firebase_core: 350ba329d1641211bc6183a3236893cafdacfea7 + firebase_core: 5d6a02f3d85acd5f8321c2d6d62877626a670659 firebase_messaging: 0aea2cd5885b65e19ede58ee3507f485c992cc75 FirebaseCore: d889d9e12535b7f36ac8bfbf1713a0836a3012cd FirebaseCoreDiagnostics: 770ac5958e1372ce67959ae4b4f31d8e127c3ac1 diff --git a/example/pubspec.yaml b/example/pubspec.yaml index dbaf61b5..4a0a755a 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -1,6 +1,6 @@ name: example description: A new Flutter project. -version: 1.0.108+111 +version: 1.0.110+113 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 1d0d4e47..68a1633b 100644 --- a/lib/src/message_list_view.dart +++ b/lib/src/message_list_view.dart @@ -115,7 +115,7 @@ class MessageListView extends StatefulWidget { this.onThreadTap, this.onReplyTap, this.dateDividerBuilder, - this.scrollPhysics = const AlwaysScrollableScrollPhysics(), + this.scrollPhysics = const ClampingScrollPhysics(), this.initialScrollIndex, this.initialAlignment, this.scrollController, From 28e01a89d440c1b1f8749b0d5ef06f288b78ad7d Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Tue, 5 Jan 2021 18:10:16 +0530 Subject: [PATCH 0761/1140] [MessageWidget] Show thread participants in case of thread. Signed-off-by: Sahil Kumar --- lib/src/extension.dart | 2 +- lib/src/message_widget.dart | 128 +++++++++++++++++---------------- lib/src/stream_chat_theme.dart | 20 +++--- pubspec.yaml | 3 +- 4 files changed, 78 insertions(+), 75 deletions(-) diff --git a/lib/src/extension.dart b/lib/src/extension.dart index f49c574f..71edefe6 100644 --- a/lib/src/extension.dart +++ b/lib/src/extension.dart @@ -5,7 +5,7 @@ extension StringExtension on String { } /// List extension -extension ListX on List { +extension IterableX on Iterable { /// Insert any item inBetween the list items List insertBetween(T item) => expand((e) sync* { yield item; diff --git a/lib/src/message_widget.dart b/lib/src/message_widget.dart index bc6646c5..8ce09579 100644 --- a/lib/src/message_widget.dart +++ b/lib/src/message_widget.dart @@ -252,7 +252,7 @@ class _MessageWidgetState extends State { bool get showInChannel => widget.showInChannelIndicator && widget.message?.showInChannel == true; - bool get _hasQuotedMessage => widget.message?.quotedMessage != null; + bool get hasQuotedMessage => widget.message?.quotedMessage != null; bool get isSendFailed => widget.message.status == MessageSendingStatus.FAILED; @@ -264,6 +264,10 @@ class _MessageWidgetState extends State { bool get isFailedState => isSendFailed || isUpdateFailed || isDeleteFailed; + bool get isGiphy => + widget.message.attachments?.any((element) => element.type == 'giphy') == + true; + bool get showBottomRow => showThreadReplyIndicator || showUsername || @@ -272,13 +276,9 @@ class _MessageWidgetState extends State { @override Widget build(BuildContext context) { - var leftPadding = widget.showUserAvatar != DisplayWidget.gone - ? widget.messageTheme.avatarTheme.constraints.maxWidth + 14.5 - : 6.0; - - final isGiphy = - widget.message.attachments?.any((element) => element.type == 'giphy') == - true; + final avatarWidth = widget.messageTheme.avatarTheme.constraints.maxWidth; + var leftPadding = + widget.showUserAvatar != DisplayWidget.gone ? avatarWidth + 8.5 : 4.5; final isOnlyEmoji = widget.message.text.characters.every((c) => Emoji.byChar(c) != null); @@ -319,15 +319,13 @@ class _MessageWidgetState extends State { crossAxisAlignment: CrossAxisAlignment.end, mainAxisSize: MainAxisSize.min, children: [ - if (widget.showUserAvatar == DisplayWidget.show) + if (widget.showUserAvatar == + DisplayWidget.show) ...[ _buildUserAvatar(), - SizedBox(width: 6), + SizedBox(width: 4), + ], if (widget.showUserAvatar == DisplayWidget.hide) - SizedBox( - width: widget.messageTheme.avatarTheme - .constraints.maxWidth + - 8, - ), + SizedBox(width: avatarWidth + 4), Flexible( child: PortalEntry( portal: Container( @@ -380,22 +378,9 @@ class _MessageWidgetState extends State { ? BorderSide.none : 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: widget + .messageTheme + .messageBorderColor, ), borderRadius: widget .borderRadiusGeometry ?? @@ -412,7 +397,7 @@ class _MessageWidgetState extends State { mainAxisSize: MainAxisSize.min, children: [ - if (_hasQuotedMessage) + if (hasQuotedMessage) _buildQuotedMessage(), ..._parseAttachments( context), @@ -542,6 +527,8 @@ class _MessageWidgetState extends State { } else { final showSendingIndicator = widget.showSendingIndicator == DisplayWidget.show; + final threadParticipants = widget.message.threadParticipants; + final showThreadParticipants = threadParticipants?.isNotEmpty == true; final replyCount = widget.message.replyCount; final msg = replyCount != 0 ? '$replyCount ${replyCount > 1 ? 'Thread Replies' : 'Thread Reply'}' @@ -554,19 +541,17 @@ class _MessageWidgetState extends State { children.addAll([ if (showSendingIndicator) _buildSendingIndicator(), - // if (showReadList) - // SizedBox.fromSize( - // size: Size((widget.readList.length * 10.0) + 10, 17), - // child: Padding( - // padding: const EdgeInsets.only(left: 4.0), - // child: _buildReadIndicator(), - // ), - // ), - if (showThreadReplyIndicator) + if (showThreadReplyIndicator) ...[ + if (showThreadParticipants) + SizedBox.fromSize( + size: Size((threadParticipants.length * 8.0) + 10, 16), + child: _buildThreadParticipantsIndicator(), + ), InkWell( onTap: widget.onThreadTap != null ? onThreadTap : null, child: Text(msg, style: widget.messageTheme?.replies), ), + ], if (showUsername) Text( widget.message.user.name, @@ -596,7 +581,7 @@ class _MessageWidgetState extends State { size: const Size(16, 32), painter: _ThreadReplyPainter( context: context, - color: widget.messageTheme.replyThreadColor, + color: widget.messageTheme.messageBorderColor, ), ), ), @@ -604,7 +589,7 @@ class _MessageWidgetState extends State { (child) => Transform( transform: Matrix4.rotationY(widget.reverse ? pi : 0), alignment: Alignment.center, - child: child, + child: Container(height: 16, child: Center(child: child)), ), ), ].insertBetween(const SizedBox(width: 8.0)), @@ -630,9 +615,29 @@ class _MessageWidgetState extends State { ); } - bool get isGiphy => - widget.message.attachments?.any((element) => element.type == 'giphy') == - true; + Widget _buildThreadParticipantsIndicator() { + var padding = 0.0; + return Stack( + children: widget.message.threadParticipants.map((user) { + padding += 10.0; + return Positioned( + left: padding - 10, + bottom: 0, + top: 0, + child: Material( + color: Colors.white, + clipBehavior: Clip.antiAlias, + shape: CircleBorder(), + child: UserAvatar( + user: user, + constraints: BoxConstraints.loose(Size.fromRadius(8)), + showOnlineStatus: false, + ), + ), + ); + }).toList(), + ); + } Widget _buildReactionIndicator( BuildContext context, @@ -866,21 +871,18 @@ class _MessageWidgetState extends State { Widget _buildUserAvatar() => Transform( transform: Matrix4.rotationY(widget.reverse ? pi : 0), alignment: Alignment.center, - child: Padding( - padding: const EdgeInsets.symmetric(horizontal: 4.0), - child: Transform.translate( - offset: Offset( - 0, - widget.translateUserAvatar - ? widget.messageTheme.avatarTheme.constraints.maxHeight / 2 - : 0, - ), - child: UserAvatar( - user: widget.message.user, - onTap: widget.onUserAvatarTap, - constraints: widget.messageTheme.avatarTheme.constraints, - showOnlineStatus: false, - ), + child: Transform.translate( + offset: Offset( + 0, + widget.translateUserAvatar + ? widget.messageTheme.avatarTheme.constraints.maxHeight / 2 + : 0, + ), + child: UserAvatar( + user: widget.message.user, + onTap: widget.onUserAvatarTap, + constraints: widget.messageTheme.avatarTheme.constraints, + showOnlineStatus: false, ), ), ); @@ -912,7 +914,7 @@ class _MessageWidgetState extends State { if (widget.message.attachments ?.any((element) => element.ogScrapeUrl != null) == true && - !_hasQuotedMessage) + !hasQuotedMessage) _buildUrlAttachment(), ], ), @@ -924,7 +926,7 @@ class _MessageWidgetState extends State { widget.message.text.characters.every((c) => Emoji.byChar(c) != null); Color _getBackgroundColor() { - if (_hasQuotedMessage) { + if (hasQuotedMessage) { return widget.messageTheme.messageBackgroundColor; } diff --git a/lib/src/stream_chat_theme.dart b/lib/src/stream_chat_theme.dart index 02abd25c..246459c6 100644 --- a/lib/src/stream_chat_theme.dart +++ b/lib/src/stream_chat_theme.dart @@ -181,8 +181,8 @@ class StreamChatThemeData { this.ownMessageTheme.messageBackgroundColor, avatarTheme: ownMessageTheme?.avatarTheme ?? this.ownMessageTheme.avatarTheme, - replyThreadColor: ownMessageTheme?.replyThreadColor ?? - this.ownMessageTheme.replyThreadColor, + messageBorderColor: ownMessageTheme?.messageBorderColor ?? + this.ownMessageTheme.messageBorderColor, ) ?? this.ownMessageTheme, otherMessageTheme: otherMessageTheme?.copyWith( @@ -199,10 +199,10 @@ class StreamChatThemeData { messageBackgroundColor: otherMessageTheme?.messageBackgroundColor ?? this.otherMessageTheme.messageBackgroundColor, + messageBorderColor: otherMessageTheme?.messageBorderColor ?? + this.otherMessageTheme.messageBorderColor, avatarTheme: otherMessageTheme?.avatarTheme ?? this.otherMessageTheme.avatarTheme, - replyThreadColor: ownMessageTheme?.replyThreadColor ?? - this.ownMessageTheme.replyThreadColor, ) ?? this.otherMessageTheme, reactionIcons: reactionIcons ?? this.reactionIcons, @@ -284,7 +284,7 @@ class StreamChatThemeData { messageBackgroundColor: colorTheme.greyGainsboro, reactionsBackgroundColor: colorTheme.white, reactionsBorderColor: colorTheme.greyWhisper, - replyThreadColor: colorTheme.greyWhisper, + messageBorderColor: colorTheme.greyGainsboro, avatarTheme: AvatarTheme( borderRadius: BorderRadius.circular(20), constraints: BoxConstraints.tightFor( @@ -316,7 +316,7 @@ class StreamChatThemeData { color: accentColor, ), messageBackgroundColor: colorTheme.white, - replyThreadColor: colorTheme.black.withAlpha(24), + messageBorderColor: colorTheme.greyWhisper, avatarTheme: AvatarTheme( borderRadius: BorderRadius.circular(20), constraints: BoxConstraints.tightFor( @@ -646,9 +646,9 @@ class MessageTheme { final TextStyle createdAt; final TextStyle replies; final Color messageBackgroundColor; + final Color messageBorderColor; final Color reactionsBackgroundColor; final Color reactionsBorderColor; - final Color replyThreadColor; final AvatarTheme avatarTheme; const MessageTheme({ @@ -657,9 +657,9 @@ class MessageTheme { this.messageAuthor, this.messageLinks, this.messageBackgroundColor, + this.messageBorderColor, this.reactionsBackgroundColor, this.reactionsBorderColor, - this.replyThreadColor, this.avatarTheme, this.createdAt, }); @@ -671,10 +671,10 @@ class MessageTheme { TextStyle createdAt, TextStyle replies, Color messageBackgroundColor, + Color messageBorderColor, AvatarTheme avatarTheme, Color reactionsBackgroundColor, Color reactionsBorderColor, - Color replyThreadColor, }) => MessageTheme( messageText: messageText ?? this.messageText, @@ -683,12 +683,12 @@ class MessageTheme { createdAt: createdAt ?? this.createdAt, messageBackgroundColor: messageBackgroundColor ?? this.messageBackgroundColor, + messageBorderColor: messageBorderColor ?? this.messageBorderColor, avatarTheme: avatarTheme ?? this.avatarTheme, replies: replies ?? this.replies, reactionsBackgroundColor: reactionsBackgroundColor ?? this.reactionsBackgroundColor, reactionsBorderColor: reactionsBorderColor ?? this.reactionsBorderColor, - replyThreadColor: replyThreadColor ?? this.replyThreadColor, ); } diff --git a/pubspec.yaml b/pubspec.yaml index 9fa13141..1c99b03b 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -28,7 +28,8 @@ dependencies: file_picker: ^2.0.12 image_picker: ^0.6.7+2 flutter_keyboard_visibility: ^3.3.0 - stream_chat: ^0.2.22 + stream_chat: + path: ../stream-chat-dart mime: ^0.9.6+3 video_compress: ^2.1.1 visibility_detector: ^0.1.5 From b38e3546d15a8b704e92f2810ee986c845c08d28 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Tue, 5 Jan 2021 16:46:26 +0100 Subject: [PATCH 0762/1140] update deps --- example/ios/Podfile.lock | 2 +- example/ios/Runner.xcodeproj/project.pbxproj | 2 -- example/pubspec.yaml | 2 +- lib/src/message_widget.dart | 4 ++-- pubspec.yaml | 3 +-- 5 files changed, 5 insertions(+), 8 deletions(-) diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock index f266b656..d73a681d 100644 --- a/example/ios/Podfile.lock +++ b/example/ios/Podfile.lock @@ -265,7 +265,7 @@ SPEC CHECKSUMS: FirebaseInstallations: 466c7b4d1f58fe16707693091da253726a731ed2 FirebaseInstanceID: bd3ffc24367f901a43c063b36c640b345a4a5dd1 FirebaseMessaging: 5eca4ef173de76253352511aafef774caa1cba2a - Flutter: 0e3d915762c693b495b44d77113d4970485de6ec + Flutter: 434fef37c0980e73bb6479ef766c45957d4b510c flutter_apns: ddc629f26016140bf52165040b0a8e8869f9ce32 flutter_app_badger: 65de4d6f0c34a891df49e6cfb8a1c0496426fa68 flutter_keyboard_visibility: 0339d06371254c3eb25eeb90ba8d17dca8f9c069 diff --git a/example/ios/Runner.xcodeproj/project.pbxproj b/example/ios/Runner.xcodeproj/project.pbxproj index 1e7527eb..b9c182b0 100644 --- a/example/ios/Runner.xcodeproj/project.pbxproj +++ b/example/ios/Runner.xcodeproj/project.pbxproj @@ -314,7 +314,6 @@ "${BUILT_PRODUCTS_DIR}/DKImagePickerController/DKImagePickerController.framework", "${BUILT_PRODUCTS_DIR}/DKPhotoGallery/DKPhotoGallery.framework", "${BUILT_PRODUCTS_DIR}/FMDB/FMDB.framework", - "${PODS_ROOT}/../Flutter/Flutter.framework", "${BUILT_PRODUCTS_DIR}/GoogleUtilities/GoogleUtilities.framework", "${BUILT_PRODUCTS_DIR}/PromisesObjC/FBLPromises.framework", "${BUILT_PRODUCTS_DIR}/Protobuf/Protobuf.framework", @@ -348,7 +347,6 @@ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/DKImagePickerController.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/DKPhotoGallery.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FMDB.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Flutter.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GoogleUtilities.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FBLPromises.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Protobuf.framework", diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 4a0a755a..142614c1 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -1,6 +1,6 @@ name: example description: A new Flutter project. -version: 1.0.110+113 +version: 1.0.111+114 environment: sdk: ">=2.2.2 <3.0.0" diff --git a/lib/src/message_widget.dart b/lib/src/message_widget.dart index 8ce09579..15364606 100644 --- a/lib/src/message_widget.dart +++ b/lib/src/message_widget.dart @@ -10,14 +10,14 @@ import 'package:flutter_portal/flutter_portal.dart'; import 'package:jiffy/jiffy.dart'; import 'package:stream_chat_flutter/src/message_actions_modal.dart'; import 'package:stream_chat_flutter/src/message_reactions_modal.dart'; -import 'package:stream_chat_flutter/src/reaction_bubble.dart'; import 'package:stream_chat_flutter/src/quoted_message_widget.dart'; +import 'package:stream_chat_flutter/src/reaction_bubble.dart'; import 'package:stream_chat_flutter/src/url_attachment.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; +import 'extension.dart'; import 'image_group.dart'; import 'message_text.dart'; -import 'extension.dart'; typedef AttachmentBuilder = Widget Function(BuildContext, Message, Attachment); typedef OnQuotedMessageTap = void Function(String); diff --git a/pubspec.yaml b/pubspec.yaml index 1c99b03b..ee58fc8e 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -28,8 +28,7 @@ dependencies: file_picker: ^2.0.12 image_picker: ^0.6.7+2 flutter_keyboard_visibility: ^3.3.0 - stream_chat: - path: ../stream-chat-dart + stream_chat: ^0.2.23 mime: ^0.9.6+3 video_compress: ^2.1.1 visibility_detector: ^0.1.5 From b23531e6329b8b305d77b3e1fd70aee62a35fb6f Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Tue, 5 Jan 2021 16:59:58 +0100 Subject: [PATCH 0763/1140] update deps --- pubspec.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pubspec.yaml b/pubspec.yaml index ee58fc8e..5a3ad4e5 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -24,10 +24,10 @@ dependencies: url_launcher: ^5.4.11 emojis: ^0.9.3 video_player: ^1.0.0 - chewie: ^0.10.4 + chewie: ^0.12.1 file_picker: ^2.0.12 image_picker: ^0.6.7+2 - flutter_keyboard_visibility: ^3.3.0 + flutter_keyboard_visibility: ^4.0.2 stream_chat: ^0.2.23 mime: ^0.9.6+3 video_compress: ^2.1.1 From bae11ad26aeb50e71ee773cb06efc47deb0ad413 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Wed, 6 Jan 2021 11:41:03 +0530 Subject: [PATCH 0764/1140] [UserListView] Fix separator color Signed-off-by: Sahil Kumar --- lib/src/user_list_view.dart | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/lib/src/user_list_view.dart b/lib/src/user_list_view.dart index 35692841..5e207672 100644 --- a/lib/src/user_list_view.dart +++ b/lib/src/user_list_view.dart @@ -478,9 +478,7 @@ class _UserListViewState extends State Widget _separatorBuilder(context, i) { return Container( height: 1, - color: Theme.of(context).brightness == Brightness.dark - ? StreamChatTheme.of(context).colorTheme.white.withOpacity(0.1) - : StreamChatTheme.of(context).colorTheme.black.withOpacity(0.1), + color: StreamChatTheme.of(context).colorTheme.greyWhisper, ); } From cc54b18a1465d83212c8573fa0cd9fe85c3eaa86 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Wed, 6 Jan 2021 13:28:35 +0530 Subject: [PATCH 0765/1140] [StreamChatTheme] Segregate theme `copyWith` and `merge` logic Signed-off-by: Sahil Kumar --- example/lib/custom_theme.dart | 41 +++--- lib/src/stream_chat.dart | 71 +--------- lib/src/stream_chat_theme.dart | 243 +++++++++++++++++++-------------- 3 files changed, 162 insertions(+), 193 deletions(-) diff --git a/example/lib/custom_theme.dart b/example/lib/custom_theme.dart index 90635993..d8abcb90 100644 --- a/example/lib/custom_theme.dart +++ b/example/lib/custom_theme.dart @@ -39,28 +39,29 @@ class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { - final theme = ThemeData( - primarySwatch: Colors.green, - ); - - return MaterialApp( - theme: theme, - builder: (context, child) => StreamChat( - child: child, - client: client, - streamChatThemeData: StreamChatThemeData.fromTheme(theme).copyWith( - ownMessageTheme: MessageTheme( - messageBackgroundColor: - StreamChatTheme.of(context).colorTheme.black, - messageText: TextStyle( - color: StreamChatTheme.of(context).colorTheme.white, - ), - avatarTheme: AvatarTheme( - borderRadius: BorderRadius.circular(8), - ), - ), + final themeData = ThemeData(primarySwatch: Colors.green); + final defaultTheme = StreamChatThemeData.fromTheme(themeData); + final customTheme = defaultTheme.merge(StreamChatThemeData( + ownMessageTheme: MessageTheme( + messageBackgroundColor: StreamChatTheme.of(context).colorTheme.black, + messageText: TextStyle( + color: StreamChatTheme.of(context).colorTheme.white, + ), + avatarTheme: AvatarTheme( + borderRadius: BorderRadius.circular(8), ), ), + )); + + return MaterialApp( + theme: themeData, + builder: (context, child) { + return StreamChat( + child: child, + client: client, + streamChatThemeData: customTheme, + ); + }, home: ChannelListPage(), ); } diff --git a/lib/src/stream_chat.dart b/lib/src/stream_chat.dart index 521dc3c0..4b012ef0 100644 --- a/lib/src/stream_chat.dart +++ b/lib/src/stream_chat.dart @@ -91,76 +91,7 @@ class StreamChatState extends State with WidgetsBindingObserver { StreamChatThemeData themeData, ) { final defaultTheme = StreamChatThemeData.getDefaultTheme(Theme.of(context)); - final theme = defaultTheme.copyWith( - defaultChannelImage: themeData?.defaultChannelImage, - primaryIconTheme: themeData?.primaryIconTheme, - defaultUserImage: themeData?.defaultUserImage, - channelTheme: defaultTheme.channelTheme.copyWith( - channelHeaderTheme: - defaultTheme.channelTheme.channelHeaderTheme.copyWith( - color: themeData?.channelTheme?.channelHeaderTheme?.color, - lastMessageAt: - themeData?.channelTheme?.channelHeaderTheme?.lastMessageAt, - title: themeData?.channelTheme?.channelHeaderTheme?.title, - avatarTheme: defaultTheme.channelPreviewTheme.avatarTheme.copyWith( - constraints: themeData - ?.channelTheme?.channelHeaderTheme?.avatarTheme?.constraints, - borderRadius: themeData - ?.channelTheme?.channelHeaderTheme?.avatarTheme?.borderRadius, - ), - ), - inputBackground: themeData?.channelTheme?.inputBackground, - messageInputButtonIconTheme: - themeData?.channelTheme?.messageInputButtonIconTheme, - messageInputButtonTheme: - themeData?.channelTheme?.messageInputButtonTheme, - ), - ownMessageTheme: defaultTheme.ownMessageTheme.copyWith( - replies: themeData?.ownMessageTheme?.replies, - createdAt: themeData?.ownMessageTheme?.createdAt, - messageText: themeData?.ownMessageTheme?.messageText, - messageBackgroundColor: - themeData?.ownMessageTheme?.messageBackgroundColor, - messageAuthor: themeData?.ownMessageTheme?.messageAuthor, - messageLinks: themeData?.ownMessageTheme?.messageLinks, - avatarTheme: defaultTheme.ownMessageTheme.avatarTheme.copyWith( - constraints: themeData?.ownMessageTheme?.avatarTheme?.constraints, - borderRadius: themeData?.ownMessageTheme?.avatarTheme?.borderRadius, - ), - reactionsBorderColor: themeData?.ownMessageTheme?.reactionsBorderColor, - reactionsBackgroundColor: - themeData?.ownMessageTheme?.reactionsBackgroundColor, - ), - otherMessageTheme: defaultTheme.otherMessageTheme.copyWith( - replies: themeData?.otherMessageTheme?.replies, - createdAt: themeData?.otherMessageTheme?.createdAt, - messageText: themeData?.otherMessageTheme?.messageText, - messageBackgroundColor: - themeData?.otherMessageTheme?.messageBackgroundColor, - messageAuthor: themeData?.otherMessageTheme?.messageAuthor, - messageLinks: themeData?.otherMessageTheme?.messageLinks, - avatarTheme: defaultTheme.otherMessageTheme.avatarTheme.copyWith( - constraints: themeData?.otherMessageTheme?.avatarTheme?.constraints, - borderRadius: themeData?.otherMessageTheme?.avatarTheme?.borderRadius, - ), - reactionsBorderColor: - themeData?.otherMessageTheme?.reactionsBorderColor, - reactionsBackgroundColor: - themeData?.otherMessageTheme?.reactionsBackgroundColor, - ), - channelPreviewTheme: defaultTheme.channelPreviewTheme.copyWith( - avatarTheme: defaultTheme.channelPreviewTheme.avatarTheme.copyWith( - constraints: themeData?.channelPreviewTheme?.avatarTheme?.constraints, - borderRadius: - themeData?.channelPreviewTheme?.avatarTheme?.borderRadius, - ), - title: themeData?.channelPreviewTheme?.title, - lastMessageAt: themeData?.channelPreviewTheme?.lastMessageAt, - subtitle: themeData?.channelPreviewTheme?.subtitle, - unreadCounterColor: themeData?.channelPreviewTheme?.unreadCounterColor, - ), - ); - return theme; + return defaultTheme.merge(themeData) ?? themeData; } /// The current user diff --git a/lib/src/stream_chat_theme.dart b/lib/src/stream_chat_theme.dart index 246459c6..73ad2046 100644 --- a/lib/src/stream_chat_theme.dart +++ b/lib/src/stream_chat_theme.dart @@ -73,7 +73,7 @@ class StreamChatThemeData { final List reactionIcons; /// Create a theme from scratch - StreamChatThemeData({ + const StreamChatThemeData({ this.textTheme, this.colorTheme, this.channelPreviewTheme, @@ -89,27 +89,18 @@ class StreamChatThemeData { /// Create a theme from a Material [Theme] factory StreamChatThemeData.fromTheme(ThemeData theme) { final defaultTheme = getDefaultTheme(theme); - - return defaultTheme.copyWith( + final customizedTheme = StreamChatThemeData( primaryIconTheme: theme.primaryIconTheme, - channelTheme: defaultTheme.channelTheme, - ownMessageTheme: defaultTheme.ownMessageTheme.copyWith( - replies: defaultTheme.ownMessageTheme.replies.copyWith( - color: theme.accentColor, - ), - messageLinks: TextStyle( - color: theme.accentColor, - ), + ownMessageTheme: MessageTheme( + replies: TextStyle(color: theme.accentColor), + messageLinks: TextStyle(color: theme.accentColor), ), - otherMessageTheme: defaultTheme.otherMessageTheme.copyWith( - replies: defaultTheme.otherMessageTheme.replies.copyWith( - color: theme.accentColor, - ), - messageLinks: TextStyle( - color: theme.accentColor, - ), + otherMessageTheme: MessageTheme( + replies: TextStyle(color: theme.accentColor), + messageLinks: TextStyle(color: theme.accentColor), ), ); + return defaultTheme.merge(customizedTheme) ?? customizedTheme; } /// Creates a copy of [StreamChatThemeData] with specified attributes overridden. @@ -126,88 +117,39 @@ class StreamChatThemeData { List reactionIcons, }) => StreamChatThemeData( - textTheme: this.textTheme?.copyWith( - title: textTheme?.title, - body: textTheme?.body, - bodyBold: textTheme?.bodyBold, - captionBold: textTheme?.captionBold, - footnote: textTheme?.footnote, - footnoteBold: textTheme?.footnoteBold, - headline: textTheme?.headline, - headlineBold: textTheme?.headlineBold, - ), - colorTheme: this.colorTheme?.copyWith( - black: colorTheme?.black, - grey: colorTheme?.grey, - greyGainsboro: colorTheme?.greyGainsboro, - greyWhisper: colorTheme?.greyWhisper, - whiteSmoke: colorTheme?.whiteSmoke, - whiteSnow: colorTheme?.whiteSnow, - white: colorTheme?.white, - blueAlice: colorTheme?.blueAlice, - ), + textTheme: textTheme ?? this.textTheme, + colorTheme: colorTheme ?? this.colorTheme, primaryIconTheme: primaryIconTheme ?? this.primaryIconTheme, defaultChannelImage: defaultChannelImage ?? this.defaultChannelImage, defaultUserImage: defaultUserImage ?? this.defaultUserImage, - channelPreviewTheme: this.channelPreviewTheme?.copyWith( - title: channelPreviewTheme.title, - subtitle: channelPreviewTheme.subtitle, - lastMessageAt: channelPreviewTheme.lastMessageAt, - avatarTheme: channelPreviewTheme.avatarTheme, - ), - channelTheme: channelTheme?.copyWith( - channelHeaderTheme: channelTheme.channelHeaderTheme ?? - this.channelTheme.channelHeaderTheme, - messageInputButtonIconTheme: - channelTheme.messageInputButtonIconTheme ?? - this.channelTheme.messageInputButtonIconTheme, - messageInputButtonTheme: channelTheme.messageInputButtonTheme ?? - this.channelTheme.messageInputButtonTheme, - inputBackground: channelTheme.inputBackground ?? - this.channelTheme.inputBackground, - ) ?? - this.channelTheme, - ownMessageTheme: ownMessageTheme?.copyWith( - messageText: ownMessageTheme?.messageText ?? - this.ownMessageTheme.messageText, - messageAuthor: ownMessageTheme?.messageAuthor ?? - this.ownMessageTheme.messageAuthor, - messageLinks: ownMessageTheme?.messageLinks ?? - this.ownMessageTheme.messageLinks, - createdAt: - ownMessageTheme?.createdAt ?? this.ownMessageTheme.createdAt, - replies: ownMessageTheme?.replies ?? this.ownMessageTheme.replies, - messageBackgroundColor: ownMessageTheme?.messageBackgroundColor ?? - this.ownMessageTheme.messageBackgroundColor, - avatarTheme: ownMessageTheme?.avatarTheme ?? - this.ownMessageTheme.avatarTheme, - messageBorderColor: ownMessageTheme?.messageBorderColor ?? - this.ownMessageTheme.messageBorderColor, - ) ?? - this.ownMessageTheme, - otherMessageTheme: otherMessageTheme?.copyWith( - messageText: otherMessageTheme?.messageText ?? - this.otherMessageTheme.messageText, - messageAuthor: otherMessageTheme?.messageAuthor ?? - this.otherMessageTheme.messageAuthor, - messageLinks: otherMessageTheme?.messageLinks ?? - this.otherMessageTheme.messageLinks, - createdAt: otherMessageTheme?.createdAt ?? - this.otherMessageTheme.createdAt, - replies: - otherMessageTheme?.replies ?? this.otherMessageTheme.replies, - messageBackgroundColor: - otherMessageTheme?.messageBackgroundColor ?? - this.otherMessageTheme.messageBackgroundColor, - messageBorderColor: otherMessageTheme?.messageBorderColor ?? - this.otherMessageTheme.messageBorderColor, - avatarTheme: otherMessageTheme?.avatarTheme ?? - this.otherMessageTheme.avatarTheme, - ) ?? - this.otherMessageTheme, + channelPreviewTheme: channelPreviewTheme ?? this.channelPreviewTheme, + channelTheme: channelTheme ?? this.channelTheme, + ownMessageTheme: ownMessageTheme ?? this.ownMessageTheme, + otherMessageTheme: otherMessageTheme ?? this.otherMessageTheme, reactionIcons: reactionIcons ?? this.reactionIcons, ); + StreamChatThemeData merge(StreamChatThemeData other) { + if (other == null) return this; + return copyWith( + textTheme: textTheme?.merge(other.textTheme) ?? other.textTheme, + colorTheme: colorTheme?.merge(other.colorTheme) ?? other.colorTheme, + primaryIconTheme: other.primaryIconTheme, + defaultChannelImage: other.defaultChannelImage, + defaultUserImage: other.defaultUserImage, + channelPreviewTheme: + channelPreviewTheme?.merge(other.channelPreviewTheme) ?? + other.channelPreviewTheme, + channelTheme: + channelTheme?.merge(other.channelTheme) ?? other.channelTheme, + ownMessageTheme: ownMessageTheme?.merge(other.ownMessageTheme) ?? + other.ownMessageTheme, + otherMessageTheme: otherMessageTheme?.merge(other.otherMessageTheme) ?? + other.otherMessageTheme, + reactionIcons: other.reactionIcons, + ); + } + /// Get the default Stream Chat theme static StreamChatThemeData getDefaultTheme(ThemeData theme) { final accentColor = Color(0xff006cff); @@ -483,6 +425,22 @@ class TextTheme { captionBold: captionBold ?? this.captionBold, ); } + + TextTheme merge(TextTheme other) { + if (other == null) return this; + return copyWith( + body: body?.merge(other.body) ?? other.body, + title: title?.merge(other.title) ?? other.title, + headlineBold: + headlineBold?.merge(other.headlineBold) ?? other.headlineBold, + headline: headline?.merge(other.headline) ?? other.headline, + bodyBold: bodyBold?.merge(other.bodyBold) ?? other.bodyBold, + footnoteBold: + footnoteBold?.merge(other.footnoteBold) ?? other.footnoteBold, + footnote: footnote?.merge(other.footnote) ?? other.footnote, + captionBold: captionBold?.merge(other.captionBold) ?? other.captionBold, + ); + } } enum ColorThemeType { @@ -502,6 +460,7 @@ class ColorTheme { final Color accentBlue; final Color accentRed; final Color accentGreen; + final Color yellow; ColorTheme.light({ this.black = const Color(0xff000000), @@ -515,6 +474,7 @@ class ColorTheme { this.accentBlue = const Color(0xff005FFF), this.accentRed = const Color(0xffFF3742), this.accentGreen = const Color(0xff20E070), + this.yellow = const Color(0Xfffbf4dd), }); ColorTheme.dark({ @@ -529,6 +489,7 @@ class ColorTheme { this.accentBlue = const Color(0xff005FFF), this.accentRed = const Color(0xffFF3742), this.accentGreen = const Color(0xff20E070), + this.yellow = const Color(0xff302d22), }); ColorTheme copyWith({ @@ -544,6 +505,7 @@ class ColorTheme { Color accentBlue, Color accentRed, Color accentGreen, + Color yellow, }) { return type == ColorThemeType.light ? ColorTheme.light( @@ -558,6 +520,7 @@ class ColorTheme { accentBlue: accentBlue ?? this.accentBlue, accentRed: accentRed ?? this.accentRed, accentGreen: accentGreen ?? this.accentGreen, + yellow: yellow ?? this.yellow, ) : ColorTheme.dark( black: black ?? this.black, @@ -571,8 +534,27 @@ class ColorTheme { accentBlue: accentBlue ?? this.accentBlue, accentRed: accentRed ?? this.accentRed, accentGreen: accentGreen ?? this.accentGreen, + yellow: yellow ?? this.yellow, ); } + + ColorTheme merge(ColorTheme other) { + if (other == null) return this; + return copyWith( + black: other.black, + grey: other.grey, + greyGainsboro: other.greyGainsboro, + greyWhisper: other.greyWhisper, + whiteSmoke: other.whiteSmoke, + whiteSnow: other.whiteSnow, + white: other.white, + blueAlice: other.blueAlice, + accentBlue: other.accentBlue, + accentRed: other.accentRed, + accentGreen: other.accentGreen, + yellow: other.yellow, + ); + } } /// Channel theme data @@ -604,20 +586,26 @@ class ChannelTheme { Color inputBackground, }) => ChannelTheme( - channelHeaderTheme: channelHeaderTheme?.copyWith( - title: channelHeaderTheme?.title ?? this.channelHeaderTheme.title, - lastMessageAt: channelHeaderTheme?.lastMessageAt ?? - this.channelHeaderTheme.lastMessageAt, - avatarTheme: channelHeaderTheme?.avatarTheme ?? - this.channelHeaderTheme.avatarTheme, - color: channelHeaderTheme?.color ?? this.channelHeaderTheme.color, - ) ?? - this.channelHeaderTheme, + channelHeaderTheme: channelHeaderTheme ?? this.channelHeaderTheme, messageInputButtonIconTheme: messageInputButtonIconTheme ?? this.messageInputButtonIconTheme, messageInputButtonTheme: messageInputButtonTheme ?? this.messageInputButtonTheme, + inputBackground: inputBackground ?? this.inputBackground, ); + + ChannelTheme merge(ChannelTheme other) { + if (other == null) return this; + return copyWith( + channelHeaderTheme: channelHeaderTheme?.merge(other.channelHeaderTheme) ?? + other.channelHeaderTheme, + messageInputButtonIconTheme: messageInputButtonIconTheme + ?.merge(other.messageInputButtonIconTheme) ?? + other.messageInputButtonIconTheme, + messageInputButtonTheme: other.messageInputButtonTheme, + inputBackground: other.inputBackground, + ); + } } class AvatarTheme { @@ -637,6 +625,14 @@ class AvatarTheme { constraints: constraints ?? this.constraints, borderRadius: borderRadius ?? this.borderRadius, ); + + AvatarTheme merge(AvatarTheme other) { + if (other == null) return this; + return copyWith( + constraints: other.constraints, + borderRadius: other.borderRadius, + ); + } } class MessageTheme { @@ -690,6 +686,24 @@ class MessageTheme { reactionsBackgroundColor ?? this.reactionsBackgroundColor, reactionsBorderColor: reactionsBorderColor ?? this.reactionsBorderColor, ); + + MessageTheme merge(MessageTheme other) { + if (other == null) return this; + return copyWith( + messageText: messageText?.merge(other.messageText) ?? other.messageText, + messageAuthor: + messageAuthor?.merge(other.messageAuthor) ?? other.messageAuthor, + messageLinks: + messageLinks?.merge(other.messageLinks) ?? other.messageLinks, + createdAt: createdAt?.merge(other.createdAt) ?? other.createdAt, + replies: replies?.merge(other.replies) ?? other.replies, + messageBackgroundColor: other.messageBackgroundColor, + messageBorderColor: other.messageBorderColor, + avatarTheme: avatarTheme?.merge(other.avatarTheme) ?? other.avatarTheme, + reactionsBackgroundColor: other.reactionsBackgroundColor, + reactionsBorderColor: other.reactionsBorderColor, + ); + } } class ChannelPreviewTheme { @@ -721,6 +735,18 @@ class ChannelPreviewTheme { avatarTheme: avatarTheme ?? this.avatarTheme, unreadCounterColor: unreadCounterColor ?? this.unreadCounterColor, ); + + ChannelPreviewTheme merge(ChannelPreviewTheme other) { + if (other == null) return this; + return copyWith( + title: title?.merge(other.title) ?? other.title, + subtitle: subtitle?.merge(other.subtitle) ?? other.subtitle, + lastMessageAt: + lastMessageAt?.merge(other.lastMessageAt) ?? other.lastMessageAt, + avatarTheme: avatarTheme?.merge(other.avatarTheme) ?? other.avatarTheme, + unreadCounterColor: other.unreadCounterColor, + ); + } } class ChannelHeaderTheme { @@ -748,4 +774,15 @@ class ChannelHeaderTheme { avatarTheme: avatarTheme ?? this.avatarTheme, color: color ?? this.color, ); + + ChannelHeaderTheme merge(ChannelHeaderTheme other) { + if (other == null) return this; + return copyWith( + title: title?.merge(other.title) ?? other.title, + lastMessageAt: + lastMessageAt?.merge(other.lastMessageAt) ?? other.lastMessageAt, + avatarTheme: avatarTheme?.merge(other.avatarTheme) ?? other.avatarTheme, + color: other.color, + ); + } } From ef4adaea6eb30efabc42c3a54007d024e6cc7533 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Wed, 6 Jan 2021 13:50:30 +0530 Subject: [PATCH 0766/1140] [MessageListView] Add messageHighlightColor property Signed-off-by: Sahil Kumar --- lib/src/message_list_view.dart | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/lib/src/message_list_view.dart b/lib/src/message_list_view.dart index 68a1633b..294c6484 100644 --- a/lib/src/message_list_view.dart +++ b/lib/src/message_list_view.dart @@ -122,6 +122,7 @@ class MessageListView extends StatefulWidget { this.itemPositionListener, this.onMessageSwiped, this.highlightInitialMessage = false, + this.messageHighlightColor, this.onShowMessage, }) : super(key: key); @@ -175,6 +176,9 @@ class MessageListView extends StatefulWidget { /// Also See [StreamChannel] final bool highlightInitialMessage; + /// Color used while highlighting initial message + final Color messageHighlightColor; + final ShowMessageCallback onShowMessage; @override @@ -845,17 +849,16 @@ class _MessageListViewState extends State { if (!initialMessageHighlightComplete && widget.highlightInitialMessage && _isInitialMessage(message.id)) { - final accentColor = Theme.of(context).accentColor; + final colorTheme = StreamChatTheme.of(context).colorTheme; + final highlightColor = widget.messageHighlightColor ?? colorTheme.yellow; child = TweenAnimationBuilder( tween: ColorTween( - begin: accentColor.withOpacity(0.7), - end: Colors.transparent, + begin: highlightColor, + end: colorTheme.white.withOpacity(0), ), - duration: const Duration(seconds: 2), + duration: const Duration(seconds: 3), child: child, - onEnd: () { - initialMessageHighlightComplete = true; - }, + onEnd: () => initialMessageHighlightComplete = true, builder: (_, color, child) { return Container( color: color, From bc6c31c25e497fdd72e5d37143fd5ba50e4cbf3b Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Wed, 6 Jan 2021 13:54:50 +0530 Subject: [PATCH 0767/1140] [GroupChatDetailsScreen] Fix divider color Signed-off-by: Sahil Kumar --- example/lib/group_chat_details_screen.dart | 21 +++------------------ 1 file changed, 3 insertions(+), 18 deletions(-) diff --git a/example/lib/group_chat_details_screen.dart b/example/lib/group_chat_details_screen.dart index 03b4877b..b1fd58c2 100644 --- a/example/lib/group_chat_details_screen.dart +++ b/example/lib/group_chat_details_screen.dart @@ -185,29 +185,14 @@ class _GroupChatDetailsScreenState extends State { itemCount: _selectedUsers.length + 1, separatorBuilder: (_, __) => Container( height: 1, - color: Theme.of(context).brightness == Brightness.dark - ? StreamChatTheme.of(context) - .colorTheme - .white - .withOpacity(0.1) - : StreamChatTheme.of(context) - .colorTheme - .black - .withOpacity(0.1), + color: StreamChatTheme.of(context).colorTheme.greyWhisper, ), itemBuilder: (_, index) { if (index == _selectedUsers.length) { return Container( height: 1, - color: Theme.of(context).brightness == Brightness.dark - ? StreamChatTheme.of(context) - .colorTheme - .white - .withOpacity(0.1) - : StreamChatTheme.of(context) - .colorTheme - .black - .withOpacity(0.1), + color: + StreamChatTheme.of(context).colorTheme.greyWhisper, ); } final user = _selectedUsers[index]; From 375450e5c10aacd8fca4a39d0e793def9f5deebc Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Wed, 6 Jan 2021 15:18:12 +0530 Subject: [PATCH 0768/1140] feat: Added bold mentions in previews, added file names for last message --- lib/src/channel_preview.dart | 59 +++++++++++++++++++++++++------- lib/src/message_search_item.dart | 45 +++++++++++++++++++++++- 2 files changed, 90 insertions(+), 14 deletions(-) diff --git a/lib/src/channel_preview.dart b/lib/src/channel_preview.dart index fe602b4a..840ff8c4 100644 --- a/lib/src/channel_preview.dart +++ b/lib/src/channel_preview.dart @@ -220,7 +220,9 @@ class ChannelPreview extends StatelessWidget { } else if (e.type == 'giphy') { return '[GIF]'; } - return null; + return e == lastMessage.attachments.last + ? e.title + : '${e.title}, '; }).where((e) => e != null), lastMessage.text ?? '', ]; @@ -228,22 +230,53 @@ class ChannelPreview extends StatelessWidget { text = parts.join(' '); } - return Text( - text, + return RichText( maxLines: 1, overflow: TextOverflow.ellipsis, - style: - StreamChatTheme.of(context).channelPreviewTheme.subtitle.copyWith( - color: StreamChatTheme.of(context) - .channelPreviewTheme - .subtitle - .color, - fontStyle: (lastMessage.isSystem || lastMessage.isDeleted) - ? FontStyle.italic - : FontStyle.normal, - ), + text: _getDisplayText( + text, + lastMessage.mentionedUsers, + StreamChatTheme.of(context).channelPreviewTheme.subtitle.copyWith( + color: StreamChatTheme.of(context) + .channelPreviewTheme + .subtitle + .color, + fontStyle: (lastMessage.isSystem || lastMessage.isDeleted) + ? FontStyle.italic + : FontStyle.normal), + StreamChatTheme.of(context).channelPreviewTheme.subtitle.copyWith( + color: StreamChatTheme.of(context) + .channelPreviewTheme + .subtitle + .color, + fontStyle: (lastMessage.isSystem || lastMessage.isDeleted) + ? FontStyle.italic + : FontStyle.normal, + fontWeight: FontWeight.bold), + ), ); }, ); } + + TextSpan _getDisplayText(String text, List mentions, + TextStyle normalTextStyle, TextStyle mentionsTextStyle) { + var textList = text.split(' '); + List resList = []; + for (var e in textList) { + if (mentions.any((element) => '@${element.name}' == e)) { + resList.add(TextSpan( + text: '$e ', + style: mentionsTextStyle, + )); + } else { + resList.add(TextSpan( + text: '$e ', + style: normalTextStyle, + )); + } + } + + return TextSpan(children: resList); + } } diff --git a/lib/src/message_search_item.dart b/lib/src/message_search_item.dart index 851659e1..be257578 100644 --- a/lib/src/message_search_item.dart +++ b/lib/src/message_search_item.dart @@ -113,7 +113,9 @@ class MessageSearchItem extends StatelessWidget { } else if (e.type == 'giphy') { return '[GIF]'; } - return null; + return e == message.attachments.last + ? (e.title ?? 'File') + : '${e.title ?? 'File'}, '; }).where((e) => e != null), message.text ?? '', ]; @@ -121,6 +123,26 @@ class MessageSearchItem extends StatelessWidget { text = parts.join(' '); } + return RichText( + maxLines: 1, + overflow: TextOverflow.ellipsis, + text: _getDisplayText( + text, + message.mentionedUsers, + StreamChatTheme.of(context).channelPreviewTheme.subtitle.copyWith( + fontStyle: (message.isSystem || message.isDeleted) + ? FontStyle.italic + : FontStyle.normal, + ), + StreamChatTheme.of(context).channelPreviewTheme.subtitle.copyWith( + fontStyle: (message.isSystem || message.isDeleted) + ? FontStyle.italic + : FontStyle.normal, + fontWeight: FontWeight.bold, + ), + ), + ); + return Text( text, maxLines: 1, @@ -132,4 +154,25 @@ class MessageSearchItem extends StatelessWidget { ), ); } + + TextSpan _getDisplayText(String text, List mentions, + TextStyle normalTextStyle, TextStyle mentionsTextStyle) { + var textList = text.split(' '); + List resList = []; + for (var e in textList) { + if (mentions.any((element) => '@${element.name}' == e)) { + resList.add(TextSpan( + text: '$e ', + style: mentionsTextStyle, + )); + } else { + resList.add(TextSpan( + text: '$e ', + style: normalTextStyle, + )); + } + } + + return TextSpan(children: resList); + } } From fc00acb8906c55e56cd9d82d17d190ba2065e9e8 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Wed, 6 Jan 2021 15:19:05 +0530 Subject: [PATCH 0769/1140] fix for preview --- lib/src/channel_preview.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/src/channel_preview.dart b/lib/src/channel_preview.dart index 840ff8c4..e325b04a 100644 --- a/lib/src/channel_preview.dart +++ b/lib/src/channel_preview.dart @@ -221,8 +221,8 @@ class ChannelPreview extends StatelessWidget { return '[GIF]'; } return e == lastMessage.attachments.last - ? e.title - : '${e.title}, '; + ? (e.title ?? 'File') + : '${e.title ?? 'File'}, '; }).where((e) => e != null), lastMessage.text ?? '', ]; From a8c60a848288828cb3ceb997bea4df4c307ff08f Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Wed, 6 Jan 2021 15:35:15 +0530 Subject: [PATCH 0770/1140] feat: Added file italics --- lib/src/channel_preview.dart | 18 +++++++++++++++--- lib/src/message_search_item.dart | 18 +++++++++++++++--- 2 files changed, 30 insertions(+), 6 deletions(-) diff --git a/lib/src/channel_preview.dart b/lib/src/channel_preview.dart index e325b04a..122e6a87 100644 --- a/lib/src/channel_preview.dart +++ b/lib/src/channel_preview.dart @@ -222,7 +222,7 @@ class ChannelPreview extends StatelessWidget { } return e == lastMessage.attachments.last ? (e.title ?? 'File') - : '${e.title ?? 'File'}, '; + : '${e.title ?? 'File'} , '; }).where((e) => e != null), lastMessage.text ?? '', ]; @@ -236,6 +236,7 @@ class ChannelPreview extends StatelessWidget { text: _getDisplayText( text, lastMessage.mentionedUsers, + lastMessage.attachments, StreamChatTheme.of(context).channelPreviewTheme.subtitle.copyWith( color: StreamChatTheme.of(context) .channelPreviewTheme @@ -259,8 +260,12 @@ class ChannelPreview extends StatelessWidget { ); } - TextSpan _getDisplayText(String text, List mentions, - TextStyle normalTextStyle, TextStyle mentionsTextStyle) { + TextSpan _getDisplayText( + String text, + List mentions, + List attachments, + TextStyle normalTextStyle, + TextStyle mentionsTextStyle) { var textList = text.split(' '); List resList = []; for (var e in textList) { @@ -269,6 +274,13 @@ class ChannelPreview extends StatelessWidget { text: '$e ', style: mentionsTextStyle, )); + } else if (attachments + .where((e) => e.title != null) + .any((element) => element.title == e)) { + resList.add(TextSpan( + text: '$e ', + style: normalTextStyle.copyWith(fontStyle: FontStyle.italic), + )); } else { resList.add(TextSpan( text: '$e ', diff --git a/lib/src/message_search_item.dart b/lib/src/message_search_item.dart index be257578..62e5f29d 100644 --- a/lib/src/message_search_item.dart +++ b/lib/src/message_search_item.dart @@ -115,7 +115,7 @@ class MessageSearchItem extends StatelessWidget { } return e == message.attachments.last ? (e.title ?? 'File') - : '${e.title ?? 'File'}, '; + : '${e.title ?? 'File'} , '; }).where((e) => e != null), message.text ?? '', ]; @@ -129,6 +129,7 @@ class MessageSearchItem extends StatelessWidget { text: _getDisplayText( text, message.mentionedUsers, + message.attachments, StreamChatTheme.of(context).channelPreviewTheme.subtitle.copyWith( fontStyle: (message.isSystem || message.isDeleted) ? FontStyle.italic @@ -155,8 +156,12 @@ class MessageSearchItem extends StatelessWidget { ); } - TextSpan _getDisplayText(String text, List mentions, - TextStyle normalTextStyle, TextStyle mentionsTextStyle) { + TextSpan _getDisplayText( + String text, + List mentions, + List attachments, + TextStyle normalTextStyle, + TextStyle mentionsTextStyle) { var textList = text.split(' '); List resList = []; for (var e in textList) { @@ -165,6 +170,13 @@ class MessageSearchItem extends StatelessWidget { text: '$e ', style: mentionsTextStyle, )); + } else if (attachments + .where((e) => e.title != null) + .any((element) => element.title == e)) { + resList.add(TextSpan( + text: '$e ', + style: normalTextStyle.copyWith(fontStyle: FontStyle.italic), + )); } else { resList.add(TextSpan( text: '$e ', From 0d71632ef23250db46e5c3584d3c1011f413b5b5 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Wed, 6 Jan 2021 16:25:00 +0530 Subject: [PATCH 0771/1140] theme: Add colors, Gradient and its implementation Signed-off-by: Sahil Kumar --- example/lib/advanced_options_page.dart | 3 + example/lib/choose_user_page.dart | 3 + example/lib/group_chat_details_screen.dart | 26 ++----- example/lib/group_info_screen.dart | 1 + example/lib/new_chat_screen.dart | 16 +--- example/lib/new_group_chat_screen.dart | 34 +++------ lib/src/image_actions_modal.dart | 88 ++++------------------ lib/src/image_footer.dart | 11 +-- lib/src/image_header.dart | 1 + lib/src/message_actions_modal.dart | 8 +- lib/src/message_list_view.dart | 18 ++--- lib/src/message_reactions_modal.dart | 22 ++++-- lib/src/message_search_list_view.dart | 21 +----- lib/src/message_widget.dart | 2 + lib/src/stream_chat_theme.dart | 45 +++++++++-- lib/src/user_list_view.dart | 10 +-- 16 files changed, 113 insertions(+), 196 deletions(-) diff --git a/example/lib/advanced_options_page.dart b/example/lib/advanced_options_page.dart index e24bd5da..9160a5d9 100644 --- a/example/lib/advanced_options_page.dart +++ b/example/lib/advanced_options_page.dart @@ -271,6 +271,9 @@ class _AdvancedOptionsPageState extends State { showDialog( barrierDismissible: false, context: context, + barrierColor: StreamChatTheme.of(context) + .colorTheme + .overlay, builder: (context) => Center( child: Container( decoration: BoxDecoration( diff --git a/example/lib/choose_user_page.dart b/example/lib/choose_user_page.dart index 55bfa36c..ede5f6df 100644 --- a/example/lib/choose_user_page.dart +++ b/example/lib/choose_user_page.dart @@ -108,6 +108,9 @@ class ChooseUserPage extends StatelessWidget { showDialog( barrierDismissible: false, context: context, + barrierColor: StreamChatTheme.of(context) + .colorTheme + .overlay, builder: (context) => Center( child: Container( decoration: BoxDecoration( diff --git a/example/lib/group_chat_details_screen.dart b/example/lib/group_chat_details_screen.dart index b1fd58c2..31ccc703 100644 --- a/example/lib/group_chat_details_screen.dart +++ b/example/lib/group_chat_details_screen.dart @@ -83,10 +83,7 @@ class _GroupChatDetailsScreenState extends State { 'NAME', style: TextStyle( fontSize: 12, - color: StreamChatTheme.of(context) - .colorTheme - .black - .withOpacity(0.5), + color: StreamChatTheme.of(context).colorTheme.grey, ), ), SizedBox(width: 16), @@ -103,11 +100,9 @@ class _GroupChatDetailsScreenState extends State { contentPadding: const EdgeInsets.all(0), hintText: 'Choose a group chat name', hintStyle: TextStyle( - fontSize: 14, - color: StreamChatTheme.of(context) - .colorTheme - .black - .withOpacity(.5)), + fontSize: 14, + color: StreamChatTheme.of(context).colorTheme.grey, + ), ), ), ), @@ -122,7 +117,7 @@ class _GroupChatDetailsScreenState extends State { icon: StreamSvgIcon.check( size: 24, color: _isGroupNameEmpty - ? Colors.grey + ? StreamChatTheme.of(context).colorTheme.grey : StreamChatTheme.of(context).colorTheme.accentBlue, ), onPressed: _isGroupNameEmpty @@ -155,14 +150,7 @@ class _GroupChatDetailsScreenState extends State { Container( width: double.maxFinite, decoration: BoxDecoration( - gradient: LinearGradient( - begin: Alignment.topCenter, - end: Alignment.bottomCenter, - colors: [ - StreamChatTheme.of(context).colorTheme.whiteSmoke, - StreamChatTheme.of(context).colorTheme.whiteSnow, - ], - ), + gradient: StreamChatTheme.of(context).colorTheme.bgGradient, ), child: Padding( padding: const EdgeInsets.symmetric( @@ -172,7 +160,7 @@ class _GroupChatDetailsScreenState extends State { child: Text( '$_totalUsers ${_totalUsers > 1 ? 'Members' : 'Member'}', style: TextStyle( - fontWeight: FontWeight.w500, + color: StreamChatTheme.of(context).colorTheme.grey, ), ), ), diff --git a/example/lib/group_info_screen.dart b/example/lib/group_info_screen.dart index ffab48df..985fe62d 100644 --- a/example/lib/group_info_screen.dart +++ b/example/lib/group_info_screen.dart @@ -589,6 +589,7 @@ class _GroupInfoScreenState extends State { showDialog( context: context, + barrierColor: StreamChatTheme.of(context).colorTheme.overlay, builder: (context) { return StatefulBuilder(builder: (context, modalSetState) { modalSetStateCallback = modalSetState; diff --git a/example/lib/new_chat_screen.dart b/example/lib/new_chat_screen.dart index ddebe848..c0be5ed3 100644 --- a/example/lib/new_chat_screen.dart +++ b/example/lib/new_chat_screen.dart @@ -237,21 +237,7 @@ class _NewChatScreenState extends State { Container( width: double.maxFinite, decoration: BoxDecoration( - gradient: LinearGradient( - begin: Alignment.centerLeft, - end: Alignment.centerRight, - colors: [ - StreamChatTheme.of(context) - .colorTheme - .black - .withOpacity(0.02), - StreamChatTheme.of(context) - .colorTheme - .white - .withOpacity(0.05), - ], - stops: [0, 1], - ), + gradient: StreamChatTheme.of(context).colorTheme.bgGradient, ), child: Padding( padding: const EdgeInsets.symmetric( diff --git a/example/lib/new_group_chat_screen.dart b/example/lib/new_group_chat_screen.dart index 505db69c..c7a25ab3 100644 --- a/example/lib/new_group_chat_screen.dart +++ b/example/lib/new_group_chat_screen.dart @@ -180,21 +180,8 @@ class _NewGroupChatScreenState extends State { child: Container( width: double.maxFinite, decoration: BoxDecoration( - gradient: LinearGradient( - begin: Alignment.centerLeft, - end: Alignment.centerRight, - colors: [ - StreamChatTheme.of(context) - .colorTheme - .black - .withOpacity(0.02), - StreamChatTheme.of(context) - .colorTheme - .white - .withOpacity(0.05), - ], - stops: [0, 1], - ), + gradient: + StreamChatTheme.of(context).colorTheme.bgGradient, ), child: Padding( padding: const EdgeInsets.symmetric( @@ -206,10 +193,7 @@ class _NewGroupChatScreenState extends State { ? 'Matches for \"$_userNameQuery\"' : 'On the platform', style: TextStyle( - color: StreamChatTheme.of(context) - .colorTheme - .black - .withOpacity(0.5), + color: StreamChatTheme.of(context).colorTheme.grey, ), ), ), @@ -271,7 +255,9 @@ class _NewGroupChatScreenState extends State { padding: const EdgeInsets.all(24), child: StreamSvgIcon.search( size: 96, - color: Colors.grey, + color: StreamChatTheme.of(context) + .colorTheme + .grey, ), ), Text( @@ -280,10 +266,10 @@ class _NewGroupChatScreenState extends State { .textTheme .footnote .copyWith( - color: StreamChatTheme.of(context) - .colorTheme - .black - .withOpacity(.5)), + color: StreamChatTheme.of(context) + .colorTheme + .grey, + ), ), ], ), diff --git a/lib/src/image_actions_modal.dart b/lib/src/image_actions_modal.dart index 0001df6f..332117d4 100644 --- a/lib/src/image_actions_modal.dart +++ b/lib/src/image_actions_modal.dart @@ -29,27 +29,8 @@ class ImageActionsModal extends StatelessWidget { Widget build(BuildContext context) { return GestureDetector( behavior: HitTestBehavior.translucent, - onTap: () { - Navigator.pop(context); - }, - child: Stack( - children: [ - Positioned.fill( - child: Container( - decoration: BoxDecoration( - gradient: LinearGradient( - begin: Alignment.topCenter, - end: Alignment.bottomCenter, - colors: [ - Colors.black.withOpacity(0.8), - Colors.transparent, - ], - stops: [0.0, 0.4], - )), - )), - _buildPage(context), - ], - ), + onTap: () => Navigator.maybePop(context), + child: _buildPage(context), ); } @@ -57,53 +38,14 @@ class ImageActionsModal extends StatelessWidget { return Material( color: Colors.transparent, child: Column( + crossAxisAlignment: CrossAxisAlignment.end, children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Padding( - padding: const EdgeInsets.all(8.0), - child: Container( - width: 40.0, - ), - ), - Column( - children: [ - Padding( - padding: const EdgeInsets.only(top: 8.0), - child: Text( - userName, - style: StreamChatTheme.of(context) - .textTheme - .headlineBold - .copyWith( - color: - StreamChatTheme.of(context).colorTheme.white), - ), - ), - Text( - sentAt, - style: StreamChatTheme.of(context) - .channelPreviewTheme - .subtitle - .copyWith( - color: StreamChatTheme.of(context) - .colorTheme - .white - .withOpacity(0.5)), - ), - ], - ), - IconButton( - icon: StreamSvgIcon.close( - size: 24.0, - color: StreamChatTheme.of(context).colorTheme.white, - ), - onPressed: () { - Navigator.pop(context); - }, - ), - ], + SizedBox( + height: kToolbarHeight, + child: IconButton( + icon: StreamSvgIcon.close(), + onPressed: () => Navigator.maybePop(context), + ), ), Align( alignment: Alignment.centerRight, @@ -127,10 +69,8 @@ class ImageActionsModal extends StatelessWidget { 'Reply', StreamSvgIcon.Icon_curve_line_left_up( size: 24.0, - color: StreamChatTheme.of(context) - .colorTheme - .black - .withOpacity(0.5), + color: + StreamChatTheme.of(context).colorTheme.grey, ), () {}), _buildButton( @@ -147,10 +87,8 @@ class ImageActionsModal extends StatelessWidget { 'Save ${urls[currentIndex].type == 'video' ? 'Video' : 'Image'}', StreamSvgIcon.Icon_save( size: 24.0, - color: StreamChatTheme.of(context) - .colorTheme - .black - .withOpacity(0.5), + color: + StreamChatTheme.of(context).colorTheme.grey, ), () async { var url = urls[currentIndex].imageUrl ?? urls[currentIndex].assetUrl ?? diff --git a/lib/src/image_footer.dart b/lib/src/image_footer.dart index 3a6cfbcc..7ee9a128 100644 --- a/lib/src/image_footer.dart +++ b/lib/src/image_footer.dart @@ -157,9 +157,7 @@ class _ImageFooterState extends State { icon: StreamSvgIcon.Icon_grid( color: StreamChatTheme.of(context).colorTheme.black, ), - onPressed: () { - _buildPhotosModal(context); - }, + onPressed: () => _showPhotosModal(context), ), ], ), @@ -168,13 +166,14 @@ class _ImageFooterState extends State { ); } - Widget _buildPhotosModal(context) { + void _showPhotosModal(context) { var videoAttachments = widget.mediaAttachments .where((element) => element.type == 'video') .toList(); showModalBottomSheet( context: context, + barrierColor: StreamChatTheme.of(context).colorTheme.overlay, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(16.0), ), @@ -207,9 +206,7 @@ class _ImageFooterState extends State { icon: StreamSvgIcon.close( color: StreamChatTheme.of(context).colorTheme.black, ), - onPressed: () { - Navigator.pop(context); - }, + onPressed: () => Navigator.maybePop(context), ), ), ], diff --git a/lib/src/image_header.dart b/lib/src/image_header.dart index 6139bc7c..1f6237ab 100644 --- a/lib/src/image_header.dart +++ b/lib/src/image_header.dart @@ -106,6 +106,7 @@ class ImageHeader extends StatelessWidget implements PreferredSizeWidget { showDialog( context: context, + barrierColor: StreamChatTheme.of(context).colorTheme.overlay, builder: (context) { return StreamChannel( channel: channel, diff --git a/lib/src/message_actions_modal.dart b/lib/src/message_actions_modal.dart index 6294ef6a..c7ff56e0 100644 --- a/lib/src/message_actions_modal.dart +++ b/lib/src/message_actions_modal.dart @@ -73,17 +73,17 @@ class MessageActionsModal extends StatelessWidget { return GestureDetector( behavior: HitTestBehavior.translucent, - onTap: () => Navigator.pop(context), + onTap: () => Navigator.maybePop(context), child: Stack( children: [ Positioned.fill( child: BackdropFilter( filter: ImageFilter.blur( - sigmaX: 10.8731, - sigmaY: 10.8731, + sigmaX: 10, + sigmaY: 10, ), child: Container( - color: Colors.black.withOpacity(.2), + color: StreamChatTheme.of(context).colorTheme.overlay, ), ), ), diff --git a/lib/src/message_list_view.dart b/lib/src/message_list_view.dart index 294c6484..db9790b9 100644 --- a/lib/src/message_list_view.dart +++ b/lib/src/message_list_view.dart @@ -350,18 +350,9 @@ class _MessageListViewState extends State { buildParentMessage(widget.parentMessage), Container( decoration: BoxDecoration( - gradient: LinearGradient( - begin: Alignment.topCenter, - end: Alignment.bottomCenter, - colors: [ - StreamChatTheme.of(context) - .colorTheme - .whiteSmoke, - StreamChatTheme.of(context) - .colorTheme - .whiteSnow, - ], - ), + gradient: StreamChatTheme.of(context) + .colorTheme + .bgGradient, ), child: Padding( padding: const EdgeInsets.all(8.0), @@ -850,7 +841,8 @@ class _MessageListViewState extends State { widget.highlightInitialMessage && _isInitialMessage(message.id)) { final colorTheme = StreamChatTheme.of(context).colorTheme; - final highlightColor = widget.messageHighlightColor ?? colorTheme.yellow; + final highlightColor = + widget.messageHighlightColor ?? colorTheme.highlight; child = TweenAnimationBuilder( tween: ColorTween( begin: highlightColor, diff --git a/lib/src/message_reactions_modal.dart b/lib/src/message_reactions_modal.dart index 232f6f84..375f5e0c 100644 --- a/lib/src/message_reactions_modal.dart +++ b/lib/src/message_reactions_modal.dart @@ -40,27 +40,35 @@ class MessageReactionsModal extends StatelessWidget { final user = StreamChat.of(context).user; final roughMaxSize = 2 * size.width / 3; + var messageTextLength = message.text.length; + if (message.quotedMessage != null) { + var quotedMessageLength = message.quotedMessage.text.length + 40; + if (message.quotedMessage.attachments?.isNotEmpty == true) { + quotedMessageLength += 40; + } + if (quotedMessageLength > messageTextLength) { + messageTextLength = quotedMessageLength; + } + } final roughSentenceSize = - message.text.length * messageTheme.messageText.fontSize * 1.2; + messageTextLength * messageTheme.messageText.fontSize * 1.2; final divFactor = message.attachments?.isNotEmpty == true ? 1 : (roughSentenceSize == 0 ? 1 : (roughSentenceSize / roughMaxSize)); return GestureDetector( behavior: HitTestBehavior.translucent, - onTap: () { - Navigator.pop(context); - }, + onTap: () => Navigator.maybePop(context), child: Stack( children: [ Positioned.fill( child: BackdropFilter( filter: ImageFilter.blur( - sigmaX: 10.8731, - sigmaY: 10.8731, + sigmaX: 10, + sigmaY: 10, ), child: Container( - color: Colors.black.withOpacity(0.2), + color: StreamChatTheme.of(context).colorTheme.overlay, ), ), ), diff --git a/lib/src/message_search_list_view.dart b/lib/src/message_search_list_view.dart index d59ae4a0..3ff9f151 100644 --- a/lib/src/message_search_list_view.dart +++ b/lib/src/message_search_list_view.dart @@ -313,21 +313,7 @@ class _MessageSearchListViewState extends State { Container( width: double.maxFinite, decoration: BoxDecoration( - gradient: LinearGradient( - begin: Alignment.centerLeft, - end: Alignment.centerRight, - colors: [ - StreamChatTheme.of(context) - .colorTheme - .black - .withOpacity(0.02), - StreamChatTheme.of(context) - .colorTheme - .white - .withOpacity(0.05), - ], - stops: [0, 1], - ), + gradient: StreamChatTheme.of(context).colorTheme.bgGradient, ), child: Padding( padding: const EdgeInsets.symmetric( @@ -337,10 +323,7 @@ class _MessageSearchListViewState extends State { child: Text( '${items.length} results', style: TextStyle( - color: StreamChatTheme.of(context) - .colorTheme - .black - .withOpacity(0.5), + color: StreamChatTheme.of(context).colorTheme.grey, ), ), ), diff --git a/lib/src/message_widget.dart b/lib/src/message_widget.dart index 15364606..30e636a4 100644 --- a/lib/src/message_widget.dart +++ b/lib/src/message_widget.dart @@ -676,6 +676,7 @@ class _MessageWidgetState extends State { final channel = StreamChannel.of(context).channel; showDialog( context: context, + barrierColor: StreamChatTheme.of(context).colorTheme.overlay, builder: (context) { return StreamChannel( channel: channel, @@ -716,6 +717,7 @@ class _MessageWidgetState extends State { final channel = StreamChannel.of(context).channel; showDialog( context: context, + barrierColor: StreamChatTheme.of(context).colorTheme.overlay, builder: (context) { return StreamChannel( channel: channel, diff --git a/lib/src/stream_chat_theme.dart b/lib/src/stream_chat_theme.dart index 73ad2046..3fac4173 100644 --- a/lib/src/stream_chat_theme.dart +++ b/lib/src/stream_chat_theme.dart @@ -460,7 +460,10 @@ class ColorTheme { final Color accentBlue; final Color accentRed; final Color accentGreen; - final Color yellow; + final Color highlight; + final Color overlay; + final Color overlayDark; + final Gradient bgGradient; ColorTheme.light({ this.black = const Color(0xff000000), @@ -474,7 +477,15 @@ class ColorTheme { this.accentBlue = const Color(0xff005FFF), this.accentRed = const Color(0xffFF3742), this.accentGreen = const Color(0xff20E070), - this.yellow = const Color(0Xfffbf4dd), + this.highlight = const Color(0xfffbf4dd), + this.overlay = const Color.fromRGBO(0, 0, 0, 0.2), + this.overlayDark = const Color.fromRGBO(0, 0, 0, 0.6), + this.bgGradient = const LinearGradient( + begin: Alignment.topCenter, + end: Alignment.bottomCenter, + colors: [const Color(0xfff7f7f7), const Color(0xfffcfcfc)], + stops: [0, 1], + ), }); ColorTheme.dark({ @@ -489,7 +500,15 @@ class ColorTheme { this.accentBlue = const Color(0xff005FFF), this.accentRed = const Color(0xffFF3742), this.accentGreen = const Color(0xff20E070), - this.yellow = const Color(0xff302d22), + this.highlight = const Color(0xff302d22), + this.overlay = const Color.fromRGBO(0, 0, 0, 0.4), + this.overlayDark = const Color.fromRGBO(255, 255, 255, 0.6), + this.bgGradient = const LinearGradient( + begin: Alignment.topCenter, + end: Alignment.bottomCenter, + colors: [const Color(0xff101214), const Color(0xff070a0d)], + stops: [0, 1], + ), }); ColorTheme copyWith({ @@ -505,7 +524,10 @@ class ColorTheme { Color accentBlue, Color accentRed, Color accentGreen, - Color yellow, + Color highlight, + Color overlay, + Color overlayDark, + Gradient bgGradient, }) { return type == ColorThemeType.light ? ColorTheme.light( @@ -520,7 +542,10 @@ class ColorTheme { accentBlue: accentBlue ?? this.accentBlue, accentRed: accentRed ?? this.accentRed, accentGreen: accentGreen ?? this.accentGreen, - yellow: yellow ?? this.yellow, + highlight: highlight ?? this.highlight, + overlay: overlay ?? this.overlay, + overlayDark: overlayDark ?? this.overlayDark, + bgGradient: bgGradient ?? this.bgGradient, ) : ColorTheme.dark( black: black ?? this.black, @@ -534,7 +559,10 @@ class ColorTheme { accentBlue: accentBlue ?? this.accentBlue, accentRed: accentRed ?? this.accentRed, accentGreen: accentGreen ?? this.accentGreen, - yellow: yellow ?? this.yellow, + highlight: highlight ?? this.highlight, + overlay: overlay ?? this.overlay, + overlayDark: overlayDark ?? this.overlayDark, + bgGradient: bgGradient ?? this.bgGradient, ); } @@ -552,7 +580,10 @@ class ColorTheme { accentBlue: other.accentBlue, accentRed: other.accentRed, accentGreen: other.accentGreen, - yellow: other.yellow, + highlight: other.highlight, + overlay: other.overlay, + overlayDark: other.overlayDark, + bgGradient: other.bgGradient, ); } } diff --git a/lib/src/user_list_view.dart b/lib/src/user_list_view.dart index 5e207672..ef51ad92 100644 --- a/lib/src/user_list_view.dart +++ b/lib/src/user_list_view.dart @@ -363,12 +363,10 @@ class _UserListViewState extends State child: Text( header, style: TextStyle( - fontWeight: FontWeight.bold, - fontSize: 14.5, - color: StreamChatTheme.of(context) - .colorTheme - .black - .withOpacity(0.3)), + fontWeight: FontWeight.bold, + fontSize: 14.5, + color: StreamChatTheme.of(context).colorTheme.grey, + ), ), ), ); From 7b2cde37e537f619601a2d68680e2ecd20fd2209 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Wed, 6 Jan 2021 16:35:55 +0530 Subject: [PATCH 0772/1140] [NewChatScreen] Fix chip clear icon color Signed-off-by: Sahil Kumar --- example/lib/new_chat_screen.dart | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/example/lib/new_chat_screen.dart b/example/lib/new_chat_screen.dart index c0be5ed3..1de36b46 100644 --- a/example/lib/new_chat_screen.dart +++ b/example/lib/new_chat_screen.dart @@ -157,8 +157,7 @@ class _NewChatScreenState extends State { decoration: BoxDecoration( color: StreamChatTheme.of(context) .colorTheme - .black - .withOpacity(0.05), + .greyGainsboro, borderRadius: BorderRadius.circular(12), ), padding: const EdgeInsets.only(left: 24), @@ -166,15 +165,19 @@ class _NewChatScreenState extends State { padding: const EdgeInsets.fromLTRB(8, 4, 12, 4), child: Text( user.name, + maxLines: 1, style: TextStyle( - color: StreamChatTheme.of(context) - .colorTheme - .black), + color: + StreamChatTheme.of(context).colorTheme.black, + ), ), ), ), - Opacity( - opacity: .8, + Container( + foregroundDecoration: BoxDecoration( + color: StreamChatTheme.of(context).colorTheme.overlay, + shape: BoxShape.circle, + ), child: UserAvatar( showOnlineStatus: false, user: user, @@ -184,11 +187,7 @@ class _NewChatScreenState extends State { ), ), ), - Positioned( - child: StreamSvgIcon.close( - color: StreamChatTheme.of(context).colorTheme.white, - ), - ), + StreamSvgIcon.close(), ], ), ); From b55d8bd2a82eb501740a05f357b9d89e57f3668e Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Wed, 6 Jan 2021 16:41:03 +0530 Subject: [PATCH 0773/1140] [UserItem] Fix selected check icon Signed-off-by: Sahil Kumar --- lib/src/stream_svg_icon.dart | 12 ++++++++++++ lib/src/user_item.dart | 10 ++-------- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/lib/src/stream_svg_icon.dart b/lib/src/stream_svg_icon.dart index e7ef46c3..edf1a697 100644 --- a/lib/src/stream_svg_icon.dart +++ b/lib/src/stream_svg_icon.dart @@ -194,6 +194,18 @@ class StreamSvgIcon extends StatelessWidget { ); } + factory StreamSvgIcon.checkSend({ + double size, + Color color, + }) { + return StreamSvgIcon( + assetName: 'Icon_check_send.svg', + color: color, + width: size, + height: size, + ); + } + factory StreamSvgIcon.penWrite({ double size, Color color, diff --git a/lib/src/user_item.dart b/lib/src/user_item.dart index 50a8b7a7..58a354fc 100644 --- a/lib/src/user_item.dart +++ b/lib/src/user_item.dart @@ -73,14 +73,8 @@ class UserItem extends StatelessWidget { ), ), trailing: selected - ? CircleAvatar( - backgroundColor: - StreamChatTheme.of(context).colorTheme.accentBlue, - child: StreamSvgIcon.check( - size: 20, - color: StreamChatTheme.of(context).colorTheme.white, - ), - radius: 10, + ? StreamSvgIcon.checkSend( + color: StreamChatTheme.of(context).colorTheme.accentBlue, ) : null, title: Text( From 1927a632e08a0c65d712ed91045e49b33c5c2ecd Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Wed, 6 Jan 2021 17:00:56 +0530 Subject: [PATCH 0774/1140] fix: fixed null sometimes popping up --- lib/src/channel_preview.dart | 12 ++++++++---- lib/src/message_search_item.dart | 12 ++++++++---- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/lib/src/channel_preview.dart b/lib/src/channel_preview.dart index 122e6a87..1f64f16f 100644 --- a/lib/src/channel_preview.dart +++ b/lib/src/channel_preview.dart @@ -269,14 +269,18 @@ class ChannelPreview extends StatelessWidget { var textList = text.split(' '); List resList = []; for (var e in textList) { - if (mentions.any((element) => '@${element.name}' == e)) { + if (mentions != null && + mentions.isNotEmpty && + mentions.any((element) => '@${element.name}' == e)) { resList.add(TextSpan( text: '$e ', style: mentionsTextStyle, )); - } else if (attachments - .where((e) => e.title != null) - .any((element) => element.title == e)) { + } else if (attachments != null && + attachments.isNotEmpty && + attachments + .where((e) => e.title != null) + .any((element) => element.title == e)) { resList.add(TextSpan( text: '$e ', style: normalTextStyle.copyWith(fontStyle: FontStyle.italic), diff --git a/lib/src/message_search_item.dart b/lib/src/message_search_item.dart index 62e5f29d..35cec093 100644 --- a/lib/src/message_search_item.dart +++ b/lib/src/message_search_item.dart @@ -165,14 +165,18 @@ class MessageSearchItem extends StatelessWidget { var textList = text.split(' '); List resList = []; for (var e in textList) { - if (mentions.any((element) => '@${element.name}' == e)) { + if (mentions != null && + mentions.isNotEmpty && + mentions.any((element) => '@${element.name}' == e)) { resList.add(TextSpan( text: '$e ', style: mentionsTextStyle, )); - } else if (attachments - .where((e) => e.title != null) - .any((element) => element.title == e)) { + } else if (attachments != null && + attachments.isNotEmpty && + attachments + .where((e) => e.title != null) + .any((element) => element.title == e)) { resList.add(TextSpan( text: '$e ', style: normalTextStyle.copyWith(fontStyle: FontStyle.italic), From 9bbad0b9e2b2a098c1b383e560c56324f63029aa Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Wed, 6 Jan 2021 17:14:55 +0530 Subject: [PATCH 0775/1140] fix: fixed extra space error --- lib/src/channel_preview.dart | 2 +- lib/src/message_search_item.dart | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/src/channel_preview.dart b/lib/src/channel_preview.dart index 1f64f16f..6c8d61fe 100644 --- a/lib/src/channel_preview.dart +++ b/lib/src/channel_preview.dart @@ -287,7 +287,7 @@ class ChannelPreview extends StatelessWidget { )); } else { resList.add(TextSpan( - text: '$e ', + text: e == textList.last ? '$e' : '$e ', style: normalTextStyle, )); } diff --git a/lib/src/message_search_item.dart b/lib/src/message_search_item.dart index 35cec093..a90b82c4 100644 --- a/lib/src/message_search_item.dart +++ b/lib/src/message_search_item.dart @@ -183,7 +183,7 @@ class MessageSearchItem extends StatelessWidget { )); } else { resList.add(TextSpan( - text: '$e ', + text: e == textList.last ? '$e' : '$e ', style: normalTextStyle, )); } From bfc9fc82f6ca85bc690fc08d5f1d35363a5d8e2c Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Wed, 6 Jan 2021 17:38:23 +0530 Subject: [PATCH 0776/1140] fix: Used text.rich instead of richtext to fix test --- lib/src/channel_preview.dart | 8 ++++---- lib/src/message_search_item.dart | 33 +++++++++++--------------------- 2 files changed, 15 insertions(+), 26 deletions(-) diff --git a/lib/src/channel_preview.dart b/lib/src/channel_preview.dart index 6c8d61fe..d7c1a418 100644 --- a/lib/src/channel_preview.dart +++ b/lib/src/channel_preview.dart @@ -230,10 +230,8 @@ class ChannelPreview extends StatelessWidget { text = parts.join(' '); } - return RichText( - maxLines: 1, - overflow: TextOverflow.ellipsis, - text: _getDisplayText( + return Text.rich( + _getDisplayText( text, lastMessage.mentionedUsers, lastMessage.attachments, @@ -255,6 +253,8 @@ class ChannelPreview extends StatelessWidget { : FontStyle.normal, fontWeight: FontWeight.bold), ), + maxLines: 1, + overflow: TextOverflow.ellipsis, ); }, ); diff --git a/lib/src/message_search_item.dart b/lib/src/message_search_item.dart index a90b82c4..060fcee5 100644 --- a/lib/src/message_search_item.dart +++ b/lib/src/message_search_item.dart @@ -123,36 +123,25 @@ class MessageSearchItem extends StatelessWidget { text = parts.join(' '); } - return RichText( - maxLines: 1, - overflow: TextOverflow.ellipsis, - text: _getDisplayText( + return Text.rich( + _getDisplayText( text, message.mentionedUsers, message.attachments, StreamChatTheme.of(context).channelPreviewTheme.subtitle.copyWith( - fontStyle: (message.isSystem || message.isDeleted) - ? FontStyle.italic - : FontStyle.normal, - ), + fontStyle: (message.isSystem || message.isDeleted) + ? FontStyle.italic + : FontStyle.normal, + ), StreamChatTheme.of(context).channelPreviewTheme.subtitle.copyWith( - fontStyle: (message.isSystem || message.isDeleted) - ? FontStyle.italic - : FontStyle.normal, - fontWeight: FontWeight.bold, - ), + fontStyle: (message.isSystem || message.isDeleted) + ? FontStyle.italic + : FontStyle.normal, + fontWeight: FontWeight.bold, + ), ), - ); - - return Text( - text, maxLines: 1, overflow: TextOverflow.ellipsis, - style: StreamChatTheme.of(context).channelPreviewTheme.subtitle.copyWith( - fontStyle: (message.isSystem || message.isDeleted) - ? FontStyle.italic - : FontStyle.normal, - ), ); } From c9ee6bfb25b933eb5db2ae8864817c32fcd5f2d4 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Wed, 6 Jan 2021 17:38:51 +0530 Subject: [PATCH 0777/1140] darfmt --- lib/src/message_search_item.dart | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/lib/src/message_search_item.dart b/lib/src/message_search_item.dart index 060fcee5..9c951a56 100644 --- a/lib/src/message_search_item.dart +++ b/lib/src/message_search_item.dart @@ -129,16 +129,16 @@ class MessageSearchItem extends StatelessWidget { message.mentionedUsers, message.attachments, StreamChatTheme.of(context).channelPreviewTheme.subtitle.copyWith( - fontStyle: (message.isSystem || message.isDeleted) - ? FontStyle.italic - : FontStyle.normal, - ), + fontStyle: (message.isSystem || message.isDeleted) + ? FontStyle.italic + : FontStyle.normal, + ), StreamChatTheme.of(context).channelPreviewTheme.subtitle.copyWith( - fontStyle: (message.isSystem || message.isDeleted) - ? FontStyle.italic - : FontStyle.normal, - fontWeight: FontWeight.bold, - ), + fontStyle: (message.isSystem || message.isDeleted) + ? FontStyle.italic + : FontStyle.normal, + fontWeight: FontWeight.bold, + ), ), maxLines: 1, overflow: TextOverflow.ellipsis, From 14a35205cf577b8c4bf169c8b9c1e0dc8f585bf2 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Wed, 6 Jan 2021 18:23:39 +0530 Subject: [PATCH 0778/1140] [Choose User, Advanced Options] QA fixes, theme changes Signed-off-by: Sahil Kumar --- example/lib/advanced_options_page.dart | 446 +++++++++++-------------- example/lib/choose_user_page.dart | 12 +- example/lib/stream_version.dart | 5 +- lib/src/stream_chat.dart | 1 + lib/src/stream_chat_theme.dart | 20 +- 5 files changed, 231 insertions(+), 253 deletions(-) diff --git a/example/lib/advanced_options_page.dart b/example/lib/advanced_options_page.dart index 9160a5d9..7555f286 100644 --- a/example/lib/advanced_options_page.dart +++ b/example/lib/advanced_options_page.dart @@ -60,15 +60,11 @@ class _AdvancedOptionsPageState extends State { body: Builder( builder: (context) { return Padding( - padding: const EdgeInsets.fromLTRB( - 16, - 16, - 16, - 0, - ), + padding: const EdgeInsets.fromLTRB(16, 16, 16, 0), child: Form( key: _formKey, child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, children: [ TextFormField( controller: _apiKeyController, @@ -93,16 +89,13 @@ class _AdvancedOptionsPageState extends State { color: StreamChatTheme.of(context).colorTheme.black, ), decoration: InputDecoration( - errorStyle: TextStyle(fontSize: 0), + errorStyle: TextStyle(height: 0, fontSize: 0), labelStyle: TextStyle( fontSize: 14, fontWeight: FontWeight.bold, color: _apiKeyError != null ? StreamChatTheme.of(context).colorTheme.accentRed - : StreamChatTheme.of(context) - .colorTheme - .black - .withOpacity(.5), + : StreamChatTheme.of(context).colorTheme.grey, ), border: UnderlineInputBorder( borderRadius: BorderRadius.circular(8), @@ -112,264 +105,231 @@ class _AdvancedOptionsPageState extends State { StreamChatTheme.of(context).colorTheme.whiteSmoke, filled: true, labelText: - 'Chat API Key ${_apiKeyError != null ? ':$_apiKeyError' : ''}', + 'Chat API Key ${_apiKeyError != null ? ': $_apiKeyError' : ''}', ), textInputAction: TextInputAction.next, ), - Padding( - padding: const EdgeInsets.only(top: 8.0), - child: TextFormField( - controller: _userIdController, - onChanged: (_) { - if (_userIdError != null) { - setState(() { - _userIdError = null; - }); - } - }, - validator: (value) { - if (value.isEmpty) { - setState(() { - _userIdError = 'Please enter the User ID'; - }); - return _userIdError; - } - return null; - }, - style: TextStyle( + SizedBox(height: 8), + TextFormField( + controller: _userIdController, + onChanged: (_) { + if (_userIdError != null) { + setState(() { + _userIdError = null; + }); + } + }, + validator: (value) { + if (value.isEmpty) { + setState(() { + _userIdError = 'Please enter the User ID'; + }); + return _userIdError; + } + return null; + }, + style: TextStyle( + fontSize: 14, + color: StreamChatTheme.of(context).colorTheme.black, + ), + textInputAction: TextInputAction.next, + decoration: InputDecoration( + errorStyle: TextStyle(height: 0, fontSize: 0), + labelStyle: TextStyle( + fontWeight: FontWeight.bold, fontSize: 14, - color: StreamChatTheme.of(context).colorTheme.black, + color: _userIdError != null + ? StreamChatTheme.of(context).colorTheme.accentRed + : StreamChatTheme.of(context).colorTheme.grey, ), - textInputAction: TextInputAction.next, - decoration: InputDecoration( - errorStyle: TextStyle(fontSize: 0), - labelStyle: TextStyle( - fontWeight: FontWeight.bold, - fontSize: 14, - color: _userIdError != null - ? StreamChatTheme.of(context).colorTheme.accentRed - : StreamChatTheme.of(context) - .colorTheme - .black - .withOpacity(.5), - ), - border: UnderlineInputBorder( - borderRadius: BorderRadius.circular(8), - borderSide: BorderSide.none, - ), - fillColor: - StreamChatTheme.of(context).colorTheme.whiteSmoke, - filled: true, - labelText: - 'User ID ${_userIdError != null ? ':$_userIdError' : ''}', + border: UnderlineInputBorder( + borderRadius: BorderRadius.circular(8), + borderSide: BorderSide.none, ), + fillColor: + StreamChatTheme.of(context).colorTheme.whiteSmoke, + filled: true, + labelText: + 'User ID ${_userIdError != null ? ': $_userIdError' : ''}', ), ), - Padding( - padding: const EdgeInsets.only(top: 8.0), - child: TextFormField( - onChanged: (_) { - if (_userTokenError != null) { - setState(() { - _userTokenError = null; - }); - } - }, - controller: _userTokenController, - validator: (value) { - if (value.isEmpty) { - setState(() { - _userTokenError = 'Please enter the user token'; - }); - return _userTokenError; - } - return null; - }, - style: TextStyle( + SizedBox(height: 8), + TextFormField( + onChanged: (_) { + if (_userTokenError != null) { + setState(() { + _userTokenError = null; + }); + } + }, + controller: _userTokenController, + validator: (value) { + if (value.isEmpty) { + setState(() { + _userTokenError = 'Please enter the user token'; + }); + return _userTokenError; + } + return null; + }, + style: TextStyle( + fontSize: 14, + color: StreamChatTheme.of(context).colorTheme.black, + ), + textInputAction: TextInputAction.next, + decoration: InputDecoration( + errorStyle: TextStyle(height: 0, fontSize: 0), + labelStyle: TextStyle( + fontWeight: FontWeight.bold, fontSize: 14, - color: StreamChatTheme.of(context).colorTheme.black, + color: _userTokenError != null + ? StreamChatTheme.of(context).colorTheme.accentRed + : StreamChatTheme.of(context).colorTheme.grey, ), - textInputAction: TextInputAction.next, - decoration: InputDecoration( - errorStyle: TextStyle(fontSize: 0), - labelStyle: TextStyle( - fontWeight: FontWeight.bold, - fontSize: 14, - color: _userTokenError != null - ? StreamChatTheme.of(context).colorTheme.accentRed - : StreamChatTheme.of(context) - .colorTheme - .black - .withOpacity(.5), - ), - border: UnderlineInputBorder( - borderRadius: BorderRadius.circular(8), - borderSide: BorderSide.none, - ), - fillColor: - StreamChatTheme.of(context).colorTheme.whiteSmoke, - filled: true, - labelText: - 'User Token ${_userTokenError != null ? ':$_userTokenError' : ''}', + border: UnderlineInputBorder( + borderRadius: BorderRadius.circular(8), + borderSide: BorderSide.none, ), + fillColor: + StreamChatTheme.of(context).colorTheme.whiteSmoke, + filled: true, + labelText: + 'User Token ${_userTokenError != null ? ': $_userTokenError' : ''}', ), ), - Padding( - padding: const EdgeInsets.only(top: 8.0), - child: TextFormField( - controller: _usernameController, - textInputAction: TextInputAction.done, - decoration: InputDecoration( - labelStyle: TextStyle( - fontSize: 14, - fontWeight: FontWeight.bold, - color: StreamChatTheme.of(context) - .colorTheme - .black - .withOpacity(.5), - ), - border: UnderlineInputBorder( - borderRadius: BorderRadius.circular(8), - borderSide: BorderSide.none, - ), - fillColor: - StreamChatTheme.of(context).colorTheme.whiteSmoke, - filled: true, - labelText: 'Username (optional)', + SizedBox(height: 8), + TextFormField( + controller: _usernameController, + textInputAction: TextInputAction.done, + decoration: InputDecoration( + labelStyle: TextStyle( + fontSize: 14, + fontWeight: FontWeight.bold, + color: StreamChatTheme.of(context).colorTheme.grey, ), + border: UnderlineInputBorder( + borderRadius: BorderRadius.circular(8), + borderSide: BorderSide.none, + ), + fillColor: + StreamChatTheme.of(context).colorTheme.whiteSmoke, + filled: true, + labelText: 'Username (optional)', ), ), - Expanded( - child: Align( - alignment: Alignment.bottomCenter, - child: FlatButton( - color: - StreamChatTheme.of(context).colorTheme.accentBlue, - minWidth: double.infinity, - height: 48, - child: Text( - 'Login', - style: TextStyle( - color: StreamChatTheme.of(context).colorTheme.white, - fontSize: 16, - ), - ), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(26), - ), - onPressed: () async { - if (loading) { - return; - } - if (_formKey.currentState.validate()) { - final apiKey = _apiKeyController.text; - final userId = _userIdController.text; - final userToken = _userTokenController.text; - final username = _usernameController.text; + Spacer(), + RaisedButton( + elevation: 0, + child: Text('Login', style: TextStyle(fontSize: 16)), + onPressed: () async { + if (loading) { + return; + } + if (_formKey.currentState.validate()) { + final apiKey = _apiKeyController.text; + final userId = _userIdController.text; + final userToken = _userTokenController.text; + final username = _usernameController.text; - loading = true; - showDialog( - barrierDismissible: false, - context: context, - barrierColor: StreamChatTheme.of(context) - .colorTheme - .overlay, - builder: (context) => Center( - child: Container( - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(16), - color: StreamChatTheme.of(context) - .colorTheme - .white, - ), - height: 100, - width: 100, - child: Center( - child: CircularProgressIndicator(), - ), - ), + loading = true; + showDialog( + barrierDismissible: false, + context: context, + barrierColor: + StreamChatTheme.of(context).colorTheme.overlay, + builder: (context) => Center( + child: Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(16), + color: StreamChatTheme.of(context) + .colorTheme + .white, ), - ); + height: 100, + width: 100, + child: Center( + child: CircularProgressIndicator(), + ), + ), + ), + ); - final client = Client( - apiKey, - logLevel: Level.INFO, - showLocalNotification: - (!kIsWeb && Platform.isAndroid) - ? showLocalNotification - : null, - persistenceEnabled: true, - ); + final client = Client( + apiKey, + logLevel: Level.INFO, + showLocalNotification: (!kIsWeb && Platform.isAndroid) + ? showLocalNotification + : null, + persistenceEnabled: true, + ); - try { - await client.setUser( - User(id: userId, extraData: { - 'name': username, - }), - userToken, - ); + try { + await client.setUser( + User(id: userId, extraData: { + 'name': username, + }), + userToken, + ); - if (!kIsWeb) { - initNotifications(client); - } + if (!kIsWeb) { + initNotifications(client); + } - final secureStorage = FlutterSecureStorage(); - secureStorage.write( - key: kStreamApiKey, - value: apiKey, - ); - secureStorage.write( - key: kStreamUserId, - value: userId, - ); - secureStorage.write( - key: kStreamToken, - value: userToken, - ); - } catch (e) { - var errorText = 'Error connecting, retry'; - if (e is Map) { - errorText = e['message'] ?? errorText; - } - Navigator.pop(context); - setState(() { - _apiKeyError = errorText; - }); - loading = false; - await client.disconnect(); - return; - } + final secureStorage = FlutterSecureStorage(); + secureStorage.write( + key: kStreamApiKey, + value: apiKey, + ); + secureStorage.write( + key: kStreamUserId, + value: userId, + ); + secureStorage.write( + key: kStreamToken, + value: userToken, + ); + } catch (e) { + var errorText = 'Error connecting, retry'; + if (e is Map) { + errorText = e['message'] ?? errorText; + } + Navigator.pop(context); + setState(() { + _apiKeyError = errorText; + }); + loading = false; + await client.disconnect(); + return; + } - if (!kIsWeb) { - initNotifications(client); - } + if (!kIsWeb) { + initNotifications(client); + } - Navigator.pop(context); - Navigator.pop(context); - await Navigator.pushReplacement( - context, - MaterialPageRoute( - builder: (context) { - return MaterialApp( - theme: ThemeData.light(), - darkTheme: ThemeData.dark(), - themeMode: ThemeMode.system, - builder: (context, widget) { - return StreamChat( - child: widget, - client: client, - ); - }, - home: ChannelListPage(), + Navigator.pop(context); + Navigator.pop(context); + await Navigator.pushReplacement( + context, + MaterialPageRoute( + builder: (context) { + return MaterialApp( + theme: ThemeData.light(), + darkTheme: ThemeData.dark(), + themeMode: ThemeMode.system, + builder: (context, widget) { + return StreamChat( + child: widget, + client: client, ); }, - ), - ); - loading = false; - } - }, - ), - ), + home: ChannelListPage(), + ); + }, + ), + ); + loading = false; + } + }, ), StreamVersion(), ], diff --git a/example/lib/choose_user_page.dart b/example/lib/choose_user_page.dart index ede5f6df..6da88a29 100644 --- a/example/lib/choose_user_page.dart +++ b/example/lib/choose_user_page.dart @@ -72,6 +72,7 @@ class ChooseUserPage extends StatelessWidget { child: SvgPicture.asset( 'assets/logo.svg', height: 40, + color: StreamChatTheme.of(context).colorTheme.accentBlue, ), ), ), @@ -92,9 +93,8 @@ class ChooseUserPage extends StatelessWidget { child: ListView.separated( separatorBuilder: (context, i) { return Container( - width: double.infinity, - color: Colors.black12, height: 1, + color: StreamChatTheme.of(context).colorTheme.greyWhisper, ); }, itemCount: users.length + 1, @@ -180,10 +180,10 @@ class ChooseUserPage extends StatelessWidget { .grey, ), ), - trailing: SvgPicture.asset( - 'assets/icon_arrow_right.svg', - height: 24, - width: 24, + trailing: StreamSvgIcon.arrow_right( + color: StreamChatTheme.of(context) + .colorTheme + .accentBlue, ), ); }), diff --git a/example/lib/stream_version.dart b/example/lib/stream_version.dart index a3d52ab6..b3f926be 100644 --- a/example/lib/stream_version.dart +++ b/example/lib/stream_version.dart @@ -28,9 +28,8 @@ class StreamVersion extends StatelessWidget { return Text( 'Stream SDK v ${streamChatDep}', style: TextStyle( - fontSize: 14.5, - color: - StreamChatTheme.of(context).colorTheme.black.withOpacity(.13), + fontSize: 14, + color: StreamChatTheme.of(context).colorTheme.greyGainsboro, ), ); }, diff --git a/lib/src/stream_chat.dart b/lib/src/stream_chat.dart index 4b012ef0..b5883fdb 100644 --- a/lib/src/stream_chat.dart +++ b/lib/src/stream_chat.dart @@ -78,6 +78,7 @@ class StreamChatState extends State with WidgetsBindingObserver { primaryIconTheme: streamTheme.primaryIconTheme, accentColor: streamTheme.colorTheme.accentBlue, scaffoldBackgroundColor: streamTheme.colorTheme.white, + buttonTheme: streamTheme.buttonTheme, ), child: widget.child, ); diff --git a/lib/src/stream_chat_theme.dart b/lib/src/stream_chat_theme.dart index 3fac4173..8640467c 100644 --- a/lib/src/stream_chat_theme.dart +++ b/lib/src/stream_chat_theme.dart @@ -45,6 +45,9 @@ class StreamChatThemeData { /// The text themes used in the widgets final TextTheme textTheme; + /// The button themes used in the widgets + final ButtonThemeData buttonTheme; + /// The text themes used in the widgets final ColorTheme colorTheme; @@ -75,6 +78,7 @@ class StreamChatThemeData { /// Create a theme from scratch const StreamChatThemeData({ this.textTheme, + this.buttonTheme, this.colorTheme, this.channelPreviewTheme, this.channelTheme, @@ -106,6 +110,7 @@ class StreamChatThemeData { /// Creates a copy of [StreamChatThemeData] with specified attributes overridden. StreamChatThemeData copyWith({ TextTheme textTheme, + ButtonThemeData buttonTheme, ColorTheme colorTheme, ChannelPreviewTheme channelPreviewTheme, ChannelTheme channelTheme, @@ -118,6 +123,7 @@ class StreamChatThemeData { }) => StreamChatThemeData( textTheme: textTheme ?? this.textTheme, + buttonTheme: buttonTheme ?? this.buttonTheme, colorTheme: colorTheme ?? this.colorTheme, primaryIconTheme: primaryIconTheme ?? this.primaryIconTheme, defaultChannelImage: defaultChannelImage ?? this.defaultChannelImage, @@ -133,6 +139,7 @@ class StreamChatThemeData { if (other == null) return this; return copyWith( textTheme: textTheme?.merge(other.textTheme) ?? other.textTheme, + buttonTheme: other.buttonTheme, colorTheme: colorTheme?.merge(other.colorTheme) ?? other.colorTheme, primaryIconTheme: other.primaryIconTheme, defaultChannelImage: other.defaultChannelImage, @@ -159,6 +166,17 @@ class StreamChatThemeData { return StreamChatThemeData( textTheme: textTheme, colorTheme: colorTheme, + buttonTheme: ButtonThemeData( + height: 48.0, + buttonColor: isDark ? Color(0xffffffff) : Color(0xff006aff), + textTheme: ButtonTextTheme.accent, + colorScheme: theme.colorScheme.copyWith( + secondary: isDark ? Color(0xff005eff) : Color(0xffffffff), + ), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(26), + ), + ), primaryIconTheme: IconThemeData(color: colorTheme.black.withOpacity(.5)), defaultChannelImage: (context, channel) => SizedBox(), defaultUserImage: (context, user) => Center( @@ -475,7 +493,7 @@ class ColorTheme { this.white = const Color(0xffffffff), this.blueAlice = const Color(0xffe9f2ff), this.accentBlue = const Color(0xff005FFF), - this.accentRed = const Color(0xffFF3742), + this.accentRed = const Color(0xffFF3842), this.accentGreen = const Color(0xff20E070), this.highlight = const Color(0xfffbf4dd), this.overlay = const Color.fromRGBO(0, 0, 0, 0.2), From ee0cdf567b8719561bfbcde9d692880dc07df180 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Wed, 6 Jan 2021 18:33:31 +0530 Subject: [PATCH 0779/1140] feat: Changed sending indicator icons to svg icons --- lib/src/channel_list_view.dart | 2 ++ lib/src/channel_preview.dart | 3 +-- lib/src/sending_indicator.dart | 6 ++---- lib/src/stream_chat_theme.dart | 34 +++++++++++++++++++--------------- lib/src/stream_svg_icon.dart | 12 ++++++++++++ 5 files changed, 36 insertions(+), 21 deletions(-) diff --git a/lib/src/channel_list_view.dart b/lib/src/channel_list_view.dart index 6c4e967e..4ffe4511 100644 --- a/lib/src/channel_list_view.dart +++ b/lib/src/channel_list_view.dart @@ -157,6 +157,7 @@ class ChannelListView extends StatefulWidget { class _ChannelListViewState extends State with WidgetsBindingObserver { final ScrollController _scrollController = ScrollController(); + final SlidableController _slideController = SlidableController(); @override Widget build(BuildContext context) { @@ -562,6 +563,7 @@ class _ChannelListViewState extends State final backgroundColor = StreamChatTheme.of(context).colorTheme.whiteSmoke; child = Slidable( + controller: _slideController, enabled: widget.swipeToAction, actionPane: SlidableBehindActionPane(), actionExtentRatio: 0.12, diff --git a/lib/src/channel_preview.dart b/lib/src/channel_preview.dart index d7c1a418..c1536653 100644 --- a/lib/src/channel_preview.dart +++ b/lib/src/channel_preview.dart @@ -104,8 +104,7 @@ class ChannelPreview extends StatelessWidget { message: channel.state.lastMessage, size: StreamChatTheme.of(context) .channelPreviewTheme - .lastMessageAt - .fontSize, + .indicatorIconSize, isMessageRead: channel.state.read ?.where((element) => element.user.id != diff --git a/lib/src/sending_indicator.dart b/lib/src/sending_indicator.dart index e3a9df06..83e02bb3 100644 --- a/lib/src/sending_indicator.dart +++ b/lib/src/sending_indicator.dart @@ -17,15 +17,13 @@ class SendingIndicator extends StatelessWidget { @override Widget build(BuildContext context) { if (isMessageRead) { - return Icon( - Icons.done_all_rounded, + return StreamSvgIcon.checkAll( size: size, color: StreamChatTheme.of(context).colorTheme.accentBlue, ); } if (message.status == MessageSendingStatus.SENT || message.status == null) { - return Icon( - Icons.done, + return StreamSvgIcon.check( size: size, color: IconTheme.of(context).color.withOpacity(0.5), ); diff --git a/lib/src/stream_chat_theme.dart b/lib/src/stream_chat_theme.dart index 246459c6..3639d229 100644 --- a/lib/src/stream_chat_theme.dart +++ b/lib/src/stream_chat_theme.dart @@ -227,22 +227,22 @@ class StreamChatThemeData { ), ), channelPreviewTheme: ChannelPreviewTheme( - unreadCounterColor: colorTheme.accentRed, - avatarTheme: AvatarTheme( - borderRadius: BorderRadius.circular(20), - constraints: BoxConstraints.tightFor( - height: 40, - width: 40, + unreadCounterColor: colorTheme.accentRed, + avatarTheme: AvatarTheme( + borderRadius: BorderRadius.circular(20), + constraints: BoxConstraints.tightFor( + height: 40, + width: 40, + ), ), - ), - title: textTheme.bodyBold, - subtitle: textTheme.footnote.copyWith( - color: Color(0xff7A7A7A), - ), - lastMessageAt: textTheme.footnote.copyWith( - color: colorTheme.black.withOpacity(.5), - ), - ), + title: textTheme.bodyBold, + subtitle: textTheme.footnote.copyWith( + color: Color(0xff7A7A7A), + ), + lastMessageAt: textTheme.footnote.copyWith( + color: colorTheme.black.withOpacity(.5), + ), + indicatorIconSize: 16.0), channelTheme: ChannelTheme( messageInputButtonIconTheme: theme.iconTheme.copyWith( color: accentColor, @@ -698,6 +698,7 @@ class ChannelPreviewTheme { final TextStyle lastMessageAt; final AvatarTheme avatarTheme; final Color unreadCounterColor; + final double indicatorIconSize; const ChannelPreviewTheme({ this.title, @@ -705,6 +706,7 @@ class ChannelPreviewTheme { this.lastMessageAt, this.avatarTheme, this.unreadCounterColor, + this.indicatorIconSize, }); ChannelPreviewTheme copyWith({ @@ -713,6 +715,7 @@ class ChannelPreviewTheme { TextStyle lastMessageAt, AvatarTheme avatarTheme, Color unreadCounterColor, + double indicatorIconSize, }) => ChannelPreviewTheme( title: title ?? this.title, @@ -720,6 +723,7 @@ class ChannelPreviewTheme { lastMessageAt: lastMessageAt ?? this.lastMessageAt, avatarTheme: avatarTheme ?? this.avatarTheme, unreadCounterColor: unreadCounterColor ?? this.unreadCounterColor, + indicatorIconSize: indicatorIconSize ?? this.indicatorIconSize, ); } diff --git a/lib/src/stream_svg_icon.dart b/lib/src/stream_svg_icon.dart index e7ef46c3..9c91d9bd 100644 --- a/lib/src/stream_svg_icon.dart +++ b/lib/src/stream_svg_icon.dart @@ -194,6 +194,18 @@ class StreamSvgIcon extends StatelessWidget { ); } + factory StreamSvgIcon.checkAll({ + double size, + Color color, + }) { + return StreamSvgIcon( + assetName: 'Icon_check_all.svg', + color: color, + width: size, + height: size, + ); + } + factory StreamSvgIcon.penWrite({ double size, Color color, From b51128f67c695bd571ae18bb6a3879c6ccf066a1 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Wed, 6 Jan 2021 18:34:03 +0530 Subject: [PATCH 0780/1140] [MessageWidget] Show message border in case the message is only emoji but is part of a thread. Signed-off-by: Sahil Kumar --- lib/src/message_widget.dart | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/src/message_widget.dart b/lib/src/message_widget.dart index 30e636a4..4b22f3ec 100644 --- a/lib/src/message_widget.dart +++ b/lib/src/message_widget.dart @@ -374,7 +374,9 @@ class _MessageWidgetState extends State { elevation: 0.0, shape: widget.shape ?? RoundedRectangleBorder( - side: isOnlyEmoji + side: isOnlyEmoji && + !(showThreadReplyIndicator || + showInChannel) ? BorderSide.none : widget.borderSide ?? BorderSide( From 6f8de144e3047dcb55c2e0fea310a7162ff40a2f Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Wed, 6 Jan 2021 18:46:36 +0530 Subject: [PATCH 0781/1140] fix: Fixed online indicator size --- lib/src/channel_bottom_sheet.dart | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/src/channel_bottom_sheet.dart b/lib/src/channel_bottom_sheet.dart index 21f85430..d03f233c 100644 --- a/lib/src/channel_bottom_sheet.dart +++ b/lib/src/channel_bottom_sheet.dart @@ -73,6 +73,8 @@ class _ChannelBottomSheetState extends State { maxWidth: 64.0, ), borderRadius: BorderRadius.circular(32.0), + onlineIndicatorConstraints: + BoxConstraints.tight(Size(16.0, 16.0)), ), SizedBox( height: 6.0, From 7ae15263e335babbb15e87a80e9eec7c3ef8f663 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Wed, 6 Jan 2021 19:07:51 +0530 Subject: [PATCH 0782/1140] [NewGroupChatScreen] Refactor Signed-off-by: Sahil Kumar --- example/lib/new_group_chat_screen.dart | 421 ++++++++++++------------- 1 file changed, 207 insertions(+), 214 deletions(-) diff --git a/example/lib/new_group_chat_screen.dart b/example/lib/new_group_chat_screen.dart index c7a25ab3..ceb91473 100644 --- a/example/lib/new_group_chat_screen.dart +++ b/example/lib/new_group_chat_screen.dart @@ -52,234 +52,227 @@ class _NewGroupChatScreenState extends State { Widget build(BuildContext context) { return Scaffold( backgroundColor: StreamChatTheme.of(context).colorTheme.whiteSnow, - body: SafeArea( - child: NestedScrollView( - floatHeaderSlivers: true, - headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) { - return [ - SliverAppBar( - brightness: Theme.of(context).brightness, - pinned: true, - forceElevated: true, - elevation: 1, - backgroundColor: StreamChatTheme.of(context).colorTheme.white, - leading: const StreamBackButton(), - title: Text( - 'Add Group Members', - style: TextStyle( - color: StreamChatTheme.of(context).colorTheme.black, - fontSize: 16, - ), - ), - centerTitle: true, - actions: [ - if (_selectedUsers.isNotEmpty) - IconButton( - icon: StreamSvgIcon.arrow_right( - color: - StreamChatTheme.of(context).colorTheme.accentBlue, - ), - onPressed: () async { - final updatedList = await Navigator.pushNamed( - context, - Routes.NEW_GROUP_CHAT_DETAILS, - arguments: _selectedUsers.toList(growable: false), - ); - if (updatedList != null) { - setState(() { - _selectedUsers - ..clear() - ..addAll(updatedList); - }); - } - }, - ) - ], + appBar: AppBar( + elevation: 1, + backgroundColor: StreamChatTheme.of(context).colorTheme.white, + leading: const StreamBackButton(), + title: Text( + 'Add Group Members', + style: TextStyle( + color: StreamChatTheme.of(context).colorTheme.black, + fontSize: 16, + ), + ), + centerTitle: true, + actions: [ + if (_selectedUsers.isNotEmpty) + IconButton( + icon: StreamSvgIcon.arrow_right( + color: StreamChatTheme.of(context).colorTheme.accentBlue, ), + onPressed: () async { + final updatedList = await Navigator.pushNamed( + context, + Routes.NEW_GROUP_CHAT_DETAILS, + arguments: _selectedUsers.toList(growable: false), + ); + if (updatedList != null) { + setState(() { + _selectedUsers + ..clear() + ..addAll(updatedList); + }); + } + }, + ) + ], + ), + body: NestedScrollView( + floatHeaderSlivers: true, + headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) { + return [ + SliverToBoxAdapter( + child: SearchTextField( + controller: _controller, + ), + ), + if (_selectedUsers.isNotEmpty) SliverToBoxAdapter( - child: SearchTextField( - controller: _controller, - ), - ), - if (_selectedUsers.isNotEmpty) - SliverToBoxAdapter( - child: Container( - height: 104, - child: ListView.separated( - scrollDirection: Axis.horizontal, - itemCount: _selectedUsers.length, - padding: const EdgeInsets.all(8), - separatorBuilder: (_, __) => SizedBox(width: 16), - itemBuilder: (_, index) { - final user = _selectedUsers.elementAt(index); - return Column( - children: [ - Stack( - children: [ - UserAvatar( - onlineIndicatorAlignment: Alignment(0.9, 0.9), - user: user, - showOnlineStatus: true, - borderRadius: BorderRadius.circular(32), - constraints: BoxConstraints.tightFor( - height: 64, - width: 64, - ), + child: Container( + height: 104, + child: ListView.separated( + scrollDirection: Axis.horizontal, + itemCount: _selectedUsers.length, + padding: const EdgeInsets.all(8), + separatorBuilder: (_, __) => SizedBox(width: 16), + itemBuilder: (_, index) { + final user = _selectedUsers.elementAt(index); + return Column( + children: [ + Stack( + children: [ + UserAvatar( + onlineIndicatorAlignment: Alignment(0.9, 0.9), + user: user, + showOnlineStatus: true, + borderRadius: BorderRadius.circular(32), + constraints: BoxConstraints.tightFor( + height: 64, + width: 64, ), - Positioned( - top: -4, - right: -4, - child: GestureDetector( - onTap: () { - if (_selectedUsers.contains(user)) { - setState( - () => _selectedUsers.remove(user)); - } - }, - child: Container( - decoration: BoxDecoration( + ), + Positioned( + top: -4, + right: -4, + child: GestureDetector( + onTap: () { + if (_selectedUsers.contains(user)) { + setState( + () => _selectedUsers.remove(user)); + } + }, + child: Container( + decoration: BoxDecoration( + color: StreamChatTheme.of(context) + .colorTheme + .white, + shape: BoxShape.circle, + border: Border.all( color: StreamChatTheme.of(context) .colorTheme - .white, - shape: BoxShape.circle, - border: Border.all( - color: StreamChatTheme.of(context) - .colorTheme - .whiteSnow, - ), - ), - child: StreamSvgIcon.close( - color: StreamChatTheme.of(context) - .colorTheme - .black, - size: 24, + .whiteSnow, ), ), - ), - ) - ], - ), - SizedBox(height: 4), - Text( - user.name.split(' ')[0], - style: TextStyle( - fontWeight: FontWeight.bold, - fontSize: 12, - ), - ), - ], - ); - }, - ), - ), - ), - SliverPersistentHeader( - pinned: true, - delegate: _HeaderDelegate( - height: 30, - child: Container( - width: double.maxFinite, - decoration: BoxDecoration( - gradient: - StreamChatTheme.of(context).colorTheme.bgGradient, - ), - child: Padding( - padding: const EdgeInsets.symmetric( - vertical: 8, - horizontal: 8, - ), - child: Text( - _isSearchActive - ? 'Matches for \"$_userNameQuery\"' - : 'On the platform', - style: TextStyle( - color: StreamChatTheme.of(context).colorTheme.grey, - ), - ), - ), - ), - ), - ), - ]; - }, - body: GestureDetector( - behavior: HitTestBehavior.opaque, - onPanDown: (_) => FocusScope.of(context).unfocus(), - child: UsersBloc( - child: UserListView( - selectedUsers: _selectedUsers, - pullToRefresh: false, - groupAlphabetically: _isSearchActive ? false : true, - onUserTap: (user, _) { - if (!_selectedUsers.contains(user)) { - setState(() { - _selectedUsers.add(user); - }); - } else { - setState(() { - _selectedUsers.remove(user); - }); - } - }, - pagination: PaginationParams( - limit: 25, - ), - filter: { - if (_userNameQuery.isNotEmpty) - 'name': { - r'$autocomplete': _userNameQuery, - }, - 'id': { - r'$ne': StreamChat.of(context).user.id, - } - }, - sort: [ - SortOption( - 'name', - direction: 1, - ), - ], - emptyBuilder: (_) { - return LayoutBuilder( - builder: (context, viewportConstraints) { - return SingleChildScrollView( - physics: AlwaysScrollableScrollPhysics(), - child: ConstrainedBox( - constraints: BoxConstraints( - minHeight: viewportConstraints.maxHeight, - ), - child: Center( - child: Column( - children: [ - Padding( - padding: const EdgeInsets.all(24), - child: StreamSvgIcon.search( - size: 96, - color: StreamChatTheme.of(context) - .colorTheme - .grey, + child: StreamSvgIcon.close( + color: StreamChatTheme.of(context) + .colorTheme + .black, + size: 24, + ), ), ), - Text( - 'No user matches these keywords...', - style: StreamChatTheme.of(context) - .textTheme - .footnote - .copyWith( - color: StreamChatTheme.of(context) - .colorTheme - .grey, - ), - ), - ], + ) + ], + ), + SizedBox(height: 4), + Text( + user.name.split(' ')[0], + style: TextStyle( + fontWeight: FontWeight.bold, + fontSize: 12, ), ), - ), + ], ); }, - ); - }, + ), + ), ), + SliverPersistentHeader( + pinned: true, + delegate: _HeaderDelegate( + height: 30, + child: Container( + width: double.maxFinite, + decoration: BoxDecoration( + gradient: StreamChatTheme.of(context).colorTheme.bgGradient, + ), + child: Padding( + padding: const EdgeInsets.symmetric( + vertical: 8, + horizontal: 8, + ), + child: Text( + _isSearchActive + ? 'Matches for \"$_userNameQuery\"' + : 'On the platform', + style: TextStyle( + color: StreamChatTheme.of(context).colorTheme.grey, + ), + ), + ), + ), + ), + ), + ]; + }, + body: GestureDetector( + behavior: HitTestBehavior.opaque, + onPanDown: (_) => FocusScope.of(context).unfocus(), + child: UsersBloc( + child: UserListView( + selectedUsers: _selectedUsers, + pullToRefresh: false, + groupAlphabetically: _isSearchActive ? false : true, + onUserTap: (user, _) { + if (!_selectedUsers.contains(user)) { + setState(() { + _selectedUsers.add(user); + }); + } else { + setState(() { + _selectedUsers.remove(user); + }); + } + }, + pagination: PaginationParams( + limit: 25, + ), + filter: { + if (_userNameQuery.isNotEmpty) + 'name': { + r'$autocomplete': _userNameQuery, + }, + 'id': { + r'$ne': StreamChat.of(context).user.id, + } + }, + sort: [ + SortOption( + 'name', + direction: 1, + ), + ], + emptyBuilder: (_) { + return LayoutBuilder( + builder: (context, viewportConstraints) { + return SingleChildScrollView( + physics: AlwaysScrollableScrollPhysics(), + child: ConstrainedBox( + constraints: BoxConstraints( + minHeight: viewportConstraints.maxHeight, + ), + child: Center( + child: Column( + children: [ + Padding( + padding: const EdgeInsets.all(24), + child: StreamSvgIcon.search( + size: 96, + color: StreamChatTheme.of(context) + .colorTheme + .grey, + ), + ), + Text( + 'No user matches these keywords...', + style: StreamChatTheme.of(context) + .textTheme + .footnote + .copyWith( + color: StreamChatTheme.of(context) + .colorTheme + .grey, + ), + ), + ], + ), + ), + ), + ); + }, + ); + }, ), ), ), From 1522f3e50c9b7b5c8af7966fd2bec7d730d9fe6f Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Wed, 6 Jan 2021 20:50:07 +0530 Subject: [PATCH 0783/1140] fix: Fixed separator and added effects to theme --- lib/src/channel_list_view.dart | 15 ++++++-- lib/src/stream_chat_theme.dart | 63 ++++++++++++++++++++++++++++++++++ 2 files changed, 75 insertions(+), 3 deletions(-) diff --git a/lib/src/channel_list_view.dart b/lib/src/channel_list_view.dart index 4ffe4511..d8e1006b 100644 --- a/lib/src/channel_list_view.dart +++ b/lib/src/channel_list_view.dart @@ -9,6 +9,7 @@ import 'package:stream_chat/stream_chat.dart'; import 'package:stream_chat_flutter/src/channels_bloc.dart'; import 'package:stream_chat_flutter/src/stream_svg_icon.dart'; import 'package:stream_chat_flutter/src/utils.dart'; +import 'dart:ui' as ui; import '../stream_chat_flutter.dart'; import 'channel_bottom_sheet.dart'; @@ -728,9 +729,17 @@ class _ChannelListViewState extends State } Widget _separatorBuilder(context, i) { - return Container( - height: 1, - color: StreamChatTheme.of(context).colorTheme.black.withOpacity(0.08), + var effect = StreamChatTheme.of(context).colorTheme.borderTop; + + return BackdropFilter( + filter: ui.ImageFilter.blur( + sigmaX: effect.sigmaX, + sigmaY: effect.sigmaY, + ), + child: Container( + height: 1, + color: effect.color.withOpacity(0.08), + ), ); } diff --git a/lib/src/stream_chat_theme.dart b/lib/src/stream_chat_theme.dart index 3639d229..760a1061 100644 --- a/lib/src/stream_chat_theme.dart +++ b/lib/src/stream_chat_theme.dart @@ -502,6 +502,10 @@ class ColorTheme { final Color accentBlue; final Color accentRed; final Color accentGreen; + final Effect borderTop; + final Effect borderBottom; + final Effect shadowIconButton; + final Effect modalShadow; ColorTheme.light({ this.black = const Color(0xff000000), @@ -515,6 +519,14 @@ class ColorTheme { this.accentBlue = const Color(0xff005FFF), this.accentRed = const Color(0xffFF3742), this.accentGreen = const Color(0xff20E070), + this.borderTop = const Effect( + sigmaX: 0, sigmaY: -1, color: Color(0xff141924), blur: 0.0), + this.borderBottom = const Effect( + sigmaX: 0, sigmaY: 1, color: Color(0xff141924), blur: 0.0), + this.shadowIconButton = const Effect( + sigmaX: 0, sigmaY: 2, color: Color(0xff000000), alpha: 0.5, blur: 4.0), + this.modalShadow = const Effect( + sigmaX: 0, sigmaY: 0, color: Color(0xff000000), alpha: 1, blur: 8.0), }); ColorTheme.dark({ @@ -529,6 +541,14 @@ class ColorTheme { this.accentBlue = const Color(0xff005FFF), this.accentRed = const Color(0xffFF3742), this.accentGreen = const Color(0xff20E070), + this.borderTop = const Effect( + sigmaX: 0, sigmaY: -1, color: Color(0xff141924), blur: 0.0), + this.borderBottom = const Effect( + sigmaX: 0, sigmaY: 1, color: Color(0xff141924), blur: 0.0), + this.shadowIconButton = const Effect( + sigmaX: 0, sigmaY: 2, color: Color(0xff000000), alpha: 0.5, blur: 4.0), + this.modalShadow = const Effect( + sigmaX: 0, sigmaY: 0, color: Color(0xff000000), alpha: 1, blur: 8.0), }); ColorTheme copyWith({ @@ -544,6 +564,10 @@ class ColorTheme { Color accentBlue, Color accentRed, Color accentGreen, + Effect borderTop, + Effect borderBottom, + Effect shadowIconButton, + Effect modalShadow, }) { return type == ColorThemeType.light ? ColorTheme.light( @@ -558,6 +582,10 @@ class ColorTheme { accentBlue: accentBlue ?? this.accentBlue, accentRed: accentRed ?? this.accentRed, accentGreen: accentGreen ?? this.accentGreen, + borderTop: borderTop ?? this.borderTop, + borderBottom: borderBottom ?? this.borderBottom, + shadowIconButton: shadowIconButton ?? this.shadowIconButton, + modalShadow: modalShadow ?? this.modalShadow, ) : ColorTheme.dark( black: black ?? this.black, @@ -571,6 +599,10 @@ class ColorTheme { accentBlue: accentBlue ?? this.accentBlue, accentRed: accentRed ?? this.accentRed, accentGreen: accentGreen ?? this.accentGreen, + borderTop: borderTop ?? this.borderTop, + borderBottom: borderBottom ?? this.borderBottom, + shadowIconButton: shadowIconButton ?? this.shadowIconButton, + modalShadow: modalShadow ?? this.modalShadow, ); } } @@ -753,3 +785,34 @@ class ChannelHeaderTheme { color: color ?? this.color, ); } + +class Effect { + final double sigmaX; + final double sigmaY; + final Color color; + final double alpha; + final double blur; + + const Effect({ + this.sigmaX, + this.sigmaY, + this.color, + this.alpha, + this.blur, + }); + + Effect copyWith({ + double sigmaX, + double sigmaY, + Color color, + double alpha, + double blur, + }) => + Effect( + sigmaX: sigmaX ?? this.sigmaX, + sigmaY: sigmaY ?? this.sigmaY, + color: color ?? this.color, + alpha: color ?? this.alpha, + blur: blur ?? this.blur, + ); +} From b4b2f26200df1b6459be82380f241b91682368fb Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Wed, 6 Jan 2021 20:59:17 +0530 Subject: [PATCH 0784/1140] Fixed conflicts and added properties to merge() --- lib/src/stream_chat_theme.dart | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/lib/src/stream_chat_theme.dart b/lib/src/stream_chat_theme.dart index b6fdf074..439bd5ef 100644 --- a/lib/src/stream_chat_theme.dart +++ b/lib/src/stream_chat_theme.dart @@ -510,8 +510,8 @@ class ColorTheme { ), this.borderTop = const Effect( sigmaX: 0, sigmaY: -1, color: Color(0xff141924), blur: 0.0), - this.borderBottom = const Effect( - sigmaX: 0, sigmaY: 1, color: Color(0xff141924), blur: 0.0), + this.borderBottom = + const Effect(sigmaX: 0, sigmaY: 1, color: Color(0xff141924), blur: 0.0), this.shadowIconButton = const Effect( sigmaX: 0, sigmaY: 2, color: Color(0xff000000), alpha: 0.5, blur: 4.0), this.modalShadow = const Effect( @@ -532,8 +532,8 @@ class ColorTheme { this.accentGreen = const Color(0xff20E070), this.borderTop = const Effect( sigmaX: 0, sigmaY: -1, color: Color(0xff141924), blur: 0.0), - this.borderBottom = const Effect( - sigmaX: 0, sigmaY: 1, color: Color(0xff141924), blur: 0.0), + this.borderBottom = + const Effect(sigmaX: 0, sigmaY: 1, color: Color(0xff141924), blur: 0.0), this.shadowIconButton = const Effect( sigmaX: 0, sigmaY: 2, color: Color(0xff000000), alpha: 0.5, blur: 4.0), this.modalShadow = const Effect( @@ -634,6 +634,10 @@ class ColorTheme { overlay: other.overlay, overlayDark: other.overlayDark, bgGradient: other.bgGradient, + borderTop: other.borderTop, + borderBottom: other.borderBottom, + shadowIconButton: other.shadowIconButton, + modalShadow: other.modalShadow, ); } } From f3aefdaf8bd9201285c0300d95b1d75da4948d92 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Wed, 6 Jan 2021 16:49:53 +0100 Subject: [PATCH 0785/1140] fix onmentiontap --- lib/src/message_text.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/message_text.dart b/lib/src/message_text.dart index a043c53a..64fc855d 100644 --- a/lib/src/message_text.dart +++ b/lib/src/message_text.dart @@ -31,7 +31,7 @@ class MessageText extends StatelessWidget { ) { if (link.startsWith('@')) { final mentionedUser = message.mentionedUsers.firstWhere( - (u) => '@${u.name.replaceAll(' ', '')}' == link, + (u) => '@${u.name}' == link, orElse: () => null, ); From e05033cce31db365ace0560a4a71f9755f972093 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Thu, 7 Jan 2021 14:33:35 +0530 Subject: [PATCH 0786/1140] Only 4 mentions allowed at a time --- lib/src/message_input.dart | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 52d91d45..cabbafec 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -1153,7 +1153,7 @@ class MessageInputState extends State { ), clipBehavior: Clip.antiAlias, child: Container( - constraints: BoxConstraints.loose(Size.fromHeight(400)), + constraints: BoxConstraints.loose(Size.fromHeight(240)), decoration: BoxDecoration( color: StreamChatTheme.of(context).colorTheme.white, ), @@ -1164,6 +1164,7 @@ class MessageInputState extends State { return ListView( padding: const EdgeInsets.all(0), shrinkWrap: true, + itemExtent: 58.0, children: snapshot.data .map((m) => ListTile( leading: UserAvatar( @@ -1177,10 +1178,16 @@ class MessageInputState extends State { ), title: Text( '${m.user.name}', + maxLines: 1, + overflow: TextOverflow.ellipsis, style: TextStyle( fontWeight: FontWeight.bold), ), - subtitle: Text('@${m.userId}'), + subtitle: Text( + '@${m.userId}', + maxLines: 1, + overflow: TextOverflow.ellipsis, + ), trailing: StreamSvgIcon.mentions( color: StreamChatTheme.of(context) .colorTheme From d4f2d797028661b188a87abab0887361b52fcc0f Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Thu, 7 Jan 2021 12:24:30 +0100 Subject: [PATCH 0787/1140] merge master --- .github/workflows/flutter-analyze.yml | 24 ++++++ CHANGELOG.md | 51 +++++++++++++ README.md | 6 +- lib/src/channel_list_view.dart | 2 +- lib/src/channel_preview.dart | 3 +- lib/src/channels_bloc.dart | 37 +++++---- lib/src/message_list_view.dart | 2 +- lib/src/message_widget.dart | 14 +++- lib/src/stream_chat.dart | 1 + lib/src/system_message.dart | 104 +++++++++++++++----------- pubspec.yaml | 2 +- 11 files changed, 178 insertions(+), 68 deletions(-) create mode 100644 .github/workflows/flutter-analyze.yml diff --git a/.github/workflows/flutter-analyze.yml b/.github/workflows/flutter-analyze.yml new file mode 100644 index 00000000..312a65ba --- /dev/null +++ b/.github/workflows/flutter-analyze.yml @@ -0,0 +1,24 @@ +name: Flutter Analyze +on: + push: + branches: + - master + + pull_request: + branches: + - '*' + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: subosito/flutter-action@v1 + with: + channel: 'beta' + - run: flutter pub get + + - name: 'Flutter Format Check' + run: flutter format --set-exit-if-changed --dry-run . + + - run: flutter analyze diff --git a/CHANGELOG.md b/CHANGELOG.md index 7d5b93f3..8ca3aa04 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,54 @@ +## 0.2.20+2 + +- Added `shouldAddChannel` to ChannelsBloc in order to check if a channel has to be added to the list when a new message arrives + +## 0.2.20+1 + +- Fixed bug that caused video attachment to show the same preview + +## 0.2.20 + +- Implement shadowban + +## 0.2.19 + +- Updated llc dependency +- Added loading builder in channellistview +- Added sendButtonLocation and animationduration to messageinput + +## 0.2.18 + +- Updated llc dependency + +## 0.2.17+2 + +- Expose ChannelsBloc.channelsComparator to sort channels on message.new event + +## 0.2.17+1 + +- Fix mention tap bug + +## 0.2.17 + +- Expose messageInputDecoration as part of the theme + +## 0.2.16 + +- Do not wrap channel preview builder. Users will have to implement they're custom onTap/onLongPress implementation +- Make public autofocus field of the TextField of message_input + +## 0.2.15 + +- Add onLongPress on channel when using custom channel builder + +## 0.2.14 + +- Add onMessageTap callbacks + +## 0.2.13+2 + +- Add debounce to on change messageinput listener + ## 0.2.13+1 - Use TextEditingController.addListener instead of TextField.onChanged diff --git a/README.md b/README.md index ba5de4c1..c5e4c9e7 100644 --- a/README.md +++ b/README.md @@ -11,8 +11,6 @@ ![](https://img.shields.io/badge/platform-flutter%20%7C%20flutter%20web-ff69b4.svg?style=flat-square) [![Gitter](https://badges.gitter.im/GetStream/stream-chat-flutter.svg)](https://gitter.im/GetStream/stream-chat-flutter?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) ![CI](https://github.com/GetStream/stream-chat-flutter/workflows/CI/badge.svg?branch=master) -[![codecov](https://codecov.io/gh/GetStream/stream-chat-flutter/branch/master/graph/badge.svg)](https://codecov.io/gh/GetStream/stream-chat-flutter) - **Quick Links** @@ -32,10 +30,10 @@ This repo includes a fully functional example app with setup instructions. The example is available under the [example](https://github.com/GetStream/stream-chat-flutter/tree/master/example) folder. ## Add dependency - +Add this to your package's pubspec.yaml file, use the latest version [![Pub](https://img.shields.io/pub/v/stream_chat_flutter.svg)](https://pub.dartlang.org/packages/stream_chat_flutter) ```yaml dependencies: - stream_chat_flutter: ^0.2.1 + stream_chat_flutter: ^latest_version ``` You should then run `flutter packages get` diff --git a/lib/src/channel_list_view.dart b/lib/src/channel_list_view.dart index d8e1006b..1ab10934 100644 --- a/lib/src/channel_list_view.dart +++ b/lib/src/channel_list_view.dart @@ -1,5 +1,6 @@ import 'dart:async'; import 'dart:convert'; +import 'dart:ui' as ui; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; @@ -9,7 +10,6 @@ import 'package:stream_chat/stream_chat.dart'; import 'package:stream_chat_flutter/src/channels_bloc.dart'; import 'package:stream_chat_flutter/src/stream_svg_icon.dart'; import 'package:stream_chat_flutter/src/utils.dart'; -import 'dart:ui' as ui; import '../stream_chat_flutter.dart'; import 'channel_bottom_sheet.dart'; diff --git a/lib/src/channel_preview.dart b/lib/src/channel_preview.dart index c1536653..eac6e3c2 100644 --- a/lib/src/channel_preview.dart +++ b/lib/src/channel_preview.dart @@ -201,7 +201,8 @@ class ChannelPreview extends StatelessWidget { stream: channel.state.messagesStream, initialData: channel.state.messages, builder: (context, snapshot) { - final lastMessage = channel.state.lastMessage; + final lastMessage = snapshot.data + ?.lastWhere((m) => m.shadowed != true, orElse: () => null); if (lastMessage == null) { return SizedBox(); } diff --git a/lib/src/channels_bloc.dart b/lib/src/channels_bloc.dart index 9b6e55bb..c3c5c6f1 100644 --- a/lib/src/channels_bloc.dart +++ b/lib/src/channels_bloc.dart @@ -14,11 +14,19 @@ class ChannelsBloc extends StatefulWidget { /// Set this to true to prevent channels to be brought to the top of the list when a new message arrives final bool lockChannelsOrder; + /// Comparator used to sort the channels when a message.new event is received + final Comparator channelsComparator; + + /// Function used to evaluate if a channel should be added to the list when a message.new event is received + final bool Function(Event) shouldAddChannel; + /// Instantiate a new ChannelsBloc const ChannelsBloc({ Key key, this.child, this.lockChannelsOrder = false, + this.channelsComparator, + this.shouldAddChannel, }) : super(key: key); @override @@ -85,23 +93,21 @@ class ChannelsBlocState extends State paginationParams.offset == null || paginationParams.offset == 0; final oldChannels = List.from(channels ?? []); - await client - .queryChannels( + final _channels = await client.queryChannels( filter: filter, sort: sortOptions, options: options, paginationParams: paginationParams, onlyOffline: onlyOffline, - ) - .then((channels) { - if (clear) { - _channelsController.add(channels); - } else { - final l = oldChannels + channels; - _channelsController.add(l); - } - _queryChannelsLoadingController.sink.add(false); - }); + ); + + if (clear) { + _channelsController.add(_channels); + } else { + final l = oldChannels + _channels; + _channelsController.add(l); + } + _queryChannelsLoadingController.sink.add(false); } catch (err, stackTrace) { print(err); print(stackTrace); @@ -126,7 +132,8 @@ class ChannelsBlocState extends State final channel = newChannels.removeAt(index); newChannels.insert(0, channel); } - } else { + } else if (widget.shouldAddChannel != null && + widget.shouldAddChannel(e)) { final hiddenIndex = _hiddenChannels.indexWhere((c) => c.cid == e.cid); if (hiddenIndex > -1) { newChannels.insert(0, _hiddenChannels[hiddenIndex]); @@ -138,6 +145,10 @@ class ChannelsBlocState extends State } } } + + if (widget.channelsComparator != null) { + newChannels.sort(widget.channelsComparator); + } _channelsController.add(newChannels); })); } diff --git a/lib/src/message_list_view.dart b/lib/src/message_list_view.dart index db9790b9..9f4cbc0d 100644 --- a/lib/src/message_list_view.dart +++ b/lib/src/message_list_view.dart @@ -243,7 +243,7 @@ class _MessageListViewState extends State { return StreamBuilder>( stream: messagesStream?.map((messages) => messages ?.where((e) => - !e.isDeleted || + (!e.isDeleted && e.shadowed != true) || (e.isDeleted && e.user.id == streamChannel.channel.client.state.user.id)) ?.toList()), diff --git a/lib/src/message_widget.dart b/lib/src/message_widget.dart index 4b22f3ec..1200f38d 100644 --- a/lib/src/message_widget.dart +++ b/lib/src/message_widget.dart @@ -572,13 +572,16 @@ class _MessageWidgetState extends State { return Padding( padding: EdgeInsets.only(left: leftPadding), - child: Row( + child: Flex( + direction: Axis.horizontal, + clipBehavior: Clip.none, crossAxisAlignment: CrossAxisAlignment.end, children: [ if (!deleted && (showThreadReplyIndicator || showInChannel)) Container( margin: EdgeInsets.only( - bottom: widget.messageTheme.replies.fontSize / 2), + bottom: widget.messageTheme.replies.fontSize / 2, + ), child: CustomPaint( size: const Size(16, 32), painter: _ThreadReplyPainter( @@ -591,7 +594,12 @@ class _MessageWidgetState extends State { (child) => Transform( transform: Matrix4.rotationY(widget.reverse ? pi : 0), alignment: Alignment.center, - child: Container(height: 16, child: Center(child: child)), + child: Container( + height: 16, + child: Center( + child: child, + ), + ), ), ), ].insertBetween(const SizedBox(width: 8.0)), diff --git a/lib/src/stream_chat.dart b/lib/src/stream_chat.dart index b5883fdb..317dfec6 100644 --- a/lib/src/stream_chat.dart +++ b/lib/src/stream_chat.dart @@ -125,6 +125,7 @@ class StreamChatState extends State with WidgetsBindingObserver { .on(EventType.messageNew) .where((e) => e.user?.id != user.id) .where((e) => e.message.silent != true) + .where((e) => e.message.shadowed != true) .listen((event) async { final channel = client.channel( event.channelType, diff --git a/lib/src/system_message.dart b/lib/src/system_message.dart index 7454b0ee..7b4dc243 100644 --- a/lib/src/system_message.dart +++ b/lib/src/system_message.dart @@ -4,11 +4,16 @@ import 'package:stream_chat_flutter/stream_chat_flutter.dart'; /// It shows a date divider depending on the date difference class SystemMessage extends StatelessWidget { + /// This message final Message message; + /// The function called when tapping on the message when the message is not failed + final void Function(Message) onMessageTap; + const SystemMessage({ Key key, @required this.message, + this.onMessageTap, }) : super(key: key); @override @@ -44,57 +49,68 @@ class SystemMessage extends StatelessWidget { dayInfo = createdAt.format('dd/MM/yyyy').toUpperCase(); } - return Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - divider, - Padding( - padding: const EdgeInsets.symmetric(horizontal: 32.0), - child: Column( - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Text( - message.text, - style: TextStyle( - fontSize: 10, - color: Theme.of(context) - .textTheme - .headline6 - .color - .withOpacity(.5), - fontWeight: FontWeight.bold, - ), - ), - Text.rich( - TextSpan( - children: [ + return GestureDetector( + behavior: HitTestBehavior.opaque, + onTap: () { + if (onMessageTap != null) { + onMessageTap(message); + } + }, + child: Container( + width: double.infinity, + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + divider, + Padding( + padding: const EdgeInsets.symmetric(horizontal: 32.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Text( + message.text, + style: TextStyle( + fontSize: 10, + color: Theme.of(context) + .textTheme + .headline6 + .color + .withOpacity(.5), + fontWeight: FontWeight.bold, + ), + ), + Text.rich( TextSpan( - text: dayInfo, + children: [ + TextSpan( + text: dayInfo, + style: TextStyle( + fontWeight: FontWeight.bold, + ), + ), + TextSpan(text: ' AT'), + TextSpan(text: ' $hourInfo'), + ], style: TextStyle( - fontWeight: FontWeight.bold, + fontWeight: FontWeight.normal, ), ), - TextSpan(text: ' AT'), - TextSpan(text: ' $hourInfo'), - ], - style: TextStyle( - fontWeight: FontWeight.normal, + style: TextStyle( + fontSize: 10, + color: Theme.of(context) + .textTheme + .headline6 + .color + .withOpacity(.5), + ), ), - ), - style: TextStyle( - fontSize: 10, - color: Theme.of(context) - .textTheme - .headline6 - .color - .withOpacity(.5), - ), + ], ), - ], - ), + ), + divider, + ], ), - divider, - ], + ), ); } } diff --git a/pubspec.yaml b/pubspec.yaml index 5a3ad4e5..e29042cb 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: stream_chat_flutter homepage: https://github.com/GetStream/stream-chat-flutter description: Stream Chat official Flutter SDK. Build your own chat experience using Dart and Flutter. -version: 0.2.13+1 +version: 0.2.20+2 repository: https://github.com/GetStream/stream-chat-flutter issue_tracker: https://github.com/GetStream/stream-chat-flutter/issues From 2829866c4eb7149dfeb111b39628a6d16800abb3 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Thu, 7 Jan 2021 17:02:36 +0530 Subject: [PATCH 0788/1140] [MessageSearchListView] Add support for `messageFilters` Signed-off-by: Sahil Kumar --- example/lib/main.dart | 10 +++-- lib/src/message_search_bloc.dart | 62 +++++++++++++++++++++------ lib/src/message_search_list_view.dart | 30 ++++++++----- 3 files changed, 76 insertions(+), 26 deletions(-) diff --git a/example/lib/main.dart b/example/lib/main.dart index 39ff4a61..0bc75cea 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -276,11 +276,15 @@ class UserMentionPage extends StatelessWidget { final user = StreamChat.of(context).user; return MessageSearchBloc( child: MessageSearchListView( - messageQuery: '@${user.name}', filters: { 'members': { - r'$in': [user.id] - } + r'$in': [user.id], + }, + }, + messageFilters: { + 'mentioned_users.id': { + r'$contains': user.id, + }, }, sortOptions: [ SortOption( diff --git a/lib/src/message_search_bloc.dart b/lib/src/message_search_bloc.dart index ab277c4c..735c1439 100644 --- a/lib/src/message_search_bloc.dart +++ b/lib/src/message_search_bloc.dart @@ -52,7 +52,7 @@ class MessageSearchBlocState extends State Stream get queryMessagesLoading => _queryMessagesLoadingController.stream; - /// Calls [Client.search] updating [queryMessagesLoading] stream + /// Calls [Client.search] updating [messageResponses] stream Future search({ Map filter, Map messageFilter, @@ -60,10 +60,31 @@ class MessageSearchBlocState extends State String query, PaginationParams pagination, }) async { - final client = StreamChat.of(context).client; + if (messageResponses?.isNotEmpty == true) return; + _messageResponses.add(null); + try { + final messages = await _search( + filter: filter, + messageFilter: messageFilter, + sort: sort, + query: query, + pagination: pagination, + ); + _messageResponses.add(messages.results); + } catch (err, stk) { + _messageResponses.addError(err, stk); + } + } - if (client.state?.user == null || - _queryMessagesLoadingController.value == true) { + /// Calls [Client.search] updating [queryMessagesLoading] stream + Future loadMore({ + Map filter, + Map messageFilter, + List sort, + String query, + PaginationParams pagination, + }) async { + if (_queryMessagesLoadingController.value == true) { return; } _queryMessagesLoadingController.add(true); @@ -74,18 +95,18 @@ class MessageSearchBlocState extends State final oldMessages = List.from(messageResponses ?? []); - final messageResponse = await client.search( - filter, - sort, - query, - pagination, - messageFilters: messageFilter, + final messages = await _search( + filter: filter, + messageFilter: messageFilter, + sort: sort, + query: query, + pagination: pagination, ); if (clear) { - _messageResponses.add(messageResponse.results); + _messageResponses.add(messages.results); } else { - final temp = oldMessages + messageResponse.results; + final temp = oldMessages + messages.results; _messageResponses.add(temp); } @@ -95,6 +116,23 @@ class MessageSearchBlocState extends State } } + Future _search({ + Map filter, + Map messageFilter, + List sort, + String query, + PaginationParams pagination, + }) { + final client = StreamChat.of(context).client; + return client.search( + filter, + sort, + query, + pagination, + messageFilters: messageFilter, + ); + } + @override Widget build(BuildContext context) { super.build(context); diff --git a/lib/src/message_search_list_view.dart b/lib/src/message_search_list_view.dart index 3ff9f151..1adb45a9 100644 --- a/lib/src/message_search_list_view.dart +++ b/lib/src/message_search_list_view.dart @@ -51,10 +51,11 @@ class MessageSearchListView extends StatefulWidget { /// Instantiate a new MessageSearchListView const MessageSearchListView({ Key key, - @required this.messageQuery, - @required this.filters, + this.messageQuery, + this.filters, this.sortOptions, this.paginationParams, + this.messageFilters, this.emptyBuilder, this.errorBuilder, this.separatorBuilder, @@ -83,6 +84,11 @@ class MessageSearchListView extends StatefulWidget { /// message_limit: how many messages should be included to each channel final PaginationParams paginationParams; + /// The message query filters to use. + /// You can query on any of the custom fields you've defined on the [Channel]. + /// You can also filter other built-in channel fields. + final Map messageFilters; + /// Builder used to create a custom item preview final MessageSearchItemBuilder itemBuilder; @@ -115,6 +121,7 @@ class _MessageSearchListViewState extends State { sort: widget.sortOptions, query: widget.messageQuery, pagination: widget.paginationParams, + messageFilter: widget.messageFilters, ); } @@ -205,9 +212,7 @@ class _MessageSearchListViewState extends State { children: [ WidgetSpan( child: Padding( - padding: const EdgeInsets.only( - right: 2.0, - ), + padding: const EdgeInsets.only(right: 2.0), child: Icon(Icons.error_outline), ), ), @@ -217,18 +222,17 @@ class _MessageSearchListViewState extends State { style: Theme.of(context).textTheme.headline6, ), Padding( - padding: const EdgeInsets.only( - top: 16.0, - ), + padding: const EdgeInsets.only(top: 16.0), child: Text(message), ), - FlatButton( + RaisedButton( onPressed: () { messageSearchBloc.search( filter: widget.filters, sort: widget.sortOptions, query: widget.messageQuery, pagination: widget.paginationParams, + messageFilter: widget.messageFilters, ); }, child: Text('Retry'), @@ -281,13 +285,14 @@ class _MessageSearchListViewState extends State { Widget child; child = LazyLoadScrollView( - onEndOfPage: () => messageSearchBloc.search( + onEndOfPage: () => messageSearchBloc.loadMore( filter: widget.filters, sort: widget.sortOptions, pagination: widget.paginationParams.copyWith( offset: messageSearchBloc.messageResponses?.length ?? 0, ), query: widget.messageQuery, + messageFilter: widget.messageFilters, ), child: ListView.separated( physics: AlwaysScrollableScrollPhysics(), @@ -344,13 +349,16 @@ class _MessageSearchListViewState extends State { jsonEncode(widget.sortOptions) != jsonEncode(oldWidget.sortOptions) || widget.paginationParams?.toJson()?.toString() != oldWidget.paginationParams?.toJson()?.toString() || - widget.messageQuery?.toString() != oldWidget.messageQuery?.toString()) { + widget.messageQuery?.toString() != oldWidget.messageQuery?.toString() || + widget.messageFilters?.toString() != + oldWidget.messageFilters?.toString()) { final messageSearchBloc = MessageSearchBloc.of(context); messageSearchBloc.search( filter: widget.filters, sort: widget.sortOptions, query: widget.messageQuery, pagination: widget.paginationParams, + messageFilter: widget.messageFilters, ); } } From ec499ce4c85f35f3d0757f134bfdc0107b50012c Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Thu, 7 Jan 2021 17:13:28 +0530 Subject: [PATCH 0789/1140] [MessageSearchListView] Fix separator color Signed-off-by: Sahil Kumar --- lib/src/message_search_list_view.dart | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/lib/src/message_search_list_view.dart b/lib/src/message_search_list_view.dart index 1adb45a9..33d6eb68 100644 --- a/lib/src/message_search_list_view.dart +++ b/lib/src/message_search_list_view.dart @@ -134,9 +134,7 @@ class _MessageSearchListViewState extends State { Widget _separatorBuilder(BuildContext context, int index) { return Container( height: 1, - color: Theme.of(context).brightness == Brightness.dark - ? StreamChatTheme.of(context).colorTheme.white.withOpacity(0.1) - : StreamChatTheme.of(context).colorTheme.black.withOpacity(0.1), + color: StreamChatTheme.of(context).colorTheme.greyWhisper, ); } From 114119dd013a680de2c725010d6d9a1125258370 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Thu, 7 Jan 2021 13:24:56 +0100 Subject: [PATCH 0790/1140] fix navigation bar --- example/ios/Podfile.lock | 2 +- example/ios/Runner.xcodeproj/project.pbxproj | 2 ++ example/lib/main.dart | 17 +++++++++++++++-- example/pubspec.yaml | 2 +- 4 files changed, 19 insertions(+), 4 deletions(-) diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock index d73a681d..f266b656 100644 --- a/example/ios/Podfile.lock +++ b/example/ios/Podfile.lock @@ -265,7 +265,7 @@ SPEC CHECKSUMS: FirebaseInstallations: 466c7b4d1f58fe16707693091da253726a731ed2 FirebaseInstanceID: bd3ffc24367f901a43c063b36c640b345a4a5dd1 FirebaseMessaging: 5eca4ef173de76253352511aafef774caa1cba2a - Flutter: 434fef37c0980e73bb6479ef766c45957d4b510c + Flutter: 0e3d915762c693b495b44d77113d4970485de6ec flutter_apns: ddc629f26016140bf52165040b0a8e8869f9ce32 flutter_app_badger: 65de4d6f0c34a891df49e6cfb8a1c0496426fa68 flutter_keyboard_visibility: 0339d06371254c3eb25eeb90ba8d17dca8f9c069 diff --git a/example/ios/Runner.xcodeproj/project.pbxproj b/example/ios/Runner.xcodeproj/project.pbxproj index b9c182b0..1e7527eb 100644 --- a/example/ios/Runner.xcodeproj/project.pbxproj +++ b/example/ios/Runner.xcodeproj/project.pbxproj @@ -314,6 +314,7 @@ "${BUILT_PRODUCTS_DIR}/DKImagePickerController/DKImagePickerController.framework", "${BUILT_PRODUCTS_DIR}/DKPhotoGallery/DKPhotoGallery.framework", "${BUILT_PRODUCTS_DIR}/FMDB/FMDB.framework", + "${PODS_ROOT}/../Flutter/Flutter.framework", "${BUILT_PRODUCTS_DIR}/GoogleUtilities/GoogleUtilities.framework", "${BUILT_PRODUCTS_DIR}/PromisesObjC/FBLPromises.framework", "${BUILT_PRODUCTS_DIR}/Protobuf/Protobuf.framework", @@ -347,6 +348,7 @@ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/DKImagePickerController.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/DKPhotoGallery.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FMDB.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Flutter.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GoogleUtilities.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FBLPromises.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Protobuf.framework", diff --git a/example/lib/main.dart b/example/lib/main.dart index 6df1dafb..e34252fd 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -7,6 +7,7 @@ import 'package:example/group_info_screen.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; import 'package:flutter_secure_storage/flutter_secure_storage.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; @@ -55,13 +56,25 @@ class MyApp extends StatelessWidget { builder: (context, child) { return StreamChat( client: client, - child: child, + child: Builder( + builder: (context) => AnnotatedRegion( + child: child, + value: SystemUiOverlayStyle( + systemNavigationBarColor: + StreamChatTheme.of(context).colorTheme.white, + systemNavigationBarIconBrightness: + Theme.of(context).brightness == Brightness.dark + ? Brightness.light + : Brightness.dark, + ), + ), + ), ); }, debugShowCheckedModeBanner: false, theme: ThemeData.light(), darkTheme: ThemeData.dark(), - themeMode: ThemeMode.system, + themeMode: ThemeMode.dark, onGenerateRoute: AppRoutes.generateRoute, initialRoute: client.state.user == null ? Routes.CHOOSE_USER : Routes.HOME, diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 142614c1..c5f52233 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -1,6 +1,6 @@ name: example description: A new Flutter project. -version: 1.0.111+114 +version: 1.0.112+115 environment: sdk: ">=2.2.2 <3.0.0" From cf32ddf850e05174e635c173aac1cdd14beb8654 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Thu, 7 Jan 2021 18:24:44 +0530 Subject: [PATCH 0791/1140] [MessageSearchListView] Add pullToRefresh Signed-off-by: Sahil Kumar --- example/lib/main.dart | 1 + lib/src/message_search_bloc.dart | 1 - lib/src/message_search_list_view.dart | 51 ++++++++++++++++++--------- 3 files changed, 35 insertions(+), 18 deletions(-) diff --git a/example/lib/main.dart b/example/lib/main.dart index 0bc75cea..69099c73 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -425,6 +425,7 @@ class _ChannelListPageState extends State { direction: SortOption.ASC, ), ], + pullToRefresh: false, paginationParams: PaginationParams(limit: 20), emptyBuilder: (_, query) { return LayoutBuilder( diff --git a/lib/src/message_search_bloc.dart b/lib/src/message_search_bloc.dart index 735c1439..67b6455d 100644 --- a/lib/src/message_search_bloc.dart +++ b/lib/src/message_search_bloc.dart @@ -60,7 +60,6 @@ class MessageSearchBlocState extends State String query, PaginationParams pagination, }) async { - if (messageResponses?.isNotEmpty == true) return; _messageResponses.add(null); try { final messages = await _search( diff --git a/lib/src/message_search_list_view.dart b/lib/src/message_search_list_view.dart index 33d6eb68..73a98a2d 100644 --- a/lib/src/message_search_list_view.dart +++ b/lib/src/message_search_list_view.dart @@ -62,6 +62,7 @@ class MessageSearchListView extends StatefulWidget { this.itemBuilder, this.onItemTap, this.showResultCount = true, + this.pullToRefresh = true, }) : super(key: key); /// Message String to search on @@ -107,6 +108,9 @@ class MessageSearchListView extends StatefulWidget { /// Set it to false to hide total results text final bool showResultCount; + /// Set it to false to disable the pull-to-refresh widget + final bool pullToRefresh; + @override _MessageSearchListViewState createState() => _MessageSearchListViewState(); } @@ -281,7 +285,35 @@ class _MessageSearchListViewState extends State { ); } - Widget child; + Widget child = ListView.separated( + physics: AlwaysScrollableScrollPhysics(), + itemCount: items.isNotEmpty ? items.length + 1 : items.length, + separatorBuilder: (_, index) { + if (widget.separatorBuilder != null) { + return widget.separatorBuilder(context, index); + } + return _separatorBuilder(context, index); + }, + itemBuilder: (context, index) { + if (index < items.length) { + return _listItemBuilder(context, items[index]); + } + return _buildQueryProgressIndicator(context, messageSearchBloc); + }, + ); + if (widget.pullToRefresh) { + child = RefreshIndicator( + onRefresh: () async => messageSearchBloc.search( + filter: widget.filters, + sort: widget.sortOptions, + query: widget.messageQuery, + pagination: widget.paginationParams, + messageFilter: widget.messageFilters, + ), + child: child, + ); + } + child = LazyLoadScrollView( onEndOfPage: () => messageSearchBloc.loadMore( filter: widget.filters, @@ -292,22 +324,7 @@ class _MessageSearchListViewState extends State { query: widget.messageQuery, messageFilter: widget.messageFilters, ), - child: ListView.separated( - physics: AlwaysScrollableScrollPhysics(), - itemCount: items.isNotEmpty ? items.length + 1 : items.length, - separatorBuilder: (_, index) { - if (widget.separatorBuilder != null) { - return widget.separatorBuilder(context, index); - } - return _separatorBuilder(context, index); - }, - itemBuilder: (context, index) { - if (index < items.length) { - return _listItemBuilder(context, items[index]); - } - return _buildQueryProgressIndicator(context, messageSearchBloc); - }, - ), + child: child, ); if (widget.showResultCount) { From 1ce97a20aacedb846dabe0a63d345c0e94b8bd6b Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Thu, 7 Jan 2021 18:39:00 +0530 Subject: [PATCH 0792/1140] feat: Added icons and redid UI for commands --- lib/src/message_input.dart | 159 ++++++++++++++++++++++++++--------- lib/src/stream_svg_icon.dart | 48 +++++++++++ lib/svgs/flag.svg | 3 + lib/svgs/giphy_icon.svg | 8 ++ lib/svgs/imgur.svg | 12 +++ lib/svgs/volume-up.svg | 3 + 6 files changed, 193 insertions(+), 40 deletions(-) create mode 100644 lib/svgs/flag.svg create mode 100644 lib/svgs/giphy_icon.svg create mode 100644 lib/svgs/imgur.svg create mode 100644 lib/svgs/volume-up.svg diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 52d91d45..07322203 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -673,7 +673,7 @@ class MessageInputState extends State { if (commands.isNotEmpty) Padding( padding: - const EdgeInsets.only(left: 8.0, top: 8.0), + const EdgeInsets.only(left: 0.0, top: 8.0), child: Row( children: [ Padding( @@ -698,31 +698,51 @@ class MessageInputState extends State { ], ), ), + SizedBox( + height: 10.0, + ), ...commands .map( - (c) => ListTile( - leading: c.name == 'giphy' - ? _buildGiphyIcon() - : null, - title: Text.rich( - TextSpan( - text: '${c.name.capitalize()}', - style: TextStyle( - fontWeight: FontWeight.bold), + (c) => InkWell( + onTap: () { + _setCommand(c); + }, + child: Container( + height: 40.0, + child: Row( children: [ - TextSpan( - text: ' /${c.name} ${c.args}', - style: TextStyle( - fontWeight: FontWeight.w300, + SizedBox( + width: 16.0, + ), + _buildCommandIcon(c.name), + SizedBox( + width: 8.0, + ), + Text.rich( + TextSpan( + text: '${c.name.capitalize()}', + style: TextStyle( + fontWeight: FontWeight.bold), + children: [ + TextSpan( + text: ' /${c.name} ${c.args}', + style: + StreamChatTheme.of(context) + .textTheme + .body + .copyWith( + color: StreamChatTheme + .of(context) + .colorTheme + .grey, + ), + ), + ], ), ), ], ), ), - //subtitle: Text(c.description), - onTap: () { - _setCommand(c); - }, ), ) .toList(), @@ -1083,28 +1103,87 @@ class MessageInputState extends State { } } - CircleAvatar _buildGiphyIcon() { - if (kIsWeb) { - return CircleAvatar( - backgroundColor: StreamChatTheme.of(context).colorTheme.black, - child: Image.asset( - 'images/giphy_icon.png', - package: 'stream_chat_flutter', - width: 24.0, - height: 24.0, - ), - radius: 12, - ); - } else { - return CircleAvatar( - child: SvgPicture.asset( - 'svgs/giphy_icon.svg', - package: 'stream_chat_flutter', - width: 24.0, - height: 24.0, - ), - radius: 12, - ); + Widget _buildCommandIcon(String iconType) { + switch (iconType) { + case 'giphy': + return CircleAvatar( + child: StreamSvgIcon.giphyIcon( + size: 24.0, + ), + radius: 12, + ); + break; + case 'ban': + return CircleAvatar( + backgroundColor: StreamChatTheme.of(context).colorTheme.accentBlue, + child: StreamSvgIcon.Icon_user_delete( + size: 16.0, + color: Colors.white, + ), + radius: 12, + ); + break; + case 'flag': + return CircleAvatar( + backgroundColor: StreamChatTheme.of(context).colorTheme.accentBlue, + child: StreamSvgIcon.flag( + size: 14.0, + color: Colors.white, + ), + radius: 12, + ); + break; + case 'imgur': + return CircleAvatar( + backgroundColor: StreamChatTheme.of(context).colorTheme.accentBlue, + child: ClipOval( + child: StreamSvgIcon.imgur( + size: 24.0, + ), + ), + radius: 12, + ); + break; + case 'mute': + return CircleAvatar( + backgroundColor: StreamChatTheme.of(context).colorTheme.accentBlue, + child: StreamSvgIcon.mute( + size: 16.0, + color: Colors.white, + ), + radius: 12, + ); + break; + case 'unban': + return CircleAvatar( + backgroundColor: StreamChatTheme.of(context).colorTheme.accentBlue, + child: StreamSvgIcon.userAdd( + size: 16.0, + color: Colors.white, + ), + radius: 12, + ); + break; + case 'unmute': + return CircleAvatar( + backgroundColor: StreamChatTheme.of(context).colorTheme.accentBlue, + child: StreamSvgIcon.volumeUp( + size: 16.0, + color: Colors.white, + ), + radius: 12, + ); + break; + default: + return CircleAvatar( + backgroundColor: StreamChatTheme.of(context).colorTheme.accentBlue, + child: StreamSvgIcon.lightning( + size: 16.0, + color: Colors.white, + ), + radius: 12, + ); + break; } } diff --git a/lib/src/stream_svg_icon.dart b/lib/src/stream_svg_icon.dart index ea5a53a5..3e8cfae2 100644 --- a/lib/src/stream_svg_icon.dart +++ b/lib/src/stream_svg_icon.dart @@ -829,4 +829,52 @@ class StreamSvgIcon extends StatelessWidget { height: size, ); } + + factory StreamSvgIcon.giphyIcon({ + double size, + Color color, + }) { + return StreamSvgIcon( + assetName: 'giphy_icon.svg', + color: color, + width: size, + height: size, + ); + } + + factory StreamSvgIcon.imgur({ + double size, + Color color, + }) { + return StreamSvgIcon( + assetName: 'imgur.svg', + color: color, + width: size, + height: size, + ); + } + + factory StreamSvgIcon.volumeUp({ + double size, + Color color, + }) { + return StreamSvgIcon( + assetName: 'volume-up.svg', + color: color, + width: size, + height: size, + ); + } + + factory StreamSvgIcon.flag({ + double size, + Color color, + }) { + return StreamSvgIcon( + assetName: 'flag.svg', + color: color, + width: size, + height: size, + ); + } } diff --git a/lib/svgs/flag.svg b/lib/svgs/flag.svg new file mode 100644 index 00000000..d5903df4 --- /dev/null +++ b/lib/svgs/flag.svg @@ -0,0 +1,3 @@ + + + diff --git a/lib/svgs/giphy_icon.svg b/lib/svgs/giphy_icon.svg new file mode 100644 index 00000000..e1a1d4bb --- /dev/null +++ b/lib/svgs/giphy_icon.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/lib/svgs/imgur.svg b/lib/svgs/imgur.svg new file mode 100644 index 00000000..1df5d71f --- /dev/null +++ b/lib/svgs/imgur.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/lib/svgs/volume-up.svg b/lib/svgs/volume-up.svg new file mode 100644 index 00000000..21f64c35 --- /dev/null +++ b/lib/svgs/volume-up.svg @@ -0,0 +1,3 @@ + + + From 68f9ec8d5ed72031ff0826337be0acb0d80ef55a Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Thu, 7 Jan 2021 18:46:37 +0530 Subject: [PATCH 0793/1140] fix test Signed-off-by: Sahil Kumar --- test/src/channel_preview_test.dart | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/test/src/channel_preview_test.dart b/test/src/channel_preview_test.dart index 578d4b28..34b9bf92 100644 --- a/test/src/channel_preview_test.dart +++ b/test/src/channel_preview_test.dart @@ -42,10 +42,18 @@ void main() { user: User(id: 'user-id'), ), ]); - when(channelState.lastMessage).thenReturn(Message( - text: 'hello', - user: User(id: 'other-user'), - )); + when(channelState.messages).thenReturn([ + Message( + text: 'hello', + user: User(id: 'other-user'), + ) + ]); + when(channelState.messagesStream).thenAnswer((i) => Stream.value([ + Message( + text: 'hello', + user: User(id: 'other-user'), + ) + ])); await tester.pumpWidget(MaterialApp( home: StreamChat( From ce61c28635442c7ea1e2c5743441f872aad2a96a Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Thu, 7 Jan 2021 18:46:37 +0530 Subject: [PATCH 0794/1140] fix test Signed-off-by: Sahil Kumar --- test/src/channel_preview_test.dart | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/test/src/channel_preview_test.dart b/test/src/channel_preview_test.dart index 578d4b28..34b9bf92 100644 --- a/test/src/channel_preview_test.dart +++ b/test/src/channel_preview_test.dart @@ -42,10 +42,18 @@ void main() { user: User(id: 'user-id'), ), ]); - when(channelState.lastMessage).thenReturn(Message( - text: 'hello', - user: User(id: 'other-user'), - )); + when(channelState.messages).thenReturn([ + Message( + text: 'hello', + user: User(id: 'other-user'), + ) + ]); + when(channelState.messagesStream).thenAnswer((i) => Stream.value([ + Message( + text: 'hello', + user: User(id: 'other-user'), + ) + ])); await tester.pumpWidget(MaterialApp( home: StreamChat( From 3b19fe6c36c46895578ba5b1463782e1e31adfd6 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Thu, 7 Jan 2021 20:57:53 +0530 Subject: [PATCH 0795/1140] feat: Redid UI For mentions --- lib/src/message_input.dart | 199 ++++++++++++++++++++++++------------- 1 file changed, 132 insertions(+), 67 deletions(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index cabbafec..e7a5b24d 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -1132,12 +1132,13 @@ class MessageInputState extends State { RenderBox renderBox = context.findRenderObject(); final size = renderBox.size; - return OverlayEntry(builder: (context) { - return Positioned( - bottom: size.height + MediaQuery.of(context).viewInsets.bottom, - left: 0, - right: 0, - child: TweenAnimationBuilder( + return OverlayEntry( + builder: (context) { + return Positioned( + bottom: size.height + MediaQuery.of(context).viewInsets.bottom, + left: 0, + right: 0, + child: TweenAnimationBuilder( tween: Tween(begin: 0.0, end: 1.0), duration: Duration(milliseconds: 300), curve: Curves.easeInOutExpo, @@ -1158,72 +1159,136 @@ class MessageInputState extends State { color: StreamChatTheme.of(context).colorTheme.white, ), child: FutureBuilder>( - future: queryMembers ?? Future.value(members), - initialData: members, - builder: (context, snapshot) { - return ListView( - padding: const EdgeInsets.all(0), - shrinkWrap: true, - itemExtent: 58.0, - children: snapshot.data - .map((m) => ListTile( - leading: UserAvatar( - constraints: BoxConstraints.tight( - Size( - 40, - 40, - ), + future: queryMembers ?? Future.value(members), + initialData: members, + builder: (context, snapshot) { + return ListView( + padding: const EdgeInsets.all(0), + shrinkWrap: true, + children: [ + SizedBox( + height: 8.0, + ), + ...snapshot.data.map( + (m) { + return Material( + color: StreamChatTheme.of(context) + .colorTheme + .white, + child: InkWell( + onTap: () { + _mentionedUsers.add(m.user); + + splits[splits.length - 1] = m.user.name; + final rejoin = splits.join('@'); + + textEditingController.value = + TextEditingValue( + text: rejoin + + textEditingController.text + .substring(textEditingController + .selection.start), + selection: TextSelection.collapsed( + offset: rejoin.length, ), - user: m.user, - ), - title: Text( - '${m.user.name}', - maxLines: 1, - overflow: TextOverflow.ellipsis, - style: TextStyle( - fontWeight: FontWeight.bold), - ), - subtitle: Text( - '@${m.userId}', - maxLines: 1, - overflow: TextOverflow.ellipsis, - ), - trailing: StreamSvgIcon.mentions( - color: StreamChatTheme.of(context) - .colorTheme - .accentBlue, - ), - onTap: () { - _mentionedUsers.add(m.user); - - splits[splits.length - 1] = m.user.name; - final rejoin = splits.join('@'); - - textEditingController.value = - TextEditingValue( - text: rejoin + - textEditingController.text - .substring( - textEditingController - .selection.start), - selection: TextSelection.collapsed( - offset: rejoin.length, + ); + _debounce.cancel(); + _mentionsOverlay?.remove(); + _mentionsOverlay = null; + }, + child: Container( + height: 56.0, + child: Row( + crossAxisAlignment: + CrossAxisAlignment.center, + children: [ + SizedBox( + width: 16.0, ), - ); - _debounce.cancel(); - _mentionsOverlay?.remove(); - _mentionsOverlay = null; - }, - )) - .toList(), - ); - }), + UserAvatar( + constraints: BoxConstraints.tight( + Size( + 40, + 40, + ), + ), + user: m.user, + ), + SizedBox( + width: 8.0, + ), + Expanded( + child: Align( + alignment: Alignment.centerLeft, + child: Column( + mainAxisAlignment: + MainAxisAlignment.center, + crossAxisAlignment: + CrossAxisAlignment.start, + children: [ + Text( + '${m.user.name}', + maxLines: 1, + overflow: + TextOverflow.ellipsis, + style: StreamChatTheme.of( + context) + .textTheme + .bodyBold, + ), + SizedBox( + height: 2.0, + ), + Text( + '@${m.userId}', + maxLines: 1, + overflow: + TextOverflow.ellipsis, + style: StreamChatTheme.of( + context) + .textTheme + .footnoteBold + .copyWith( + color: StreamChatTheme + .of(context) + .colorTheme + .grey), + ), + ], + ), + ), + ), + Padding( + padding: const EdgeInsets.only( + right: 18.0, left: 8.0), + child: StreamSvgIcon.mentions( + color: StreamChatTheme.of(context) + .colorTheme + .accentBlue, + ), + ), + ], + ), + ), + ), + ); + }, + ).toList(), + SizedBox( + height: 8.0, + ), + ], + ); + }, + ), ), ), ); - }), - ); - }); + }, + ), + ); + }, + ); } OverlayEntry _buildEmojiOverlay() { From b0e76a5408db0a92e8a72cd4917cb34bb573f691 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Thu, 7 Jan 2021 21:01:20 +0530 Subject: [PATCH 0796/1140] fix: fixed test --- test/src/channel_preview_test.dart | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/test/src/channel_preview_test.dart b/test/src/channel_preview_test.dart index 578d4b28..34b9bf92 100644 --- a/test/src/channel_preview_test.dart +++ b/test/src/channel_preview_test.dart @@ -42,10 +42,18 @@ void main() { user: User(id: 'user-id'), ), ]); - when(channelState.lastMessage).thenReturn(Message( - text: 'hello', - user: User(id: 'other-user'), - )); + when(channelState.messages).thenReturn([ + Message( + text: 'hello', + user: User(id: 'other-user'), + ) + ]); + when(channelState.messagesStream).thenAnswer((i) => Stream.value([ + Message( + text: 'hello', + user: User(id: 'other-user'), + ) + ])); await tester.pumpWidget(MaterialApp( home: StreamChat( From b5e72ff6106b1a8fb1f30ab90e29344d3eb00190 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Thu, 7 Jan 2021 17:04:27 +0100 Subject: [PATCH 0797/1140] fix chip text color --- example/ios/Podfile.lock | 2 +- example/ios/Runner.xcodeproj/project.pbxproj | 2 ++ example/pubspec.yaml | 2 +- lib/src/message_input.dart | 11 ++++------- 4 files changed, 8 insertions(+), 9 deletions(-) diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock index d73a681d..f266b656 100644 --- a/example/ios/Podfile.lock +++ b/example/ios/Podfile.lock @@ -265,7 +265,7 @@ SPEC CHECKSUMS: FirebaseInstallations: 466c7b4d1f58fe16707693091da253726a731ed2 FirebaseInstanceID: bd3ffc24367f901a43c063b36c640b345a4a5dd1 FirebaseMessaging: 5eca4ef173de76253352511aafef774caa1cba2a - Flutter: 434fef37c0980e73bb6479ef766c45957d4b510c + Flutter: 0e3d915762c693b495b44d77113d4970485de6ec flutter_apns: ddc629f26016140bf52165040b0a8e8869f9ce32 flutter_app_badger: 65de4d6f0c34a891df49e6cfb8a1c0496426fa68 flutter_keyboard_visibility: 0339d06371254c3eb25eeb90ba8d17dca8f9c069 diff --git a/example/ios/Runner.xcodeproj/project.pbxproj b/example/ios/Runner.xcodeproj/project.pbxproj index b9c182b0..1e7527eb 100644 --- a/example/ios/Runner.xcodeproj/project.pbxproj +++ b/example/ios/Runner.xcodeproj/project.pbxproj @@ -314,6 +314,7 @@ "${BUILT_PRODUCTS_DIR}/DKImagePickerController/DKImagePickerController.framework", "${BUILT_PRODUCTS_DIR}/DKPhotoGallery/DKPhotoGallery.framework", "${BUILT_PRODUCTS_DIR}/FMDB/FMDB.framework", + "${PODS_ROOT}/../Flutter/Flutter.framework", "${BUILT_PRODUCTS_DIR}/GoogleUtilities/GoogleUtilities.framework", "${BUILT_PRODUCTS_DIR}/PromisesObjC/FBLPromises.framework", "${BUILT_PRODUCTS_DIR}/Protobuf/Protobuf.framework", @@ -347,6 +348,7 @@ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/DKImagePickerController.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/DKPhotoGallery.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FMDB.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Flutter.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GoogleUtilities.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FBLPromises.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Protobuf.framework", diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 142614c1..c5f52233 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -1,6 +1,6 @@ name: example description: A new Flutter project. -version: 1.0.111+114 +version: 1.0.112+115 environment: sdk: ">=2.2.2 <3.0.0" diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 07322203..d9acda56 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -22,9 +22,9 @@ import 'package:stream_chat_flutter/src/stream_svg_icon.dart'; import 'package:stream_chat_flutter/src/user_avatar.dart'; import 'package:substring_highlight/substring_highlight.dart'; import 'package:video_compress/video_compress.dart'; -import 'extension.dart'; import '../stream_chat_flutter.dart'; +import 'extension.dart'; import 'quoted_message_widget.dart'; import 'stream_channel.dart'; @@ -477,9 +477,7 @@ class MessageInputState extends State { mainAxisAlignment: MainAxisAlignment.center, children: [ StreamSvgIcon.lightning( - color: StreamChatTheme.of(context) - .colorTheme - .white, + color: Colors.white, size: 16.0, ), Text( @@ -488,9 +486,8 @@ class MessageInputState extends State { .textTheme .footnote .copyWith( - color: StreamChatTheme.of(context) - .colorTheme - .white), + color: Colors.white, + ), ), ], ), From 640f361513b24d703fe2d0207e753d5990d0c0e9 Mon Sep 17 00:00:00 2001 From: Neevash Ramdial Date: Thu, 7 Jan 2021 12:04:34 -0400 Subject: [PATCH 0798/1140] Move Flutter widgets to packages directory --- example/android/app/google-services.json | 235 ------------------ .../flutter_widgets/CHANGELOG.md | 0 LICENSE => packages/flutter_widgets/LICENSE | 0 .../flutter_widgets/README.md | 0 .../flutter_widgets/analysis_options.yaml | 0 .../animations}/typing_dots.json | 0 .../flutter_widgets/example}/.gitignore | 0 .../flutter_widgets/example}/.metadata | 0 .../flutter_widgets/example}/README.md | 0 .../example}/android/.gitignore | 0 .../example}/android/app/build.gradle | 0 .../android/app/src/debug/AndroidManifest.xml | 0 .../android/app/src/main/AndroidManifest.xml | 0 .../kotlin/com/example/example/Application.kt | 0 .../com/example/example/MainActivity.kt | 0 .../main/res/drawable/launch_background.xml | 0 .../src/main/res/mipmap-hdpi/ic_launcher.png | Bin .../src/main/res/mipmap-mdpi/ic_launcher.png | Bin .../src/main/res/mipmap-xhdpi/ic_launcher.png | Bin .../main/res/mipmap-xxhdpi/ic_launcher.png | Bin .../main/res/mipmap-xxxhdpi/ic_launcher.png | Bin .../app/src/main/res/values/styles.xml | 0 .../app/src/profile/AndroidManifest.xml | 0 .../example}/android/build.gradle | 0 .../example}/android/gradle.properties | 0 .../gradle/wrapper/gradle-wrapper.properties | 0 .../example}/android/settings.gradle | 0 .../example}/android/settings_aar.gradle | 0 .../example}/assets/android_icon.png | Bin .../example}/assets/icon_arrow_right.svg | 0 .../example}/assets/ios_icon.png | Bin .../flutter_widgets/example}/assets/logo.svg | 0 .../flutter_widgets/example}/ios/.gitignore | 0 .../example}/ios/Flutter/.last_build_id | 0 .../ios/Flutter/AppFrameworkInfo.plist | 0 .../example}/ios/Flutter/Debug.xcconfig | 0 .../example}/ios/Flutter/Release.xcconfig | 0 .../flutter_widgets/example}/ios/Gemfile | 0 .../flutter_widgets/example}/ios/Gemfile.lock | 0 .../example}/ios/Notifications/Info.plist | 0 .../Notifications/NotificationService.swift | 0 .../Notifications/Notifications.entitlements | 0 .../flutter_widgets/example}/ios/Podfile | 0 .../flutter_widgets/example}/ios/Podfile.lock | 0 .../ios/Runner.xcodeproj/project.pbxproj | 0 .../contents.xcworkspacedata | 0 .../xcshareddata/IDEWorkspaceChecks.plist | 0 .../xcshareddata/WorkspaceSettings.xcsettings | 0 .../xcschemes/Notifications.xcscheme | 0 .../xcshareddata/xcschemes/Runner.xcscheme | 0 .../contents.xcworkspacedata | 0 .../xcshareddata/IDEWorkspaceChecks.plist | 0 .../xcshareddata/WorkspaceSettings.xcsettings | 0 .../example}/ios/Runner/AppDelegate.swift | 0 .../AppIcon.appiconset/Contents.json | 0 .../Icon-App-1024x1024@1x.png | Bin .../AppIcon.appiconset/Icon-App-20x20@1x.png | Bin .../AppIcon.appiconset/Icon-App-20x20@2x.png | Bin .../AppIcon.appiconset/Icon-App-20x20@3x.png | Bin .../AppIcon.appiconset/Icon-App-29x29@1x.png | Bin .../AppIcon.appiconset/Icon-App-29x29@2x.png | Bin .../AppIcon.appiconset/Icon-App-29x29@3x.png | Bin .../AppIcon.appiconset/Icon-App-40x40@1x.png | Bin .../AppIcon.appiconset/Icon-App-40x40@2x.png | Bin .../AppIcon.appiconset/Icon-App-40x40@3x.png | Bin .../AppIcon.appiconset/Icon-App-60x60@2x.png | Bin .../AppIcon.appiconset/Icon-App-60x60@3x.png | Bin .../AppIcon.appiconset/Icon-App-76x76@1x.png | Bin .../AppIcon.appiconset/Icon-App-76x76@2x.png | Bin .../Icon-App-83.5x83.5@2x.png | Bin .../LaunchImage.imageset/Contents.json | 0 .../LaunchImage.imageset/LaunchImage.png | Bin .../LaunchImage.imageset/LaunchImage@2x.png | Bin .../LaunchImage.imageset/LaunchImage@3x.png | Bin .../LaunchImage.imageset/README.md | 0 .../Runner/Base.lproj/LaunchScreen.storyboard | 0 .../ios/Runner/Base.lproj/Main.storyboard | 0 .../example}/ios/Runner/Info.plist | 0 .../ios/Runner/Runner-Bridging-Header.h | 0 .../example}/ios/Runner/Runner.entitlements | 0 .../example}/ios/fastlane/Appfile | 0 .../example}/ios/fastlane/Fastfile | 0 .../example}/ios/fastlane/Matchfile | 0 .../example}/ios/fastlane/Pluginfile | 0 .../example}/ios/fastlane/README.md | 0 .../fastlane/beta_gym_export_options.plist | 0 .../example}/ios/fastlane/report.xml | 0 .../example}/lib/advanced_options_page.dart | 0 .../example}/lib/chat_info_screen.dart | 0 .../example}/lib/chips_input_text_field.dart | 0 .../example}/lib/choose_user_page.dart | 0 .../example}/lib/custom_message.dart | 0 .../example}/lib/custom_theme.dart | 0 .../lib/customize_channel_preview.dart | 0 .../lib/customize_message_widget.dart | 0 .../lib/group_chat_details_screen.dart | 0 .../example}/lib/group_info_screen.dart | 0 .../flutter_widgets/example}/lib/main.dart | 0 .../example}/lib/multiple_conversation.dart | 0 .../example}/lib/new_chat_screen.dart | 0 .../example}/lib/new_group_chat_screen.dart | 0 .../example}/lib/notifications_service.dart | 0 .../example}/lib/routes/app_routes.dart | 0 .../example}/lib/routes/routes.dart | 0 .../example}/lib/search_text_field.dart | 0 .../example}/lib/single_conversation.dart | 0 .../example}/lib/split_view.dart | 0 .../example}/lib/stream_version.dart | 0 .../flutter_widgets/example}/lib/threads.dart | 0 .../flutter_widgets/example}/pubspec.yaml | 0 .../test_driver/single_conversation.dart | 0 .../test_driver/single_conversation_test.dart | 0 .../flutter_widgets/example}/web/favicon.png | Bin .../example}/web/icons/Icon-192.png | Bin .../example}/web/icons/Icon-512.png | Bin .../flutter_widgets/example}/web/index.html | 0 .../example}/web/manifest.json | 0 .../flutter_widgets/example}/web/sql-wasm.js | 0 .../example}/web/sql-wasm.wasm | Bin .../flutter_widgets/images}/giphy_icon.png | Bin .../flutter_widgets/images}/placeholder.png | Bin .../lib}/src/attachment_error.dart | 0 .../lib}/src/attachment_title.dart | 0 .../flutter_widgets/lib}/src/back_button.dart | 0 .../lib}/src/channel_bottom_sheet.dart | 0 .../lib}/src/channel_file_display_screen.dart | 0 .../lib}/src/channel_header.dart | 0 .../lib}/src/channel_image.dart | 0 .../lib}/src/channel_info.dart | 0 .../lib}/src/channel_list_header.dart | 0 .../lib}/src/channel_list_view.dart | 0 .../src/channel_media_display_screen.dart | 0 .../lib}/src/channel_name.dart | 0 .../lib}/src/channel_preview.dart | 0 .../lib}/src/channel_unread_indicator.dart | 0 .../lib}/src/channels_bloc.dart | 0 .../lib}/src/compress_video_service.dart | 0 .../lib}/src/date_divider.dart | 0 .../lib}/src/deleted_message.dart | 0 .../flutter_widgets/lib}/src/extension.dart | 0 .../lib}/src/file_attachment.dart | 0 .../lib}/src/full_screen_media.dart | 0 .../lib}/src/giphy_attachment.dart | 0 .../flutter_widgets/lib}/src/group_image.dart | 0 .../lib}/src/image_actions_modal.dart | 0 .../lib}/src/image_attachment.dart | 0 .../lib}/src/image_footer.dart | 0 .../flutter_widgets/lib}/src/image_group.dart | 0 .../lib}/src/image_header.dart | 0 .../lib}/src/lazy_load_scroll_view.dart | 0 .../lib}/src/media_list_view.dart | 0 .../flutter_widgets/lib}/src/media_utils.dart | 0 .../lib}/src/message_actions_modal.dart | 0 .../lib}/src/message_input.dart | 0 .../lib}/src/message_list_view.dart | 0 .../lib}/src/message_reactions_modal.dart | 0 .../lib}/src/message_search_bloc.dart | 0 .../lib}/src/message_search_item.dart | 0 .../lib}/src/message_search_list_view.dart | 0 .../lib}/src/message_text.dart | 0 .../lib}/src/message_widget.dart | 0 .../lib}/src/option_list_tile.dart | 0 .../lib}/src/quoted_message_widget.dart | 0 .../lib}/src/reaction_bubble.dart | 0 .../lib}/src/reaction_icon.dart | 0 .../lib}/src/reaction_picker.dart | 0 .../lib}/src/sending_indicator.dart | 0 .../lib}/src/stream_channel.dart | 0 .../flutter_widgets/lib}/src/stream_chat.dart | 0 .../lib}/src/stream_chat_theme.dart | 0 .../lib}/src/stream_neumorphic_button.dart | 0 .../lib}/src/stream_svg_icon.dart | 0 .../flutter_widgets/lib}/src/swipeable.dart | 0 .../lib}/src/system_message.dart | 0 .../lib}/src/thread_header.dart | 0 .../lib}/src/typing_indicator.dart | 0 .../lib}/src/unread_indicator.dart | 0 .../lib}/src/url_attachment.dart | 0 .../flutter_widgets/lib}/src/user_avatar.dart | 0 .../flutter_widgets/lib}/src/user_item.dart | 0 .../lib}/src/user_list_view.dart | 0 .../lib}/src/user_reaction_display.dart | 0 .../flutter_widgets/lib}/src/users_bloc.dart | 0 .../flutter_widgets/lib}/src/utils.dart | 0 .../lib}/src/video_attachment.dart | 0 .../lib}/stream_chat_flutter.dart | 0 .../lib}/svgs/Empty State_Camera.svg | 0 .../lib}/svgs/Empty State_Files.svg | 0 .../lib}/svgs/Empty State_No channel.svg | 0 .../lib}/svgs/Empty State_Search.svg | 0 .../lib}/svgs/Empty State_picture.svg | 0 .../flutter_widgets/lib}/svgs/Giphy icon.svg | 0 .../lib}/svgs/Icon_LOL_reaction.svg | 0 .../lib}/svgs/Icon_Thread_Reply.svg | 0 .../lib}/svgs/Icon_User_add.svg | 0 .../lib}/svgs/Icon_User_deselect.svg | 0 .../lib}/svgs/Icon_arrow_right.svg | 0 .../flutter_widgets/lib}/svgs/Icon_attach.svg | 0 .../flutter_widgets/lib}/svgs/Icon_camera.svg | 0 .../flutter_widgets/lib}/svgs/Icon_check.svg | 0 .../lib}/svgs/Icon_check_all.svg | 0 .../lib}/svgs/Icon_check_big.svg | 0 .../lib}/svgs/Icon_check_send.svg | 0 .../lib}/svgs/Icon_circle_right.svg | 0 .../lib}/svgs/Icon_circle_up.svg | 0 .../flutter_widgets/lib}/svgs/Icon_close.svg | 0 .../lib}/svgs/Icon_close_black.svg | 0 .../lib}/svgs/Icon_close_sml.svg | 0 .../lib}/svgs/Icon_cloud_download.svg | 0 .../lib}/svgs/Icon_contacts.svg | 0 .../flutter_widgets/lib}/svgs/Icon_copy.svg | 0 .../lib}/svgs/Icon_curve_line_left_up.svg | 0 .../lib}/svgs/Icon_curve_line_left_up_big.svg | 0 .../flutter_widgets/lib}/svgs/Icon_delete.svg | 0 .../flutter_widgets/lib}/svgs/Icon_down.svg | 0 .../lib}/svgs/Icon_download.svg | 0 .../flutter_widgets/lib}/svgs/Icon_edit.svg | 0 .../lib}/svgs/Icon_empty_circle_left.svg | 0 .../flutter_widgets/lib}/svgs/Icon_error.svg | 0 .../lib}/svgs/Icon_eye-off.svg | 0 .../flutter_widgets/lib}/svgs/Icon_grid.svg | 0 .../flutter_widgets/lib}/svgs/Icon_group.svg | 0 .../flutter_widgets/lib}/svgs/Icon_left.svg | 0 .../svgs/Icon_lightning-command runner.svg | 0 .../lib}/svgs/Icon_love_reaction.svg | 0 .../lib}/svgs/Icon_menu_point_v.svg | 0 .../lib}/svgs/Icon_message.svg | 0 .../flutter_widgets/lib}/svgs/Icon_mute.svg | 0 .../lib}/svgs/Icon_notification.svg | 0 .../lib}/svgs/Icon_pen-write.svg | 0 .../flutter_widgets/lib}/svgs/Icon_record.svg | 0 .../flutter_widgets/lib}/svgs/Icon_right.svg | 0 .../flutter_widgets/lib}/svgs/Icon_save.svg | 0 .../flutter_widgets/lib}/svgs/Icon_search.svg | 0 .../lib}/svgs/Icon_send_message.svg | 0 .../flutter_widgets/lib}/svgs/Icon_smile.svg | 0 .../lib}/svgs/Icon_thumbs_down_reaction.svg | 0 .../lib}/svgs/Icon_thumbs_up_reaction.svg | 0 .../flutter_widgets/lib}/svgs/Icon_time.svg | 0 .../flutter_widgets/lib}/svgs/Icon_user.svg | 0 .../lib}/svgs/Icon_user_delete.svg | 0 .../lib}/svgs/Icon_user_settings.svg | 0 .../lib}/svgs/Icon_wut_reaction.svg | 0 .../lib}/svgs/STREAM MARK 1.svg | 0 .../svgs/UI_Reverse Pagination Loading.svg | 0 .../lib}/svgs/eye-line_big.svg | 0 .../flutter_widgets/lib}/svgs/files.svg | 0 .../flutter_widgets/lib}/svgs/filetype_7z.svg | 0 .../lib}/svgs/filetype_CSV.svg | 0 .../lib}/svgs/filetype_DOC.svg | 0 .../lib}/svgs/filetype_DOCX.svg | 0 .../lib}/svgs/filetype_Generic.svg | 0 .../flutter_widgets/lib}/svgs/filetype_MD.svg | 0 .../lib}/svgs/filetype_ODT.svg | 0 .../lib}/svgs/filetype_PDF.svg | 0 .../lib}/svgs/filetype_PPT.svg | 0 .../lib}/svgs/filetype_PPTX-1.svg | 0 .../lib}/svgs/filetype_PPTX.svg | 0 .../lib}/svgs/filetype_RAR.svg | 0 .../lib}/svgs/filetype_RTF.svg | 0 .../lib}/svgs/filetype_TAR.svg | 0 .../lib}/svgs/filetype_TXT.svg | 0 .../lib}/svgs/filetype_XLS.svg | 0 .../lib}/svgs/filetype_XLSX.svg | 0 .../lib}/svgs/filetype_ZIP.svg | 0 .../lib}/svgs/filetype_html.svg | 0 .../lib}/svgs/giphy icon blue.svg | 0 .../flutter_widgets/lib}/svgs/icon_SHARE.svg | 0 .../lib}/svgs/icon_delete_grey.svg | 0 .../lib}/svgs/icon_mentions.svg | 0 .../flutter_widgets/lib}/svgs/mentions.svg | 0 .../flutter_widgets/lib}/svgs/pictures.svg | 0 .../flutter_widgets/lib}/svgs/settings.svg | 0 .../flutter_widgets/lib}/svgs/share_arrow.svg | 0 .../flutter_widgets/pubspec.yaml | 0 .../screenshots}/channel_header.png | Bin .../screenshots}/channel_header_paint.png | Bin .../screenshots}/channel_image.png | Bin .../screenshots}/channel_image_paint.png | Bin .../screenshots}/channel_list_view.png | Bin .../screenshots}/channel_list_view_paint.png | Bin .../screenshots}/channel_preview.png | Bin .../screenshots}/channel_preview_paint.png | Bin .../screenshots}/message_input.png | Bin .../screenshots}/message_input2.png | Bin .../screenshots}/message_input2_paint.png | Bin .../screenshots}/message_input_paint.png | Bin .../screenshots}/message_listview.png | Bin .../screenshots}/message_listview_paint.png | Bin .../screenshots}/message_widget.png | Bin .../screenshots}/message_widget_paint.png | Bin .../screenshots}/reaction_picker.png | Bin .../screenshots}/reaction_picker_paint.png | Bin .../screenshots}/thread_header.png | Bin .../screenshots}/thread_header_paint.png | Bin .../flutter_widgets/svgs}/giphy_icon.svg | 0 .../flutter_widgets/svgs}/icon_camera.svg | 0 .../flutter_widgets/svgs}/icon_pen_write.svg | 0 .../svgs}/icon_picture_empty_state.svg | 0 .../flutter_widgets/svgs}/video_call_icon.svg | 0 .../test}/src/channel_preview_test.dart | 0 .../test}/src/message_action_modal_test.dart | 0 .../src/message_reaction_modal_test.dart | 0 .../flutter_widgets/test}/src/mocks.dart | 0 .../test}/src/reaction_bubble_test.dart | 0 305 files changed, 235 deletions(-) delete mode 100644 example/android/app/google-services.json rename CHANGELOG.md => packages/flutter_widgets/CHANGELOG.md (100%) rename LICENSE => packages/flutter_widgets/LICENSE (100%) rename README.md => packages/flutter_widgets/README.md (100%) rename analysis_options.yaml => packages/flutter_widgets/analysis_options.yaml (100%) rename {animations => packages/flutter_widgets/animations}/typing_dots.json (100%) rename {example => packages/flutter_widgets/example}/.gitignore (100%) rename {example => packages/flutter_widgets/example}/.metadata (100%) rename {example => packages/flutter_widgets/example}/README.md (100%) rename {example => packages/flutter_widgets/example}/android/.gitignore (100%) rename {example => packages/flutter_widgets/example}/android/app/build.gradle (100%) rename {example => packages/flutter_widgets/example}/android/app/src/debug/AndroidManifest.xml (100%) rename {example => packages/flutter_widgets/example}/android/app/src/main/AndroidManifest.xml (100%) rename {example => packages/flutter_widgets/example}/android/app/src/main/kotlin/com/example/example/Application.kt (100%) rename {example => packages/flutter_widgets/example}/android/app/src/main/kotlin/com/example/example/MainActivity.kt (100%) rename {example => packages/flutter_widgets/example}/android/app/src/main/res/drawable/launch_background.xml (100%) rename {example => packages/flutter_widgets/example}/android/app/src/main/res/mipmap-hdpi/ic_launcher.png (100%) rename {example => packages/flutter_widgets/example}/android/app/src/main/res/mipmap-mdpi/ic_launcher.png (100%) rename {example => packages/flutter_widgets/example}/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png (100%) rename {example => packages/flutter_widgets/example}/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png (100%) rename {example => packages/flutter_widgets/example}/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png (100%) rename {example => packages/flutter_widgets/example}/android/app/src/main/res/values/styles.xml (100%) rename {example => packages/flutter_widgets/example}/android/app/src/profile/AndroidManifest.xml (100%) rename {example => packages/flutter_widgets/example}/android/build.gradle (100%) rename {example => packages/flutter_widgets/example}/android/gradle.properties (100%) rename {example => packages/flutter_widgets/example}/android/gradle/wrapper/gradle-wrapper.properties (100%) rename {example => packages/flutter_widgets/example}/android/settings.gradle (100%) rename {example => packages/flutter_widgets/example}/android/settings_aar.gradle (100%) rename {example => packages/flutter_widgets/example}/assets/android_icon.png (100%) rename {example => packages/flutter_widgets/example}/assets/icon_arrow_right.svg (100%) rename {example => packages/flutter_widgets/example}/assets/ios_icon.png (100%) rename {example => packages/flutter_widgets/example}/assets/logo.svg (100%) rename {example => packages/flutter_widgets/example}/ios/.gitignore (100%) rename {example => packages/flutter_widgets/example}/ios/Flutter/.last_build_id (100%) rename {example => packages/flutter_widgets/example}/ios/Flutter/AppFrameworkInfo.plist (100%) rename {example => packages/flutter_widgets/example}/ios/Flutter/Debug.xcconfig (100%) rename {example => packages/flutter_widgets/example}/ios/Flutter/Release.xcconfig (100%) rename {example => packages/flutter_widgets/example}/ios/Gemfile (100%) rename {example => packages/flutter_widgets/example}/ios/Gemfile.lock (100%) rename {example => packages/flutter_widgets/example}/ios/Notifications/Info.plist (100%) rename {example => packages/flutter_widgets/example}/ios/Notifications/NotificationService.swift (100%) rename {example => packages/flutter_widgets/example}/ios/Notifications/Notifications.entitlements (100%) rename {example => packages/flutter_widgets/example}/ios/Podfile (100%) rename {example => packages/flutter_widgets/example}/ios/Podfile.lock (100%) rename {example => packages/flutter_widgets/example}/ios/Runner.xcodeproj/project.pbxproj (100%) rename {example => packages/flutter_widgets/example}/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata (100%) rename {example => packages/flutter_widgets/example}/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist (100%) rename {example => packages/flutter_widgets/example}/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings (100%) rename {example => packages/flutter_widgets/example}/ios/Runner.xcodeproj/xcshareddata/xcschemes/Notifications.xcscheme (100%) rename {example => packages/flutter_widgets/example}/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme (100%) rename {example => packages/flutter_widgets/example}/ios/Runner.xcworkspace/contents.xcworkspacedata (100%) rename {example => packages/flutter_widgets/example}/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist (100%) rename {example => packages/flutter_widgets/example}/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings (100%) rename {example => packages/flutter_widgets/example}/ios/Runner/AppDelegate.swift (100%) rename {example => packages/flutter_widgets/example}/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json (100%) rename {example => packages/flutter_widgets/example}/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png (100%) rename {example => packages/flutter_widgets/example}/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png (100%) rename {example => packages/flutter_widgets/example}/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png (100%) rename {example => packages/flutter_widgets/example}/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png (100%) rename {example => packages/flutter_widgets/example}/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png (100%) rename {example => packages/flutter_widgets/example}/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png (100%) rename {example => packages/flutter_widgets/example}/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png (100%) rename {example => packages/flutter_widgets/example}/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png (100%) rename {example => packages/flutter_widgets/example}/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png (100%) rename {example => packages/flutter_widgets/example}/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png (100%) rename {example => packages/flutter_widgets/example}/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png (100%) rename {example => packages/flutter_widgets/example}/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png (100%) rename {example => packages/flutter_widgets/example}/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png (100%) rename {example => packages/flutter_widgets/example}/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png (100%) rename {example => packages/flutter_widgets/example}/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png (100%) rename {example => packages/flutter_widgets/example}/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json (100%) rename {example => packages/flutter_widgets/example}/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png (100%) rename {example => packages/flutter_widgets/example}/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png (100%) rename {example => packages/flutter_widgets/example}/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png (100%) rename {example => packages/flutter_widgets/example}/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md (100%) rename {example => packages/flutter_widgets/example}/ios/Runner/Base.lproj/LaunchScreen.storyboard (100%) rename {example => packages/flutter_widgets/example}/ios/Runner/Base.lproj/Main.storyboard (100%) rename {example => packages/flutter_widgets/example}/ios/Runner/Info.plist (100%) rename {example => packages/flutter_widgets/example}/ios/Runner/Runner-Bridging-Header.h (100%) rename {example => packages/flutter_widgets/example}/ios/Runner/Runner.entitlements (100%) rename {example => packages/flutter_widgets/example}/ios/fastlane/Appfile (100%) rename {example => packages/flutter_widgets/example}/ios/fastlane/Fastfile (100%) rename {example => packages/flutter_widgets/example}/ios/fastlane/Matchfile (100%) rename {example => packages/flutter_widgets/example}/ios/fastlane/Pluginfile (100%) rename {example => packages/flutter_widgets/example}/ios/fastlane/README.md (100%) rename {example => packages/flutter_widgets/example}/ios/fastlane/beta_gym_export_options.plist (100%) rename {example => packages/flutter_widgets/example}/ios/fastlane/report.xml (100%) rename {example => packages/flutter_widgets/example}/lib/advanced_options_page.dart (100%) rename {example => packages/flutter_widgets/example}/lib/chat_info_screen.dart (100%) rename {example => packages/flutter_widgets/example}/lib/chips_input_text_field.dart (100%) rename {example => packages/flutter_widgets/example}/lib/choose_user_page.dart (100%) rename {example => packages/flutter_widgets/example}/lib/custom_message.dart (100%) rename {example => packages/flutter_widgets/example}/lib/custom_theme.dart (100%) rename {example => packages/flutter_widgets/example}/lib/customize_channel_preview.dart (100%) rename {example => packages/flutter_widgets/example}/lib/customize_message_widget.dart (100%) rename {example => packages/flutter_widgets/example}/lib/group_chat_details_screen.dart (100%) rename {example => packages/flutter_widgets/example}/lib/group_info_screen.dart (100%) rename {example => packages/flutter_widgets/example}/lib/main.dart (100%) rename {example => packages/flutter_widgets/example}/lib/multiple_conversation.dart (100%) rename {example => packages/flutter_widgets/example}/lib/new_chat_screen.dart (100%) rename {example => packages/flutter_widgets/example}/lib/new_group_chat_screen.dart (100%) rename {example => packages/flutter_widgets/example}/lib/notifications_service.dart (100%) rename {example => packages/flutter_widgets/example}/lib/routes/app_routes.dart (100%) rename {example => packages/flutter_widgets/example}/lib/routes/routes.dart (100%) rename {example => packages/flutter_widgets/example}/lib/search_text_field.dart (100%) rename {example => packages/flutter_widgets/example}/lib/single_conversation.dart (100%) rename {example => packages/flutter_widgets/example}/lib/split_view.dart (100%) rename {example => packages/flutter_widgets/example}/lib/stream_version.dart (100%) rename {example => packages/flutter_widgets/example}/lib/threads.dart (100%) rename {example => packages/flutter_widgets/example}/pubspec.yaml (100%) rename {example => packages/flutter_widgets/example}/test_driver/single_conversation.dart (100%) rename {example => packages/flutter_widgets/example}/test_driver/single_conversation_test.dart (100%) rename {example => packages/flutter_widgets/example}/web/favicon.png (100%) rename {example => packages/flutter_widgets/example}/web/icons/Icon-192.png (100%) rename {example => packages/flutter_widgets/example}/web/icons/Icon-512.png (100%) rename {example => packages/flutter_widgets/example}/web/index.html (100%) rename {example => packages/flutter_widgets/example}/web/manifest.json (100%) rename {example => packages/flutter_widgets/example}/web/sql-wasm.js (100%) rename {example => packages/flutter_widgets/example}/web/sql-wasm.wasm (100%) rename {images => packages/flutter_widgets/images}/giphy_icon.png (100%) rename {images => packages/flutter_widgets/images}/placeholder.png (100%) rename {lib => packages/flutter_widgets/lib}/src/attachment_error.dart (100%) rename {lib => packages/flutter_widgets/lib}/src/attachment_title.dart (100%) rename {lib => packages/flutter_widgets/lib}/src/back_button.dart (100%) rename {lib => packages/flutter_widgets/lib}/src/channel_bottom_sheet.dart (100%) rename {lib => packages/flutter_widgets/lib}/src/channel_file_display_screen.dart (100%) rename {lib => packages/flutter_widgets/lib}/src/channel_header.dart (100%) rename {lib => packages/flutter_widgets/lib}/src/channel_image.dart (100%) rename {lib => packages/flutter_widgets/lib}/src/channel_info.dart (100%) rename {lib => packages/flutter_widgets/lib}/src/channel_list_header.dart (100%) rename {lib => packages/flutter_widgets/lib}/src/channel_list_view.dart (100%) rename {lib => packages/flutter_widgets/lib}/src/channel_media_display_screen.dart (100%) rename {lib => packages/flutter_widgets/lib}/src/channel_name.dart (100%) rename {lib => packages/flutter_widgets/lib}/src/channel_preview.dart (100%) rename {lib => packages/flutter_widgets/lib}/src/channel_unread_indicator.dart (100%) rename {lib => packages/flutter_widgets/lib}/src/channels_bloc.dart (100%) rename {lib => packages/flutter_widgets/lib}/src/compress_video_service.dart (100%) rename {lib => packages/flutter_widgets/lib}/src/date_divider.dart (100%) rename {lib => packages/flutter_widgets/lib}/src/deleted_message.dart (100%) rename {lib => packages/flutter_widgets/lib}/src/extension.dart (100%) rename {lib => packages/flutter_widgets/lib}/src/file_attachment.dart (100%) rename {lib => packages/flutter_widgets/lib}/src/full_screen_media.dart (100%) rename {lib => packages/flutter_widgets/lib}/src/giphy_attachment.dart (100%) rename {lib => packages/flutter_widgets/lib}/src/group_image.dart (100%) rename {lib => packages/flutter_widgets/lib}/src/image_actions_modal.dart (100%) rename {lib => packages/flutter_widgets/lib}/src/image_attachment.dart (100%) rename {lib => packages/flutter_widgets/lib}/src/image_footer.dart (100%) rename {lib => packages/flutter_widgets/lib}/src/image_group.dart (100%) rename {lib => packages/flutter_widgets/lib}/src/image_header.dart (100%) rename {lib => packages/flutter_widgets/lib}/src/lazy_load_scroll_view.dart (100%) rename {lib => packages/flutter_widgets/lib}/src/media_list_view.dart (100%) rename {lib => packages/flutter_widgets/lib}/src/media_utils.dart (100%) rename {lib => packages/flutter_widgets/lib}/src/message_actions_modal.dart (100%) rename {lib => packages/flutter_widgets/lib}/src/message_input.dart (100%) rename {lib => packages/flutter_widgets/lib}/src/message_list_view.dart (100%) rename {lib => packages/flutter_widgets/lib}/src/message_reactions_modal.dart (100%) rename {lib => packages/flutter_widgets/lib}/src/message_search_bloc.dart (100%) rename {lib => packages/flutter_widgets/lib}/src/message_search_item.dart (100%) rename {lib => packages/flutter_widgets/lib}/src/message_search_list_view.dart (100%) rename {lib => packages/flutter_widgets/lib}/src/message_text.dart (100%) rename {lib => packages/flutter_widgets/lib}/src/message_widget.dart (100%) rename {lib => packages/flutter_widgets/lib}/src/option_list_tile.dart (100%) rename {lib => packages/flutter_widgets/lib}/src/quoted_message_widget.dart (100%) rename {lib => packages/flutter_widgets/lib}/src/reaction_bubble.dart (100%) rename {lib => packages/flutter_widgets/lib}/src/reaction_icon.dart (100%) rename {lib => packages/flutter_widgets/lib}/src/reaction_picker.dart (100%) rename {lib => packages/flutter_widgets/lib}/src/sending_indicator.dart (100%) rename {lib => packages/flutter_widgets/lib}/src/stream_channel.dart (100%) rename {lib => packages/flutter_widgets/lib}/src/stream_chat.dart (100%) rename {lib => packages/flutter_widgets/lib}/src/stream_chat_theme.dart (100%) rename {lib => packages/flutter_widgets/lib}/src/stream_neumorphic_button.dart (100%) rename {lib => packages/flutter_widgets/lib}/src/stream_svg_icon.dart (100%) rename {lib => packages/flutter_widgets/lib}/src/swipeable.dart (100%) rename {lib => packages/flutter_widgets/lib}/src/system_message.dart (100%) rename {lib => packages/flutter_widgets/lib}/src/thread_header.dart (100%) rename {lib => packages/flutter_widgets/lib}/src/typing_indicator.dart (100%) rename {lib => packages/flutter_widgets/lib}/src/unread_indicator.dart (100%) rename {lib => packages/flutter_widgets/lib}/src/url_attachment.dart (100%) rename {lib => packages/flutter_widgets/lib}/src/user_avatar.dart (100%) rename {lib => packages/flutter_widgets/lib}/src/user_item.dart (100%) rename {lib => packages/flutter_widgets/lib}/src/user_list_view.dart (100%) rename {lib => packages/flutter_widgets/lib}/src/user_reaction_display.dart (100%) rename {lib => packages/flutter_widgets/lib}/src/users_bloc.dart (100%) rename {lib => packages/flutter_widgets/lib}/src/utils.dart (100%) rename {lib => packages/flutter_widgets/lib}/src/video_attachment.dart (100%) rename {lib => packages/flutter_widgets/lib}/stream_chat_flutter.dart (100%) rename {lib => packages/flutter_widgets/lib}/svgs/Empty State_Camera.svg (100%) rename {lib => packages/flutter_widgets/lib}/svgs/Empty State_Files.svg (100%) rename {lib => packages/flutter_widgets/lib}/svgs/Empty State_No channel.svg (100%) rename {lib => packages/flutter_widgets/lib}/svgs/Empty State_Search.svg (100%) rename {lib => packages/flutter_widgets/lib}/svgs/Empty State_picture.svg (100%) rename {lib => packages/flutter_widgets/lib}/svgs/Giphy icon.svg (100%) rename {lib => packages/flutter_widgets/lib}/svgs/Icon_LOL_reaction.svg (100%) rename {lib => packages/flutter_widgets/lib}/svgs/Icon_Thread_Reply.svg (100%) rename {lib => packages/flutter_widgets/lib}/svgs/Icon_User_add.svg (100%) rename {lib => packages/flutter_widgets/lib}/svgs/Icon_User_deselect.svg (100%) rename {lib => packages/flutter_widgets/lib}/svgs/Icon_arrow_right.svg (100%) rename {lib => packages/flutter_widgets/lib}/svgs/Icon_attach.svg (100%) rename {lib => packages/flutter_widgets/lib}/svgs/Icon_camera.svg (100%) rename {lib => packages/flutter_widgets/lib}/svgs/Icon_check.svg (100%) rename {lib => packages/flutter_widgets/lib}/svgs/Icon_check_all.svg (100%) rename {lib => packages/flutter_widgets/lib}/svgs/Icon_check_big.svg (100%) rename {lib => packages/flutter_widgets/lib}/svgs/Icon_check_send.svg (100%) rename {lib => packages/flutter_widgets/lib}/svgs/Icon_circle_right.svg (100%) rename {lib => packages/flutter_widgets/lib}/svgs/Icon_circle_up.svg (100%) rename {lib => packages/flutter_widgets/lib}/svgs/Icon_close.svg (100%) rename {lib => packages/flutter_widgets/lib}/svgs/Icon_close_black.svg (100%) rename {lib => packages/flutter_widgets/lib}/svgs/Icon_close_sml.svg (100%) rename {lib => packages/flutter_widgets/lib}/svgs/Icon_cloud_download.svg (100%) rename {lib => packages/flutter_widgets/lib}/svgs/Icon_contacts.svg (100%) rename {lib => packages/flutter_widgets/lib}/svgs/Icon_copy.svg (100%) rename {lib => packages/flutter_widgets/lib}/svgs/Icon_curve_line_left_up.svg (100%) rename {lib => packages/flutter_widgets/lib}/svgs/Icon_curve_line_left_up_big.svg (100%) rename {lib => packages/flutter_widgets/lib}/svgs/Icon_delete.svg (100%) rename {lib => packages/flutter_widgets/lib}/svgs/Icon_down.svg (100%) rename {lib => packages/flutter_widgets/lib}/svgs/Icon_download.svg (100%) rename {lib => packages/flutter_widgets/lib}/svgs/Icon_edit.svg (100%) rename {lib => packages/flutter_widgets/lib}/svgs/Icon_empty_circle_left.svg (100%) rename {lib => packages/flutter_widgets/lib}/svgs/Icon_error.svg (100%) rename {lib => packages/flutter_widgets/lib}/svgs/Icon_eye-off.svg (100%) rename {lib => packages/flutter_widgets/lib}/svgs/Icon_grid.svg (100%) rename {lib => packages/flutter_widgets/lib}/svgs/Icon_group.svg (100%) rename {lib => packages/flutter_widgets/lib}/svgs/Icon_left.svg (100%) rename {lib => packages/flutter_widgets/lib}/svgs/Icon_lightning-command runner.svg (100%) rename {lib => packages/flutter_widgets/lib}/svgs/Icon_love_reaction.svg (100%) rename {lib => packages/flutter_widgets/lib}/svgs/Icon_menu_point_v.svg (100%) rename {lib => packages/flutter_widgets/lib}/svgs/Icon_message.svg (100%) rename {lib => packages/flutter_widgets/lib}/svgs/Icon_mute.svg (100%) rename {lib => packages/flutter_widgets/lib}/svgs/Icon_notification.svg (100%) rename {lib => packages/flutter_widgets/lib}/svgs/Icon_pen-write.svg (100%) rename {lib => packages/flutter_widgets/lib}/svgs/Icon_record.svg (100%) rename {lib => packages/flutter_widgets/lib}/svgs/Icon_right.svg (100%) rename {lib => packages/flutter_widgets/lib}/svgs/Icon_save.svg (100%) rename {lib => packages/flutter_widgets/lib}/svgs/Icon_search.svg (100%) rename {lib => packages/flutter_widgets/lib}/svgs/Icon_send_message.svg (100%) rename {lib => packages/flutter_widgets/lib}/svgs/Icon_smile.svg (100%) rename {lib => packages/flutter_widgets/lib}/svgs/Icon_thumbs_down_reaction.svg (100%) rename {lib => packages/flutter_widgets/lib}/svgs/Icon_thumbs_up_reaction.svg (100%) rename {lib => packages/flutter_widgets/lib}/svgs/Icon_time.svg (100%) rename {lib => packages/flutter_widgets/lib}/svgs/Icon_user.svg (100%) rename {lib => packages/flutter_widgets/lib}/svgs/Icon_user_delete.svg (100%) rename {lib => packages/flutter_widgets/lib}/svgs/Icon_user_settings.svg (100%) rename {lib => packages/flutter_widgets/lib}/svgs/Icon_wut_reaction.svg (100%) rename {lib => packages/flutter_widgets/lib}/svgs/STREAM MARK 1.svg (100%) rename {lib => packages/flutter_widgets/lib}/svgs/UI_Reverse Pagination Loading.svg (100%) rename {lib => packages/flutter_widgets/lib}/svgs/eye-line_big.svg (100%) rename {lib => packages/flutter_widgets/lib}/svgs/files.svg (100%) rename {lib => packages/flutter_widgets/lib}/svgs/filetype_7z.svg (100%) rename {lib => packages/flutter_widgets/lib}/svgs/filetype_CSV.svg (100%) rename {lib => packages/flutter_widgets/lib}/svgs/filetype_DOC.svg (100%) rename {lib => packages/flutter_widgets/lib}/svgs/filetype_DOCX.svg (100%) rename {lib => packages/flutter_widgets/lib}/svgs/filetype_Generic.svg (100%) rename {lib => packages/flutter_widgets/lib}/svgs/filetype_MD.svg (100%) rename {lib => packages/flutter_widgets/lib}/svgs/filetype_ODT.svg (100%) rename {lib => packages/flutter_widgets/lib}/svgs/filetype_PDF.svg (100%) rename {lib => packages/flutter_widgets/lib}/svgs/filetype_PPT.svg (100%) rename {lib => packages/flutter_widgets/lib}/svgs/filetype_PPTX-1.svg (100%) rename {lib => packages/flutter_widgets/lib}/svgs/filetype_PPTX.svg (100%) rename {lib => packages/flutter_widgets/lib}/svgs/filetype_RAR.svg (100%) rename {lib => packages/flutter_widgets/lib}/svgs/filetype_RTF.svg (100%) rename {lib => packages/flutter_widgets/lib}/svgs/filetype_TAR.svg (100%) rename {lib => packages/flutter_widgets/lib}/svgs/filetype_TXT.svg (100%) rename {lib => packages/flutter_widgets/lib}/svgs/filetype_XLS.svg (100%) rename {lib => packages/flutter_widgets/lib}/svgs/filetype_XLSX.svg (100%) rename {lib => packages/flutter_widgets/lib}/svgs/filetype_ZIP.svg (100%) rename {lib => packages/flutter_widgets/lib}/svgs/filetype_html.svg (100%) rename {lib => packages/flutter_widgets/lib}/svgs/giphy icon blue.svg (100%) rename {lib => packages/flutter_widgets/lib}/svgs/icon_SHARE.svg (100%) rename {lib => packages/flutter_widgets/lib}/svgs/icon_delete_grey.svg (100%) rename {lib => packages/flutter_widgets/lib}/svgs/icon_mentions.svg (100%) rename {lib => packages/flutter_widgets/lib}/svgs/mentions.svg (100%) rename {lib => packages/flutter_widgets/lib}/svgs/pictures.svg (100%) rename {lib => packages/flutter_widgets/lib}/svgs/settings.svg (100%) rename {lib => packages/flutter_widgets/lib}/svgs/share_arrow.svg (100%) rename pubspec.yaml => packages/flutter_widgets/pubspec.yaml (100%) rename {screenshots => packages/flutter_widgets/screenshots}/channel_header.png (100%) rename {screenshots => packages/flutter_widgets/screenshots}/channel_header_paint.png (100%) rename {screenshots => packages/flutter_widgets/screenshots}/channel_image.png (100%) rename {screenshots => packages/flutter_widgets/screenshots}/channel_image_paint.png (100%) rename {screenshots => packages/flutter_widgets/screenshots}/channel_list_view.png (100%) rename {screenshots => packages/flutter_widgets/screenshots}/channel_list_view_paint.png (100%) rename {screenshots => packages/flutter_widgets/screenshots}/channel_preview.png (100%) rename {screenshots => packages/flutter_widgets/screenshots}/channel_preview_paint.png (100%) rename {screenshots => packages/flutter_widgets/screenshots}/message_input.png (100%) rename {screenshots => packages/flutter_widgets/screenshots}/message_input2.png (100%) rename {screenshots => packages/flutter_widgets/screenshots}/message_input2_paint.png (100%) rename {screenshots => packages/flutter_widgets/screenshots}/message_input_paint.png (100%) rename {screenshots => packages/flutter_widgets/screenshots}/message_listview.png (100%) rename {screenshots => packages/flutter_widgets/screenshots}/message_listview_paint.png (100%) rename {screenshots => packages/flutter_widgets/screenshots}/message_widget.png (100%) rename {screenshots => packages/flutter_widgets/screenshots}/message_widget_paint.png (100%) rename {screenshots => packages/flutter_widgets/screenshots}/reaction_picker.png (100%) rename {screenshots => packages/flutter_widgets/screenshots}/reaction_picker_paint.png (100%) rename {screenshots => packages/flutter_widgets/screenshots}/thread_header.png (100%) rename {screenshots => packages/flutter_widgets/screenshots}/thread_header_paint.png (100%) rename {svgs => packages/flutter_widgets/svgs}/giphy_icon.svg (100%) rename {svgs => packages/flutter_widgets/svgs}/icon_camera.svg (100%) rename {svgs => packages/flutter_widgets/svgs}/icon_pen_write.svg (100%) rename {svgs => packages/flutter_widgets/svgs}/icon_picture_empty_state.svg (100%) rename {svgs => packages/flutter_widgets/svgs}/video_call_icon.svg (100%) rename {test => packages/flutter_widgets/test}/src/channel_preview_test.dart (100%) rename {test => packages/flutter_widgets/test}/src/message_action_modal_test.dart (100%) rename {test => packages/flutter_widgets/test}/src/message_reaction_modal_test.dart (100%) rename {test => packages/flutter_widgets/test}/src/mocks.dart (100%) rename {test => packages/flutter_widgets/test}/src/reaction_bubble_test.dart (100%) diff --git a/example/android/app/google-services.json b/example/android/app/google-services.json deleted file mode 100644 index fa5842bf..00000000 --- a/example/android/app/google-services.json +++ /dev/null @@ -1,235 +0,0 @@ -{ - "project_info": { - "project_number": "674907137625", - "firebase_url": "https://stream-chat-internal.firebaseio.com", - "project_id": "stream-chat-internal", - "storage_bucket": "stream-chat-internal.appspot.com" - }, - "client": [ - { - "client_info": { - "mobilesdk_app_id": "1:674907137625:android:e55b74fd5747e39ad7f348", - "android_client_info": { - "package_name": "com.example.example" - } - }, - "oauth_client": [ - { - "client_id": "674907137625-o5iqvv6dtmljtn069b5djv19ad9a7js0.apps.googleusercontent.com", - "client_type": 3 - } - ], - "api_key": [ - { - "current_key": "AIzaSyBArS4RH7lUn3xbD-jhzWl5hVWZhliRgY0" - } - ], - "services": { - "appinvite_service": { - "other_platform_oauth_client": [ - { - "client_id": "674907137625-o5iqvv6dtmljtn069b5djv19ad9a7js0.apps.googleusercontent.com", - "client_type": 3 - }, - { - "client_id": "674907137625-flarfn9cefu4lermgpbc4b8rm8l15ian.apps.googleusercontent.com", - "client_type": 2, - "ios_info": { - "bundle_id": "io.getstream.flutter" - } - } - ] - } - } - }, - { - "client_info": { - "mobilesdk_app_id": "1:674907137625:android:05257db0ea1f2505d7f348", - "android_client_info": { - "package_name": "io.getstream.chat.android.client.sample" - } - }, - "oauth_client": [ - { - "client_id": "674907137625-o5iqvv6dtmljtn069b5djv19ad9a7js0.apps.googleusercontent.com", - "client_type": 3 - } - ], - "api_key": [ - { - "current_key": "AIzaSyBArS4RH7lUn3xbD-jhzWl5hVWZhliRgY0" - } - ], - "services": { - "appinvite_service": { - "other_platform_oauth_client": [ - { - "client_id": "674907137625-o5iqvv6dtmljtn069b5djv19ad9a7js0.apps.googleusercontent.com", - "client_type": 3 - }, - { - "client_id": "674907137625-flarfn9cefu4lermgpbc4b8rm8l15ian.apps.googleusercontent.com", - "client_type": 2, - "ios_info": { - "bundle_id": "io.getstream.flutter" - } - } - ] - } - } - }, - { - "client_info": { - "mobilesdk_app_id": "1:674907137625:android:c41e48c4c799aee8d7f348", - "android_client_info": { - "package_name": "io.getstream.chat.example" - } - }, - "oauth_client": [ - { - "client_id": "674907137625-o5iqvv6dtmljtn069b5djv19ad9a7js0.apps.googleusercontent.com", - "client_type": 3 - } - ], - "api_key": [ - { - "current_key": "AIzaSyBArS4RH7lUn3xbD-jhzWl5hVWZhliRgY0" - } - ], - "services": { - "appinvite_service": { - "other_platform_oauth_client": [ - { - "client_id": "674907137625-o5iqvv6dtmljtn069b5djv19ad9a7js0.apps.googleusercontent.com", - "client_type": 3 - }, - { - "client_id": "674907137625-flarfn9cefu4lermgpbc4b8rm8l15ian.apps.googleusercontent.com", - "client_type": 2, - "ios_info": { - "bundle_id": "io.getstream.flutter" - } - } - ] - } - } - }, - { - "client_info": { - "mobilesdk_app_id": "1:674907137625:android:c36d6f4ab7491192d7f348", - "android_client_info": { - "package_name": "io.getstream.chat.sample" - } - }, - "oauth_client": [ - { - "client_id": "674907137625-o5iqvv6dtmljtn069b5djv19ad9a7js0.apps.googleusercontent.com", - "client_type": 3 - } - ], - "api_key": [ - { - "current_key": "AIzaSyBArS4RH7lUn3xbD-jhzWl5hVWZhliRgY0" - } - ], - "services": { - "appinvite_service": { - "other_platform_oauth_client": [ - { - "client_id": "674907137625-o5iqvv6dtmljtn069b5djv19ad9a7js0.apps.googleusercontent.com", - "client_type": 3 - }, - { - "client_id": "674907137625-flarfn9cefu4lermgpbc4b8rm8l15ian.apps.googleusercontent.com", - "client_type": 2, - "ios_info": { - "bundle_id": "io.getstream.flutter" - } - } - ] - } - } - }, - { - "client_info": { - "mobilesdk_app_id": "1:674907137625:android:d91b4d966e372431d7f348", - "android_client_info": { - "package_name": "io.getstream.chat.sample.debug" - } - }, - "oauth_client": [ - { - "client_id": "674907137625-o5iqvv6dtmljtn069b5djv19ad9a7js0.apps.googleusercontent.com", - "client_type": 3 - } - ], - "api_key": [ - { - "current_key": "AIzaSyBArS4RH7lUn3xbD-jhzWl5hVWZhliRgY0" - } - ], - "services": { - "appinvite_service": { - "other_platform_oauth_client": [ - { - "client_id": "674907137625-o5iqvv6dtmljtn069b5djv19ad9a7js0.apps.googleusercontent.com", - "client_type": 3 - }, - { - "client_id": "674907137625-flarfn9cefu4lermgpbc4b8rm8l15ian.apps.googleusercontent.com", - "client_type": 2, - "ios_info": { - "bundle_id": "io.getstream.flutter" - } - } - ] - } - } - }, - { - "client_info": { - "mobilesdk_app_id": "1:674907137625:android:ff6593c705df1c43d7f348", - "android_client_info": { - "package_name": "io.getstream.chat.sdk" - } - }, - "oauth_client": [ - { - "client_id": "674907137625-khntpmmm3s1756v4jugnhcifgjlqrmd0.apps.googleusercontent.com", - "client_type": 1, - "android_info": { - "package_name": "io.getstream.chat.sdk", - "certificate_hash": "38f7d663a2ed58ae8990d365c41bd82df62185dc" - } - }, - { - "client_id": "674907137625-o5iqvv6dtmljtn069b5djv19ad9a7js0.apps.googleusercontent.com", - "client_type": 3 - } - ], - "api_key": [ - { - "current_key": "AIzaSyBArS4RH7lUn3xbD-jhzWl5hVWZhliRgY0" - } - ], - "services": { - "appinvite_service": { - "other_platform_oauth_client": [ - { - "client_id": "674907137625-o5iqvv6dtmljtn069b5djv19ad9a7js0.apps.googleusercontent.com", - "client_type": 3 - }, - { - "client_id": "674907137625-flarfn9cefu4lermgpbc4b8rm8l15ian.apps.googleusercontent.com", - "client_type": 2, - "ios_info": { - "bundle_id": "io.getstream.flutter" - } - } - ] - } - } - } - ], - "configuration_version": "1" -} \ No newline at end of file diff --git a/CHANGELOG.md b/packages/flutter_widgets/CHANGELOG.md similarity index 100% rename from CHANGELOG.md rename to packages/flutter_widgets/CHANGELOG.md diff --git a/LICENSE b/packages/flutter_widgets/LICENSE similarity index 100% rename from LICENSE rename to packages/flutter_widgets/LICENSE diff --git a/README.md b/packages/flutter_widgets/README.md similarity index 100% rename from README.md rename to packages/flutter_widgets/README.md diff --git a/analysis_options.yaml b/packages/flutter_widgets/analysis_options.yaml similarity index 100% rename from analysis_options.yaml rename to packages/flutter_widgets/analysis_options.yaml diff --git a/animations/typing_dots.json b/packages/flutter_widgets/animations/typing_dots.json similarity index 100% rename from animations/typing_dots.json rename to packages/flutter_widgets/animations/typing_dots.json diff --git a/example/.gitignore b/packages/flutter_widgets/example/.gitignore similarity index 100% rename from example/.gitignore rename to packages/flutter_widgets/example/.gitignore diff --git a/example/.metadata b/packages/flutter_widgets/example/.metadata similarity index 100% rename from example/.metadata rename to packages/flutter_widgets/example/.metadata diff --git a/example/README.md b/packages/flutter_widgets/example/README.md similarity index 100% rename from example/README.md rename to packages/flutter_widgets/example/README.md diff --git a/example/android/.gitignore b/packages/flutter_widgets/example/android/.gitignore similarity index 100% rename from example/android/.gitignore rename to packages/flutter_widgets/example/android/.gitignore diff --git a/example/android/app/build.gradle b/packages/flutter_widgets/example/android/app/build.gradle similarity index 100% rename from example/android/app/build.gradle rename to packages/flutter_widgets/example/android/app/build.gradle diff --git a/example/android/app/src/debug/AndroidManifest.xml b/packages/flutter_widgets/example/android/app/src/debug/AndroidManifest.xml similarity index 100% rename from example/android/app/src/debug/AndroidManifest.xml rename to packages/flutter_widgets/example/android/app/src/debug/AndroidManifest.xml diff --git a/example/android/app/src/main/AndroidManifest.xml b/packages/flutter_widgets/example/android/app/src/main/AndroidManifest.xml similarity index 100% rename from example/android/app/src/main/AndroidManifest.xml rename to packages/flutter_widgets/example/android/app/src/main/AndroidManifest.xml diff --git a/example/android/app/src/main/kotlin/com/example/example/Application.kt b/packages/flutter_widgets/example/android/app/src/main/kotlin/com/example/example/Application.kt similarity index 100% rename from example/android/app/src/main/kotlin/com/example/example/Application.kt rename to packages/flutter_widgets/example/android/app/src/main/kotlin/com/example/example/Application.kt diff --git a/example/android/app/src/main/kotlin/com/example/example/MainActivity.kt b/packages/flutter_widgets/example/android/app/src/main/kotlin/com/example/example/MainActivity.kt similarity index 100% rename from example/android/app/src/main/kotlin/com/example/example/MainActivity.kt rename to packages/flutter_widgets/example/android/app/src/main/kotlin/com/example/example/MainActivity.kt diff --git a/example/android/app/src/main/res/drawable/launch_background.xml b/packages/flutter_widgets/example/android/app/src/main/res/drawable/launch_background.xml similarity index 100% rename from example/android/app/src/main/res/drawable/launch_background.xml rename to packages/flutter_widgets/example/android/app/src/main/res/drawable/launch_background.xml diff --git a/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/packages/flutter_widgets/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png similarity index 100% rename from example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png rename to packages/flutter_widgets/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png diff --git a/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/packages/flutter_widgets/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png similarity index 100% rename from example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png rename to packages/flutter_widgets/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png diff --git a/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/packages/flutter_widgets/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png similarity index 100% rename from example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png rename to packages/flutter_widgets/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png diff --git a/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/packages/flutter_widgets/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png similarity index 100% rename from example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png rename to packages/flutter_widgets/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png diff --git a/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/packages/flutter_widgets/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png similarity index 100% rename from example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png rename to packages/flutter_widgets/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png diff --git a/example/android/app/src/main/res/values/styles.xml b/packages/flutter_widgets/example/android/app/src/main/res/values/styles.xml similarity index 100% rename from example/android/app/src/main/res/values/styles.xml rename to packages/flutter_widgets/example/android/app/src/main/res/values/styles.xml diff --git a/example/android/app/src/profile/AndroidManifest.xml b/packages/flutter_widgets/example/android/app/src/profile/AndroidManifest.xml similarity index 100% rename from example/android/app/src/profile/AndroidManifest.xml rename to packages/flutter_widgets/example/android/app/src/profile/AndroidManifest.xml diff --git a/example/android/build.gradle b/packages/flutter_widgets/example/android/build.gradle similarity index 100% rename from example/android/build.gradle rename to packages/flutter_widgets/example/android/build.gradle diff --git a/example/android/gradle.properties b/packages/flutter_widgets/example/android/gradle.properties similarity index 100% rename from example/android/gradle.properties rename to packages/flutter_widgets/example/android/gradle.properties diff --git a/example/android/gradle/wrapper/gradle-wrapper.properties b/packages/flutter_widgets/example/android/gradle/wrapper/gradle-wrapper.properties similarity index 100% rename from example/android/gradle/wrapper/gradle-wrapper.properties rename to packages/flutter_widgets/example/android/gradle/wrapper/gradle-wrapper.properties diff --git a/example/android/settings.gradle b/packages/flutter_widgets/example/android/settings.gradle similarity index 100% rename from example/android/settings.gradle rename to packages/flutter_widgets/example/android/settings.gradle diff --git a/example/android/settings_aar.gradle b/packages/flutter_widgets/example/android/settings_aar.gradle similarity index 100% rename from example/android/settings_aar.gradle rename to packages/flutter_widgets/example/android/settings_aar.gradle diff --git a/example/assets/android_icon.png b/packages/flutter_widgets/example/assets/android_icon.png similarity index 100% rename from example/assets/android_icon.png rename to packages/flutter_widgets/example/assets/android_icon.png diff --git a/example/assets/icon_arrow_right.svg b/packages/flutter_widgets/example/assets/icon_arrow_right.svg similarity index 100% rename from example/assets/icon_arrow_right.svg rename to packages/flutter_widgets/example/assets/icon_arrow_right.svg diff --git a/example/assets/ios_icon.png b/packages/flutter_widgets/example/assets/ios_icon.png similarity index 100% rename from example/assets/ios_icon.png rename to packages/flutter_widgets/example/assets/ios_icon.png diff --git a/example/assets/logo.svg b/packages/flutter_widgets/example/assets/logo.svg similarity index 100% rename from example/assets/logo.svg rename to packages/flutter_widgets/example/assets/logo.svg diff --git a/example/ios/.gitignore b/packages/flutter_widgets/example/ios/.gitignore similarity index 100% rename from example/ios/.gitignore rename to packages/flutter_widgets/example/ios/.gitignore diff --git a/example/ios/Flutter/.last_build_id b/packages/flutter_widgets/example/ios/Flutter/.last_build_id similarity index 100% rename from example/ios/Flutter/.last_build_id rename to packages/flutter_widgets/example/ios/Flutter/.last_build_id diff --git a/example/ios/Flutter/AppFrameworkInfo.plist b/packages/flutter_widgets/example/ios/Flutter/AppFrameworkInfo.plist similarity index 100% rename from example/ios/Flutter/AppFrameworkInfo.plist rename to packages/flutter_widgets/example/ios/Flutter/AppFrameworkInfo.plist diff --git a/example/ios/Flutter/Debug.xcconfig b/packages/flutter_widgets/example/ios/Flutter/Debug.xcconfig similarity index 100% rename from example/ios/Flutter/Debug.xcconfig rename to packages/flutter_widgets/example/ios/Flutter/Debug.xcconfig diff --git a/example/ios/Flutter/Release.xcconfig b/packages/flutter_widgets/example/ios/Flutter/Release.xcconfig similarity index 100% rename from example/ios/Flutter/Release.xcconfig rename to packages/flutter_widgets/example/ios/Flutter/Release.xcconfig diff --git a/example/ios/Gemfile b/packages/flutter_widgets/example/ios/Gemfile similarity index 100% rename from example/ios/Gemfile rename to packages/flutter_widgets/example/ios/Gemfile diff --git a/example/ios/Gemfile.lock b/packages/flutter_widgets/example/ios/Gemfile.lock similarity index 100% rename from example/ios/Gemfile.lock rename to packages/flutter_widgets/example/ios/Gemfile.lock diff --git a/example/ios/Notifications/Info.plist b/packages/flutter_widgets/example/ios/Notifications/Info.plist similarity index 100% rename from example/ios/Notifications/Info.plist rename to packages/flutter_widgets/example/ios/Notifications/Info.plist diff --git a/example/ios/Notifications/NotificationService.swift b/packages/flutter_widgets/example/ios/Notifications/NotificationService.swift similarity index 100% rename from example/ios/Notifications/NotificationService.swift rename to packages/flutter_widgets/example/ios/Notifications/NotificationService.swift diff --git a/example/ios/Notifications/Notifications.entitlements b/packages/flutter_widgets/example/ios/Notifications/Notifications.entitlements similarity index 100% rename from example/ios/Notifications/Notifications.entitlements rename to packages/flutter_widgets/example/ios/Notifications/Notifications.entitlements diff --git a/example/ios/Podfile b/packages/flutter_widgets/example/ios/Podfile similarity index 100% rename from example/ios/Podfile rename to packages/flutter_widgets/example/ios/Podfile diff --git a/example/ios/Podfile.lock b/packages/flutter_widgets/example/ios/Podfile.lock similarity index 100% rename from example/ios/Podfile.lock rename to packages/flutter_widgets/example/ios/Podfile.lock diff --git a/example/ios/Runner.xcodeproj/project.pbxproj b/packages/flutter_widgets/example/ios/Runner.xcodeproj/project.pbxproj similarity index 100% rename from example/ios/Runner.xcodeproj/project.pbxproj rename to packages/flutter_widgets/example/ios/Runner.xcodeproj/project.pbxproj diff --git a/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/packages/flutter_widgets/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata similarity index 100% rename from example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata rename to packages/flutter_widgets/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata diff --git a/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/packages/flutter_widgets/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist similarity index 100% rename from example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist rename to packages/flutter_widgets/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/packages/flutter_widgets/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings similarity index 100% rename from example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings rename to packages/flutter_widgets/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings diff --git a/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Notifications.xcscheme b/packages/flutter_widgets/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Notifications.xcscheme similarity index 100% rename from example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Notifications.xcscheme rename to packages/flutter_widgets/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Notifications.xcscheme diff --git a/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/packages/flutter_widgets/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme similarity index 100% rename from example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme rename to packages/flutter_widgets/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme diff --git a/example/ios/Runner.xcworkspace/contents.xcworkspacedata b/packages/flutter_widgets/example/ios/Runner.xcworkspace/contents.xcworkspacedata similarity index 100% rename from example/ios/Runner.xcworkspace/contents.xcworkspacedata rename to packages/flutter_widgets/example/ios/Runner.xcworkspace/contents.xcworkspacedata diff --git a/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/packages/flutter_widgets/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist similarity index 100% rename from example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist rename to packages/flutter_widgets/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/packages/flutter_widgets/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings similarity index 100% rename from example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings rename to packages/flutter_widgets/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings diff --git a/example/ios/Runner/AppDelegate.swift b/packages/flutter_widgets/example/ios/Runner/AppDelegate.swift similarity index 100% rename from example/ios/Runner/AppDelegate.swift rename to packages/flutter_widgets/example/ios/Runner/AppDelegate.swift diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/packages/flutter_widgets/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json similarity index 100% rename from example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json rename to packages/flutter_widgets/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png b/packages/flutter_widgets/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png similarity index 100% rename from example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png rename to packages/flutter_widgets/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png b/packages/flutter_widgets/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png similarity index 100% rename from example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png rename to packages/flutter_widgets/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png b/packages/flutter_widgets/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png similarity index 100% rename from example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png rename to packages/flutter_widgets/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/packages/flutter_widgets/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png similarity index 100% rename from example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png rename to packages/flutter_widgets/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png b/packages/flutter_widgets/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png similarity index 100% rename from example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png rename to packages/flutter_widgets/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/packages/flutter_widgets/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png similarity index 100% rename from example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png rename to packages/flutter_widgets/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png b/packages/flutter_widgets/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png similarity index 100% rename from example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png rename to packages/flutter_widgets/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png b/packages/flutter_widgets/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png similarity index 100% rename from example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png rename to packages/flutter_widgets/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/packages/flutter_widgets/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png similarity index 100% rename from example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png rename to packages/flutter_widgets/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/packages/flutter_widgets/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png similarity index 100% rename from example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png rename to packages/flutter_widgets/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/packages/flutter_widgets/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png similarity index 100% rename from example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png rename to packages/flutter_widgets/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/packages/flutter_widgets/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png similarity index 100% rename from example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png rename to packages/flutter_widgets/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/packages/flutter_widgets/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png similarity index 100% rename from example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png rename to packages/flutter_widgets/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png b/packages/flutter_widgets/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png similarity index 100% rename from example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png rename to packages/flutter_widgets/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png b/packages/flutter_widgets/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png similarity index 100% rename from example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png rename to packages/flutter_widgets/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png diff --git a/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json b/packages/flutter_widgets/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json similarity index 100% rename from example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json rename to packages/flutter_widgets/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json diff --git a/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png b/packages/flutter_widgets/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png similarity index 100% rename from example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png rename to packages/flutter_widgets/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png diff --git a/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png b/packages/flutter_widgets/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png similarity index 100% rename from example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png rename to packages/flutter_widgets/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png diff --git a/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png b/packages/flutter_widgets/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png similarity index 100% rename from example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png rename to packages/flutter_widgets/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png diff --git a/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md b/packages/flutter_widgets/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md similarity index 100% rename from example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md rename to packages/flutter_widgets/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md diff --git a/example/ios/Runner/Base.lproj/LaunchScreen.storyboard b/packages/flutter_widgets/example/ios/Runner/Base.lproj/LaunchScreen.storyboard similarity index 100% rename from example/ios/Runner/Base.lproj/LaunchScreen.storyboard rename to packages/flutter_widgets/example/ios/Runner/Base.lproj/LaunchScreen.storyboard diff --git a/example/ios/Runner/Base.lproj/Main.storyboard b/packages/flutter_widgets/example/ios/Runner/Base.lproj/Main.storyboard similarity index 100% rename from example/ios/Runner/Base.lproj/Main.storyboard rename to packages/flutter_widgets/example/ios/Runner/Base.lproj/Main.storyboard diff --git a/example/ios/Runner/Info.plist b/packages/flutter_widgets/example/ios/Runner/Info.plist similarity index 100% rename from example/ios/Runner/Info.plist rename to packages/flutter_widgets/example/ios/Runner/Info.plist diff --git a/example/ios/Runner/Runner-Bridging-Header.h b/packages/flutter_widgets/example/ios/Runner/Runner-Bridging-Header.h similarity index 100% rename from example/ios/Runner/Runner-Bridging-Header.h rename to packages/flutter_widgets/example/ios/Runner/Runner-Bridging-Header.h diff --git a/example/ios/Runner/Runner.entitlements b/packages/flutter_widgets/example/ios/Runner/Runner.entitlements similarity index 100% rename from example/ios/Runner/Runner.entitlements rename to packages/flutter_widgets/example/ios/Runner/Runner.entitlements diff --git a/example/ios/fastlane/Appfile b/packages/flutter_widgets/example/ios/fastlane/Appfile similarity index 100% rename from example/ios/fastlane/Appfile rename to packages/flutter_widgets/example/ios/fastlane/Appfile diff --git a/example/ios/fastlane/Fastfile b/packages/flutter_widgets/example/ios/fastlane/Fastfile similarity index 100% rename from example/ios/fastlane/Fastfile rename to packages/flutter_widgets/example/ios/fastlane/Fastfile diff --git a/example/ios/fastlane/Matchfile b/packages/flutter_widgets/example/ios/fastlane/Matchfile similarity index 100% rename from example/ios/fastlane/Matchfile rename to packages/flutter_widgets/example/ios/fastlane/Matchfile diff --git a/example/ios/fastlane/Pluginfile b/packages/flutter_widgets/example/ios/fastlane/Pluginfile similarity index 100% rename from example/ios/fastlane/Pluginfile rename to packages/flutter_widgets/example/ios/fastlane/Pluginfile diff --git a/example/ios/fastlane/README.md b/packages/flutter_widgets/example/ios/fastlane/README.md similarity index 100% rename from example/ios/fastlane/README.md rename to packages/flutter_widgets/example/ios/fastlane/README.md diff --git a/example/ios/fastlane/beta_gym_export_options.plist b/packages/flutter_widgets/example/ios/fastlane/beta_gym_export_options.plist similarity index 100% rename from example/ios/fastlane/beta_gym_export_options.plist rename to packages/flutter_widgets/example/ios/fastlane/beta_gym_export_options.plist diff --git a/example/ios/fastlane/report.xml b/packages/flutter_widgets/example/ios/fastlane/report.xml similarity index 100% rename from example/ios/fastlane/report.xml rename to packages/flutter_widgets/example/ios/fastlane/report.xml diff --git a/example/lib/advanced_options_page.dart b/packages/flutter_widgets/example/lib/advanced_options_page.dart similarity index 100% rename from example/lib/advanced_options_page.dart rename to packages/flutter_widgets/example/lib/advanced_options_page.dart diff --git a/example/lib/chat_info_screen.dart b/packages/flutter_widgets/example/lib/chat_info_screen.dart similarity index 100% rename from example/lib/chat_info_screen.dart rename to packages/flutter_widgets/example/lib/chat_info_screen.dart diff --git a/example/lib/chips_input_text_field.dart b/packages/flutter_widgets/example/lib/chips_input_text_field.dart similarity index 100% rename from example/lib/chips_input_text_field.dart rename to packages/flutter_widgets/example/lib/chips_input_text_field.dart diff --git a/example/lib/choose_user_page.dart b/packages/flutter_widgets/example/lib/choose_user_page.dart similarity index 100% rename from example/lib/choose_user_page.dart rename to packages/flutter_widgets/example/lib/choose_user_page.dart diff --git a/example/lib/custom_message.dart b/packages/flutter_widgets/example/lib/custom_message.dart similarity index 100% rename from example/lib/custom_message.dart rename to packages/flutter_widgets/example/lib/custom_message.dart diff --git a/example/lib/custom_theme.dart b/packages/flutter_widgets/example/lib/custom_theme.dart similarity index 100% rename from example/lib/custom_theme.dart rename to packages/flutter_widgets/example/lib/custom_theme.dart diff --git a/example/lib/customize_channel_preview.dart b/packages/flutter_widgets/example/lib/customize_channel_preview.dart similarity index 100% rename from example/lib/customize_channel_preview.dart rename to packages/flutter_widgets/example/lib/customize_channel_preview.dart diff --git a/example/lib/customize_message_widget.dart b/packages/flutter_widgets/example/lib/customize_message_widget.dart similarity index 100% rename from example/lib/customize_message_widget.dart rename to packages/flutter_widgets/example/lib/customize_message_widget.dart diff --git a/example/lib/group_chat_details_screen.dart b/packages/flutter_widgets/example/lib/group_chat_details_screen.dart similarity index 100% rename from example/lib/group_chat_details_screen.dart rename to packages/flutter_widgets/example/lib/group_chat_details_screen.dart diff --git a/example/lib/group_info_screen.dart b/packages/flutter_widgets/example/lib/group_info_screen.dart similarity index 100% rename from example/lib/group_info_screen.dart rename to packages/flutter_widgets/example/lib/group_info_screen.dart diff --git a/example/lib/main.dart b/packages/flutter_widgets/example/lib/main.dart similarity index 100% rename from example/lib/main.dart rename to packages/flutter_widgets/example/lib/main.dart diff --git a/example/lib/multiple_conversation.dart b/packages/flutter_widgets/example/lib/multiple_conversation.dart similarity index 100% rename from example/lib/multiple_conversation.dart rename to packages/flutter_widgets/example/lib/multiple_conversation.dart diff --git a/example/lib/new_chat_screen.dart b/packages/flutter_widgets/example/lib/new_chat_screen.dart similarity index 100% rename from example/lib/new_chat_screen.dart rename to packages/flutter_widgets/example/lib/new_chat_screen.dart diff --git a/example/lib/new_group_chat_screen.dart b/packages/flutter_widgets/example/lib/new_group_chat_screen.dart similarity index 100% rename from example/lib/new_group_chat_screen.dart rename to packages/flutter_widgets/example/lib/new_group_chat_screen.dart diff --git a/example/lib/notifications_service.dart b/packages/flutter_widgets/example/lib/notifications_service.dart similarity index 100% rename from example/lib/notifications_service.dart rename to packages/flutter_widgets/example/lib/notifications_service.dart diff --git a/example/lib/routes/app_routes.dart b/packages/flutter_widgets/example/lib/routes/app_routes.dart similarity index 100% rename from example/lib/routes/app_routes.dart rename to packages/flutter_widgets/example/lib/routes/app_routes.dart diff --git a/example/lib/routes/routes.dart b/packages/flutter_widgets/example/lib/routes/routes.dart similarity index 100% rename from example/lib/routes/routes.dart rename to packages/flutter_widgets/example/lib/routes/routes.dart diff --git a/example/lib/search_text_field.dart b/packages/flutter_widgets/example/lib/search_text_field.dart similarity index 100% rename from example/lib/search_text_field.dart rename to packages/flutter_widgets/example/lib/search_text_field.dart diff --git a/example/lib/single_conversation.dart b/packages/flutter_widgets/example/lib/single_conversation.dart similarity index 100% rename from example/lib/single_conversation.dart rename to packages/flutter_widgets/example/lib/single_conversation.dart diff --git a/example/lib/split_view.dart b/packages/flutter_widgets/example/lib/split_view.dart similarity index 100% rename from example/lib/split_view.dart rename to packages/flutter_widgets/example/lib/split_view.dart diff --git a/example/lib/stream_version.dart b/packages/flutter_widgets/example/lib/stream_version.dart similarity index 100% rename from example/lib/stream_version.dart rename to packages/flutter_widgets/example/lib/stream_version.dart diff --git a/example/lib/threads.dart b/packages/flutter_widgets/example/lib/threads.dart similarity index 100% rename from example/lib/threads.dart rename to packages/flutter_widgets/example/lib/threads.dart diff --git a/example/pubspec.yaml b/packages/flutter_widgets/example/pubspec.yaml similarity index 100% rename from example/pubspec.yaml rename to packages/flutter_widgets/example/pubspec.yaml diff --git a/example/test_driver/single_conversation.dart b/packages/flutter_widgets/example/test_driver/single_conversation.dart similarity index 100% rename from example/test_driver/single_conversation.dart rename to packages/flutter_widgets/example/test_driver/single_conversation.dart diff --git a/example/test_driver/single_conversation_test.dart b/packages/flutter_widgets/example/test_driver/single_conversation_test.dart similarity index 100% rename from example/test_driver/single_conversation_test.dart rename to packages/flutter_widgets/example/test_driver/single_conversation_test.dart diff --git a/example/web/favicon.png b/packages/flutter_widgets/example/web/favicon.png similarity index 100% rename from example/web/favicon.png rename to packages/flutter_widgets/example/web/favicon.png diff --git a/example/web/icons/Icon-192.png b/packages/flutter_widgets/example/web/icons/Icon-192.png similarity index 100% rename from example/web/icons/Icon-192.png rename to packages/flutter_widgets/example/web/icons/Icon-192.png diff --git a/example/web/icons/Icon-512.png b/packages/flutter_widgets/example/web/icons/Icon-512.png similarity index 100% rename from example/web/icons/Icon-512.png rename to packages/flutter_widgets/example/web/icons/Icon-512.png diff --git a/example/web/index.html b/packages/flutter_widgets/example/web/index.html similarity index 100% rename from example/web/index.html rename to packages/flutter_widgets/example/web/index.html diff --git a/example/web/manifest.json b/packages/flutter_widgets/example/web/manifest.json similarity index 100% rename from example/web/manifest.json rename to packages/flutter_widgets/example/web/manifest.json diff --git a/example/web/sql-wasm.js b/packages/flutter_widgets/example/web/sql-wasm.js similarity index 100% rename from example/web/sql-wasm.js rename to packages/flutter_widgets/example/web/sql-wasm.js diff --git a/example/web/sql-wasm.wasm b/packages/flutter_widgets/example/web/sql-wasm.wasm similarity index 100% rename from example/web/sql-wasm.wasm rename to packages/flutter_widgets/example/web/sql-wasm.wasm diff --git a/images/giphy_icon.png b/packages/flutter_widgets/images/giphy_icon.png similarity index 100% rename from images/giphy_icon.png rename to packages/flutter_widgets/images/giphy_icon.png diff --git a/images/placeholder.png b/packages/flutter_widgets/images/placeholder.png similarity index 100% rename from images/placeholder.png rename to packages/flutter_widgets/images/placeholder.png diff --git a/lib/src/attachment_error.dart b/packages/flutter_widgets/lib/src/attachment_error.dart similarity index 100% rename from lib/src/attachment_error.dart rename to packages/flutter_widgets/lib/src/attachment_error.dart diff --git a/lib/src/attachment_title.dart b/packages/flutter_widgets/lib/src/attachment_title.dart similarity index 100% rename from lib/src/attachment_title.dart rename to packages/flutter_widgets/lib/src/attachment_title.dart diff --git a/lib/src/back_button.dart b/packages/flutter_widgets/lib/src/back_button.dart similarity index 100% rename from lib/src/back_button.dart rename to packages/flutter_widgets/lib/src/back_button.dart diff --git a/lib/src/channel_bottom_sheet.dart b/packages/flutter_widgets/lib/src/channel_bottom_sheet.dart similarity index 100% rename from lib/src/channel_bottom_sheet.dart rename to packages/flutter_widgets/lib/src/channel_bottom_sheet.dart diff --git a/lib/src/channel_file_display_screen.dart b/packages/flutter_widgets/lib/src/channel_file_display_screen.dart similarity index 100% rename from lib/src/channel_file_display_screen.dart rename to packages/flutter_widgets/lib/src/channel_file_display_screen.dart diff --git a/lib/src/channel_header.dart b/packages/flutter_widgets/lib/src/channel_header.dart similarity index 100% rename from lib/src/channel_header.dart rename to packages/flutter_widgets/lib/src/channel_header.dart diff --git a/lib/src/channel_image.dart b/packages/flutter_widgets/lib/src/channel_image.dart similarity index 100% rename from lib/src/channel_image.dart rename to packages/flutter_widgets/lib/src/channel_image.dart diff --git a/lib/src/channel_info.dart b/packages/flutter_widgets/lib/src/channel_info.dart similarity index 100% rename from lib/src/channel_info.dart rename to packages/flutter_widgets/lib/src/channel_info.dart diff --git a/lib/src/channel_list_header.dart b/packages/flutter_widgets/lib/src/channel_list_header.dart similarity index 100% rename from lib/src/channel_list_header.dart rename to packages/flutter_widgets/lib/src/channel_list_header.dart diff --git a/lib/src/channel_list_view.dart b/packages/flutter_widgets/lib/src/channel_list_view.dart similarity index 100% rename from lib/src/channel_list_view.dart rename to packages/flutter_widgets/lib/src/channel_list_view.dart diff --git a/lib/src/channel_media_display_screen.dart b/packages/flutter_widgets/lib/src/channel_media_display_screen.dart similarity index 100% rename from lib/src/channel_media_display_screen.dart rename to packages/flutter_widgets/lib/src/channel_media_display_screen.dart diff --git a/lib/src/channel_name.dart b/packages/flutter_widgets/lib/src/channel_name.dart similarity index 100% rename from lib/src/channel_name.dart rename to packages/flutter_widgets/lib/src/channel_name.dart diff --git a/lib/src/channel_preview.dart b/packages/flutter_widgets/lib/src/channel_preview.dart similarity index 100% rename from lib/src/channel_preview.dart rename to packages/flutter_widgets/lib/src/channel_preview.dart diff --git a/lib/src/channel_unread_indicator.dart b/packages/flutter_widgets/lib/src/channel_unread_indicator.dart similarity index 100% rename from lib/src/channel_unread_indicator.dart rename to packages/flutter_widgets/lib/src/channel_unread_indicator.dart diff --git a/lib/src/channels_bloc.dart b/packages/flutter_widgets/lib/src/channels_bloc.dart similarity index 100% rename from lib/src/channels_bloc.dart rename to packages/flutter_widgets/lib/src/channels_bloc.dart diff --git a/lib/src/compress_video_service.dart b/packages/flutter_widgets/lib/src/compress_video_service.dart similarity index 100% rename from lib/src/compress_video_service.dart rename to packages/flutter_widgets/lib/src/compress_video_service.dart diff --git a/lib/src/date_divider.dart b/packages/flutter_widgets/lib/src/date_divider.dart similarity index 100% rename from lib/src/date_divider.dart rename to packages/flutter_widgets/lib/src/date_divider.dart diff --git a/lib/src/deleted_message.dart b/packages/flutter_widgets/lib/src/deleted_message.dart similarity index 100% rename from lib/src/deleted_message.dart rename to packages/flutter_widgets/lib/src/deleted_message.dart diff --git a/lib/src/extension.dart b/packages/flutter_widgets/lib/src/extension.dart similarity index 100% rename from lib/src/extension.dart rename to packages/flutter_widgets/lib/src/extension.dart diff --git a/lib/src/file_attachment.dart b/packages/flutter_widgets/lib/src/file_attachment.dart similarity index 100% rename from lib/src/file_attachment.dart rename to packages/flutter_widgets/lib/src/file_attachment.dart diff --git a/lib/src/full_screen_media.dart b/packages/flutter_widgets/lib/src/full_screen_media.dart similarity index 100% rename from lib/src/full_screen_media.dart rename to packages/flutter_widgets/lib/src/full_screen_media.dart diff --git a/lib/src/giphy_attachment.dart b/packages/flutter_widgets/lib/src/giphy_attachment.dart similarity index 100% rename from lib/src/giphy_attachment.dart rename to packages/flutter_widgets/lib/src/giphy_attachment.dart diff --git a/lib/src/group_image.dart b/packages/flutter_widgets/lib/src/group_image.dart similarity index 100% rename from lib/src/group_image.dart rename to packages/flutter_widgets/lib/src/group_image.dart diff --git a/lib/src/image_actions_modal.dart b/packages/flutter_widgets/lib/src/image_actions_modal.dart similarity index 100% rename from lib/src/image_actions_modal.dart rename to packages/flutter_widgets/lib/src/image_actions_modal.dart diff --git a/lib/src/image_attachment.dart b/packages/flutter_widgets/lib/src/image_attachment.dart similarity index 100% rename from lib/src/image_attachment.dart rename to packages/flutter_widgets/lib/src/image_attachment.dart diff --git a/lib/src/image_footer.dart b/packages/flutter_widgets/lib/src/image_footer.dart similarity index 100% rename from lib/src/image_footer.dart rename to packages/flutter_widgets/lib/src/image_footer.dart diff --git a/lib/src/image_group.dart b/packages/flutter_widgets/lib/src/image_group.dart similarity index 100% rename from lib/src/image_group.dart rename to packages/flutter_widgets/lib/src/image_group.dart diff --git a/lib/src/image_header.dart b/packages/flutter_widgets/lib/src/image_header.dart similarity index 100% rename from lib/src/image_header.dart rename to packages/flutter_widgets/lib/src/image_header.dart diff --git a/lib/src/lazy_load_scroll_view.dart b/packages/flutter_widgets/lib/src/lazy_load_scroll_view.dart similarity index 100% rename from lib/src/lazy_load_scroll_view.dart rename to packages/flutter_widgets/lib/src/lazy_load_scroll_view.dart diff --git a/lib/src/media_list_view.dart b/packages/flutter_widgets/lib/src/media_list_view.dart similarity index 100% rename from lib/src/media_list_view.dart rename to packages/flutter_widgets/lib/src/media_list_view.dart diff --git a/lib/src/media_utils.dart b/packages/flutter_widgets/lib/src/media_utils.dart similarity index 100% rename from lib/src/media_utils.dart rename to packages/flutter_widgets/lib/src/media_utils.dart diff --git a/lib/src/message_actions_modal.dart b/packages/flutter_widgets/lib/src/message_actions_modal.dart similarity index 100% rename from lib/src/message_actions_modal.dart rename to packages/flutter_widgets/lib/src/message_actions_modal.dart diff --git a/lib/src/message_input.dart b/packages/flutter_widgets/lib/src/message_input.dart similarity index 100% rename from lib/src/message_input.dart rename to packages/flutter_widgets/lib/src/message_input.dart diff --git a/lib/src/message_list_view.dart b/packages/flutter_widgets/lib/src/message_list_view.dart similarity index 100% rename from lib/src/message_list_view.dart rename to packages/flutter_widgets/lib/src/message_list_view.dart diff --git a/lib/src/message_reactions_modal.dart b/packages/flutter_widgets/lib/src/message_reactions_modal.dart similarity index 100% rename from lib/src/message_reactions_modal.dart rename to packages/flutter_widgets/lib/src/message_reactions_modal.dart diff --git a/lib/src/message_search_bloc.dart b/packages/flutter_widgets/lib/src/message_search_bloc.dart similarity index 100% rename from lib/src/message_search_bloc.dart rename to packages/flutter_widgets/lib/src/message_search_bloc.dart diff --git a/lib/src/message_search_item.dart b/packages/flutter_widgets/lib/src/message_search_item.dart similarity index 100% rename from lib/src/message_search_item.dart rename to packages/flutter_widgets/lib/src/message_search_item.dart diff --git a/lib/src/message_search_list_view.dart b/packages/flutter_widgets/lib/src/message_search_list_view.dart similarity index 100% rename from lib/src/message_search_list_view.dart rename to packages/flutter_widgets/lib/src/message_search_list_view.dart diff --git a/lib/src/message_text.dart b/packages/flutter_widgets/lib/src/message_text.dart similarity index 100% rename from lib/src/message_text.dart rename to packages/flutter_widgets/lib/src/message_text.dart diff --git a/lib/src/message_widget.dart b/packages/flutter_widgets/lib/src/message_widget.dart similarity index 100% rename from lib/src/message_widget.dart rename to packages/flutter_widgets/lib/src/message_widget.dart diff --git a/lib/src/option_list_tile.dart b/packages/flutter_widgets/lib/src/option_list_tile.dart similarity index 100% rename from lib/src/option_list_tile.dart rename to packages/flutter_widgets/lib/src/option_list_tile.dart diff --git a/lib/src/quoted_message_widget.dart b/packages/flutter_widgets/lib/src/quoted_message_widget.dart similarity index 100% rename from lib/src/quoted_message_widget.dart rename to packages/flutter_widgets/lib/src/quoted_message_widget.dart diff --git a/lib/src/reaction_bubble.dart b/packages/flutter_widgets/lib/src/reaction_bubble.dart similarity index 100% rename from lib/src/reaction_bubble.dart rename to packages/flutter_widgets/lib/src/reaction_bubble.dart diff --git a/lib/src/reaction_icon.dart b/packages/flutter_widgets/lib/src/reaction_icon.dart similarity index 100% rename from lib/src/reaction_icon.dart rename to packages/flutter_widgets/lib/src/reaction_icon.dart diff --git a/lib/src/reaction_picker.dart b/packages/flutter_widgets/lib/src/reaction_picker.dart similarity index 100% rename from lib/src/reaction_picker.dart rename to packages/flutter_widgets/lib/src/reaction_picker.dart diff --git a/lib/src/sending_indicator.dart b/packages/flutter_widgets/lib/src/sending_indicator.dart similarity index 100% rename from lib/src/sending_indicator.dart rename to packages/flutter_widgets/lib/src/sending_indicator.dart diff --git a/lib/src/stream_channel.dart b/packages/flutter_widgets/lib/src/stream_channel.dart similarity index 100% rename from lib/src/stream_channel.dart rename to packages/flutter_widgets/lib/src/stream_channel.dart diff --git a/lib/src/stream_chat.dart b/packages/flutter_widgets/lib/src/stream_chat.dart similarity index 100% rename from lib/src/stream_chat.dart rename to packages/flutter_widgets/lib/src/stream_chat.dart diff --git a/lib/src/stream_chat_theme.dart b/packages/flutter_widgets/lib/src/stream_chat_theme.dart similarity index 100% rename from lib/src/stream_chat_theme.dart rename to packages/flutter_widgets/lib/src/stream_chat_theme.dart diff --git a/lib/src/stream_neumorphic_button.dart b/packages/flutter_widgets/lib/src/stream_neumorphic_button.dart similarity index 100% rename from lib/src/stream_neumorphic_button.dart rename to packages/flutter_widgets/lib/src/stream_neumorphic_button.dart diff --git a/lib/src/stream_svg_icon.dart b/packages/flutter_widgets/lib/src/stream_svg_icon.dart similarity index 100% rename from lib/src/stream_svg_icon.dart rename to packages/flutter_widgets/lib/src/stream_svg_icon.dart diff --git a/lib/src/swipeable.dart b/packages/flutter_widgets/lib/src/swipeable.dart similarity index 100% rename from lib/src/swipeable.dart rename to packages/flutter_widgets/lib/src/swipeable.dart diff --git a/lib/src/system_message.dart b/packages/flutter_widgets/lib/src/system_message.dart similarity index 100% rename from lib/src/system_message.dart rename to packages/flutter_widgets/lib/src/system_message.dart diff --git a/lib/src/thread_header.dart b/packages/flutter_widgets/lib/src/thread_header.dart similarity index 100% rename from lib/src/thread_header.dart rename to packages/flutter_widgets/lib/src/thread_header.dart diff --git a/lib/src/typing_indicator.dart b/packages/flutter_widgets/lib/src/typing_indicator.dart similarity index 100% rename from lib/src/typing_indicator.dart rename to packages/flutter_widgets/lib/src/typing_indicator.dart diff --git a/lib/src/unread_indicator.dart b/packages/flutter_widgets/lib/src/unread_indicator.dart similarity index 100% rename from lib/src/unread_indicator.dart rename to packages/flutter_widgets/lib/src/unread_indicator.dart diff --git a/lib/src/url_attachment.dart b/packages/flutter_widgets/lib/src/url_attachment.dart similarity index 100% rename from lib/src/url_attachment.dart rename to packages/flutter_widgets/lib/src/url_attachment.dart diff --git a/lib/src/user_avatar.dart b/packages/flutter_widgets/lib/src/user_avatar.dart similarity index 100% rename from lib/src/user_avatar.dart rename to packages/flutter_widgets/lib/src/user_avatar.dart diff --git a/lib/src/user_item.dart b/packages/flutter_widgets/lib/src/user_item.dart similarity index 100% rename from lib/src/user_item.dart rename to packages/flutter_widgets/lib/src/user_item.dart diff --git a/lib/src/user_list_view.dart b/packages/flutter_widgets/lib/src/user_list_view.dart similarity index 100% rename from lib/src/user_list_view.dart rename to packages/flutter_widgets/lib/src/user_list_view.dart diff --git a/lib/src/user_reaction_display.dart b/packages/flutter_widgets/lib/src/user_reaction_display.dart similarity index 100% rename from lib/src/user_reaction_display.dart rename to packages/flutter_widgets/lib/src/user_reaction_display.dart diff --git a/lib/src/users_bloc.dart b/packages/flutter_widgets/lib/src/users_bloc.dart similarity index 100% rename from lib/src/users_bloc.dart rename to packages/flutter_widgets/lib/src/users_bloc.dart diff --git a/lib/src/utils.dart b/packages/flutter_widgets/lib/src/utils.dart similarity index 100% rename from lib/src/utils.dart rename to packages/flutter_widgets/lib/src/utils.dart diff --git a/lib/src/video_attachment.dart b/packages/flutter_widgets/lib/src/video_attachment.dart similarity index 100% rename from lib/src/video_attachment.dart rename to packages/flutter_widgets/lib/src/video_attachment.dart diff --git a/lib/stream_chat_flutter.dart b/packages/flutter_widgets/lib/stream_chat_flutter.dart similarity index 100% rename from lib/stream_chat_flutter.dart rename to packages/flutter_widgets/lib/stream_chat_flutter.dart diff --git a/lib/svgs/Empty State_Camera.svg b/packages/flutter_widgets/lib/svgs/Empty State_Camera.svg similarity index 100% rename from lib/svgs/Empty State_Camera.svg rename to packages/flutter_widgets/lib/svgs/Empty State_Camera.svg diff --git a/lib/svgs/Empty State_Files.svg b/packages/flutter_widgets/lib/svgs/Empty State_Files.svg similarity index 100% rename from lib/svgs/Empty State_Files.svg rename to packages/flutter_widgets/lib/svgs/Empty State_Files.svg diff --git a/lib/svgs/Empty State_No channel.svg b/packages/flutter_widgets/lib/svgs/Empty State_No channel.svg similarity index 100% rename from lib/svgs/Empty State_No channel.svg rename to packages/flutter_widgets/lib/svgs/Empty State_No channel.svg diff --git a/lib/svgs/Empty State_Search.svg b/packages/flutter_widgets/lib/svgs/Empty State_Search.svg similarity index 100% rename from lib/svgs/Empty State_Search.svg rename to packages/flutter_widgets/lib/svgs/Empty State_Search.svg diff --git a/lib/svgs/Empty State_picture.svg b/packages/flutter_widgets/lib/svgs/Empty State_picture.svg similarity index 100% rename from lib/svgs/Empty State_picture.svg rename to packages/flutter_widgets/lib/svgs/Empty State_picture.svg diff --git a/lib/svgs/Giphy icon.svg b/packages/flutter_widgets/lib/svgs/Giphy icon.svg similarity index 100% rename from lib/svgs/Giphy icon.svg rename to packages/flutter_widgets/lib/svgs/Giphy icon.svg diff --git a/lib/svgs/Icon_LOL_reaction.svg b/packages/flutter_widgets/lib/svgs/Icon_LOL_reaction.svg similarity index 100% rename from lib/svgs/Icon_LOL_reaction.svg rename to packages/flutter_widgets/lib/svgs/Icon_LOL_reaction.svg diff --git a/lib/svgs/Icon_Thread_Reply.svg b/packages/flutter_widgets/lib/svgs/Icon_Thread_Reply.svg similarity index 100% rename from lib/svgs/Icon_Thread_Reply.svg rename to packages/flutter_widgets/lib/svgs/Icon_Thread_Reply.svg diff --git a/lib/svgs/Icon_User_add.svg b/packages/flutter_widgets/lib/svgs/Icon_User_add.svg similarity index 100% rename from lib/svgs/Icon_User_add.svg rename to packages/flutter_widgets/lib/svgs/Icon_User_add.svg diff --git a/lib/svgs/Icon_User_deselect.svg b/packages/flutter_widgets/lib/svgs/Icon_User_deselect.svg similarity index 100% rename from lib/svgs/Icon_User_deselect.svg rename to packages/flutter_widgets/lib/svgs/Icon_User_deselect.svg diff --git a/lib/svgs/Icon_arrow_right.svg b/packages/flutter_widgets/lib/svgs/Icon_arrow_right.svg similarity index 100% rename from lib/svgs/Icon_arrow_right.svg rename to packages/flutter_widgets/lib/svgs/Icon_arrow_right.svg diff --git a/lib/svgs/Icon_attach.svg b/packages/flutter_widgets/lib/svgs/Icon_attach.svg similarity index 100% rename from lib/svgs/Icon_attach.svg rename to packages/flutter_widgets/lib/svgs/Icon_attach.svg diff --git a/lib/svgs/Icon_camera.svg b/packages/flutter_widgets/lib/svgs/Icon_camera.svg similarity index 100% rename from lib/svgs/Icon_camera.svg rename to packages/flutter_widgets/lib/svgs/Icon_camera.svg diff --git a/lib/svgs/Icon_check.svg b/packages/flutter_widgets/lib/svgs/Icon_check.svg similarity index 100% rename from lib/svgs/Icon_check.svg rename to packages/flutter_widgets/lib/svgs/Icon_check.svg diff --git a/lib/svgs/Icon_check_all.svg b/packages/flutter_widgets/lib/svgs/Icon_check_all.svg similarity index 100% rename from lib/svgs/Icon_check_all.svg rename to packages/flutter_widgets/lib/svgs/Icon_check_all.svg diff --git a/lib/svgs/Icon_check_big.svg b/packages/flutter_widgets/lib/svgs/Icon_check_big.svg similarity index 100% rename from lib/svgs/Icon_check_big.svg rename to packages/flutter_widgets/lib/svgs/Icon_check_big.svg diff --git a/lib/svgs/Icon_check_send.svg b/packages/flutter_widgets/lib/svgs/Icon_check_send.svg similarity index 100% rename from lib/svgs/Icon_check_send.svg rename to packages/flutter_widgets/lib/svgs/Icon_check_send.svg diff --git a/lib/svgs/Icon_circle_right.svg b/packages/flutter_widgets/lib/svgs/Icon_circle_right.svg similarity index 100% rename from lib/svgs/Icon_circle_right.svg rename to packages/flutter_widgets/lib/svgs/Icon_circle_right.svg diff --git a/lib/svgs/Icon_circle_up.svg b/packages/flutter_widgets/lib/svgs/Icon_circle_up.svg similarity index 100% rename from lib/svgs/Icon_circle_up.svg rename to packages/flutter_widgets/lib/svgs/Icon_circle_up.svg diff --git a/lib/svgs/Icon_close.svg b/packages/flutter_widgets/lib/svgs/Icon_close.svg similarity index 100% rename from lib/svgs/Icon_close.svg rename to packages/flutter_widgets/lib/svgs/Icon_close.svg diff --git a/lib/svgs/Icon_close_black.svg b/packages/flutter_widgets/lib/svgs/Icon_close_black.svg similarity index 100% rename from lib/svgs/Icon_close_black.svg rename to packages/flutter_widgets/lib/svgs/Icon_close_black.svg diff --git a/lib/svgs/Icon_close_sml.svg b/packages/flutter_widgets/lib/svgs/Icon_close_sml.svg similarity index 100% rename from lib/svgs/Icon_close_sml.svg rename to packages/flutter_widgets/lib/svgs/Icon_close_sml.svg diff --git a/lib/svgs/Icon_cloud_download.svg b/packages/flutter_widgets/lib/svgs/Icon_cloud_download.svg similarity index 100% rename from lib/svgs/Icon_cloud_download.svg rename to packages/flutter_widgets/lib/svgs/Icon_cloud_download.svg diff --git a/lib/svgs/Icon_contacts.svg b/packages/flutter_widgets/lib/svgs/Icon_contacts.svg similarity index 100% rename from lib/svgs/Icon_contacts.svg rename to packages/flutter_widgets/lib/svgs/Icon_contacts.svg diff --git a/lib/svgs/Icon_copy.svg b/packages/flutter_widgets/lib/svgs/Icon_copy.svg similarity index 100% rename from lib/svgs/Icon_copy.svg rename to packages/flutter_widgets/lib/svgs/Icon_copy.svg diff --git a/lib/svgs/Icon_curve_line_left_up.svg b/packages/flutter_widgets/lib/svgs/Icon_curve_line_left_up.svg similarity index 100% rename from lib/svgs/Icon_curve_line_left_up.svg rename to packages/flutter_widgets/lib/svgs/Icon_curve_line_left_up.svg diff --git a/lib/svgs/Icon_curve_line_left_up_big.svg b/packages/flutter_widgets/lib/svgs/Icon_curve_line_left_up_big.svg similarity index 100% rename from lib/svgs/Icon_curve_line_left_up_big.svg rename to packages/flutter_widgets/lib/svgs/Icon_curve_line_left_up_big.svg diff --git a/lib/svgs/Icon_delete.svg b/packages/flutter_widgets/lib/svgs/Icon_delete.svg similarity index 100% rename from lib/svgs/Icon_delete.svg rename to packages/flutter_widgets/lib/svgs/Icon_delete.svg diff --git a/lib/svgs/Icon_down.svg b/packages/flutter_widgets/lib/svgs/Icon_down.svg similarity index 100% rename from lib/svgs/Icon_down.svg rename to packages/flutter_widgets/lib/svgs/Icon_down.svg diff --git a/lib/svgs/Icon_download.svg b/packages/flutter_widgets/lib/svgs/Icon_download.svg similarity index 100% rename from lib/svgs/Icon_download.svg rename to packages/flutter_widgets/lib/svgs/Icon_download.svg diff --git a/lib/svgs/Icon_edit.svg b/packages/flutter_widgets/lib/svgs/Icon_edit.svg similarity index 100% rename from lib/svgs/Icon_edit.svg rename to packages/flutter_widgets/lib/svgs/Icon_edit.svg diff --git a/lib/svgs/Icon_empty_circle_left.svg b/packages/flutter_widgets/lib/svgs/Icon_empty_circle_left.svg similarity index 100% rename from lib/svgs/Icon_empty_circle_left.svg rename to packages/flutter_widgets/lib/svgs/Icon_empty_circle_left.svg diff --git a/lib/svgs/Icon_error.svg b/packages/flutter_widgets/lib/svgs/Icon_error.svg similarity index 100% rename from lib/svgs/Icon_error.svg rename to packages/flutter_widgets/lib/svgs/Icon_error.svg diff --git a/lib/svgs/Icon_eye-off.svg b/packages/flutter_widgets/lib/svgs/Icon_eye-off.svg similarity index 100% rename from lib/svgs/Icon_eye-off.svg rename to packages/flutter_widgets/lib/svgs/Icon_eye-off.svg diff --git a/lib/svgs/Icon_grid.svg b/packages/flutter_widgets/lib/svgs/Icon_grid.svg similarity index 100% rename from lib/svgs/Icon_grid.svg rename to packages/flutter_widgets/lib/svgs/Icon_grid.svg diff --git a/lib/svgs/Icon_group.svg b/packages/flutter_widgets/lib/svgs/Icon_group.svg similarity index 100% rename from lib/svgs/Icon_group.svg rename to packages/flutter_widgets/lib/svgs/Icon_group.svg diff --git a/lib/svgs/Icon_left.svg b/packages/flutter_widgets/lib/svgs/Icon_left.svg similarity index 100% rename from lib/svgs/Icon_left.svg rename to packages/flutter_widgets/lib/svgs/Icon_left.svg diff --git a/lib/svgs/Icon_lightning-command runner.svg b/packages/flutter_widgets/lib/svgs/Icon_lightning-command runner.svg similarity index 100% rename from lib/svgs/Icon_lightning-command runner.svg rename to packages/flutter_widgets/lib/svgs/Icon_lightning-command runner.svg diff --git a/lib/svgs/Icon_love_reaction.svg b/packages/flutter_widgets/lib/svgs/Icon_love_reaction.svg similarity index 100% rename from lib/svgs/Icon_love_reaction.svg rename to packages/flutter_widgets/lib/svgs/Icon_love_reaction.svg diff --git a/lib/svgs/Icon_menu_point_v.svg b/packages/flutter_widgets/lib/svgs/Icon_menu_point_v.svg similarity index 100% rename from lib/svgs/Icon_menu_point_v.svg rename to packages/flutter_widgets/lib/svgs/Icon_menu_point_v.svg diff --git a/lib/svgs/Icon_message.svg b/packages/flutter_widgets/lib/svgs/Icon_message.svg similarity index 100% rename from lib/svgs/Icon_message.svg rename to packages/flutter_widgets/lib/svgs/Icon_message.svg diff --git a/lib/svgs/Icon_mute.svg b/packages/flutter_widgets/lib/svgs/Icon_mute.svg similarity index 100% rename from lib/svgs/Icon_mute.svg rename to packages/flutter_widgets/lib/svgs/Icon_mute.svg diff --git a/lib/svgs/Icon_notification.svg b/packages/flutter_widgets/lib/svgs/Icon_notification.svg similarity index 100% rename from lib/svgs/Icon_notification.svg rename to packages/flutter_widgets/lib/svgs/Icon_notification.svg diff --git a/lib/svgs/Icon_pen-write.svg b/packages/flutter_widgets/lib/svgs/Icon_pen-write.svg similarity index 100% rename from lib/svgs/Icon_pen-write.svg rename to packages/flutter_widgets/lib/svgs/Icon_pen-write.svg diff --git a/lib/svgs/Icon_record.svg b/packages/flutter_widgets/lib/svgs/Icon_record.svg similarity index 100% rename from lib/svgs/Icon_record.svg rename to packages/flutter_widgets/lib/svgs/Icon_record.svg diff --git a/lib/svgs/Icon_right.svg b/packages/flutter_widgets/lib/svgs/Icon_right.svg similarity index 100% rename from lib/svgs/Icon_right.svg rename to packages/flutter_widgets/lib/svgs/Icon_right.svg diff --git a/lib/svgs/Icon_save.svg b/packages/flutter_widgets/lib/svgs/Icon_save.svg similarity index 100% rename from lib/svgs/Icon_save.svg rename to packages/flutter_widgets/lib/svgs/Icon_save.svg diff --git a/lib/svgs/Icon_search.svg b/packages/flutter_widgets/lib/svgs/Icon_search.svg similarity index 100% rename from lib/svgs/Icon_search.svg rename to packages/flutter_widgets/lib/svgs/Icon_search.svg diff --git a/lib/svgs/Icon_send_message.svg b/packages/flutter_widgets/lib/svgs/Icon_send_message.svg similarity index 100% rename from lib/svgs/Icon_send_message.svg rename to packages/flutter_widgets/lib/svgs/Icon_send_message.svg diff --git a/lib/svgs/Icon_smile.svg b/packages/flutter_widgets/lib/svgs/Icon_smile.svg similarity index 100% rename from lib/svgs/Icon_smile.svg rename to packages/flutter_widgets/lib/svgs/Icon_smile.svg diff --git a/lib/svgs/Icon_thumbs_down_reaction.svg b/packages/flutter_widgets/lib/svgs/Icon_thumbs_down_reaction.svg similarity index 100% rename from lib/svgs/Icon_thumbs_down_reaction.svg rename to packages/flutter_widgets/lib/svgs/Icon_thumbs_down_reaction.svg diff --git a/lib/svgs/Icon_thumbs_up_reaction.svg b/packages/flutter_widgets/lib/svgs/Icon_thumbs_up_reaction.svg similarity index 100% rename from lib/svgs/Icon_thumbs_up_reaction.svg rename to packages/flutter_widgets/lib/svgs/Icon_thumbs_up_reaction.svg diff --git a/lib/svgs/Icon_time.svg b/packages/flutter_widgets/lib/svgs/Icon_time.svg similarity index 100% rename from lib/svgs/Icon_time.svg rename to packages/flutter_widgets/lib/svgs/Icon_time.svg diff --git a/lib/svgs/Icon_user.svg b/packages/flutter_widgets/lib/svgs/Icon_user.svg similarity index 100% rename from lib/svgs/Icon_user.svg rename to packages/flutter_widgets/lib/svgs/Icon_user.svg diff --git a/lib/svgs/Icon_user_delete.svg b/packages/flutter_widgets/lib/svgs/Icon_user_delete.svg similarity index 100% rename from lib/svgs/Icon_user_delete.svg rename to packages/flutter_widgets/lib/svgs/Icon_user_delete.svg diff --git a/lib/svgs/Icon_user_settings.svg b/packages/flutter_widgets/lib/svgs/Icon_user_settings.svg similarity index 100% rename from lib/svgs/Icon_user_settings.svg rename to packages/flutter_widgets/lib/svgs/Icon_user_settings.svg diff --git a/lib/svgs/Icon_wut_reaction.svg b/packages/flutter_widgets/lib/svgs/Icon_wut_reaction.svg similarity index 100% rename from lib/svgs/Icon_wut_reaction.svg rename to packages/flutter_widgets/lib/svgs/Icon_wut_reaction.svg diff --git a/lib/svgs/STREAM MARK 1.svg b/packages/flutter_widgets/lib/svgs/STREAM MARK 1.svg similarity index 100% rename from lib/svgs/STREAM MARK 1.svg rename to packages/flutter_widgets/lib/svgs/STREAM MARK 1.svg diff --git a/lib/svgs/UI_Reverse Pagination Loading.svg b/packages/flutter_widgets/lib/svgs/UI_Reverse Pagination Loading.svg similarity index 100% rename from lib/svgs/UI_Reverse Pagination Loading.svg rename to packages/flutter_widgets/lib/svgs/UI_Reverse Pagination Loading.svg diff --git a/lib/svgs/eye-line_big.svg b/packages/flutter_widgets/lib/svgs/eye-line_big.svg similarity index 100% rename from lib/svgs/eye-line_big.svg rename to packages/flutter_widgets/lib/svgs/eye-line_big.svg diff --git a/lib/svgs/files.svg b/packages/flutter_widgets/lib/svgs/files.svg similarity index 100% rename from lib/svgs/files.svg rename to packages/flutter_widgets/lib/svgs/files.svg diff --git a/lib/svgs/filetype_7z.svg b/packages/flutter_widgets/lib/svgs/filetype_7z.svg similarity index 100% rename from lib/svgs/filetype_7z.svg rename to packages/flutter_widgets/lib/svgs/filetype_7z.svg diff --git a/lib/svgs/filetype_CSV.svg b/packages/flutter_widgets/lib/svgs/filetype_CSV.svg similarity index 100% rename from lib/svgs/filetype_CSV.svg rename to packages/flutter_widgets/lib/svgs/filetype_CSV.svg diff --git a/lib/svgs/filetype_DOC.svg b/packages/flutter_widgets/lib/svgs/filetype_DOC.svg similarity index 100% rename from lib/svgs/filetype_DOC.svg rename to packages/flutter_widgets/lib/svgs/filetype_DOC.svg diff --git a/lib/svgs/filetype_DOCX.svg b/packages/flutter_widgets/lib/svgs/filetype_DOCX.svg similarity index 100% rename from lib/svgs/filetype_DOCX.svg rename to packages/flutter_widgets/lib/svgs/filetype_DOCX.svg diff --git a/lib/svgs/filetype_Generic.svg b/packages/flutter_widgets/lib/svgs/filetype_Generic.svg similarity index 100% rename from lib/svgs/filetype_Generic.svg rename to packages/flutter_widgets/lib/svgs/filetype_Generic.svg diff --git a/lib/svgs/filetype_MD.svg b/packages/flutter_widgets/lib/svgs/filetype_MD.svg similarity index 100% rename from lib/svgs/filetype_MD.svg rename to packages/flutter_widgets/lib/svgs/filetype_MD.svg diff --git a/lib/svgs/filetype_ODT.svg b/packages/flutter_widgets/lib/svgs/filetype_ODT.svg similarity index 100% rename from lib/svgs/filetype_ODT.svg rename to packages/flutter_widgets/lib/svgs/filetype_ODT.svg diff --git a/lib/svgs/filetype_PDF.svg b/packages/flutter_widgets/lib/svgs/filetype_PDF.svg similarity index 100% rename from lib/svgs/filetype_PDF.svg rename to packages/flutter_widgets/lib/svgs/filetype_PDF.svg diff --git a/lib/svgs/filetype_PPT.svg b/packages/flutter_widgets/lib/svgs/filetype_PPT.svg similarity index 100% rename from lib/svgs/filetype_PPT.svg rename to packages/flutter_widgets/lib/svgs/filetype_PPT.svg diff --git a/lib/svgs/filetype_PPTX-1.svg b/packages/flutter_widgets/lib/svgs/filetype_PPTX-1.svg similarity index 100% rename from lib/svgs/filetype_PPTX-1.svg rename to packages/flutter_widgets/lib/svgs/filetype_PPTX-1.svg diff --git a/lib/svgs/filetype_PPTX.svg b/packages/flutter_widgets/lib/svgs/filetype_PPTX.svg similarity index 100% rename from lib/svgs/filetype_PPTX.svg rename to packages/flutter_widgets/lib/svgs/filetype_PPTX.svg diff --git a/lib/svgs/filetype_RAR.svg b/packages/flutter_widgets/lib/svgs/filetype_RAR.svg similarity index 100% rename from lib/svgs/filetype_RAR.svg rename to packages/flutter_widgets/lib/svgs/filetype_RAR.svg diff --git a/lib/svgs/filetype_RTF.svg b/packages/flutter_widgets/lib/svgs/filetype_RTF.svg similarity index 100% rename from lib/svgs/filetype_RTF.svg rename to packages/flutter_widgets/lib/svgs/filetype_RTF.svg diff --git a/lib/svgs/filetype_TAR.svg b/packages/flutter_widgets/lib/svgs/filetype_TAR.svg similarity index 100% rename from lib/svgs/filetype_TAR.svg rename to packages/flutter_widgets/lib/svgs/filetype_TAR.svg diff --git a/lib/svgs/filetype_TXT.svg b/packages/flutter_widgets/lib/svgs/filetype_TXT.svg similarity index 100% rename from lib/svgs/filetype_TXT.svg rename to packages/flutter_widgets/lib/svgs/filetype_TXT.svg diff --git a/lib/svgs/filetype_XLS.svg b/packages/flutter_widgets/lib/svgs/filetype_XLS.svg similarity index 100% rename from lib/svgs/filetype_XLS.svg rename to packages/flutter_widgets/lib/svgs/filetype_XLS.svg diff --git a/lib/svgs/filetype_XLSX.svg b/packages/flutter_widgets/lib/svgs/filetype_XLSX.svg similarity index 100% rename from lib/svgs/filetype_XLSX.svg rename to packages/flutter_widgets/lib/svgs/filetype_XLSX.svg diff --git a/lib/svgs/filetype_ZIP.svg b/packages/flutter_widgets/lib/svgs/filetype_ZIP.svg similarity index 100% rename from lib/svgs/filetype_ZIP.svg rename to packages/flutter_widgets/lib/svgs/filetype_ZIP.svg diff --git a/lib/svgs/filetype_html.svg b/packages/flutter_widgets/lib/svgs/filetype_html.svg similarity index 100% rename from lib/svgs/filetype_html.svg rename to packages/flutter_widgets/lib/svgs/filetype_html.svg diff --git a/lib/svgs/giphy icon blue.svg b/packages/flutter_widgets/lib/svgs/giphy icon blue.svg similarity index 100% rename from lib/svgs/giphy icon blue.svg rename to packages/flutter_widgets/lib/svgs/giphy icon blue.svg diff --git a/lib/svgs/icon_SHARE.svg b/packages/flutter_widgets/lib/svgs/icon_SHARE.svg similarity index 100% rename from lib/svgs/icon_SHARE.svg rename to packages/flutter_widgets/lib/svgs/icon_SHARE.svg diff --git a/lib/svgs/icon_delete_grey.svg b/packages/flutter_widgets/lib/svgs/icon_delete_grey.svg similarity index 100% rename from lib/svgs/icon_delete_grey.svg rename to packages/flutter_widgets/lib/svgs/icon_delete_grey.svg diff --git a/lib/svgs/icon_mentions.svg b/packages/flutter_widgets/lib/svgs/icon_mentions.svg similarity index 100% rename from lib/svgs/icon_mentions.svg rename to packages/flutter_widgets/lib/svgs/icon_mentions.svg diff --git a/lib/svgs/mentions.svg b/packages/flutter_widgets/lib/svgs/mentions.svg similarity index 100% rename from lib/svgs/mentions.svg rename to packages/flutter_widgets/lib/svgs/mentions.svg diff --git a/lib/svgs/pictures.svg b/packages/flutter_widgets/lib/svgs/pictures.svg similarity index 100% rename from lib/svgs/pictures.svg rename to packages/flutter_widgets/lib/svgs/pictures.svg diff --git a/lib/svgs/settings.svg b/packages/flutter_widgets/lib/svgs/settings.svg similarity index 100% rename from lib/svgs/settings.svg rename to packages/flutter_widgets/lib/svgs/settings.svg diff --git a/lib/svgs/share_arrow.svg b/packages/flutter_widgets/lib/svgs/share_arrow.svg similarity index 100% rename from lib/svgs/share_arrow.svg rename to packages/flutter_widgets/lib/svgs/share_arrow.svg diff --git a/pubspec.yaml b/packages/flutter_widgets/pubspec.yaml similarity index 100% rename from pubspec.yaml rename to packages/flutter_widgets/pubspec.yaml diff --git a/screenshots/channel_header.png b/packages/flutter_widgets/screenshots/channel_header.png similarity index 100% rename from screenshots/channel_header.png rename to packages/flutter_widgets/screenshots/channel_header.png diff --git a/screenshots/channel_header_paint.png b/packages/flutter_widgets/screenshots/channel_header_paint.png similarity index 100% rename from screenshots/channel_header_paint.png rename to packages/flutter_widgets/screenshots/channel_header_paint.png diff --git a/screenshots/channel_image.png b/packages/flutter_widgets/screenshots/channel_image.png similarity index 100% rename from screenshots/channel_image.png rename to packages/flutter_widgets/screenshots/channel_image.png diff --git a/screenshots/channel_image_paint.png b/packages/flutter_widgets/screenshots/channel_image_paint.png similarity index 100% rename from screenshots/channel_image_paint.png rename to packages/flutter_widgets/screenshots/channel_image_paint.png diff --git a/screenshots/channel_list_view.png b/packages/flutter_widgets/screenshots/channel_list_view.png similarity index 100% rename from screenshots/channel_list_view.png rename to packages/flutter_widgets/screenshots/channel_list_view.png diff --git a/screenshots/channel_list_view_paint.png b/packages/flutter_widgets/screenshots/channel_list_view_paint.png similarity index 100% rename from screenshots/channel_list_view_paint.png rename to packages/flutter_widgets/screenshots/channel_list_view_paint.png diff --git a/screenshots/channel_preview.png b/packages/flutter_widgets/screenshots/channel_preview.png similarity index 100% rename from screenshots/channel_preview.png rename to packages/flutter_widgets/screenshots/channel_preview.png diff --git a/screenshots/channel_preview_paint.png b/packages/flutter_widgets/screenshots/channel_preview_paint.png similarity index 100% rename from screenshots/channel_preview_paint.png rename to packages/flutter_widgets/screenshots/channel_preview_paint.png diff --git a/screenshots/message_input.png b/packages/flutter_widgets/screenshots/message_input.png similarity index 100% rename from screenshots/message_input.png rename to packages/flutter_widgets/screenshots/message_input.png diff --git a/screenshots/message_input2.png b/packages/flutter_widgets/screenshots/message_input2.png similarity index 100% rename from screenshots/message_input2.png rename to packages/flutter_widgets/screenshots/message_input2.png diff --git a/screenshots/message_input2_paint.png b/packages/flutter_widgets/screenshots/message_input2_paint.png similarity index 100% rename from screenshots/message_input2_paint.png rename to packages/flutter_widgets/screenshots/message_input2_paint.png diff --git a/screenshots/message_input_paint.png b/packages/flutter_widgets/screenshots/message_input_paint.png similarity index 100% rename from screenshots/message_input_paint.png rename to packages/flutter_widgets/screenshots/message_input_paint.png diff --git a/screenshots/message_listview.png b/packages/flutter_widgets/screenshots/message_listview.png similarity index 100% rename from screenshots/message_listview.png rename to packages/flutter_widgets/screenshots/message_listview.png diff --git a/screenshots/message_listview_paint.png b/packages/flutter_widgets/screenshots/message_listview_paint.png similarity index 100% rename from screenshots/message_listview_paint.png rename to packages/flutter_widgets/screenshots/message_listview_paint.png diff --git a/screenshots/message_widget.png b/packages/flutter_widgets/screenshots/message_widget.png similarity index 100% rename from screenshots/message_widget.png rename to packages/flutter_widgets/screenshots/message_widget.png diff --git a/screenshots/message_widget_paint.png b/packages/flutter_widgets/screenshots/message_widget_paint.png similarity index 100% rename from screenshots/message_widget_paint.png rename to packages/flutter_widgets/screenshots/message_widget_paint.png diff --git a/screenshots/reaction_picker.png b/packages/flutter_widgets/screenshots/reaction_picker.png similarity index 100% rename from screenshots/reaction_picker.png rename to packages/flutter_widgets/screenshots/reaction_picker.png diff --git a/screenshots/reaction_picker_paint.png b/packages/flutter_widgets/screenshots/reaction_picker_paint.png similarity index 100% rename from screenshots/reaction_picker_paint.png rename to packages/flutter_widgets/screenshots/reaction_picker_paint.png diff --git a/screenshots/thread_header.png b/packages/flutter_widgets/screenshots/thread_header.png similarity index 100% rename from screenshots/thread_header.png rename to packages/flutter_widgets/screenshots/thread_header.png diff --git a/screenshots/thread_header_paint.png b/packages/flutter_widgets/screenshots/thread_header_paint.png similarity index 100% rename from screenshots/thread_header_paint.png rename to packages/flutter_widgets/screenshots/thread_header_paint.png diff --git a/svgs/giphy_icon.svg b/packages/flutter_widgets/svgs/giphy_icon.svg similarity index 100% rename from svgs/giphy_icon.svg rename to packages/flutter_widgets/svgs/giphy_icon.svg diff --git a/svgs/icon_camera.svg b/packages/flutter_widgets/svgs/icon_camera.svg similarity index 100% rename from svgs/icon_camera.svg rename to packages/flutter_widgets/svgs/icon_camera.svg diff --git a/svgs/icon_pen_write.svg b/packages/flutter_widgets/svgs/icon_pen_write.svg similarity index 100% rename from svgs/icon_pen_write.svg rename to packages/flutter_widgets/svgs/icon_pen_write.svg diff --git a/svgs/icon_picture_empty_state.svg b/packages/flutter_widgets/svgs/icon_picture_empty_state.svg similarity index 100% rename from svgs/icon_picture_empty_state.svg rename to packages/flutter_widgets/svgs/icon_picture_empty_state.svg diff --git a/svgs/video_call_icon.svg b/packages/flutter_widgets/svgs/video_call_icon.svg similarity index 100% rename from svgs/video_call_icon.svg rename to packages/flutter_widgets/svgs/video_call_icon.svg diff --git a/test/src/channel_preview_test.dart b/packages/flutter_widgets/test/src/channel_preview_test.dart similarity index 100% rename from test/src/channel_preview_test.dart rename to packages/flutter_widgets/test/src/channel_preview_test.dart diff --git a/test/src/message_action_modal_test.dart b/packages/flutter_widgets/test/src/message_action_modal_test.dart similarity index 100% rename from test/src/message_action_modal_test.dart rename to packages/flutter_widgets/test/src/message_action_modal_test.dart diff --git a/test/src/message_reaction_modal_test.dart b/packages/flutter_widgets/test/src/message_reaction_modal_test.dart similarity index 100% rename from test/src/message_reaction_modal_test.dart rename to packages/flutter_widgets/test/src/message_reaction_modal_test.dart diff --git a/test/src/mocks.dart b/packages/flutter_widgets/test/src/mocks.dart similarity index 100% rename from test/src/mocks.dart rename to packages/flutter_widgets/test/src/mocks.dart diff --git a/test/src/reaction_bubble_test.dart b/packages/flutter_widgets/test/src/reaction_bubble_test.dart similarity index 100% rename from test/src/reaction_bubble_test.dart rename to packages/flutter_widgets/test/src/reaction_bubble_test.dart From 141cc55b056e839d97778fd11d1b59d3f76f0fb9 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Thu, 7 Jan 2021 17:04:53 +0100 Subject: [PATCH 0799/1140] fix chip text color --- example/pubspec.yaml | 2 +- lib/src/message_input.dart | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/example/pubspec.yaml b/example/pubspec.yaml index c5f52233..539166ec 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -1,6 +1,6 @@ name: example description: A new Flutter project. -version: 1.0.112+115 +version: 1.0.113+116 environment: sdk: ">=2.2.2 <3.0.0" diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index d9acda56..de0aa115 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -477,7 +477,7 @@ class MessageInputState extends State { mainAxisAlignment: MainAxisAlignment.center, children: [ StreamSvgIcon.lightning( - color: Colors.white, + color: Colors.white, size: 16.0, ), Text( From e7eb0a27f6b0746bc6419656fecd23b3deee29dc Mon Sep 17 00:00:00 2001 From: Neevash Ramdial Date: Thu, 7 Jan 2021 12:07:01 -0400 Subject: [PATCH 0800/1140] add melos files --- .gitignore | 92 +++++------- LICENSE | 219 ++++++++++++++++++++++++++++ README.md | 53 +++++++ analysis_options.yaml | 13 ++ melos.yaml | 59 ++++++++ packages/flutter_widgets/.gitignore | 65 +++++++++ 6 files changed, 447 insertions(+), 54 deletions(-) create mode 100644 LICENSE create mode 100644 README.md create mode 100644 analysis_options.yaml create mode 100644 melos.yaml create mode 100644 packages/flutter_widgets/.gitignore diff --git a/.gitignore b/.gitignore index 1d3bae26..0ce95373 100644 --- a/.gitignore +++ b/.gitignore @@ -1,65 +1,49 @@ -# Miscellaneous -*.class -*.log -*.pyc -*.swp .DS_Store .atom/ -.buildlog/ -.history -.svn/ - -# IntelliJ related -*.iml -*.ipr -*.iws .idea/ -# The .vscode folder contains launch configuration and tasks you configure in -# VS Code which you may wish to be included in version control, so this line -# is commented out by default. -#.vscode/ - -# Flutter/Dart/Pub related -**/doc/api/ -.dart_tool/ -.flutter-plugins -.flutter-plugins-dependencies .packages -.pub-cache/ .pub/ -/build/ -coverage/ -coverage_helper_test.dart - -# Web related -lib/generated_plugin_registrant.dart - -# Exceptions to above rules. -!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages -# See https://www.dartlang.org/guides/libraries/private-files - -# Files and directories created by pub .dart_tool/ -.packages -build/ -# If you're building an application, you may want to check-in your pubspec.lock pubspec.lock +flutter_export_environment.sh -# Directory created by dartdoc -# If you don't generate documentation locally you can remove this line. -doc/api/ +examples/all_plugins/pubspec.yaml -# Avoid committing generated Javascript files: -*.dart.js -*.info.json # Produced by the --dump-info flag. -*.js # When generated by dart2js. Don't specify *.js if your - # project includes source files written in JavaScript. -*.js_ -*.js.deps -*.js.map +Podfile +Podfile.lock +Pods/ +.symlinks/ +**/Flutter/App.framework/ +**/Flutter/ephemeral/ +**/Flutter/Flutter.framework/ +**/Flutter/Generated.xcconfig +**/Flutter/flutter_assets/ -fvm -google-services.json -example/ios/dist -.vscode/ \ No newline at end of file +ServiceDefinitions.json +xcuserdata/ +**/DerivedData/ + +local.properties +keystore.properties +.gradle/ +gradlew +gradlew.bat +gradle-wrapper.jar +.flutter-plugins-dependencies +*.iml + +generated_plugin_registrant.dart +GeneratedPluginRegistrant.h +GeneratedPluginRegistrant.m +GeneratedPluginRegistrant.java +GeneratedPluginRegistrant.swift +build/ +.flutter-plugins + +.project +.classpath +.settings +/.fvm + +.melos_tool/ \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 00000000..f2d1eaf3 --- /dev/null +++ b/LICENSE @@ -0,0 +1,219 @@ +SOURCE CODE LICENSE AGREEMENT + +IMPORTANT - READ THIS CAREFULLY BEFORE DOWNLOADING, INSTALLING, USING OR +ELECTRONICALLY ACCESSING THIS PROPRIETARY PRODUCT. + +THIS IS A LEGAL AGREEMENT BETWEEN STREAM.IO, INC. (“STREAM.IO”) AND THE +BUSINESS ENTITY OR PERSON FOR WHOM YOU (“YOU”) ARE ACTING (“CUSTOMER”) AS THE +LICENSEE OF THE PROPRIETARY SOFTWARE INTO WHICH THIS AGREEMENT HAS BEEN +INCLUDED (THE “AGREEMENT”). YOU AGREE THAT YOU ARE THE CUSTOMER, OR YOU ARE AN +EMPLOYEE OR AGENT OF CUSTOMER AND ARE ENTERING INTO THIS AGREEMENT FOR LICENSE +OF THE SOFTWARE BY CUSTOMER FOR CUSTOMER’S BUSINESS PURPOSES AS DESCRIBED IN +AND IN ACCORDANCE WITH THIS AGREEMENT. YOU HEREBY AGREE THAT YOU ENTER INTO +THIS AGREEMENT ON BEHALF OF CUSTOMER AND THAT YOU HAVE THE AUTHORITY TO BIND +CUSTOMER TO THIS AGREEMENT. + +STREAM.IO IS WILLING TO LICENSE THE SOFTWARE TO CUSTOMER ONLY ON THE FOLLOWING +CONDITIONS: (1) YOU ARE A CURRENT CUSTOMER OF STREAM.IO; (2) YOU ARE NOT A +COMPETITOR OF STREAM.IO; AND (3) THAT YOU ACCEPT ALL THE TERMS IN THIS +AGREEMENT. BY DOWNLOADING, INSTALLING, CONFIGURING, ACCESSING OR OTHERWISE +USING THE SOFTWARE, INCLUDING ANY UPDATES, UPGRADES, OR NEWER VERSIONS, YOU +REPRESENT, WARRANT AND ACKNOWLEDGE THAT (A) CUSTOMER IS A CURRENT CUSTOMER OF +STREAM.IO; (B) CUSTOMER IS NOT A COMPETITOR OF STREAM.IO; AND THAT (C) YOU HAVE +READ THIS AGREEMENT, UNDERSTAND THIS AGREEMENT, AND THAT CUSTOMER AGREES TO BE +BOUND BY ALL THE TERMS OF THIS AGREEMENT. + +IF YOU DO NOT AGREE TO ALL THE TERMS AND CONDITIONS OF THIS AGREEMENT, +STREAM.IO IS UNWILLING TO LICENSE THE SOFTWARE TO CUSTOMER, AND THEREFORE, DO +NOT COMPLETE THE DOWNLOAD PROCESS, ACCESS OR OTHERWISE USE THE SOFTWARE, AND +CUSTOMER SHOULD IMMEDIATELY RETURN THE SOFTWARE AND CEASE ANY USE OF THE +SOFTWARE. + +1. SOFTWARE. The Stream.io software accompanying this Agreement, may include +Source Code, Executable Object Code, associated media, printed materials and +documentation (collectively, the “Software”). The Software also includes any +updates or upgrades to or new versions of the original Software, if and when +made available to you by Stream.io. “Source Code” means computer programming +code in human readable form that is not suitable for machine execution without +the intervening steps of interpretation or compilation. “Executable Object +Code" means the computer programming code in any other form than Source Code +that is not readily perceivable by humans and suitable for machine execution +without the intervening steps of interpretation or compilation. “Site” means a +Customer location controlled by Customer. “Authorized User” means any employee +or contractor of Customer working at the Site, who has signed a written +confidentiality agreement with Customer or is otherwise bound in writing by +confidentiality and use obligations at least as restrictive as those imposed +under this Agreement. + +2. LICENSE GRANT. Subject to the terms and conditions of this Agreement, in +consideration for the representations, warranties, and covenants made by +Customer in this Agreement, Stream.io grants to Customer, during the term of +this Agreement, a personal, non-exclusive, non-transferable, non-sublicensable +license to: + +a. install and use Software Source Code on password protected computers at a Site, +restricted to Authorized Users; + +b. create derivative works, improvements (whether or not patentable), extensions +and other modifications to the Software Source Code (“Modifications”) to build +unique scalable newsfeeds, activity streams, and in-app messaging via Stream’s +application program interface (“API”); + +c. compile the Software Source Code to create Executable Object Code versions of +the Software Source Code and Modifications to build such newsfeeds, activity +streams, and in-app messaging via the API; + +d. install, execute and use such Executable Object Code versions solely for +Customer’s internal business use (including development of websites through +which data generated by Stream services will be streamed (“Apps”)); + +e. use and distribute such Executable Object Code as part of Customer’s Apps; and + +f. make electronic copies of the Software and Modifications as required for backup +or archival purposes. + +3. RESTRICTIONS. Customer is responsible for all activities that occur in +connection with the Software. Customer will not, and will not attempt to: (a) +sublicense or transfer the Software or any Source Code related to the Software +or any of Customer’s rights under this Agreement, except as otherwise provided +in this Agreement, (b) use the Software Source Code for the benefit of a third +party or to operate a service; (c) allow any third party to access or use the +Software Source Code; (d) sublicense or distribute the Software Source Code or +any Modifications in Source Code or other derivative works based on any part of +the Software Source Code; (e) use the Software in any manner that competes with +Stream.io or its business; or (e) otherwise use the Software in any manner that +exceeds the scope of use permitted in this Agreement. Customer shall use the +Software in compliance with any accompanying documentation any laws applicable +to Customer. + +4. OPEN SOURCE. Customer and its Authorized Users shall not use any software or +software components that are open source in conjunction with the Software +Source Code or any Modifications in Source Code or in any way that could +subject the Software to any open source licenses. + +5. CONTRACTORS. Under the rights granted to Customer under this Agreement, +Customer may permit its employees, contractors, and agencies of Customer to +become Authorized Users to exercise the rights to the Software granted to +Customer in accordance with this Agreement solely on behalf of Customer to +provide services to Customer; provided that Customer shall be liable for the +acts and omissions of all Authorized Users to the extent any of such acts or +omissions, if performed by Customer, would constitute a breach of, or otherwise +give rise to liability to Customer under, this Agreement. Customer shall not +and shall not permit any Authorized User to use the Software except as +expressly permitted in this Agreement. + +6. COMPETITIVE PRODUCT DEVELOPMENT. Customer shall not use the Software in any way +to engage in the development of products or services which could be reasonably +construed to provide a complete or partial functional or commercial alternative +to Stream.io’s products or services (a “Competitive Product”). Customer shall +ensure that there is no direct or indirect use of, or sharing of, Software +source code, or other information based upon or derived from the Software to +develop such products or services. Without derogating from the generality of +the foregoing, development of Competitive Products shall include having direct +or indirect access to, supervising, consulting or assisting in the development +of, or producing any specifications, documentation, object code or source code +for, all or part of a Competitive Product. + +7. LIMITATION ON MODIFICATIONS. Notwithstanding any provision in this Agreement, +Modifications may only be created and used by Customer as permitted by this +Agreement and Modification Source Code may not be distributed to third parties. +Customer will not assert against Stream.io, its affiliates, or their customers, +direct or indirect, agents and contractors, in any way, any patent rights that +Customer may obtain relating to any Modifications for Stream.io, its +affiliates’, or their customers’, direct or indirect, agents’ and contractors’ +manufacture, use, import, offer for sale or sale of any Stream.io products or +services. + +8. DELIVERY AND ACCEPTANCE. The Software will be delivered electronically pursuant +to Stream.io standard download procedures. The Software is deemed accepted upon +delivery. + +9. IMPLEMENTATION AND SUPPORT. Stream.io has no obligation under this Agreement to +provide any support or consultation concerning the Software. + +10. TERM AND TERMINATION. The term of this Agreement begins when the Software is +downloaded or accessed and shall continue until terminated. Either party may +terminate this Agreement upon written notice. This Agreement shall +automatically terminate if Customer is or becomes a competitor of Stream.io or +makes or sells any Competitive Products. Upon termination of this Agreement for +any reason, (a) all rights granted to Customer in this Agreement immediately +cease to exist, (b) Customer must promptly discontinue all use of the Software +and return to Stream.io or destroy all copies of the Software in Customer’s +possession or control. Any continued use of the Software by Customer or attempt +by Customer to exercise any rights under this Agreement after this Agreement +has terminated shall be considered copyright infringement and subject Customer +to applicable remedies for copyright infringement. Sections 2, 5, 6, 8 and 9 +shall survive expiration or termination of this Agreement for any reason. + +11. OWNERSHIP. As between the parties, the Software and all worldwide intellectual +property rights and proprietary rights relating thereto or embodied therein, +are the exclusive property of Stream.io and its suppliers. Stream.io and its +suppliers reserve all rights in and to the Software not expressly granted to +Customer in this Agreement, and no other licenses or rights are granted by +implication, estoppel or otherwise. + +12. WARRANTY DISCLAIMER. USE OF THIS SOFTWARE IS ENTIRELY AT YOURS AND CUSTOMER’S +OWN RISK. THE SOFTWARE IS PROVIDED “AS IS” WITHOUT ANY WARRANTY OF ANY KIND +WHATSOEVER. STREAM.IO DOES NOT MAKE, AND HEREBY DISCLAIMS, ANY WARRANTY OF ANY +KIND, WHETHER EXPRESS, IMPLIED, STATUTORY OR OTHERWISE, INCLUDING WITHOUT +LIMITATION, THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +PURPOSE, TITLE, NON-INFRINGEMENT OF THIRD-PARTY RIGHTS, RESULTS, EFFORTS, +QUALITY OR QUIET ENJOYMENT. STREAM.IO DOES NOT WARRANT THAT THE SOFTWARE IS +ERROR-FREE, WILL FUNCTION WITHOUT INTERRUPTION, WILL MEET ANY SPECIFIC NEED +THAT CUSTOMER HAS, THAT ALL DEFECTS WILL BE CORRECTED OR THAT IT IS +SUFFICIENTLY DOCUMENTED TO BE USABLE BY CUSTOMER. TO THE EXTENT THAT STREAM.IO +MAY NOT DISCLAIM ANY WARRANTY AS A MATTER OF APPLICABLE LAW, THE SCOPE AND +DURATION OF SUCH WARRANTY WILL BE THE MINIMUM PERMITTED UNDER SUCH LAW. +CUSTOMER ACKNOWLEDGES THAT IT HAS RELIED ON NO WARRANTIES OTHER THAN THE +EXPRESS WARRANTIES IN THIS AGREEMENT. + +13. LIMITATION OF LIABILITY. TO THE FULLEST EXTENT PERMISSIBLE BY LAW, STREAM.IO’S +TOTAL LIABILITY FOR ALL DAMAGES ARISING OUT OF OR RELATED TO THE SOFTWARE OR +THIS AGREEMENT, WHETHER IN CONTRACT, TORT (INCLUDING NEGLIGENCE) OR OTHERWISE, +SHALL NOT EXCEED $100. IN NO EVENT WILL STREAM.IO BE LIABLE FOR ANY INDIRECT, +CONSEQUENTIAL, EXEMPLARY, PUNITIVE, SPECIAL OR INCIDENTAL DAMAGES OF ANY KIND +WHATSOEVER, INCLUDING ANY LOST DATA AND LOST PROFITS, ARISING FROM OR RELATING +TO THE SOFTWARE EVEN IF STREAM.IO HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. CUSTOMER ACKNOWLEDGES THAT THIS PROVISION REFLECTS THE AGREED UPON +ALLOCATION OF RISK FOR THIS AGREEMENT AND THAT STREAM.IO WOULD NOT ENTER INTO +THIS AGREEMENT WITHOUT THESE LIMITATIONS ON ITS LIABILITY. + +14. General. Customer may not assign or transfer this Agreement, by operation of +law or otherwise, or any of its rights under this Agreement (including the +license rights granted to Customer) to any third party without Stream.io’s +prior written consent, which consent will not be unreasonably withheld or +delayed. Stream.io may assign this Agreement, without consent, including, but +limited to, affiliate or any successor to all or substantially all its business +or assets to which this Agreement relates, whether by merger, sale of assets, +sale of stock, reorganization or otherwise. Any attempted assignment or +transfer in violation of the foregoing will be null and void. Stream.io shall +not be liable hereunder by reason of any failure or delay in the performance of +its obligations hereunder for any cause which is beyond the reasonable control. +All notices, consents, and approvals under this Agreement must be delivered in +writing by courier, by electronic mail, or by certified or registered mail, +(postage prepaid and return receipt requested) to the other party at the +address set forth in the customer agreement between Stream.io and Customer and +will be effective upon receipt or when delivery is refused. This Agreement will +be governed by and interpreted in accordance with the laws of the State of +Colorado, without reference to its choice of laws rules. The United Nations +Convention on Contracts for the International Sale of Goods does not apply to +this Agreement. Any action or proceeding arising from or relating to this +Agreement shall be brought in a federal or state court in Denver, Colorado, and +each party irrevocably submits to the jurisdiction and venue of any such court +in any such action or proceeding. All waivers must be in writing. Any waiver or +failure to enforce any provision of this Agreement on one occasion will not be +deemed a waiver of any other provision or of such provision on any other +occasion. If any provision of this Agreement is unenforceable, such provision +will be changed and interpreted to accomplish the objectives of such provision +to the greatest extent possible under applicable law and the remaining +provisions will continue in full force and effect. Customer shall not violate +any applicable law, rule or regulation, including those regarding the export of +technical data. The headings of Sections of this Agreement are for convenience +and are not to be used in interpreting this Agreement. As used in this +Agreement, the word “including” means “including but not limited to.” This +Agreement (including all exhibits and attachments) constitutes the entire +agreement between the parties regarding the subject hereof and supersedes all +prior or contemporaneous agreements, understandings and communication, whether +written or oral. This Agreement may be amended only by a written document +signed by both parties. The terms of any purchase order or similar document +submitted by Customer to Stream.io will have no effect. diff --git a/README.md b/README.md new file mode 100644 index 00000000..916d0667 --- /dev/null +++ b/README.md @@ -0,0 +1,53 @@ +# Stream Chat Dart + +![](https://camo.githubusercontent.com/f5f074f3e1cde523ae0d425347149e20f861024d1d8e19b22053294ad85c43c8/68747470733a2f2f692e696d6775722e636f6d2f4c344d6a3853322e706e67) + +This repository contains code for our [Dart](https://dart.dev/) and [Flutter](https://flutter.dev/) chat clients. + +Stream allows developers to rapidly deploy scalable feeds and chat messaging with an industry leading 99.999% uptime SLA guarantee. + +## Structure +Stream Chat Dart is a monorepo built using [Melos](https://docs.page/invertase/melos). Individual packages can be found in the `packages` directory while configuration and top level commands can be found in `melos.yaml`. + +## Available Commands +### Analyze +> Requires `tuneup` to be activated globally. Please see https://pub.dev/packages/tuneup +```shell +melos run analyze +``` + +### Pub Lint +Runs pub publish with ``--dry-run`` +```shell +melos run lint:pub +``` + +### Build iOS +Builds iOS examples without codesign +```shell +melos run build:examples:ios +``` + +### Build APK +Builds an Android APK for examples +```shell +melos run build:examples:android +``` + +### Build MACOS +Builds MacOs for all examples +```shell +melos run build:examples:macos +``` + +### Test +Runs `flutter test` on all packages +```shell +melos run test +``` + +### Test Web +Runs `flutter test --platform=chrome` on all packages +```shell +melos run test:web +``` diff --git a/analysis_options.yaml b/analysis_options.yaml new file mode 100644 index 00000000..3ba5d599 --- /dev/null +++ b/analysis_options.yaml @@ -0,0 +1,13 @@ +include: package:pedantic/analysis_options.1.9.0.yaml + +analyzer: + exclude: + # Ignore generated files + - '**/*.g.dart' + - 'lib/src/generated/*.dart' + +linter: + rules: + public_member_api_docs: true + prefer_final_in_for_each: true + prefer_final_locals: true \ No newline at end of file diff --git a/melos.yaml b/melos.yaml new file mode 100644 index 00000000..ea99c335 --- /dev/null +++ b/melos.yaml @@ -0,0 +1,59 @@ +name: stream_chat_dart + +versioning: + mode: independent + +packages: + - packages/** + +scripts: + + # - Requires `pub global activate tuneup`. + analyze: > + melos exec -c 1 --fail-fast -- \ + pub global run tuneup check + + format: pub global run flutter_plugin_tools format + + + build:examples:ios: > + melos exec -c 1 --scope="*example*" --fail-fast -- \ + flutter build ios --no-codesign + + + build:examples:android: > + melos exec -c 1 --scope="*example*" --fail-fast -- \ + flutter build apk + + # Build any plugin example apps that have MacOS support. + # - Requires `flutter config --enable-macos-desktop` enabled. + # - Requires `flutter channel master && flutter upgrade`. + build:examples:macos: > + melos exec -c 1 --scope="*example*" --dir-exists=macos --fail-fast -- \ + flutter build macos + + + test: > + melos exec -c 1 --fail-fast --dir-exists=test --ignore="*example*" --ignore="*web*" -- \ + flutter test + + test:web: > + melos exec -c 1 --fail-fast --dir-exists=test --scope="*web*" -- \ + flutter test --platform=chrome + + + lint:pub: > + melos exec -c 5 --fail-fast --no-private --ignore="*example*" -- \ + pub publish --dry-run + + + postclean: > + melos exec -- \ + rm -rf ./build ./android/.gradle ./ios/.symlinks ./ios/Pods ./android/.idea ./.idea ./.dart-tool/build + +dev_dependencies: + pedantic: 1.9.2 + +environment: + sdk: ">=2.1.0 <3.0.0" + flutter: ">=1.12.13+hotfix.5 <2.0.0" \ No newline at end of file diff --git a/packages/flutter_widgets/.gitignore b/packages/flutter_widgets/.gitignore new file mode 100644 index 00000000..1d3bae26 --- /dev/null +++ b/packages/flutter_widgets/.gitignore @@ -0,0 +1,65 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# IntelliJ related +*.iml +*.ipr +*.iws +.idea/ + +# The .vscode folder contains launch configuration and tasks you configure in +# VS Code which you may wish to be included in version control, so this line +# is commented out by default. +#.vscode/ + +# Flutter/Dart/Pub related +**/doc/api/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ +coverage/ +coverage_helper_test.dart + +# Web related +lib/generated_plugin_registrant.dart + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages +# See https://www.dartlang.org/guides/libraries/private-files + +# Files and directories created by pub +.dart_tool/ +.packages +build/ +# If you're building an application, you may want to check-in your pubspec.lock +pubspec.lock + +# Directory created by dartdoc +# If you don't generate documentation locally you can remove this line. +doc/api/ + +# Avoid committing generated Javascript files: +*.dart.js +*.info.json # Produced by the --dump-info flag. +*.js # When generated by dart2js. Don't specify *.js if your + # project includes source files written in JavaScript. +*.js_ +*.js.deps +*.js.map + +fvm +google-services.json +example/ios/dist +.vscode/ \ No newline at end of file From f28cc91301748f18e10c497dedf2d8cb3950d351 Mon Sep 17 00:00:00 2001 From: Neevash Ramdial Date: Thu, 7 Jan 2021 12:09:26 -0400 Subject: [PATCH 0801/1140] add dart client to packages --- packages/dart_client/.gitignore | 60 + packages/dart_client/.metadata | 10 + packages/dart_client/CHANGELOG.md | 424 ++ packages/dart_client/LICENSE | 219 + packages/dart_client/README.md | 107 + packages/dart_client/analysis_options.yaml | 62 + packages/dart_client/build.yaml | 11 + packages/dart_client/example/README.md | 1 + .../dart_client/example/android/.gitignore | 7 + .../example/android/app/build.gradle | 67 + .../android/app/src/debug/AndroidManifest.xml | 7 + .../android/app/src/main/AndroidManifest.xml | 31 + .../example/stream_chat_dart/MainActivity.kt | 12 + .../main/res/drawable/launch_background.xml | 12 + .../src/main/res/mipmap-hdpi/ic_launcher.png | Bin 0 -> 544 bytes .../src/main/res/mipmap-mdpi/ic_launcher.png | Bin 0 -> 442 bytes .../src/main/res/mipmap-xhdpi/ic_launcher.png | Bin 0 -> 721 bytes .../main/res/mipmap-xxhdpi/ic_launcher.png | Bin 0 -> 1031 bytes .../main/res/mipmap-xxxhdpi/ic_launcher.png | Bin 0 -> 1443 bytes .../app/src/main/res/values/styles.xml | 8 + .../app/src/profile/AndroidManifest.xml | 7 + .../dart_client/example/android/build.gradle | 31 + .../example/android/gradle.properties | 4 + .../gradle/wrapper/gradle-wrapper.properties | 6 + .../example/android/settings.gradle | 15 + packages/dart_client/example/ios/.gitignore | 32 + .../ios/Flutter/AppFrameworkInfo.plist | 26 + .../example/ios/Flutter/Debug.xcconfig | 2 + .../example/ios/Flutter/Release.xcconfig | 2 + .../ios/Runner.xcodeproj/project.pbxproj | 584 +++ .../contents.xcworkspacedata | 7 + .../xcshareddata/xcschemes/Runner.xcscheme | 91 + .../contents.xcworkspacedata | 10 + .../example/ios/Runner/AppDelegate.swift | 13 + .../AppIcon.appiconset/Contents.json | 122 + .../Icon-App-1024x1024@1x.png | Bin 0 -> 10932 bytes .../AppIcon.appiconset/Icon-App-20x20@1x.png | Bin 0 -> 564 bytes .../AppIcon.appiconset/Icon-App-20x20@2x.png | Bin 0 -> 1283 bytes .../AppIcon.appiconset/Icon-App-20x20@3x.png | Bin 0 -> 1588 bytes .../AppIcon.appiconset/Icon-App-29x29@1x.png | Bin 0 -> 1025 bytes .../AppIcon.appiconset/Icon-App-29x29@2x.png | Bin 0 -> 1716 bytes .../AppIcon.appiconset/Icon-App-29x29@3x.png | Bin 0 -> 1920 bytes .../AppIcon.appiconset/Icon-App-40x40@1x.png | Bin 0 -> 1283 bytes .../AppIcon.appiconset/Icon-App-40x40@2x.png | Bin 0 -> 1895 bytes .../AppIcon.appiconset/Icon-App-40x40@3x.png | Bin 0 -> 2665 bytes .../AppIcon.appiconset/Icon-App-60x60@2x.png | Bin 0 -> 2665 bytes .../AppIcon.appiconset/Icon-App-60x60@3x.png | Bin 0 -> 3831 bytes .../AppIcon.appiconset/Icon-App-76x76@1x.png | Bin 0 -> 1888 bytes .../AppIcon.appiconset/Icon-App-76x76@2x.png | Bin 0 -> 3294 bytes .../Icon-App-83.5x83.5@2x.png | Bin 0 -> 3612 bytes .../LaunchImage.imageset/Contents.json | 23 + .../LaunchImage.imageset/LaunchImage.png | Bin 0 -> 68 bytes .../LaunchImage.imageset/LaunchImage@2x.png | Bin 0 -> 68 bytes .../LaunchImage.imageset/LaunchImage@3x.png | Bin 0 -> 68 bytes .../LaunchImage.imageset/README.md | 5 + .../Runner/Base.lproj/LaunchScreen.storyboard | 37 + .../ios/Runner/Base.lproj/Main.storyboard | 26 + .../dart_client/example/ios/Runner/Info.plist | 50 + .../ios/Runner/Runner-Bridging-Header.h | 1 + .../example/lib/channel_header.dart | 83 + .../example/lib/channel_image.dart | 25 + .../example/lib/channel_list_page.dart | 138 + .../example/lib/channel_list_view.dart | 208 + .../example/lib/channel_name_text.dart | 19 + .../example/lib/channel_page_app_bar.dart | 41 + .../example/lib/channel_preview.dart | 139 + .../example/lib/connection_indicator.dart | 100 + packages/dart_client/example/lib/main.dart | 94 + .../example/lib/message_input.dart | 137 + .../example/lib/message_list_view.dart | 280 ++ .../dart_client/example/lib/message_page.dart | 110 + .../example/lib/message_widget.dart | 353 ++ .../example/lib/stream_channel.dart | 128 + .../dart_client/example/lib/stream_chat.dart | 95 + .../dart_client/example/lib/user_avatar.dart | 29 + packages/dart_client/example/pubspec.yaml | 33 + .../dart_client/example/test/widget_test.dart | 29 + .../example/web/icons/Icon-192.png | Bin 0 -> 5292 bytes .../example/web/icons/Icon-512.png | Bin 0 -> 8252 bytes packages/dart_client/example/web/index.html | 20 + .../dart_client/example/web/manifest.json | 23 + packages/dart_client/lib/src/api/channel.dart | 1518 ++++++ .../lib/src/api/connection_status.dart | 11 + .../dart_client/lib/src/api/requests.dart | 97 + .../dart_client/lib/src/api/requests.g.dart | 31 + .../dart_client/lib/src/api/responses.dart | 375 ++ .../dart_client/lib/src/api/responses.g.dart | 382 ++ .../dart_client/lib/src/api/retry_policy.dart | 37 + .../dart_client/lib/src/api/retry_queue.dart | 202 + .../lib/src/api/web_socket_channel_html.dart | 7 + .../lib/src/api/web_socket_channel_io.dart | 7 + .../lib/src/api/web_socket_channel_stub.dart | 9 + .../dart_client/lib/src/api/websocket.dart | 295 ++ packages/dart_client/lib/src/client.dart | 1388 ++++++ .../dart_client/lib/src/db/models.part.dart | 258 + .../lib/src/db/offline_storage.dart | 841 ++++ .../lib/src/db/offline_storage.g.dart | 4160 ++++++++++++++++ .../lib/src/db/shared/native_db.dart | 64 + .../lib/src/db/shared/shared_db.dart | 3 + .../lib/src/db/shared/unsupported_db.dart | 12 + .../dart_client/lib/src/db/shared/web_db.dart | 18 + packages/dart_client/lib/src/event_type.dart | 94 + packages/dart_client/lib/src/exceptions.dart | 54 + .../dart_client/lib/src/models/action.dart | 31 + .../dart_client/lib/src/models/action.g.dart | 25 + .../lib/src/models/attachment.dart | 207 + .../lib/src/models/attachment.g.dart | 74 + .../lib/src/models/channel_config.dart | 84 + .../lib/src/models/channel_config.g.dart | 58 + .../lib/src/models/channel_model.dart | 145 + .../lib/src/models/channel_model.g.dart | 69 + .../lib/src/models/channel_state.dart | 66 + .../lib/src/models/channel_state.g.dart | 56 + .../dart_client/lib/src/models/command.dart | 30 + .../dart_client/lib/src/models/command.g.dart | 21 + .../dart_client/lib/src/models/device.dart | 25 + .../dart_client/lib/src/models/device.g.dart | 19 + .../dart_client/lib/src/models/event.dart | 183 + .../dart_client/lib/src/models/event.g.dart | 156 + .../dart_client/lib/src/models/member.dart | 96 + .../dart_client/lib/src/models/member.g.dart | 49 + .../dart_client/lib/src/models/message.dart | 278 ++ .../dart_client/lib/src/models/message.g.dart | 135 + packages/dart_client/lib/src/models/mute.dart | 36 + .../dart_client/lib/src/models/mute.g.dart | 44 + .../dart_client/lib/src/models/own_user.dart | 83 + .../lib/src/models/own_user.g.dart | 77 + .../dart_client/lib/src/models/reaction.dart | 68 + .../lib/src/models/reaction.g.dart | 47 + packages/dart_client/lib/src/models/read.dart | 31 + .../dart_client/lib/src/models/read.g.dart | 27 + .../lib/src/models/serialization.dart | 49 + packages/dart_client/lib/src/models/user.dart | 108 + .../dart_client/lib/src/models/user.g.dart | 51 + .../dart_client/lib/src/notifications.dart | 119 + packages/dart_client/lib/stream_chat.dart | 29 + packages/dart_client/lib/version.dart | 5 + packages/dart_client/peanut.yaml | 3 + packages/dart_client/pubspec.yaml | 36 + .../test/src/api/channel_test.dart | 2099 ++++++++ .../test/src/api/requests_test.dart | 18 + .../test/src/api/responses_test.dart | 4336 +++++++++++++++++ .../test/src/api/web_socket_stub_test.dart | 9 + .../test/src/api/websocket_test.dart | 353 ++ .../dart_client/test/src/client_test.dart | 979 ++++ .../test/src/models/action_test.dart | 46 + .../test/src/models/attachment_test.dart | 69 + .../test/src/models/channel_state_test.dart | 1112 +++++ .../test/src/models/channel_test.dart | 56 + .../test/src/models/command_test.dart | 40 + .../test/src/models/device_test.dart | 31 + .../test/src/models/event_test.dart | 89 + .../test/src/models/member_test.dart | 35 + .../test/src/models/message_test.dart | 153 + .../test/src/models/reaction_test.dart | 72 + .../test/src/models/read_test.dart | 40 + .../test/src/models/serialization_test.dart | 60 + .../test/src/models/user_test.dart | 28 + packages/dart_client/test/version_test.dart | 23 + .../test_integration/client_test.dart | 21 + 160 files changed, 26368 insertions(+) create mode 100644 packages/dart_client/.gitignore create mode 100644 packages/dart_client/.metadata create mode 100644 packages/dart_client/CHANGELOG.md create mode 100644 packages/dart_client/LICENSE create mode 100644 packages/dart_client/README.md create mode 100644 packages/dart_client/analysis_options.yaml create mode 100644 packages/dart_client/build.yaml create mode 100644 packages/dart_client/example/README.md create mode 100644 packages/dart_client/example/android/.gitignore create mode 100644 packages/dart_client/example/android/app/build.gradle create mode 100644 packages/dart_client/example/android/app/src/debug/AndroidManifest.xml create mode 100644 packages/dart_client/example/android/app/src/main/AndroidManifest.xml create mode 100644 packages/dart_client/example/android/app/src/main/kotlin/com/example/stream_chat_dart/MainActivity.kt create mode 100644 packages/dart_client/example/android/app/src/main/res/drawable/launch_background.xml create mode 100644 packages/dart_client/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png create mode 100644 packages/dart_client/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png create mode 100644 packages/dart_client/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png create mode 100644 packages/dart_client/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png create mode 100644 packages/dart_client/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png create mode 100644 packages/dart_client/example/android/app/src/main/res/values/styles.xml create mode 100644 packages/dart_client/example/android/app/src/profile/AndroidManifest.xml create mode 100644 packages/dart_client/example/android/build.gradle create mode 100644 packages/dart_client/example/android/gradle.properties create mode 100644 packages/dart_client/example/android/gradle/wrapper/gradle-wrapper.properties create mode 100644 packages/dart_client/example/android/settings.gradle create mode 100644 packages/dart_client/example/ios/.gitignore create mode 100644 packages/dart_client/example/ios/Flutter/AppFrameworkInfo.plist create mode 100644 packages/dart_client/example/ios/Flutter/Debug.xcconfig create mode 100644 packages/dart_client/example/ios/Flutter/Release.xcconfig create mode 100644 packages/dart_client/example/ios/Runner.xcodeproj/project.pbxproj create mode 100644 packages/dart_client/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata create mode 100644 packages/dart_client/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme create mode 100644 packages/dart_client/example/ios/Runner.xcworkspace/contents.xcworkspacedata create mode 100644 packages/dart_client/example/ios/Runner/AppDelegate.swift create mode 100644 packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json create mode 100644 packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png create mode 100644 packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png create mode 100644 packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png create mode 100644 packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png create mode 100644 packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png create mode 100644 packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png create mode 100644 packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png create mode 100644 packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png create mode 100644 packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png create mode 100644 packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png create mode 100644 packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png create mode 100644 packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png create mode 100644 packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png create mode 100644 packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png create mode 100644 packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png create mode 100644 packages/dart_client/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json create mode 100644 packages/dart_client/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png create mode 100644 packages/dart_client/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png create mode 100644 packages/dart_client/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png create mode 100644 packages/dart_client/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md create mode 100644 packages/dart_client/example/ios/Runner/Base.lproj/LaunchScreen.storyboard create mode 100644 packages/dart_client/example/ios/Runner/Base.lproj/Main.storyboard create mode 100644 packages/dart_client/example/ios/Runner/Info.plist create mode 100644 packages/dart_client/example/ios/Runner/Runner-Bridging-Header.h create mode 100644 packages/dart_client/example/lib/channel_header.dart create mode 100644 packages/dart_client/example/lib/channel_image.dart create mode 100644 packages/dart_client/example/lib/channel_list_page.dart create mode 100644 packages/dart_client/example/lib/channel_list_view.dart create mode 100644 packages/dart_client/example/lib/channel_name_text.dart create mode 100644 packages/dart_client/example/lib/channel_page_app_bar.dart create mode 100644 packages/dart_client/example/lib/channel_preview.dart create mode 100644 packages/dart_client/example/lib/connection_indicator.dart create mode 100644 packages/dart_client/example/lib/main.dart create mode 100644 packages/dart_client/example/lib/message_input.dart create mode 100644 packages/dart_client/example/lib/message_list_view.dart create mode 100644 packages/dart_client/example/lib/message_page.dart create mode 100644 packages/dart_client/example/lib/message_widget.dart create mode 100644 packages/dart_client/example/lib/stream_channel.dart create mode 100644 packages/dart_client/example/lib/stream_chat.dart create mode 100644 packages/dart_client/example/lib/user_avatar.dart create mode 100644 packages/dart_client/example/pubspec.yaml create mode 100644 packages/dart_client/example/test/widget_test.dart create mode 100644 packages/dart_client/example/web/icons/Icon-192.png create mode 100644 packages/dart_client/example/web/icons/Icon-512.png create mode 100644 packages/dart_client/example/web/index.html create mode 100644 packages/dart_client/example/web/manifest.json create mode 100644 packages/dart_client/lib/src/api/channel.dart create mode 100644 packages/dart_client/lib/src/api/connection_status.dart create mode 100644 packages/dart_client/lib/src/api/requests.dart create mode 100644 packages/dart_client/lib/src/api/requests.g.dart create mode 100644 packages/dart_client/lib/src/api/responses.dart create mode 100644 packages/dart_client/lib/src/api/responses.g.dart create mode 100644 packages/dart_client/lib/src/api/retry_policy.dart create mode 100644 packages/dart_client/lib/src/api/retry_queue.dart create mode 100644 packages/dart_client/lib/src/api/web_socket_channel_html.dart create mode 100644 packages/dart_client/lib/src/api/web_socket_channel_io.dart create mode 100644 packages/dart_client/lib/src/api/web_socket_channel_stub.dart create mode 100644 packages/dart_client/lib/src/api/websocket.dart create mode 100644 packages/dart_client/lib/src/client.dart create mode 100644 packages/dart_client/lib/src/db/models.part.dart create mode 100644 packages/dart_client/lib/src/db/offline_storage.dart create mode 100644 packages/dart_client/lib/src/db/offline_storage.g.dart create mode 100644 packages/dart_client/lib/src/db/shared/native_db.dart create mode 100644 packages/dart_client/lib/src/db/shared/shared_db.dart create mode 100644 packages/dart_client/lib/src/db/shared/unsupported_db.dart create mode 100644 packages/dart_client/lib/src/db/shared/web_db.dart create mode 100644 packages/dart_client/lib/src/event_type.dart create mode 100644 packages/dart_client/lib/src/exceptions.dart create mode 100644 packages/dart_client/lib/src/models/action.dart create mode 100644 packages/dart_client/lib/src/models/action.g.dart create mode 100644 packages/dart_client/lib/src/models/attachment.dart create mode 100644 packages/dart_client/lib/src/models/attachment.g.dart create mode 100644 packages/dart_client/lib/src/models/channel_config.dart create mode 100644 packages/dart_client/lib/src/models/channel_config.g.dart create mode 100644 packages/dart_client/lib/src/models/channel_model.dart create mode 100644 packages/dart_client/lib/src/models/channel_model.g.dart create mode 100644 packages/dart_client/lib/src/models/channel_state.dart create mode 100644 packages/dart_client/lib/src/models/channel_state.g.dart create mode 100644 packages/dart_client/lib/src/models/command.dart create mode 100644 packages/dart_client/lib/src/models/command.g.dart create mode 100644 packages/dart_client/lib/src/models/device.dart create mode 100644 packages/dart_client/lib/src/models/device.g.dart create mode 100644 packages/dart_client/lib/src/models/event.dart create mode 100644 packages/dart_client/lib/src/models/event.g.dart create mode 100644 packages/dart_client/lib/src/models/member.dart create mode 100644 packages/dart_client/lib/src/models/member.g.dart create mode 100644 packages/dart_client/lib/src/models/message.dart create mode 100644 packages/dart_client/lib/src/models/message.g.dart create mode 100644 packages/dart_client/lib/src/models/mute.dart create mode 100644 packages/dart_client/lib/src/models/mute.g.dart create mode 100644 packages/dart_client/lib/src/models/own_user.dart create mode 100644 packages/dart_client/lib/src/models/own_user.g.dart create mode 100644 packages/dart_client/lib/src/models/reaction.dart create mode 100644 packages/dart_client/lib/src/models/reaction.g.dart create mode 100644 packages/dart_client/lib/src/models/read.dart create mode 100644 packages/dart_client/lib/src/models/read.g.dart create mode 100644 packages/dart_client/lib/src/models/serialization.dart create mode 100644 packages/dart_client/lib/src/models/user.dart create mode 100644 packages/dart_client/lib/src/models/user.g.dart create mode 100644 packages/dart_client/lib/src/notifications.dart create mode 100644 packages/dart_client/lib/stream_chat.dart create mode 100644 packages/dart_client/lib/version.dart create mode 100644 packages/dart_client/peanut.yaml create mode 100644 packages/dart_client/pubspec.yaml create mode 100644 packages/dart_client/test/src/api/channel_test.dart create mode 100644 packages/dart_client/test/src/api/requests_test.dart create mode 100644 packages/dart_client/test/src/api/responses_test.dart create mode 100644 packages/dart_client/test/src/api/web_socket_stub_test.dart create mode 100644 packages/dart_client/test/src/api/websocket_test.dart create mode 100644 packages/dart_client/test/src/client_test.dart create mode 100644 packages/dart_client/test/src/models/action_test.dart create mode 100644 packages/dart_client/test/src/models/attachment_test.dart create mode 100644 packages/dart_client/test/src/models/channel_state_test.dart create mode 100644 packages/dart_client/test/src/models/channel_test.dart create mode 100644 packages/dart_client/test/src/models/command_test.dart create mode 100644 packages/dart_client/test/src/models/device_test.dart create mode 100644 packages/dart_client/test/src/models/event_test.dart create mode 100644 packages/dart_client/test/src/models/member_test.dart create mode 100644 packages/dart_client/test/src/models/message_test.dart create mode 100644 packages/dart_client/test/src/models/reaction_test.dart create mode 100644 packages/dart_client/test/src/models/read_test.dart create mode 100644 packages/dart_client/test/src/models/serialization_test.dart create mode 100644 packages/dart_client/test/src/models/user_test.dart create mode 100644 packages/dart_client/test/version_test.dart create mode 100644 packages/dart_client/test_integration/client_test.dart diff --git a/packages/dart_client/.gitignore b/packages/dart_client/.gitignore new file mode 100644 index 00000000..2ea557c4 --- /dev/null +++ b/packages/dart_client/.gitignore @@ -0,0 +1,60 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# IntelliJ related +*.iml +*.ipr +*.iws +.idea/ + +# The .vscode folder contains launch configuration and tasks you configure in +# VS Code which you may wish to be included in version control, so this line +# is commented out by default. +#.vscode/ + +# Flutter/Dart/Pub related +**/doc/api/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ +coverage/ +coverage_helper_test.dart + +# Web related +lib/generated_plugin_registrant.dart + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages +# See https://www.dartlang.org/guides/libraries/private-files + +# Files and directories created by pub +.dart_tool/ +.packages +build/ +# If you're building an application, you may want to check-in your pubspec.lock +pubspec.lock + +# Directory created by dartdoc +# If you don't generate documentation locally you can remove this line. +doc/api/ + +# Avoid committing generated Javascript files: +*.dart.js +*.info.json # Produced by the --dump-info flag. +*.js # When generated by dart2js. Don't specify *.js if your + # project includes source files written in JavaScript. +*.js_ +*.js.deps +*.js.map diff --git a/packages/dart_client/.metadata b/packages/dart_client/.metadata new file mode 100644 index 00000000..946cda16 --- /dev/null +++ b/packages/dart_client/.metadata @@ -0,0 +1,10 @@ +# This file tracks properties of this Flutter project. +# Used by Flutter tool to assess capabilities and perform upgrades etc. +# +# This file should be version controlled and should not be manually edited. + +version: + revision: 659dc8129d4edb9166e9a0d600439d135740933f + channel: beta + +project_type: package diff --git a/packages/dart_client/CHANGELOG.md b/packages/dart_client/CHANGELOG.md new file mode 100644 index 00000000..a570a254 --- /dev/null +++ b/packages/dart_client/CHANGELOG.md @@ -0,0 +1,424 @@ +## 0.2.23+1 + +- Throw an error when calling queryChannels without an active connection +- Wait to establish a connection if calling queryChannels while connecting + +## 0.2.23 + +- Add thread_participants in message model + +## 0.2.22 + +- Add thread-less message reply feature (QuotedMessage) + +## 0.2.21+2 + +- Fix but not throwing error during querychannels and persistance disabled +- Fix reaction.updated event handling + +## 0.2.21+1 + +- Fix error in the offline storage queryChannelCids query + +## 0.2.21 + +- Fix channel.hide(clearHistory: true) not clearing local messages +- Add banned field to member + +## 0.2.20 + +- Return offline data only if the backend is unreachable. This avoids the glitch of the ChannelListView because we cannot sort by custom properties. + +## 0.2.19 + +- Added message filters for `Client.search()` + +## 0.2.18 + +- Correctly dispose resources when disposing the client state +- Limit parallel queryChannels with same parameters to 1 +- Added `clearUser` parameter to `client.disconnect` to remove the user instance of the client + +## 0.2.17+1 + +- Do not retry messages when server returns error + +## 0.2.17 + +- Add shadow ban feature + +## 0.2.16 + +- Listen for user.updated events + +## 0.2.15+2 + +- Fix reaction score updates + +## 0.2.15+1 + +- Listen to reaction.updated event + +## 0.2.15 + +- Fix search message response + +## 0.2.14 + +- Add event.extradata + +## 0.2.13+1 + +- Let user change channel.extradata if the channel is not initialized yet + +## 0.2.13 + +- Add parent_id to events for typing indicators in threads + +## 0.2.12+2 + +- Fix error with reactions with null user + +## 0.2.12 + +- Do not save channels in memory if not being watched. This was leading to some bugs in some specific use-cases. + +## 0.2.11 + +- Fix user.name getter +- Use detached loggers +- Throw error while connecting if it comes from backend +- Fix ws reconnection + +## 0.2.10+2 + +- Fix bug with event filtering + +## 0.2.10+1 + +- Add default limit to pagination + +## 0.2.10 + +- Added `channel.state.unreadCountStream` + +## 0.2.9 + +- Adding a message on `Channel.update` is now optional + +## 0.2.8+1 + +- Fix retry logic + +## 0.2.8 + +- Add missing event types +- Fix local sorting on offline storage + +## 0.2.7+1 + +- `Client.channel` returns an existing channel if available +- Update message in the offline storage if attachment has expired (for the new CDN) +- Fix `GetMessagesByIdResponse` format +- Do not query messages if already existing in offline storage + +## 0.2.6 + +- Experimental support for Flutter web and MacOs + +## 0.2.5+2 + +- Cleaned up Serialization on extra_data + +## 0.2.5+1 + +- Fix `channel.show` api call + +## 0.2.5 + +- Add `channelType` and `channelId` properties to event object + +## 0.2.4+2 + +- Fix query members messing channel state + +## 0.2.4+1 + +- Do not resync if there is no channel in offlinestorage + +## 0.2.4 + +- Add null-safety to ws disconnect +- Add pagination parameters to queryUsers request + +## 0.2.3+3 + +- Fix reaction add/remove logic + +## 0.2.3+2 + +- Skip system messages during unreadCount computation + +## 0.2.3+1 + +- Removed moor_ffi from dependencies in favor of moor/ffi + +## 0.2.3 + +- Fix reject invite payload + +- Add multi-tenant properties to channel and user + +## 0.2.2+1 + +- Fix queryChannels payload + +## 0.2.2 + +- Fix add/remove/invite members api calls + +## 0.2.1 + +- Add `isMutedStream` to `Channel` +- Add `isGroup` to `Channel` +- Add `isDistinct` to `Channel` + +## 0.2.0+2 + +- Fix search messages response class + +## 0.2.0+1 + +- Fix offline members update +- Add channel mutes +- Fix default channel sort + +## 0.2.0 + +- Add `lastMessage` getter to Channel.state +- Add `isSystem` property to Message +- Incremental websocket reconnection timeout +- Add translate message api call +- Add queryMembers api call +- Add user list to client state +- Synchronize channel members status +- Add offline storage +- Add push notifications helper functions + +## 0.2.0-alpha+23 + +- Add `lastMessage` getter to `Channel.state` + +## 0.2.0-alpha+22 + +- Add `isSystem` property to Message + +## 0.2.0-alpha+21 + +- Incremental websocket reconnection timeout + +## 0.2.0-alpha+20 + +- More robust offline storage insertions + +## 0.2.0-alpha+19 + +- Add translate message api call +- Add queryMembers api call + +## 0.2.0-alpha+18 + +- Revert moor_ffi version to 0.5.0 + +## 0.2.0-alpha+17 + +- Add user list to client + +- Synchronize channel members status + +## 0.2.0-alpha+16 + +- Try QueryChannels when `resync` endpoint returns an error + +## 0.2.0-alpha+15 + +- Fix receiving reactions + +## 0.2.0-alpha+14 + +- Avoid sending local event for optimistic updates + +## 0.2.0-alpha+13 + +- Fix offline on app first start up + +## 0.2.0-alpha+12 + +- Fix retry mechanism in threads +- Fix delete channel query + +## 0.2.0-alpha+9 + +- Add retry mechanism and retry queue + +## 0.2.0-alpha+8 + +- Add copyWith to Attachment + +## 0.2.0-alpha+7 + +- Add channel deleted/updated event handling + +## 0.2.0-alpha+6 + +- Align with stable release + +## 0.2.0-alpha+5 + +- Rename client parameters + +## 0.2.0-alpha+3 + +- Remove dependencies on notification service + +- Expose some helping method for integrate offline storage with push notifications + +## 0.2.0-alpha+2 + +- Fix unread count + +## 0.2.0-alpha + +- Offline storage + +- Push notifications + +- Minor bug fixes + +## 0.1.30 + +- Add silent property to message + +## 0.1.29 + +- Fix read event handling + +## 0.1.28 + +- Fix bug clearing members when receiving a message + +## 0.1.27 + +- Update dependencies + +## 0.1.26 + +- Remove wrong `members` property from `ChannelModel` + +## 0.1.25 + +- Fix online status + +## 0.1.24 + +- Fix unread count + +## 0.1.22 + +- Add mute/unmute channel + +## 0.1.20 + +- Fix channel query path without id + +## 0.1.19 + +- Fix loading message replies + +## 0.1.18 + +- Export dio error + +## 0.1.17 + +- Ignore current user typing events + +- Add event types + +## 0.1.16 + +- Fix message update + +## 0.1.15 + +- Fix mentions handling + +## 0.1.14 + +- Handle message modification and commands + +## 0.1.13 + +- Add message.updated event handling + +## 0.1.12 + +- Add export multipart_file from dio + +## 0.1.11 + +- Add channel config checks + +## 0.1.10 + +- Rename Channel.channelClients to channels + +## 0.1.9 + +- Fix channel update on message delete + +## 0.1.8 + +- Add delete message handling + +## 0.1.7 + +- Add reaction handling + +## 0.1.6 + +- Add initialized completer + +- Update example + +## 0.1.5 + +- Add `ClientState` and `ChannelClientState` classes to handle channel state updates using events + +- Update example supporting threads + +## 0.1.4 + +- Update some api with wrong or incomplete signatures + +- Add documentation for public apis + +## 0.1.2 + +- add websocket reconnection logic + +- add token expiration mechanism + +## 0.1.1 + +- add typing events handling + +## 0.1.0 + +- a better example can be found in the example/ directory + +- fix some api calls and add missing one + +## 0.0.2 + +- first beta version \ No newline at end of file diff --git a/packages/dart_client/LICENSE b/packages/dart_client/LICENSE new file mode 100644 index 00000000..f2d1eaf3 --- /dev/null +++ b/packages/dart_client/LICENSE @@ -0,0 +1,219 @@ +SOURCE CODE LICENSE AGREEMENT + +IMPORTANT - READ THIS CAREFULLY BEFORE DOWNLOADING, INSTALLING, USING OR +ELECTRONICALLY ACCESSING THIS PROPRIETARY PRODUCT. + +THIS IS A LEGAL AGREEMENT BETWEEN STREAM.IO, INC. (“STREAM.IO”) AND THE +BUSINESS ENTITY OR PERSON FOR WHOM YOU (“YOU”) ARE ACTING (“CUSTOMER”) AS THE +LICENSEE OF THE PROPRIETARY SOFTWARE INTO WHICH THIS AGREEMENT HAS BEEN +INCLUDED (THE “AGREEMENT”). YOU AGREE THAT YOU ARE THE CUSTOMER, OR YOU ARE AN +EMPLOYEE OR AGENT OF CUSTOMER AND ARE ENTERING INTO THIS AGREEMENT FOR LICENSE +OF THE SOFTWARE BY CUSTOMER FOR CUSTOMER’S BUSINESS PURPOSES AS DESCRIBED IN +AND IN ACCORDANCE WITH THIS AGREEMENT. YOU HEREBY AGREE THAT YOU ENTER INTO +THIS AGREEMENT ON BEHALF OF CUSTOMER AND THAT YOU HAVE THE AUTHORITY TO BIND +CUSTOMER TO THIS AGREEMENT. + +STREAM.IO IS WILLING TO LICENSE THE SOFTWARE TO CUSTOMER ONLY ON THE FOLLOWING +CONDITIONS: (1) YOU ARE A CURRENT CUSTOMER OF STREAM.IO; (2) YOU ARE NOT A +COMPETITOR OF STREAM.IO; AND (3) THAT YOU ACCEPT ALL THE TERMS IN THIS +AGREEMENT. BY DOWNLOADING, INSTALLING, CONFIGURING, ACCESSING OR OTHERWISE +USING THE SOFTWARE, INCLUDING ANY UPDATES, UPGRADES, OR NEWER VERSIONS, YOU +REPRESENT, WARRANT AND ACKNOWLEDGE THAT (A) CUSTOMER IS A CURRENT CUSTOMER OF +STREAM.IO; (B) CUSTOMER IS NOT A COMPETITOR OF STREAM.IO; AND THAT (C) YOU HAVE +READ THIS AGREEMENT, UNDERSTAND THIS AGREEMENT, AND THAT CUSTOMER AGREES TO BE +BOUND BY ALL THE TERMS OF THIS AGREEMENT. + +IF YOU DO NOT AGREE TO ALL THE TERMS AND CONDITIONS OF THIS AGREEMENT, +STREAM.IO IS UNWILLING TO LICENSE THE SOFTWARE TO CUSTOMER, AND THEREFORE, DO +NOT COMPLETE THE DOWNLOAD PROCESS, ACCESS OR OTHERWISE USE THE SOFTWARE, AND +CUSTOMER SHOULD IMMEDIATELY RETURN THE SOFTWARE AND CEASE ANY USE OF THE +SOFTWARE. + +1. SOFTWARE. The Stream.io software accompanying this Agreement, may include +Source Code, Executable Object Code, associated media, printed materials and +documentation (collectively, the “Software”). The Software also includes any +updates or upgrades to or new versions of the original Software, if and when +made available to you by Stream.io. “Source Code” means computer programming +code in human readable form that is not suitable for machine execution without +the intervening steps of interpretation or compilation. “Executable Object +Code" means the computer programming code in any other form than Source Code +that is not readily perceivable by humans and suitable for machine execution +without the intervening steps of interpretation or compilation. “Site” means a +Customer location controlled by Customer. “Authorized User” means any employee +or contractor of Customer working at the Site, who has signed a written +confidentiality agreement with Customer or is otherwise bound in writing by +confidentiality and use obligations at least as restrictive as those imposed +under this Agreement. + +2. LICENSE GRANT. Subject to the terms and conditions of this Agreement, in +consideration for the representations, warranties, and covenants made by +Customer in this Agreement, Stream.io grants to Customer, during the term of +this Agreement, a personal, non-exclusive, non-transferable, non-sublicensable +license to: + +a. install and use Software Source Code on password protected computers at a Site, +restricted to Authorized Users; + +b. create derivative works, improvements (whether or not patentable), extensions +and other modifications to the Software Source Code (“Modifications”) to build +unique scalable newsfeeds, activity streams, and in-app messaging via Stream’s +application program interface (“API”); + +c. compile the Software Source Code to create Executable Object Code versions of +the Software Source Code and Modifications to build such newsfeeds, activity +streams, and in-app messaging via the API; + +d. install, execute and use such Executable Object Code versions solely for +Customer’s internal business use (including development of websites through +which data generated by Stream services will be streamed (“Apps”)); + +e. use and distribute such Executable Object Code as part of Customer’s Apps; and + +f. make electronic copies of the Software and Modifications as required for backup +or archival purposes. + +3. RESTRICTIONS. Customer is responsible for all activities that occur in +connection with the Software. Customer will not, and will not attempt to: (a) +sublicense or transfer the Software or any Source Code related to the Software +or any of Customer’s rights under this Agreement, except as otherwise provided +in this Agreement, (b) use the Software Source Code for the benefit of a third +party or to operate a service; (c) allow any third party to access or use the +Software Source Code; (d) sublicense or distribute the Software Source Code or +any Modifications in Source Code or other derivative works based on any part of +the Software Source Code; (e) use the Software in any manner that competes with +Stream.io or its business; or (e) otherwise use the Software in any manner that +exceeds the scope of use permitted in this Agreement. Customer shall use the +Software in compliance with any accompanying documentation any laws applicable +to Customer. + +4. OPEN SOURCE. Customer and its Authorized Users shall not use any software or +software components that are open source in conjunction with the Software +Source Code or any Modifications in Source Code or in any way that could +subject the Software to any open source licenses. + +5. CONTRACTORS. Under the rights granted to Customer under this Agreement, +Customer may permit its employees, contractors, and agencies of Customer to +become Authorized Users to exercise the rights to the Software granted to +Customer in accordance with this Agreement solely on behalf of Customer to +provide services to Customer; provided that Customer shall be liable for the +acts and omissions of all Authorized Users to the extent any of such acts or +omissions, if performed by Customer, would constitute a breach of, or otherwise +give rise to liability to Customer under, this Agreement. Customer shall not +and shall not permit any Authorized User to use the Software except as +expressly permitted in this Agreement. + +6. COMPETITIVE PRODUCT DEVELOPMENT. Customer shall not use the Software in any way +to engage in the development of products or services which could be reasonably +construed to provide a complete or partial functional or commercial alternative +to Stream.io’s products or services (a “Competitive Product”). Customer shall +ensure that there is no direct or indirect use of, or sharing of, Software +source code, or other information based upon or derived from the Software to +develop such products or services. Without derogating from the generality of +the foregoing, development of Competitive Products shall include having direct +or indirect access to, supervising, consulting or assisting in the development +of, or producing any specifications, documentation, object code or source code +for, all or part of a Competitive Product. + +7. LIMITATION ON MODIFICATIONS. Notwithstanding any provision in this Agreement, +Modifications may only be created and used by Customer as permitted by this +Agreement and Modification Source Code may not be distributed to third parties. +Customer will not assert against Stream.io, its affiliates, or their customers, +direct or indirect, agents and contractors, in any way, any patent rights that +Customer may obtain relating to any Modifications for Stream.io, its +affiliates’, or their customers’, direct or indirect, agents’ and contractors’ +manufacture, use, import, offer for sale or sale of any Stream.io products or +services. + +8. DELIVERY AND ACCEPTANCE. The Software will be delivered electronically pursuant +to Stream.io standard download procedures. The Software is deemed accepted upon +delivery. + +9. IMPLEMENTATION AND SUPPORT. Stream.io has no obligation under this Agreement to +provide any support or consultation concerning the Software. + +10. TERM AND TERMINATION. The term of this Agreement begins when the Software is +downloaded or accessed and shall continue until terminated. Either party may +terminate this Agreement upon written notice. This Agreement shall +automatically terminate if Customer is or becomes a competitor of Stream.io or +makes or sells any Competitive Products. Upon termination of this Agreement for +any reason, (a) all rights granted to Customer in this Agreement immediately +cease to exist, (b) Customer must promptly discontinue all use of the Software +and return to Stream.io or destroy all copies of the Software in Customer’s +possession or control. Any continued use of the Software by Customer or attempt +by Customer to exercise any rights under this Agreement after this Agreement +has terminated shall be considered copyright infringement and subject Customer +to applicable remedies for copyright infringement. Sections 2, 5, 6, 8 and 9 +shall survive expiration or termination of this Agreement for any reason. + +11. OWNERSHIP. As between the parties, the Software and all worldwide intellectual +property rights and proprietary rights relating thereto or embodied therein, +are the exclusive property of Stream.io and its suppliers. Stream.io and its +suppliers reserve all rights in and to the Software not expressly granted to +Customer in this Agreement, and no other licenses or rights are granted by +implication, estoppel or otherwise. + +12. WARRANTY DISCLAIMER. USE OF THIS SOFTWARE IS ENTIRELY AT YOURS AND CUSTOMER’S +OWN RISK. THE SOFTWARE IS PROVIDED “AS IS” WITHOUT ANY WARRANTY OF ANY KIND +WHATSOEVER. STREAM.IO DOES NOT MAKE, AND HEREBY DISCLAIMS, ANY WARRANTY OF ANY +KIND, WHETHER EXPRESS, IMPLIED, STATUTORY OR OTHERWISE, INCLUDING WITHOUT +LIMITATION, THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +PURPOSE, TITLE, NON-INFRINGEMENT OF THIRD-PARTY RIGHTS, RESULTS, EFFORTS, +QUALITY OR QUIET ENJOYMENT. STREAM.IO DOES NOT WARRANT THAT THE SOFTWARE IS +ERROR-FREE, WILL FUNCTION WITHOUT INTERRUPTION, WILL MEET ANY SPECIFIC NEED +THAT CUSTOMER HAS, THAT ALL DEFECTS WILL BE CORRECTED OR THAT IT IS +SUFFICIENTLY DOCUMENTED TO BE USABLE BY CUSTOMER. TO THE EXTENT THAT STREAM.IO +MAY NOT DISCLAIM ANY WARRANTY AS A MATTER OF APPLICABLE LAW, THE SCOPE AND +DURATION OF SUCH WARRANTY WILL BE THE MINIMUM PERMITTED UNDER SUCH LAW. +CUSTOMER ACKNOWLEDGES THAT IT HAS RELIED ON NO WARRANTIES OTHER THAN THE +EXPRESS WARRANTIES IN THIS AGREEMENT. + +13. LIMITATION OF LIABILITY. TO THE FULLEST EXTENT PERMISSIBLE BY LAW, STREAM.IO’S +TOTAL LIABILITY FOR ALL DAMAGES ARISING OUT OF OR RELATED TO THE SOFTWARE OR +THIS AGREEMENT, WHETHER IN CONTRACT, TORT (INCLUDING NEGLIGENCE) OR OTHERWISE, +SHALL NOT EXCEED $100. IN NO EVENT WILL STREAM.IO BE LIABLE FOR ANY INDIRECT, +CONSEQUENTIAL, EXEMPLARY, PUNITIVE, SPECIAL OR INCIDENTAL DAMAGES OF ANY KIND +WHATSOEVER, INCLUDING ANY LOST DATA AND LOST PROFITS, ARISING FROM OR RELATING +TO THE SOFTWARE EVEN IF STREAM.IO HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. CUSTOMER ACKNOWLEDGES THAT THIS PROVISION REFLECTS THE AGREED UPON +ALLOCATION OF RISK FOR THIS AGREEMENT AND THAT STREAM.IO WOULD NOT ENTER INTO +THIS AGREEMENT WITHOUT THESE LIMITATIONS ON ITS LIABILITY. + +14. General. Customer may not assign or transfer this Agreement, by operation of +law or otherwise, or any of its rights under this Agreement (including the +license rights granted to Customer) to any third party without Stream.io’s +prior written consent, which consent will not be unreasonably withheld or +delayed. Stream.io may assign this Agreement, without consent, including, but +limited to, affiliate or any successor to all or substantially all its business +or assets to which this Agreement relates, whether by merger, sale of assets, +sale of stock, reorganization or otherwise. Any attempted assignment or +transfer in violation of the foregoing will be null and void. Stream.io shall +not be liable hereunder by reason of any failure or delay in the performance of +its obligations hereunder for any cause which is beyond the reasonable control. +All notices, consents, and approvals under this Agreement must be delivered in +writing by courier, by electronic mail, or by certified or registered mail, +(postage prepaid and return receipt requested) to the other party at the +address set forth in the customer agreement between Stream.io and Customer and +will be effective upon receipt or when delivery is refused. This Agreement will +be governed by and interpreted in accordance with the laws of the State of +Colorado, without reference to its choice of laws rules. The United Nations +Convention on Contracts for the International Sale of Goods does not apply to +this Agreement. Any action or proceeding arising from or relating to this +Agreement shall be brought in a federal or state court in Denver, Colorado, and +each party irrevocably submits to the jurisdiction and venue of any such court +in any such action or proceeding. All waivers must be in writing. Any waiver or +failure to enforce any provision of this Agreement on one occasion will not be +deemed a waiver of any other provision or of such provision on any other +occasion. If any provision of this Agreement is unenforceable, such provision +will be changed and interpreted to accomplish the objectives of such provision +to the greatest extent possible under applicable law and the remaining +provisions will continue in full force and effect. Customer shall not violate +any applicable law, rule or regulation, including those regarding the export of +technical data. The headings of Sections of this Agreement are for convenience +and are not to be used in interpreting this Agreement. As used in this +Agreement, the word “including” means “including but not limited to.” This +Agreement (including all exhibits and attachments) constitutes the entire +agreement between the parties regarding the subject hereof and supersedes all +prior or contemporaneous agreements, understandings and communication, whether +written or oral. This Agreement may be amended only by a written document +signed by both parties. The terms of any purchase order or similar document +submitted by Customer to Stream.io will have no effect. diff --git a/packages/dart_client/README.md b/packages/dart_client/README.md new file mode 100644 index 00000000..241c2f4e --- /dev/null +++ b/packages/dart_client/README.md @@ -0,0 +1,107 @@ +# Stream Chat Dart +[![Pub](https://img.shields.io/pub/v/stream_chat.svg)](https://pub.dartlang.org/packages/stream_chat) +![](https://img.shields.io/badge/platform-flutter%20%7C%20flutter%20web-ff69b4.svg?style=flat-square) +![CI](https://github.com/GetStream/stream-chat-dart/workflows/CI/badge.svg?branch=master) +[![codecov](https://codecov.io/gh/GetStream/stream-chat-dart/branch/master/graph/badge.svg)](https://codecov.io/gh/GetStream/stream-chat-dart) + +stream-chat-dart is the official Dart client for Stream Chat, a service for building chat applications. This library can be used on any Dart project and on both mobile and web apps with Flutter. + +You can sign up for a Stream account at https://getstream.io/chat/ + +## Getting started + +### Add dependency + +```yaml +dependencies: + stream_chat: ^0.2.0 +``` + +You should then run `flutter packages get` + +## Example Project + +There is a detailed Flutter example project in the `example` folder. You can directly run and play on it. + +## Setup API Client + +First you need to instantiate a chat client. The Chat client will manage API call, event handling and manage the websocket connection to Stream Chat servers. You should only create the client once and re-use it across your application. + +```dart +final client = Client("stream-chat-api-key"); +``` + +### Logging + +By default the Chat Client will write all messages with level Warn or Error to stdout. + +#### Change Logging Level + +During development you might want to enable more logging information, you can change the default log level when constructing the client. + +```dart +final client = Client("stream-chat-api-key", logLevel: Level.INFO); +``` + +#### Custom Logger + +You can handle the log messages directly instead of have them written to stdout, this is very convenient if you use an error tracking tool or if you want to centralize your logs into one facility. + +```dart +myLogHandlerFunction = (LogRecord record) { + // do something with the record (ie. send it to Sentry or Fabric) +} + +final client = Client("stream-chat-api-key", logHandlerFunction: myLogHandlerFunction); +``` + +### Offline storage + +By default the library saves information about channels and messages in a SQLite DB. + +Set the property `persistenceEnabled` to false if you don't want to use the offline storage. + +## Flutter Web + +Due to Moor web (for offline storage) you need to include the sql.js library: + +```html + + + + + + + + + +``` + +You can grab the latest version of sql-wasm.js and sql-wasm.wasm [here](https://github.com/sql-js/sql.js/releases) and copy them into your `/web` folder. + +## Contributing + +### Code conventions + +- Make sure that you run `dartfmt` before commiting your code +- Make sure all public methods and functions are well documented + +### Running tests + +- run `flutter test` + +### Releasing a new version + +- update the package version on `pubspec.yaml` and `version.dart` + +- add a changelog entry on `CHANGELOG.md` + +- run `flutter pub publish` to publish the package + +### Watch models and generate JSON code + +JSON serialization relies on code generation; make sure to keep that running while you make changes to the library + +```bash +flutter pub run build_runner watch +``` diff --git a/packages/dart_client/analysis_options.yaml b/packages/dart_client/analysis_options.yaml new file mode 100644 index 00000000..87c12424 --- /dev/null +++ b/packages/dart_client/analysis_options.yaml @@ -0,0 +1,62 @@ +include: package:pedantic/analysis_options.yaml + +analyzer: + exclude: + - lib/**/*.g.dart + - example/* + - test/* + +linter: + rules: + # these rules are documented on and in the same order as + # the Dart Lint rules page to make maintenance easier + # https://github.com/dart-lang/linter/blob/master/example/all.yaml + # - always_declare_return_types + # - always_specify_types + # - annotate_overrides + # - avoid_as + - avoid_empty_else + - avoid_init_to_null + - avoid_return_types_on_setters + - avoid_web_libraries_in_flutter + - await_only_futures + - camel_case_types + - cancel_subscriptions + - close_sinks + # - comment_references # we do not presume as to what people want to reference in their dartdocs + # - constant_identifier_names # https://github.com/dart-lang/linter/issues/204 + - control_flow_in_finally + - empty_constructor_bodies + - empty_statements + - hash_and_equals + - implementation_imports + # - invariant_booleans + # - iterable_contains_unrelated_type + - library_names + # - library_prefixes + # - list_remove_unrelated_type + # - literal_only_boolean_expressions + - non_constant_identifier_names + # - one_member_abstracts + # - only_throw_errors + # - overridden_fields + - package_api_docs + - package_names + - package_prefixed_library_names + - prefer_is_not_empty + # - prefer_mixin # https://github.com/dart-lang/language/issues/32 + - public_member_api_docs + - slash_for_doc_comments + # - sort_constructors_first + # - sort_unnamed_constructors_first + # - super_goes_last # no longer needed w/ Dart 2 + - test_types_in_equals + - throw_in_finally + # - type_annotate_public_apis # subset of always_specify_types + - type_init_formals + # - unawaited_futures + - unnecessary_brace_in_string_interps + - unnecessary_getters_setters + - unnecessary_statements + - unrelated_type_equality_checks + - valid_regexps \ No newline at end of file diff --git a/packages/dart_client/build.yaml b/packages/dart_client/build.yaml new file mode 100644 index 00000000..ea58f519 --- /dev/null +++ b/packages/dart_client/build.yaml @@ -0,0 +1,11 @@ +targets: + $default: + builders: + moor_generator: + options: + generate_connect_constructor: true + json_serializable: + options: + explicit_to_json: true + field_rename: snake + any_map: true diff --git a/packages/dart_client/example/README.md b/packages/dart_client/example/README.md new file mode 100644 index 00000000..5bbae90f --- /dev/null +++ b/packages/dart_client/example/README.md @@ -0,0 +1 @@ +# Stream Chat Example App diff --git a/packages/dart_client/example/android/.gitignore b/packages/dart_client/example/android/.gitignore new file mode 100644 index 00000000..bc2100d8 --- /dev/null +++ b/packages/dart_client/example/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/packages/dart_client/example/android/app/build.gradle b/packages/dart_client/example/android/app/build.gradle new file mode 100644 index 00000000..0aa3ddb0 --- /dev/null +++ b/packages/dart_client/example/android/app/build.gradle @@ -0,0 +1,67 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.stream_chat" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + } + + buildTypes { + release { + // TODO: Add your own signing config for the release build. + // Signing with the debug keys for now, so `flutter run --release` works. + signingConfig signingConfigs.debug + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" + testImplementation 'junit:junit:4.12' + androidTestImplementation 'androidx.test:runner:1.1.1' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1' +} diff --git a/packages/dart_client/example/android/app/src/debug/AndroidManifest.xml b/packages/dart_client/example/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 00000000..f3e724c3 --- /dev/null +++ b/packages/dart_client/example/android/app/src/debug/AndroidManifest.xml @@ -0,0 +1,7 @@ + + + + diff --git a/packages/dart_client/example/android/app/src/main/AndroidManifest.xml b/packages/dart_client/example/android/app/src/main/AndroidManifest.xml new file mode 100644 index 00000000..03a0d883 --- /dev/null +++ b/packages/dart_client/example/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + diff --git a/packages/dart_client/example/android/app/src/main/kotlin/com/example/stream_chat_dart/MainActivity.kt b/packages/dart_client/example/android/app/src/main/kotlin/com/example/stream_chat_dart/MainActivity.kt new file mode 100644 index 00000000..ad61bdd4 --- /dev/null +++ b/packages/dart_client/example/android/app/src/main/kotlin/com/example/stream_chat_dart/MainActivity.kt @@ -0,0 +1,12 @@ +package com.example.stream_chat + +import androidx.annotation.NonNull; +import io.flutter.embedding.android.FlutterActivity +import io.flutter.embedding.engine.FlutterEngine +import io.flutter.plugins.GeneratedPluginRegistrant + +class MainActivity: FlutterActivity() { + override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) { + GeneratedPluginRegistrant.registerWith(flutterEngine); + } +} diff --git a/packages/dart_client/example/android/app/src/main/res/drawable/launch_background.xml b/packages/dart_client/example/android/app/src/main/res/drawable/launch_background.xml new file mode 100644 index 00000000..304732f8 --- /dev/null +++ b/packages/dart_client/example/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/packages/dart_client/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/packages/dart_client/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..db77bb4b7b0906d62b1847e87f15cdcacf6a4f29 GIT binary patch literal 544 zcmeAS@N?(olHy`uVBq!ia0vp^9w5xY3?!3`olAj~WQl7;NpOBzNqJ&XDuZK6ep0G} zXKrG8YEWuoN@d~6R2!h8bpbvhu0Wd6uZuB!w&u2PAxD2eNXD>P5D~Wn-+_Wa#27Xc zC?Zj|6r#X(-D3u$NCt}(Ms06KgJ4FxJVv{GM)!I~&n8Bnc94O7-Hd)cjDZswgC;Qs zO=b+9!WcT8F?0rF7!Uys2bs@gozCP?z~o%U|N3vA*22NaGQG zlg@K`O_XuxvZ&Ks^m&R!`&1=spLvfx7oGDKDwpwW`#iqdw@AL`7MR}m`rwr|mZgU`8P7SBkL78fFf!WnuYWm$5Z0 zNXhDbCv&49sM544K|?c)WrFfiZvCi9h0O)B3Pgg&ebxsLQ05GG~ AQ2+n{ literal 0 HcmV?d00001 diff --git a/packages/dart_client/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/packages/dart_client/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..17987b79bb8a35cc66c3c1fd44f5a5526c1b78be GIT binary patch literal 442 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA3?vioaBc-sk|nMYCBgY=CFO}lsSJ)O`AMk? zp1FzXsX?iUDV2pMQ*D5Xx&nMcT!A!W`0S9QKQy;}1Cl^CgaH=;G9cpY;r$Q>i*pfB zP2drbID<_#qf;rPZx^FqH)F_D#*k@@q03KywUtLX8Ua?`H+NMzkczFPK3lFz@i_kW%1NOn0|D2I9n9wzH8m|-tHjsw|9>@K=iMBhxvkv6m8Y-l zytQ?X=U+MF$@3 zt`~i=@j|6y)RWMK--}M|=T`o&^Ni>IoWKHEbBXz7?A@mgWoL>!*SXo`SZH-*HSdS+ yn*9;$7;m`l>wYBC5bq;=U}IMqLzqbYCidGC!)_gkIk_C@Uy!y&wkt5C($~2D>~)O*cj@FGjOCM)M>_ixfudOh)?xMu#Fs z#}Y=@YDTwOM)x{K_j*Q;dPdJ?Mz0n|pLRx{4n|)f>SXlmV)XB04CrSJn#dS5nK2lM zrZ9#~WelCp7&e13Y$jvaEXHskn$2V!!DN-nWS__6T*l;H&Fopn?A6HZ-6WRLFP=R` zqG+CE#d4|IbyAI+rJJ`&x9*T`+a=p|0O(+s{UBcyZdkhj=yS1>AirP+0R;mf2uMgM zC}@~JfByORAh4SyRgi&!(cja>F(l*O+nd+@4m$|6K6KDn_&uvCpV23&>G9HJp{xgg zoq1^2_p9@|WEo z*X_Uko@K)qYYv~>43eQGMdbiGbo>E~Q& zrYBH{QP^@Sti!`2)uG{irBBq@y*$B zi#&(U-*=fp74j)RyIw49+0MRPMRU)+a2r*PJ$L5roHt2$UjExCTZSbq%V!HeS7J$N zdG@vOZB4v_lF7Plrx+hxo7(fCV&}fHq)$ literal 0 HcmV?d00001 diff --git a/packages/dart_client/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/packages/dart_client/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..d5f1c8d34e7a88e3f88bea192c3a370d44689c3c GIT binary patch literal 1031 zcmeAS@N?(olHy`uVBq!ia0vp^6F``Q8Ax83A=Cw=BuiW)N`mv#O3D+9QW+dm@{>{( zJaZG%Q-e|yQz{EjrrIztFa`(sgt!6~Yi|1%a`XoT0ojZ}lNrNjb9xjc(B0U1_% zz5^97Xt*%oq$rQy4?0GKNfJ44uvxI)gC`h-NZ|&0-7(qS@?b!5r36oQ}zyZrNO3 zMO=Or+<~>+A&uN&E!^Sl+>xE!QC-|oJv`ApDhqC^EWD|@=#J`=d#Xzxs4ah}w&Jnc z$|q_opQ^2TrnVZ0o~wh<3t%W&flvYGe#$xqda2bR_R zvPYgMcHgjZ5nSA^lJr%;<&0do;O^tDDh~=pIxA#coaCY>&N%M2^tq^U%3DB@ynvKo}b?yu-bFc-u0JHzced$sg7S3zqI(2 z#Km{dPr7I=pQ5>FuK#)QwK?Y`E`B?nP+}U)I#c1+FM*1kNvWG|a(TpksZQ3B@sD~b zpQ2)*V*TdwjFOtHvV|;OsiDqHi=6%)o4b!)x$)%9pGTsE z-JL={-Ffv+T87W(Xpooq<`r*VzWQcgBN$$`u}f>-ZQI1BB8ykN*=e4rIsJx9>z}*o zo~|9I;xof literal 0 HcmV?d00001 diff --git a/packages/dart_client/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/packages/dart_client/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..4d6372eebdb28e45604e46eeda8dd24651419bc0 GIT binary patch literal 1443 zcmb`G{WsKk6vsdJTdFg%tJav9_E4vzrOaqkWF|A724Nly!y+?N9`YV6wZ}5(X(D_N(?!*n3`|_r0Hc?=PQw&*vnU?QTFY zB_MsH|!j$PP;I}?dppoE_gA(4uc!jV&0!l7_;&p2^pxNo>PEcNJv za5_RT$o2Mf!<+r?&EbHH6nMoTsDOa;mN(wv8RNsHpG)`^ymG-S5By8=l9iVXzN_eG%Xg2@Xeq76tTZ*dGh~Lo9vl;Zfs+W#BydUw zCkZ$o1LqWQO$FC9aKlLl*7x9^0q%0}$OMlp@Kk_jHXOjofdePND+j!A{q!8~Jn+s3 z?~~w@4?egS02}8NuulUA=L~QQfm;MzCGd)XhiftT;+zFO&JVyp2mBww?;QByS_1w! zrQlx%{^cMj0|Bo1FjwY@Q8?Hx0cIPF*@-ZRFpPc#bBw{5@tD(5%sClzIfl8WU~V#u zm5Q;_F!wa$BSpqhN>W@2De?TKWR*!ujY;Yylk_X5#~V!L*Gw~;$%4Q8~Mad z@`-kG?yb$a9cHIApZDVZ^U6Xkp<*4rU82O7%}0jjHlK{id@?-wpN*fCHXyXh(bLt* zPc}H-x0e4E&nQ>y%B-(EL=9}RyC%MyX=upHuFhAk&MLbsF0LP-q`XnH78@fT+pKPW zu72MW`|?8ht^tz$iC}ZwLp4tB;Q49K!QCF3@!iB1qOI=?w z7In!}F~ij(18UYUjnbmC!qKhPo%24?8U1x{7o(+?^Zu0Hx81|FuS?bJ0jgBhEMzf< zCgUq7r2OCB(`XkKcN-TL>u5y#dD6D!)5W?`O5)V^>jb)P)GBdy%t$uUMpf$SNV31$ zb||OojAbvMP?T@$h_ZiFLFVHDmbyMhJF|-_)HX3%m=CDI+ID$0^C>kzxprBW)hw(v zr!Gmda);ICoQyhV_oP5+C%?jcG8v+D@9f?Dk*!BxY}dazmrT@64UrP3hlslANK)bq z$67n83eh}OeW&SV@HG95P|bjfqJ7gw$e+`Hxo!4cx`jdK1bJ>YDSpGKLPZ^1cv$ek zIB?0S<#tX?SJCLWdMd{-ME?$hc7A$zBOdIJ)4!KcAwb=VMov)nK;9z>x~rfT1>dS+ zZ6#`2v@`jgbqq)P22H)Tx2CpmM^o1$B+xT6`(v%5xJ(?j#>Q$+rx_R|7TzDZe{J6q zG1*EcU%tE?!kO%^M;3aM6JN*LAKUVb^xz8-Pxo#jR5(-KBeLJvA@-gxNHx0M-ZJLl z;#JwQoh~9V?`UVo#}{6ka@II>++D@%KqGpMdlQ}?9E*wFcf5(#XQnP$Dk5~%iX^>f z%$y;?M0BLp{O3a(-4A?ewryHrrD%cx#Q^%KY1H zNre$ve+vceSLZcNY4U(RBX&)oZn*Py()h)XkE?PL$!bNb{N5FVI2Y%LKEm%yvpyTP z(1P?z~7YxD~Rf<(a@_y` literal 0 HcmV?d00001 diff --git a/packages/dart_client/example/android/app/src/main/res/values/styles.xml b/packages/dart_client/example/android/app/src/main/res/values/styles.xml new file mode 100644 index 00000000..00fa4417 --- /dev/null +++ b/packages/dart_client/example/android/app/src/main/res/values/styles.xml @@ -0,0 +1,8 @@ + + + + diff --git a/packages/dart_client/example/android/app/src/profile/AndroidManifest.xml b/packages/dart_client/example/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 00000000..f3e724c3 --- /dev/null +++ b/packages/dart_client/example/android/app/src/profile/AndroidManifest.xml @@ -0,0 +1,7 @@ + + + + diff --git a/packages/dart_client/example/android/build.gradle b/packages/dart_client/example/android/build.gradle new file mode 100644 index 00000000..3100ad2d --- /dev/null +++ b/packages/dart_client/example/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/packages/dart_client/example/android/gradle.properties b/packages/dart_client/example/android/gradle.properties new file mode 100644 index 00000000..38c8d454 --- /dev/null +++ b/packages/dart_client/example/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +android.useAndroidX=true +android.enableJetifier=true diff --git a/packages/dart_client/example/android/gradle/wrapper/gradle-wrapper.properties b/packages/dart_client/example/android/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 00000000..296b146b --- /dev/null +++ b/packages/dart_client/example/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/packages/dart_client/example/android/settings.gradle b/packages/dart_client/example/android/settings.gradle new file mode 100644 index 00000000..5a2f14fb --- /dev/null +++ b/packages/dart_client/example/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/packages/dart_client/example/ios/.gitignore b/packages/dart_client/example/ios/.gitignore new file mode 100644 index 00000000..e96ef602 --- /dev/null +++ b/packages/dart_client/example/ios/.gitignore @@ -0,0 +1,32 @@ +*.mode1v3 +*.mode2v3 +*.moved-aside +*.pbxuser +*.perspectivev3 +**/*sync/ +.sconsign.dblite +.tags* +**/.vagrant/ +**/DerivedData/ +Icon? +**/Pods/ +**/.symlinks/ +profile +xcuserdata +**/.generated/ +Flutter/App.framework +Flutter/Flutter.framework +Flutter/Flutter.podspec +Flutter/Generated.xcconfig +Flutter/app.flx +Flutter/app.zip +Flutter/flutter_assets/ +Flutter/flutter_export_environment.sh +ServiceDefinitions.json +Runner/GeneratedPluginRegistrant.* + +# Exceptions to above rules. +!default.mode1v3 +!default.mode2v3 +!default.pbxuser +!default.perspectivev3 diff --git a/packages/dart_client/example/ios/Flutter/AppFrameworkInfo.plist b/packages/dart_client/example/ios/Flutter/AppFrameworkInfo.plist new file mode 100644 index 00000000..6b4c0f78 --- /dev/null +++ b/packages/dart_client/example/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 8.0 + + diff --git a/packages/dart_client/example/ios/Flutter/Debug.xcconfig b/packages/dart_client/example/ios/Flutter/Debug.xcconfig new file mode 100644 index 00000000..e8efba11 --- /dev/null +++ b/packages/dart_client/example/ios/Flutter/Debug.xcconfig @@ -0,0 +1,2 @@ +#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" +#include "Generated.xcconfig" diff --git a/packages/dart_client/example/ios/Flutter/Release.xcconfig b/packages/dart_client/example/ios/Flutter/Release.xcconfig new file mode 100644 index 00000000..399e9340 --- /dev/null +++ b/packages/dart_client/example/ios/Flutter/Release.xcconfig @@ -0,0 +1,2 @@ +#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" +#include "Generated.xcconfig" diff --git a/packages/dart_client/example/ios/Runner.xcodeproj/project.pbxproj b/packages/dart_client/example/ios/Runner.xcodeproj/project.pbxproj new file mode 100644 index 00000000..7a054ad3 --- /dev/null +++ b/packages/dart_client/example/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,584 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; + 3B80C3941E831B6300D905FE /* App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; }; + 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; + 850BCB2A5C430C0BF58BF0DD /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2BA5904E77DC05E990FD1802 /* Pods_Runner.framework */; }; + 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; }; + 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */, + 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */, + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 0409BEB0CDB875557BCCDE42 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; + 1232C268B110F97C5CB93E3C /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; + 14A9392BD3E7B6A07FC5103E /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; + 2BA5904E77DC05E990FD1802 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; + 3B80C3931E831B6300D905FE /* App.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = App.framework; path = Flutter/App.framework; sourceTree = ""; }; + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; + 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; + 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; + 9740EEBA1CF902C7004384FC /* Flutter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Flutter.framework; path = Flutter/Flutter.framework; sourceTree = ""; }; + 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; + 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 97C146EB1CF9000F007C117D /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */, + 3B80C3941E831B6300D905FE /* App.framework in Frameworks */, + 850BCB2A5C430C0BF58BF0DD /* Pods_Runner.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 198533D8779F8F2800613F27 /* Frameworks */ = { + isa = PBXGroup; + children = ( + 2BA5904E77DC05E990FD1802 /* Pods_Runner.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; + 9740EEB11CF90186004384FC /* Flutter */ = { + isa = PBXGroup; + children = ( + 3B80C3931E831B6300D905FE /* App.framework */, + 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, + 9740EEBA1CF902C7004384FC /* Flutter.framework */, + 9740EEB21CF90195004384FC /* Debug.xcconfig */, + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, + 9740EEB31CF90195004384FC /* Generated.xcconfig */, + ); + name = Flutter; + sourceTree = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + 9E7371E7FEDE0F7EBA0661C0 /* Pods */, + 198533D8779F8F2800613F27 /* Frameworks */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 97C146F11CF9000F007C117D /* Supporting Files */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; + 97C146F11CF9000F007C117D /* Supporting Files */ = { + isa = PBXGroup; + children = ( + ); + name = "Supporting Files"; + sourceTree = ""; + }; + 9E7371E7FEDE0F7EBA0661C0 /* Pods */ = { + isa = PBXGroup; + children = ( + 0409BEB0CDB875557BCCDE42 /* Pods-Runner.debug.xcconfig */, + 1232C268B110F97C5CB93E3C /* Pods-Runner.release.xcconfig */, + 14A9392BD3E7B6A07FC5103E /* Pods-Runner.profile.xcconfig */, + ); + name = Pods; + path = Pods; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 97C146ED1CF9000F007C117D /* Runner */ = { + isa = PBXNativeTarget; + buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; + buildPhases = ( + 9233D2646E621705569E6ED8 /* [CP] Check Pods Manifest.lock */, + 9740EEB61CF901F6004384FC /* Run Script */, + 97C146EA1CF9000F007C117D /* Sources */, + 97C146EB1CF9000F007C117D /* Frameworks */, + 97C146EC1CF9000F007C117D /* Resources */, + 9705A1C41CF9048500538489 /* Embed Frameworks */, + 3B06AD1E1E4923F5004D2608 /* Thin Binary */, + 11808FAFAB0708F9F9320974 /* [CP] Embed Pods Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Runner; + productName = Runner; + productReference = 97C146EE1CF9000F007C117D /* Runner.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 97C146E61CF9000F007C117D /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 1020; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 11808FAFAB0708F9F9320974 /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "[CP] Embed Pods Frameworks"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" thin"; + }; + 9233D2646E621705569E6ED8 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Profile; + }; + 249021D4217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + ENABLE_BITCODE = NO; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.streamChatDart; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 97C147061CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + ENABLE_BITCODE = NO; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.streamChatDart; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Debug; + }; + 97C147071CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + ENABLE_BITCODE = NO; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.streamChatDart; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/packages/dart_client/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/packages/dart_client/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 00000000..1d526a16 --- /dev/null +++ b/packages/dart_client/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/packages/dart_client/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/packages/dart_client/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme new file mode 100644 index 00000000..a28140cf --- /dev/null +++ b/packages/dart_client/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/dart_client/example/ios/Runner.xcworkspace/contents.xcworkspacedata b/packages/dart_client/example/ios/Runner.xcworkspace/contents.xcworkspacedata new file mode 100644 index 00000000..21a3cc14 --- /dev/null +++ b/packages/dart_client/example/ios/Runner.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,10 @@ + + + + + + + diff --git a/packages/dart_client/example/ios/Runner/AppDelegate.swift b/packages/dart_client/example/ios/Runner/AppDelegate.swift new file mode 100644 index 00000000..70693e4a --- /dev/null +++ b/packages/dart_client/example/ios/Runner/AppDelegate.swift @@ -0,0 +1,13 @@ +import UIKit +import Flutter + +@UIApplicationMain +@objc class AppDelegate: FlutterAppDelegate { + override func application( + _ application: UIApplication, + didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? + ) -> Bool { + GeneratedPluginRegistrant.register(with: self) + return super.application(application, didFinishLaunchingWithOptions: launchOptions) + } +} diff --git a/packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 00000000..d36b1fab --- /dev/null +++ b/packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,122 @@ +{ + "images" : [ + { + "size" : "20x20", + "idiom" : "iphone", + "filename" : "Icon-App-20x20@2x.png", + "scale" : "2x" + }, + { + "size" : "20x20", + "idiom" : "iphone", + "filename" : "Icon-App-20x20@3x.png", + "scale" : "3x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@1x.png", + "scale" : "1x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@2x.png", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@3x.png", + "scale" : "3x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "Icon-App-40x40@2x.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "Icon-App-40x40@3x.png", + "scale" : "3x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "Icon-App-60x60@2x.png", + "scale" : "2x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "Icon-App-60x60@3x.png", + "scale" : "3x" + }, + { + "size" : "20x20", + "idiom" : "ipad", + "filename" : "Icon-App-20x20@1x.png", + "scale" : "1x" + }, + { + "size" : "20x20", + "idiom" : "ipad", + "filename" : "Icon-App-20x20@2x.png", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "Icon-App-29x29@1x.png", + "scale" : "1x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "Icon-App-29x29@2x.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "Icon-App-40x40@1x.png", + "scale" : "1x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "Icon-App-40x40@2x.png", + "scale" : "2x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "Icon-App-76x76@1x.png", + "scale" : "1x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "Icon-App-76x76@2x.png", + "scale" : "2x" + }, + { + "size" : "83.5x83.5", + "idiom" : "ipad", + "filename" : "Icon-App-83.5x83.5@2x.png", + "scale" : "2x" + }, + { + "size" : "1024x1024", + "idiom" : "ios-marketing", + "filename" : "Icon-App-1024x1024@1x.png", + "scale" : "1x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png b/packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png new file mode 100644 index 0000000000000000000000000000000000000000..dc9ada4725e9b0ddb1deab583e5b5102493aa332 GIT binary patch literal 10932 zcmeHN2~<R zh`|8`A_PQ1nSu(UMFx?8j8PC!!VDphaL#`F42fd#7Vlc`zIE4n%Y~eiz4y1j|NDpi z?<@|pSJ-HM`qifhf@m%MamgwK83`XpBA<+azdF#2QsT{X@z0A9Bq>~TVErigKH1~P zRX-!h-f0NJ4Mh++{D}J+K>~~rq}d%o%+4dogzXp7RxX4C>Km5XEI|PAFDmo;DFm6G zzjVoB`@qW98Yl0Kvc-9w09^PrsobmG*Eju^=3f?0o-t$U)TL1B3;sZ^!++3&bGZ!o-*6w?;oOhf z=A+Qb$scV5!RbG+&2S}BQ6YH!FKb0``VVX~T$dzzeSZ$&9=X$3)_7Z{SspSYJ!lGE z7yig_41zpQ)%5dr4ff0rh$@ky3-JLRk&DK)NEIHecf9c*?Z1bUB4%pZjQ7hD!A0r-@NF(^WKdr(LXj|=UE7?gBYGgGQV zidf2`ZT@pzXf7}!NH4q(0IMcxsUGDih(0{kRSez&z?CFA0RVXsVFw3^u=^KMtt95q z43q$b*6#uQDLoiCAF_{RFc{!H^moH_cmll#Fc^KXi{9GDl{>%+3qyfOE5;Zq|6#Hb zp^#1G+z^AXfRKaa9HK;%b3Ux~U@q?xg<2DXP%6k!3E)PA<#4$ui8eDy5|9hA5&{?v z(-;*1%(1~-NTQ`Is1_MGdQ{+i*ccd96ab$R$T3=% zw_KuNF@vI!A>>Y_2pl9L{9h1-C6H8<)J4gKI6{WzGBi<@u3P6hNsXG=bRq5c+z;Gc3VUCe;LIIFDmQAGy+=mRyF++u=drBWV8-^>0yE9N&*05XHZpPlE zxu@?8(ZNy7rm?|<+UNe0Vs6&o?l`Pt>P&WaL~M&#Eh%`rg@Mbb)J&@DA-wheQ>hRV z<(XhigZAT z>=M;URcdCaiO3d^?H<^EiEMDV+7HsTiOhoaMX%P65E<(5xMPJKxf!0u>U~uVqnPN7T!X!o@_gs3Ct1 zlZ_$5QXP4{Aj645wG_SNT&6m|O6~Tsl$q?nK*)(`{J4b=(yb^nOATtF1_aS978$x3 zx>Q@s4i3~IT*+l{@dx~Hst21fR*+5}S1@cf>&8*uLw-0^zK(+OpW?cS-YG1QBZ5q! zgTAgivzoF#`cSz&HL>Ti!!v#?36I1*l^mkrx7Y|K6L#n!-~5=d3;K<;Zqi|gpNUn_ z_^GaQDEQ*jfzh;`j&KXb66fWEk1K7vxQIMQ_#Wu_%3 z4Oeb7FJ`8I>Px;^S?)}2+4D_83gHEq>8qSQY0PVP?o)zAv3K~;R$fnwTmI-=ZLK`= zTm+0h*e+Yfr(IlH3i7gUclNH^!MU>id$Jw>O?2i0Cila#v|twub21@e{S2v}8Z13( zNDrTXZVgris|qYm<0NU(tAPouG!QF4ZNpZPkX~{tVf8xY690JqY1NVdiTtW+NqyRP zZ&;T0ikb8V{wxmFhlLTQ&?OP7 z;(z*<+?J2~z*6asSe7h`$8~Se(@t(#%?BGLVs$p``;CyvcT?7Y!{tIPva$LxCQ&4W z6v#F*);|RXvI%qnoOY&i4S*EL&h%hP3O zLsrFZhv&Hu5tF$Lx!8(hs&?!Kx5&L(fdu}UI5d*wn~A`nPUhG&Rv z2#ixiJdhSF-K2tpVL=)5UkXRuPAFrEW}7mW=uAmtVQ&pGE-&az6@#-(Te^n*lrH^m@X-ftVcwO_#7{WI)5v(?>uC9GG{lcGXYJ~Q8q zbMFl7;t+kV;|;KkBW2!P_o%Czhw&Q(nXlxK9ak&6r5t_KH8#1Mr-*0}2h8R9XNkr zto5-b7P_auqTJb(TJlmJ9xreA=6d=d)CVbYP-r4$hDn5|TIhB>SReMfh&OVLkMk-T zYf%$taLF0OqYF?V{+6Xkn>iX@TuqQ?&cN6UjC9YF&%q{Ut3zv{U2)~$>-3;Dp)*(? zg*$mu8^i=-e#acaj*T$pNowo{xiGEk$%DusaQiS!KjJH96XZ-hXv+jk%ard#fu=@Q z$AM)YWvE^{%tDfK%nD49=PI|wYu}lYVbB#a7wtN^Nml@CE@{Gv7+jo{_V?I*jkdLD zJE|jfdrmVbkfS>rN*+`#l%ZUi5_bMS<>=MBDNlpiSb_tAF|Zy`K7kcp@|d?yaTmB^ zo?(vg;B$vxS|SszusORgDg-*Uitzdi{dUV+glA~R8V(?`3GZIl^egW{a919!j#>f` znL1o_^-b`}xnU0+~KIFLQ)$Q6#ym%)(GYC`^XM*{g zv3AM5$+TtDRs%`2TyR^$(hqE7Y1b&`Jd6dS6B#hDVbJlUXcG3y*439D8MrK!2D~6gn>UD4Imctb z+IvAt0iaW73Iq$K?4}H`7wq6YkTMm`tcktXgK0lKPmh=>h+l}Y+pDtvHnG>uqBA)l zAH6BV4F}v$(o$8Gfo*PB>IuaY1*^*`OTx4|hM8jZ?B6HY;F6p4{`OcZZ(us-RVwDx zUzJrCQlp@mz1ZFiSZ*$yX3c_#h9J;yBE$2g%xjmGF4ca z&yL`nGVs!Zxsh^j6i%$a*I3ZD2SoNT`{D%mU=LKaEwbN(_J5%i-6Va?@*>=3(dQy` zOv%$_9lcy9+(t>qohkuU4r_P=R^6ME+wFu&LA9tw9RA?azGhjrVJKy&8=*qZT5Dr8g--d+S8zAyJ$1HlW3Olryt`yE zFIph~Z6oF&o64rw{>lgZISC6p^CBer9C5G6yq%?8tC+)7*d+ib^?fU!JRFxynRLEZ zj;?PwtS}Ao#9whV@KEmwQgM0TVP{hs>dg(1*DiMUOKHdQGIqa0`yZnHk9mtbPfoLx zo;^V6pKUJ!5#n`w2D&381#5#_t}AlTGEgDz$^;u;-vxDN?^#5!zN9ngytY@oTv!nc zp1Xn8uR$1Z;7vY`-<*?DfPHB;x|GUi_fI9@I9SVRv1)qETbNU_8{5U|(>Du84qP#7 z*l9Y$SgA&wGbj>R1YeT9vYjZuC@|{rajTL0f%N@>3$DFU=`lSPl=Iv;EjuGjBa$Gw zHD-;%YOE@<-!7-Mn`0WuO3oWuL6tB2cpPw~Nvuj|KM@))ixuDK`9;jGMe2d)7gHin zS<>k@!x;!TJEc#HdL#RF(`|4W+H88d4V%zlh(7#{q2d0OQX9*FW^`^_<3r$kabWAB z$9BONo5}*(%kx zOXi-yM_cmB3>inPpI~)duvZykJ@^^aWzQ=eQ&STUa}2uT@lV&WoRzkUoE`rR0)`=l zFT%f|LA9fCw>`enm$p7W^E@U7RNBtsh{_-7vVz3DtB*y#*~(L9+x9*wn8VjWw|Q~q zKFsj1Yl>;}%MG3=PY`$g$_mnyhuV&~O~u~)968$0b2!Jkd;2MtAP#ZDYw9hmK_+M$ zb3pxyYC&|CuAbtiG8HZjj?MZJBFbt`ryf+c1dXFuC z0*ZQhBzNBd*}s6K_G}(|Z_9NDV162#y%WSNe|FTDDhx)K!c(mMJh@h87@8(^YdK$&d*^WQe8Z53 z(|@MRJ$Lk-&ii74MPIs80WsOFZ(NX23oR-?As+*aq6b?~62@fSVmM-_*cb1RzZ)`5$agEiL`-E9s7{GM2?(KNPgK1(+c*|-FKoy}X(D_b#etO|YR z(BGZ)0Ntfv-7R4GHoXp?l5g#*={S1{u-QzxCGng*oWr~@X-5f~RA14b8~B+pLKvr4 zfgL|7I>jlak9>D4=(i(cqYf7#318!OSR=^`xxvI!bBlS??`xxWeg?+|>MxaIdH1U~#1tHu zB{QMR?EGRmQ_l4p6YXJ{o(hh-7Tdm>TAX380TZZZyVkqHNzjUn*_|cb?T? zt;d2s-?B#Mc>T-gvBmQZx(y_cfkXZO~{N zT6rP7SD6g~n9QJ)8F*8uHxTLCAZ{l1Y&?6v)BOJZ)=R-pY=Y=&1}jE7fQ>USS}xP#exo57uND0i*rEk@$;nLvRB@u~s^dwRf?G?_enN@$t* zbL%JO=rV(3Ju8#GqUpeE3l_Wu1lN9Y{D4uaUe`g>zlj$1ER$6S6@{m1!~V|bYkhZA z%CvrDRTkHuajMU8;&RZ&itnC~iYLW4DVkP<$}>#&(`UO>!n)Po;Mt(SY8Yb`AS9lt znbX^i?Oe9r_o=?})IHKHoQGKXsps_SE{hwrg?6dMI|^+$CeC&z@*LuF+P`7LfZ*yr+KN8B4{Nzv<`A(wyR@!|gw{zB6Ha ziwPAYh)oJ(nlqSknu(8g9N&1hu0$vFK$W#mp%>X~AU1ay+EKWcFdif{% z#4!4aoVVJ;ULmkQf!ke2}3hqxLK>eq|-d7Ly7-J9zMpT`?dxo6HdfJA|t)?qPEVBDv z{y_b?4^|YA4%WW0VZd8C(ZgQzRI5(I^)=Ub`Y#MHc@nv0w-DaJAqsbEHDWG8Ia6ju zo-iyr*sq((gEwCC&^TYBWt4_@|81?=B-?#P6NMff(*^re zYqvDuO`K@`mjm_Jd;mW_tP`3$cS?R$jR1ZN09$YO%_iBqh5ftzSpMQQtxKFU=FYmP zeY^jph+g<4>YO;U^O>-NFLn~-RqlHvnZl2yd2A{Yc1G@Ga$d+Q&(f^tnPf+Z7serIU};17+2DU_f4Z z@GaPFut27d?!YiD+QP@)T=77cR9~MK@bd~pY%X(h%L={{OIb8IQmf-!xmZkm8A0Ga zQSWONI17_ru5wpHg3jI@i9D+_Y|pCqVuHJNdHUauTD=R$JcD2K_liQisqG$(sm=k9;L* z!L?*4B~ql7uioSX$zWJ?;q-SWXRFhz2Jt4%fOHA=Bwf|RzhwqdXGr78y$J)LR7&3T zE1WWz*>GPWKZ0%|@%6=fyx)5rzUpI;bCj>3RKzNG_1w$fIFCZ&UR0(7S?g}`&Pg$M zf`SLsz8wK82Vyj7;RyKmY{a8G{2BHG%w!^T|Njr!h9TO2LaP^_f22Q1=l$QiU84ao zHe_#{S6;qrC6w~7{y(hs-?-j?lbOfgH^E=XcSgnwW*eEz{_Z<_Px$?ny*JR5%f>l)FnDQ543{x%ZCiu33$Wg!pQFfT_}?5Q|_VSlIbLC`dpoMXL}9 zHfd9&47Mo(7D231gb+kjFxZHS4-m~7WurTH&doVX2KI5sU4v(sJ1@T9eCIKPjsqSr z)C01LsCxk=72-vXmX}CQD#BD;Cthymh&~=f$Q8nn0J<}ZrusBy4PvRNE}+1ceuj8u z0mW5k8fmgeLnTbWHGwfKA3@PdZxhn|PypR&^p?weGftrtCbjF#+zk_5BJh7;0`#Wr zgDpM_;Ax{jO##IrT`Oz;MvfwGfV$zD#c2xckpcXC6oou4ML~ezCc2EtnsQTB4tWNg z?4bkf;hG7IMfhgNI(FV5Gs4|*GyMTIY0$B=_*mso9Ityq$m^S>15>-?0(zQ<8Qy<_TjHE33(?_M8oaM zyc;NxzRVK@DL6RJnX%U^xW0Gpg(lXp(!uK1v0YgHjs^ZXSQ|m#lV7ip7{`C_J2TxPmfw%h$|%acrYHt)Re^PB%O&&=~a zhS(%I#+V>J-vjIib^<+s%ludY7y^C(P8nmqn9fp!i+?vr`bziDE=bx`%2W#Xyrj|i z!XQ4v1%L`m{7KT7q+LZNB^h8Ha2e=`Wp65^0;J00)_^G=au=8Yo;1b`CV&@#=jIBo zjN^JNVfYSs)+kDdGe7`1&8!?MQYKS?DuHZf3iogk_%#9E|5S zWeHrmAo>P;ejX7mwq#*}W25m^ZI+{(Z8fI?4jM_fffY0nok=+88^|*_DwcW>mR#e+ zX$F_KMdb6sRz!~7KkyN0G(3XQ+;z3X%PZ4gh;n-%62U<*VUKNv(D&Q->Na@Xb&u5Q3`3DGf+a8O5x7c#7+R+EAYl@R5us)CIw z7sT@_y~Ao@uL#&^LIh&QceqiT^+lb0YbFZt_SHOtWA%mgPEKVNvVgCsXy{5+zl*X8 zCJe)Q@y>wH^>l4;h1l^Y*9%-23TSmE>q5nI@?mt%n;Sj4Qq`Z+ib)a*a^cJc%E9^J zB;4s+K@rARbcBLT5P=@r;IVnBMKvT*)ew*R;&8vu%?Z&S>s?8?)3*YawM0P4!q$Kv zMmKh3lgE~&w&v%wVzH3Oe=jeNT=n@Y6J6TdHWTjXfX~-=1A1Bw`EW8rn}MqeI34nh zexFeA?&C3B2(E?0{drE@DA2pu(A#ElY&6el60Rn|Qpn-FkfQ8M93AfWIr)drgDFEU zghdWK)^71EWCP(@(=c4kfH1Y(4iugD4fve6;nSUpLT%!)MUHs1!zJYy4y||C+SwQ! z)KM&$7_tyM`sljP2fz6&Z;jxRn{Wup8IOUx8D4uh&(=O zx-7$a;U><*5L^!%xRlw)vAbh;sdlR||& ze}8_8%)c2Fwy=F&H|LM+p{pZB5DKTx>Y?F1N%BlZkXf!}JeGuMZk~LPi7{cidvUGB zAJ4LVeNV%XO>LTrklB#^-;8nb;}6l;1oW&WS=Mz*Az!4cqqQzbOSFq`$Q%PfD7srM zpKgP-D_0XPTRX*hAqeq0TDkJ;5HB1%$3Np)99#16c{ zJImlNL(npL!W|Gr_kxl1GVmF5&^$^YherS7+~q$p zt}{a=*RiD2Ikv6o=IM1kgc7zqpaZ;OB)P!1zz*i3{U()Dq#jG)egvK}@uFLa`oyWZ zf~=MV)|yJn`M^$N%ul5);JuQvaU1r2wt(}J_Qgyy`qWQI`hEeRX0uC@c1(dQ2}=U$ tNIIaX+dr)NRWXcxoR{>fqI{SF_dm1Ylv~=3YHI)h002ovPDHLkV1g(pWS;;4 literal 0 HcmV?d00001 diff --git a/packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..f091b6b0bca859a3f474b03065bef75ba58a9e4c GIT binary patch literal 1588 zcmV-42Fv-0P)C1SqPt}wig>|5Crh^=oyX$BK<}M8eLU3e2hGT;=G|!_SP)7zNI6fqUMB=)y zRAZ>eDe#*r`yDAVgB_R*LB*MAc)8(b{g{9McCXW!lq7r(btRoB9!8B-#AI6JMb~YFBEvdsV)`mEQO^&#eRKx@b&x- z5lZm*!WfD8oCLzfHGz#u7sT0^VLMI1MqGxF^v+`4YYnVYgk*=kU?HsSz{v({E3lb9 z>+xILjBN)t6`=g~IBOelGQ(O990@BfXf(DRI5I$qN$0Gkz-FSc$3a+2fX$AedL4u{ z4V+5Ong(9LiGcIKW?_352sR;LtDPmPJXI{YtT=O8=76o9;*n%_m|xo!i>7$IrZ-{l z-x3`7M}qzHsPV@$v#>H-TpjDh2UE$9g6sysUREDy_R(a)>=eHw-WAyfIN z*qb!_hW>G)Tu8nSw9yn#3wFMiLcfc4pY0ek1}8(NqkBR@t4{~oC>ryc-h_ByH(Cg5 z>ao-}771+xE3um9lWAY1FeQFxowa1(!J(;Jg*wrg!=6FdRX+t_<%z&d&?|Bn){>zm zZQj(aA_HeBY&OC^jj*)N`8fa^ePOU72VpInJoI1?`ty#lvlNzs(&MZX+R%2xS~5Kh zX*|AU4QE#~SgPzOXe9>tRj>hjU@c1k5Y_mW*Jp3fI;)1&g3j|zDgC+}2Q_v%YfDax z!?umcN^n}KYQ|a$Lr+51Nf9dkkYFSjZZjkma$0KOj+;aQ&721~t7QUKx61J3(P4P1 zstI~7-wOACnWP4=8oGOwz%vNDqD8w&Q`qcNGGrbbf&0s9L0De{4{mRS?o0MU+nR_! zrvshUau0G^DeMhM_v{5BuLjb#Hh@r23lDAk8oF(C+P0rsBpv85EP>4CVMx#04MOfG z;P%vktHcXwTj~+IE(~px)3*MY77e}p#|c>TD?sMatC0Tu4iKKJ0(X8jxQY*gYtxsC z(zYC$g|@+I+kY;dg_dE>scBf&bP1Nc@Hz<3R)V`=AGkc;8CXqdi=B4l2k|g;2%#m& z*jfX^%b!A8#bI!j9-0Fi0bOXl(-c^AB9|nQaE`*)Hw+o&jS9@7&Gov#HbD~#d{twV zXd^Tr^mWLfFh$@Dr$e;PBEz4(-2q1FF0}c;~B5sA}+Q>TOoP+t>wf)V9Iy=5ruQa;z)y zI9C9*oUga6=hxw6QasLPnee@3^Rr*M{CdaL5=R41nLs(AHk_=Y+A9$2&H(B7!_pURs&8aNw7?`&Z&xY_Ye z)~D5Bog^td-^QbUtkTirdyK^mTHAOuptDflut!#^lnKqU md>ggs(5nOWAqO?umG&QVYK#ibz}*4>0000U6E9hRK9^#O7(mu>ETqrXGsduA8$)?`v2seloOCza43C{NQ$$gAOH**MCn0Q?+L7dl7qnbRdqZ8LSVp1ItDxhxD?t@5_yHg6A8yI zC*%Wgg22K|8E#!~cTNYR~@Y9KepMPrrB8cABapAFa=`H+UGhkXUZV1GnwR1*lPyZ;*K(i~2gp|@bzp8}og7e*#% zEnr|^CWdVV!-4*Y_7rFvlww2Ze+>j*!Z!pQ?2l->4q#nqRu9`ELo6RMS5=br47g_X zRw}P9a7RRYQ%2Vsd0Me{_(EggTnuN6j=-?uFS6j^u69elMypu?t>op*wBx<=Wx8?( ztpe^(fwM6jJX7M-l*k3kEpWOl_Vk3@(_w4oc}4YF4|Rt=2V^XU?#Yz`8(e?aZ@#li0n*=g^qOcVpd-Wbok=@b#Yw zqn8u9a)z>l(1kEaPYZ6hwubN6i<8QHgsu0oE) ziJ(p;Wxm>sf!K+cw>R-(^Y2_bahB+&KI9y^);#0qt}t-$C|Bo71lHi{_+lg#f%RFy z0um=e3$K3i6K{U_4K!EX?F&rExl^W|G8Z8;`5z-k}OGNZ0#WVb$WCpQu-_YsiqKP?BB# vzVHS-CTUF4Ozn5G+mq_~Qqto~ahA+K`|lyv3(-e}00000NkvXXu0mjfd`9t{ literal 0 HcmV?d00001 diff --git a/packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..d0ef06e7edb86cdfe0d15b4b0d98334a86163658 GIT binary patch literal 1716 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 literal 0 HcmV?d00001 diff --git a/packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..c8f9ed8f5cee1c98386d13b17e89f719e83555b2 GIT binary patch literal 1895 zcmV-t2blPYP)FQtfgmafE#=YDCq`qUBt#QpG%*H6QHY765~R=q zZ6iudfM}q!Pz#~9JgOi8QJ|DSu?1-*(kSi1K4#~5?#|rh?sS)(-JQqX*}ciXJ56_H zdw=^s_srbAdqxlvGyrgGet#6T7_|j;95sL%MtM;q86vOxKM$f#puR)Bjv9Zvz9-di zXOTSsZkM83)E9PYBXC<$6(|>lNLVBb&&6y{NByFCp%6+^ALR@NCTse_wqvNmSWI-m z!$%KlHFH2omF!>#%1l3LTZg(s7eof$7*xB)ZQ0h?ejh?Ta9fDv59+u#MokW+1t8Zb zgHv%K(u9G^Lv`lh#f3<6!JVTL3(dCpxHbnbA;kKqQyd1~^Xe0VIaYBSWm6nsr;dFj z4;G-RyL?cYgsN1{L4ZFFNa;8)Rv0fM0C(~Tkit94 zz#~A)59?QjD&pAPSEQ)p8gP|DS{ng)j=2ux)_EzzJ773GmQ_Cic%3JJhC0t2cx>|v zJcVusIB!%F90{+}8hG3QU4KNeKmK%T>mN57NnCZ^56=0?&3@!j>a>B43pi{!u z7JyDj7`6d)qVp^R=%j>UIY6f+3`+qzIc!Y_=+uN^3BYV|o+$vGo-j-Wm<10%A=(Yk^beI{t%ld@yhKjq0iNjqN4XMGgQtbKubPM$JWBz}YA65k%dm*awtC^+f;a-x4+ddbH^7iDWGg&N0n#MW{kA|=8iMUiFYvMoDY@sPC#t$55gn6ykUTPAr`a@!(;np824>2xJthS z*ZdmT`g5-`BuJs`0LVhz+D9NNa3<=6m;cQLaF?tCv8)zcRSh66*Z|vXhG@$I%U~2l z?`Q zykI#*+rQ=z6Jm=Bui-SfpDYLA=|vzGE(dYm=OC8XM&MDo7ux4UF1~0J1+i%aCUpRe zt3L_uNyQ*cE(38Uy03H%I*)*Bh=Lb^Xj3?I^Hnbeq72(EOK^Y93CNp*uAA{5Lc=ky zx=~RKa4{iTm{_>_vSCm?$Ej=i6@=m%@VvAITnigVg{&@!7CDgs908761meDK5azA} z4?=NOH|PdvabgJ&fW2{Mo$Q0CcD8Qc84%{JPYt5EiG{MdLIAeX%T=D7NIP4%Hw}p9 zg)==!2Lbp#j{u_}hMiao9=!VSyx0gHbeCS`;q&vzeq|fs`y&^X-lso(Ls@-706qmA z7u*T5PMo_w3{se1t2`zWeO^hOvTsohG_;>J0wVqVe+n)AbQCx)yh9;w+J6?NF5Lmo zecS@ieAKL8%bVd@+-KT{yI|S}O>pYckUFs;ry9Ow$CD@ztz5K-*D$^{i(_1llhSh^ zEkL$}tsQt5>QA^;QgjgIfBDmcOgi5YDyu?t6vSnbp=1+@6D& z5MJ}B8q;bRlVoxasyhcUF1+)o`&3r0colr}QJ3hcSdLu;9;td>kf@Tcn<@9sIx&=m z;AD;SCh95=&p;$r{Xz3iWCO^MX83AGJ(yH&eTXgv|0=34#-&WAmw{)U7OU9!Wz^!7 zZ%jZFi@JR;>Mhi7S>V7wQ176|FdW2m?&`qa(ScO^CFPR80HucLHOTy%5s*HR0^8)i h0WYBP*#0Ks^FNSabJA*5${_#%002ovPDHLkV1oKhTl@e3 literal 0 HcmV?d00001 diff --git a/packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..a6d6b8609df07bf62e5100a53a01510388bd2b22 GIT binary patch literal 2665 zcmV-v3YPVWP)oFh3q0MFesq&64WThn3$;G69TfjsAv=f2G9}p zgSx99+!YV6qME!>9MD13x)k(+XE7W?_O4LoLb5ND8 zaV{9+P@>42xDfRiYBMSgD$0!vssptcb;&?u9u(LLBKmkZ>RMD=kvD3h`sk6!QYtBa ztlZI#nu$8lJ^q2Z79UTgZe>BU73(Aospiq+?SdMt8lDZ;*?@tyWVZVS_Q7S&*tJaiRlJ z+aSMOmbg3@h5}v;A*c8SbqM3icg-`Cnwl;7Ts%A1RkNIp+Txl-Ckkvg4oxrqGA5ewEgYqwtECD<_3Egu)xGllKt&J8g&+=ac@Jq4-?w6M3b*>w5 z69N3O%=I^6&UL5gZ!}trC7bUj*12xLdkNs~Bz4QdJJ*UDZox2UGR}SNg@lmOvhCc~ z*f_UeXv(=#I#*7>VZx2ObEN~UoGUTl=-@)E;YtCRZ>SVp$p9yG5hEFZ!`wI!spd)n zSk+vK0Vin7FL{7f&6OB%f;SH22dtbcF<|9fi2Fp%q4kxL!b1#l^)8dUwJ zwEf{(wJj@8iYDVnKB`eSU+;ml-t2`@%_)0jDM`+a46xhDbBj2+&Ih>1A>6aky#(-SYyE{R3f#y57wfLs z6w1p~$bp;6!9DX$M+J~S@D6vJAaElETnsX4h9a5tvPhC3L@qB~bOzkL@^z0k_hS{T4PF*TDrgdXp+dzsE? z>V|VR035Pl9n5&-RePFdS{7KAr2vPOqR9=M$vXA1Yy5>w;EsF`;OK{2pkn-kpp9Pw z)r;5JfJKKaT$4qCb{TaXHjb$QA{y0EYy*+b1XI;6Ah- zw13P)xT`>~eFoJC!>{2XL(a_#upp3gaR1#5+L(Jmzp4TBnx{~WHedpJ1ch8JFk~Sw z>F+gN+i+VD?gMXwcIhn8rz`>e>J^TI3E-MW>f}6R-pL}>WMOa0k#jN+`RyUVUC;#D zg|~oS^$6%wpF{^Qr+}X>0PKcr3Fc&>Z>uv@C);pwDs@2bZWhYP!rvGx?_|q{d`t<*XEb#=aOb=N+L@CVBGqImZf&+a zCQEa3$~@#kC);pasdG=f6tuIi0PO-y&tvX%>Mv=oY3U$nD zJ#gMegnQ46pq+3r=;zmgcG+zRc9D~c>z+jo9&D+`E6$LmyFqlmCYw;-Zooma{sR@~ z)_^|YL1&&@|GXo*pivH7k!msl+$Sew3%XJnxajt0K%3M6Bd&YFNy9}tWG^aovK2eX z1aL1%7;KRDrA@eG-Wr6w+;*H_VD~qLiVI`{_;>o)k`{8xa3EJT1O_>#iy_?va0eR? zDV=N%;Zjb%Z2s$@O>w@iqt!I}tLjGk!=p`D23I}N4Be@$(|iSA zf3Ih7b<{zqpDB4WF_5X1(peKe+rASze%u8eKLn#KKXt;UZ+Adf$_TO+vTqshLLJ5c z52HucO=lrNVae5XWOLm!V@n-ObU11!b+DN<$RuU+YsrBq*lYT;?AwJpmNKniF0Q1< zJCo>Q$=v$@&y=sj6{r!Y&y&`0$-I}S!H_~pI&2H8Z1C|BX4VgZ^-! zje3-;x0PBD!M`v*J_)rL^+$<1VJhH*2Fi~aA7s&@_rUHYJ9zD=M%4AFQ`}k8OC$9s XsPq=LnkwKG00000NkvXXu0mjfhAk5^ literal 0 HcmV?d00001 diff --git a/packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..a6d6b8609df07bf62e5100a53a01510388bd2b22 GIT binary patch literal 2665 zcmV-v3YPVWP)oFh3q0MFesq&64WThn3$;G69TfjsAv=f2G9}p zgSx99+!YV6qME!>9MD13x)k(+XE7W?_O4LoLb5ND8 zaV{9+P@>42xDfRiYBMSgD$0!vssptcb;&?u9u(LLBKmkZ>RMD=kvD3h`sk6!QYtBa ztlZI#nu$8lJ^q2Z79UTgZe>BU73(Aospiq+?SdMt8lDZ;*?@tyWVZVS_Q7S&*tJaiRlJ z+aSMOmbg3@h5}v;A*c8SbqM3icg-`Cnwl;7Ts%A1RkNIp+Txl-Ckkvg4oxrqGA5ewEgYqwtECD<_3Egu)xGllKt&J8g&+=ac@Jq4-?w6M3b*>w5 z69N3O%=I^6&UL5gZ!}trC7bUj*12xLdkNs~Bz4QdJJ*UDZox2UGR}SNg@lmOvhCc~ z*f_UeXv(=#I#*7>VZx2ObEN~UoGUTl=-@)E;YtCRZ>SVp$p9yG5hEFZ!`wI!spd)n zSk+vK0Vin7FL{7f&6OB%f;SH22dtbcF<|9fi2Fp%q4kxL!b1#l^)8dUwJ zwEf{(wJj@8iYDVnKB`eSU+;ml-t2`@%_)0jDM`+a46xhDbBj2+&Ih>1A>6aky#(-SYyE{R3f#y57wfLs z6w1p~$bp;6!9DX$M+J~S@D6vJAaElETnsX4h9a5tvPhC3L@qB~bOzkL@^z0k_hS{T4PF*TDrgdXp+dzsE? z>V|VR035Pl9n5&-RePFdS{7KAr2vPOqR9=M$vXA1Yy5>w;EsF`;OK{2pkn-kpp9Pw z)r;5JfJKKaT$4qCb{TaXHjb$QA{y0EYy*+b1XI;6Ah- zw13P)xT`>~eFoJC!>{2XL(a_#upp3gaR1#5+L(Jmzp4TBnx{~WHedpJ1ch8JFk~Sw z>F+gN+i+VD?gMXwcIhn8rz`>e>J^TI3E-MW>f}6R-pL}>WMOa0k#jN+`RyUVUC;#D zg|~oS^$6%wpF{^Qr+}X>0PKcr3Fc&>Z>uv@C);pwDs@2bZWhYP!rvGx?_|q{d`t<*XEb#=aOb=N+L@CVBGqImZf&+a zCQEa3$~@#kC);pasdG=f6tuIi0PO-y&tvX%>Mv=oY3U$nD zJ#gMegnQ46pq+3r=;zmgcG+zRc9D~c>z+jo9&D+`E6$LmyFqlmCYw;-Zooma{sR@~ z)_^|YL1&&@|GXo*pivH7k!msl+$Sew3%XJnxajt0K%3M6Bd&YFNy9}tWG^aovK2eX z1aL1%7;KRDrA@eG-Wr6w+;*H_VD~qLiVI`{_;>o)k`{8xa3EJT1O_>#iy_?va0eR? zDV=N%;Zjb%Z2s$@O>w@iqt!I}tLjGk!=p`D23I}N4Be@$(|iSA zf3Ih7b<{zqpDB4WF_5X1(peKe+rASze%u8eKLn#KKXt;UZ+Adf$_TO+vTqshLLJ5c z52HucO=lrNVae5XWOLm!V@n-ObU11!b+DN<$RuU+YsrBq*lYT;?AwJpmNKniF0Q1< zJCo>Q$=v$@&y=sj6{r!Y&y&`0$-I}S!H_~pI&2H8Z1C|BX4VgZ^-! zje3-;x0PBD!M`v*J_)rL^+$<1VJhH*2Fi~aA7s&@_rUHYJ9zD=M%4AFQ`}k8OC$9s XsPq=LnkwKG00000NkvXXu0mjfhAk5^ literal 0 HcmV?d00001 diff --git a/packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..75b2d164a5a98e212cca15ea7bf2ab5de5108680 GIT binary patch literal 3831 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 literal 0 HcmV?d00001 diff --git a/packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png new file mode 100644 index 0000000000000000000000000000000000000000..c4df70d39da7941ef3f6dcb7f06a192d8dcb308d GIT binary patch literal 1888 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 iW8Zci7-kcv6Uzs@r-FtIZ-&5|)J Q1PU{Fy85}Sb4q9e0B4a5jsO4v literal 0 HcmV?d00001 diff --git a/packages/dart_client/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png b/packages/dart_client/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..9da19eacad3b03bb08bbddbbf4ac48dd78b3d838 GIT binary patch literal 68 zcmeAS@N?(olHy`uVBq!ia0vp^j3CUx0wlM}@Gt=>Zci7-kcv6Uzs@r-FtIZ-&5|)J Q1PU{Fy85}Sb4q9e0B4a5jsO4v literal 0 HcmV?d00001 diff --git a/packages/dart_client/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png b/packages/dart_client/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..9da19eacad3b03bb08bbddbbf4ac48dd78b3d838 GIT binary patch literal 68 zcmeAS@N?(olHy`uVBq!ia0vp^j3CUx0wlM}@Gt=>Zci7-kcv6Uzs@r-FtIZ-&5|)J Q1PU{Fy85}Sb4q9e0B4a5jsO4v literal 0 HcmV?d00001 diff --git a/packages/dart_client/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md b/packages/dart_client/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md new file mode 100644 index 00000000..89c2725b --- /dev/null +++ b/packages/dart_client/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md @@ -0,0 +1,5 @@ +# Launch Screen Assets + +You can customize the launch screen with your own desired assets by replacing the image files in this directory. + +You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images. \ No newline at end of file diff --git a/packages/dart_client/example/ios/Runner/Base.lproj/LaunchScreen.storyboard b/packages/dart_client/example/ios/Runner/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 00000000..f2e259c7 --- /dev/null +++ b/packages/dart_client/example/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/dart_client/example/ios/Runner/Base.lproj/Main.storyboard b/packages/dart_client/example/ios/Runner/Base.lproj/Main.storyboard new file mode 100644 index 00000000..f3c28516 --- /dev/null +++ b/packages/dart_client/example/ios/Runner/Base.lproj/Main.storyboard @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/dart_client/example/ios/Runner/Info.plist b/packages/dart_client/example/ios/Runner/Info.plist new file mode 100644 index 00000000..d89e1ca3 --- /dev/null +++ b/packages/dart_client/example/ios/Runner/Info.plist @@ -0,0 +1,50 @@ + + + + + NSAppTransportSecurity + + NSAllowsArbitraryLoads + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + stream_chat + CFBundlePackageType + APPL + CFBundleShortVersionString + $(FLUTTER_BUILD_NAME) + CFBundleSignature + ???? + CFBundleVersion + $(FLUTTER_BUILD_NUMBER) + LSRequiresIPhoneOS + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UIViewControllerBasedStatusBarAppearance + + + diff --git a/packages/dart_client/example/ios/Runner/Runner-Bridging-Header.h b/packages/dart_client/example/ios/Runner/Runner-Bridging-Header.h new file mode 100644 index 00000000..308a2a56 --- /dev/null +++ b/packages/dart_client/example/ios/Runner/Runner-Bridging-Header.h @@ -0,0 +1 @@ +#import "GeneratedPluginRegistrant.h" diff --git a/packages/dart_client/example/lib/channel_header.dart b/packages/dart_client/example/lib/channel_header.dart new file mode 100644 index 00000000..c452a2f5 --- /dev/null +++ b/packages/dart_client/example/lib/channel_header.dart @@ -0,0 +1,83 @@ +import 'package:flutter/material.dart'; +import 'package:stream_chat/stream_chat.dart'; +import 'package:timeago/timeago.dart' as timeago; + +import './channel_name_text.dart'; +import 'channel_image.dart'; +import 'stream_channel.dart'; + +class ChannelHeader extends StatelessWidget implements PreferredSizeWidget { + final bool showBackButton; + final VoidCallback onBackPressed; + + ChannelHeader({ + Key key, + this.showBackButton = true, + this.onBackPressed, + }) : preferredSize = Size.fromHeight(kToolbarHeight), + super(key: key); + + @override + Widget build(BuildContext context) { + final streamChat = StreamChannel.of(context); + return AppBar( + leading: showBackButton ? _buildBackButton(context) : Container(), + actions: [ + Padding( + padding: const EdgeInsets.only(right: 10.0), + child: ChannelImage(channel: streamChat.channel), + ), + ], + centerTitle: true, + title: Column( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + ChannelNameText( + channel: streamChat.channel, + ), + _buildLastActive(context, streamChat.channel), + ], + ), + ); + } + + StatelessWidget _buildLastActive(BuildContext context, Channel channel) { + return (channel.lastMessageAt != null) + ? Text( + 'Active ${timeago.format(channel.lastMessageAt)}', + style: Theme.of(context).textTheme.caption, + ) + : Container(); + } + + Padding _buildBackButton(BuildContext context) { + return Padding( + padding: const EdgeInsets.all(14.0), + child: RawMaterialButton( + shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(4)), + elevation: 0, + highlightElevation: 0, + focusElevation: 0, + disabledElevation: 0, + hoverElevation: 0, + onPressed: () { + if (onBackPressed != null) { + onBackPressed(); + } else { + Navigator.of(context).pop(); + } + }, + fillColor: Colors.black.withOpacity(.1), + padding: EdgeInsets.all(4), + child: Icon( + Icons.arrow_back_ios, + size: 15, + color: Colors.black, + ), + ), + ); + } + + @override + final Size preferredSize; +} diff --git a/packages/dart_client/example/lib/channel_image.dart b/packages/dart_client/example/lib/channel_image.dart new file mode 100644 index 00000000..f28db180 --- /dev/null +++ b/packages/dart_client/example/lib/channel_image.dart @@ -0,0 +1,25 @@ +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:flutter/material.dart'; +import 'package:stream_chat/stream_chat.dart'; + +class ChannelImage extends StatelessWidget { + const ChannelImage({ + Key key, + @required this.channel, + }) : super(key: key); + + final Channel channel; + + @override + Widget build(BuildContext context) { + return CircleAvatar( + radius: 20, + backgroundImage: channel.extraData.containsKey('image') + ? CachedNetworkImageProvider(channel.extraData['image'] as String) + : null, + child: channel.extraData.containsKey('image') + ? null + : Text(channel.config.name[0]), + ); + } +} diff --git a/packages/dart_client/example/lib/channel_list_page.dart b/packages/dart_client/example/lib/channel_list_page.dart new file mode 100644 index 00000000..7c3864b5 --- /dev/null +++ b/packages/dart_client/example/lib/channel_list_page.dart @@ -0,0 +1,138 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/widgets.dart'; +import 'package:stream_chat/stream_chat.dart'; + +import './connection_indicator.dart'; +import './message_page.dart'; +import './stream_channel.dart'; +import 'channel_list_view.dart'; +import 'channel_page_app_bar.dart'; +import 'stream_chat.dart'; + +class ChannelListPage extends StatefulWidget { + ChannelListPage({ + this.filter, + this.options, + this.sort, + this.pagination, + }); + + final Map filter; + final Map options; + final List sort; + final PaginationParams pagination; + + @override + ChannelListPageState createState() => ChannelListPageState(); +} + +class ChannelListPageState extends State { + String _selectedChannelId; + bool showSplit; + IndicatorController _indicatorController = IndicatorController(); + + @override + Widget build(BuildContext context) { + showSplit = MediaQuery.of(context).size.width > 1000; + return Flex( + direction: Axis.horizontal, + children: [ + Flexible( + flex: 1, + child: Scaffold( + bottomNavigationBar: ConnectionIndicator( + indicatorController: _indicatorController, + ), + appBar: ChannelPageAppBar(), + body: ChannelListView( + channelWidget: MessagePage(), + options: widget.options, + filter: widget.filter, + pagination: widget.pagination, + sort: widget.sort, + onChannelTap: showSplit + ? (channelClient, _) { + _navigateToChannel(context, channelClient); + } + : null, + ), + floatingActionButton: FloatingActionButton( + onPressed: () {}, + backgroundColor: Colors.white, + child: Icon( + Icons.send, + ), + ), + ), + ), + showSplit ? _buildMessageView(context) : Container(), + ], + ); + } + + Flexible _buildMessageView(BuildContext context) { + return Flexible( + flex: 2, + child: _selectedChannelId == null + ? Scaffold( + body: Center( + child: Text( + 'Pick a channel to show the messages 💬', + style: Theme.of(context).textTheme.headline, + ), + ), + ) + : StreamChannel( + channelClient: StreamChat.of(context) + .client + .state + .channels + .firstWhere((c) => c.id == _selectedChannelId), + child: MessagePage(), + ), + ); + } + + void _navigateToChannel( + BuildContext context, + Channel channel, + ) { + setState(() { + _selectedChannelId = channel.id; + }); + } + + @override + void initState() { + super.initState(); + + final streamChat = StreamChat.of(context); + streamChat.client.wsConnectionStatus.addListener(() { + if (streamChat.client.wsConnectionStatus.value == + ConnectionStatus.disconnected) { + _indicatorController.showIndicator( + duration: Duration(minutes: 1), + color: Colors.red, + text: 'Disconnected', + ); + } else if (streamChat.client.wsConnectionStatus.value == + ConnectionStatus.connecting) { + _indicatorController.showIndicator( + duration: Duration(minutes: 1), + color: Colors.yellow, + text: 'Reconnecting', + ); + } else if (streamChat.client.wsConnectionStatus.value == + ConnectionStatus.connected) { + _indicatorController.showIndicator( + duration: Duration(seconds: 5), + color: Colors.green, + text: 'Connected', + ); + streamChat.clearChannels(); + + streamChat.queryChannels(); + } + }); + } +} diff --git a/packages/dart_client/example/lib/channel_list_view.dart b/packages/dart_client/example/lib/channel_list_view.dart new file mode 100644 index 00000000..9c89d4d6 --- /dev/null +++ b/packages/dart_client/example/lib/channel_list_view.dart @@ -0,0 +1,208 @@ +import 'package:flutter/material.dart'; +import 'package:stream_chat/stream_chat.dart'; + +import 'channel_preview.dart'; +import 'stream_channel.dart'; +import 'stream_chat.dart'; + +typedef ChannelTapCallback = void Function(Channel, Widget); + +class ChannelListView extends StatefulWidget { + ChannelListView({ + Key key, + this.filter, + this.options, + this.sort, + this.pagination, + this.onChannelTap, + this.channelWidget, + this.channelPreview, + }) : assert(channelWidget != null || onChannelTap != null), + super(key: key); + + final Map filter; + final Map options; + final List sort; + final PaginationParams pagination; + final ScrollController _scrollController = ScrollController(); + final ChannelTapCallback onChannelTap; + final Widget channelWidget; + final Widget channelPreview; + + @override + _ChannelListViewState createState() => _ChannelListViewState(); +} + +class _ChannelListViewState extends State { + @override + Widget build(BuildContext context) { + final streamChat = StreamChat.of(context); + return RefreshIndicator( + onRefresh: () async { + streamChat.clearChannels(); + return streamChat.queryChannels( + filter: widget.filter, + sortOptions: widget.sort, + paginationParams: widget.pagination, + options: widget.options, + ); + }, + child: StreamBuilder>( + stream: streamChat.client.state.channelsStream, + builder: (context, snapshot) { + if (!snapshot.hasData) { + return Center( + child: CircularProgressIndicator(), + ); + } + + if (snapshot.hasError) { + print((snapshot.error as Error).stackTrace); + return Center( + child: Text(snapshot.error.toString()), + ); + } + + final channelsStates = snapshot.data; + return ListView.custom( + physics: AlwaysScrollableScrollPhysics(), + controller: widget._scrollController, + childrenDelegate: SliverChildBuilderDelegate( + (context, i) { + return _itemBuilder(context, i, channelsStates); + }, + childCount: (channelsStates.length * 2) + 1, + findChildIndexCallback: (key) { + final ValueKey valueKey = key; + final index = channelsStates + .indexWhere((cs) => 'CHANNEL-${cs.id}' == valueKey.value); + return index != -1 ? (index * 2) : null; + }, + ), + ); + }), + ); + } + + Widget _itemBuilder(context, int i, List channelsStates) { + if (i % 2 != 0) { + return _separatorBuilder(context, i); + } + + i = i ~/ 2; + + final streamChat = StreamChat.of(context); + if (i < channelsStates.length) { + final channelState = channelsStates[i]; + + final channelClient = streamChat.client.state.channels + .firstWhere((c) => c.cid == channelState.cid); + + ChannelTapCallback onTap; + if (widget.onChannelTap != null) { + onTap = widget.onChannelTap; + } else { + onTap = (client, _) { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) { + return StreamChannel( + child: widget.channelWidget, + channelClient: client, + ); + }, + ), + ); + }; + } + + Widget child; + if (widget.channelPreview != null) { + child = Stack( + children: [ + widget.channelPreview, + Positioned.fill( + child: Material( + color: Colors.transparent, + child: InkWell( + onTap: () { + onTap(channelClient, widget.channelWidget); + }, + ), + ), + ), + ], + ); + } else { + child = ChannelPreview( + onTap: (channelClient) { + onTap(channelClient, widget.channelWidget); + }, + ); + } + + return StreamChannel( + key: ValueKey('CHANNEL-${channelClient?.id}'), + child: child, + channelClient: channelClient, + ); + } else { + return _buildQueryProgressIndicator(context, streamChat); + } + } + + Widget _buildQueryProgressIndicator(context, StreamChat streamChat) { + return StreamBuilder( + stream: streamChat.queryChannelsLoading, + initialData: false, + builder: (context, snapshot) { + return Container( + height: 100, + padding: EdgeInsets.all(32), + child: Center( + child: snapshot.data ? CircularProgressIndicator() : Container(), + ), + ); + }); + } + + Widget _separatorBuilder(context, i) { + return Container( + height: 1, + color: Colors.black.withOpacity(0.1), + margin: EdgeInsets.symmetric(horizontal: 16), + ); + } + + void _listenChannelPagination(StreamChat streamChat) { + if (widget._scrollController.position.maxScrollExtent == + widget._scrollController.position.pixels) { + streamChat.queryChannels( + filter: widget.filter, + sortOptions: widget.sort, + paginationParams: widget.pagination.copyWith( + offset: streamChat.channels.length, + ), + options: widget.options, + ); + } + } + + @override + void initState() { + super.initState(); + + final streamChat = StreamChat.of(context); + streamChat.queryChannels( + filter: widget.filter, + sortOptions: widget.sort, + paginationParams: widget.pagination, + options: widget.options, + ); + + widget._scrollController.addListener(() { + _listenChannelPagination(streamChat); + }); + } +} diff --git a/packages/dart_client/example/lib/channel_name_text.dart b/packages/dart_client/example/lib/channel_name_text.dart new file mode 100644 index 00000000..f31f38c5 --- /dev/null +++ b/packages/dart_client/example/lib/channel_name_text.dart @@ -0,0 +1,19 @@ +import 'package:flutter/material.dart'; +import 'package:stream_chat/stream_chat.dart'; + +class ChannelNameText extends StatelessWidget { + const ChannelNameText({ + Key key, + this.channel, + }) : super(key: key); + + final Channel channel; + + @override + Widget build(BuildContext context) { + return Text( + channel.extraData['name'] as String ?? channel.config.name, + style: Theme.of(context).textTheme.body2, + ); + } +} diff --git a/packages/dart_client/example/lib/channel_page_app_bar.dart b/packages/dart_client/example/lib/channel_page_app_bar.dart new file mode 100644 index 00000000..8ee1e754 --- /dev/null +++ b/packages/dart_client/example/lib/channel_page_app_bar.dart @@ -0,0 +1,41 @@ +import 'package:flutter/material.dart'; + +class ChannelPageAppBar extends StatelessWidget implements PreferredSizeWidget { + ChannelPageAppBar({ + Key key, + }) : preferredSize = Size.fromHeight(kToolbarHeight), + super(key: key); + + @override + Widget build(BuildContext context) { + return SafeArea( + child: Material( + elevation: 4, + child: Padding( + padding: EdgeInsets.symmetric(vertical: 5, horizontal: 30), + child: Container( + decoration: BoxDecoration( + color: Colors.black.withAlpha(5), + borderRadius: BorderRadius.circular(32.0), + border: Border.all(color: Colors.black.withOpacity(.2))), + child: Padding( + padding: const EdgeInsets.only(left: 8.0), + child: TextField( + style: Theme.of(context).textTheme.body1, + autofocus: false, + decoration: InputDecoration( + hintText: 'Search', + prefixText: ' ', + border: InputBorder.none, + ), + ), + ), + ), + ), + ), + ); + } + + @override + final Size preferredSize; +} diff --git a/packages/dart_client/example/lib/channel_preview.dart b/packages/dart_client/example/lib/channel_preview.dart new file mode 100644 index 00000000..8926e107 --- /dev/null +++ b/packages/dart_client/example/lib/channel_preview.dart @@ -0,0 +1,139 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/widgets.dart'; +import 'package:jiffy/jiffy.dart'; +import 'package:stream_chat/stream_chat.dart'; + +import 'channel_image.dart'; +import 'channel_name_text.dart'; +import 'stream_channel.dart'; +import 'stream_chat.dart'; + +class ChannelPreview extends StatelessWidget { + final void Function(Channel) onTap; + + const ChannelPreview({ + Key key, + this.onTap, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + final streamChannel = StreamChannel.of(context); + return _buildChannelPreview( + context, + streamChannel, + ); + } + + StreamChannel _buildChannelPreview( + BuildContext context, + StreamChannelState streamChannel, + ) { + final channelClient = StreamChat.of(context) + .client + .state + .channels + .firstWhere((c) => c.cid == streamChannel.channel.cid); + return StreamChannel( + channelClient: channelClient, + child: ListTile( + onTap: () { + onTap(channelClient); + }, + leading: ChannelImage( + channel: streamChannel.channel, + ), + title: ChannelNameText( + channel: streamChannel.channel, + ), + subtitle: _buildSubtitle( + streamChannel, + ), + trailing: Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.end, + children: [ + _buildDate(context, streamChannel.channel.lastMessageAt), + ], + ), + ), + ); + } + + Text _buildDate(BuildContext context, DateTime lastMessageAt) { + String stringDate; + final now = DateTime.now(); + + if (now.year != lastMessageAt.year || + now.month != lastMessageAt.month || + now.day != lastMessageAt.day) { + stringDate = Jiffy(lastMessageAt.toLocal()).format('dd/MM/yyyy'); + } else { + stringDate = Jiffy(lastMessageAt.toLocal()).format('HH:mm'); + } + + return Text( + stringDate, + style: Theme.of(context).textTheme.caption, + ); + } + + Widget _buildSubtitle( + StreamChannelState streamChannel, + ) { + return StreamBuilder>( + stream: streamChannel.channelClient.state.typingEventsStream, + initialData: [], + builder: (context, snapshot) { + final typings = snapshot.data; + final opacity = + streamChannel.channelClient.state.unreadCount > .0 ? 1.0 : 0.5; + return typings.isNotEmpty + ? _buildTypings(typings, context, opacity) + : _buildLastMessage(context, streamChannel, opacity); + }); + } + + Widget _buildLastMessage( + BuildContext context, StreamChannelState streamChannel, double opacity) { + final lastMessage = streamChannel.channel.state.messages.isNotEmpty + ? streamChannel.channel.state.messages.last + : null; + if (lastMessage == null) { + return SizedBox.fromSize( + size: Size.zero, + ); + } + + final prefix = lastMessage.attachments + .map((e) { + if (e.type == 'image') { + return '📷'; + } else if (e.type == 'video') { + return '🎬'; + } + return null; + }) + .where((e) => e != null) + .join(' '); + + return Text( + '$prefix ${lastMessage.text ?? ''}', + maxLines: 1, + overflow: TextOverflow.ellipsis, + style: Theme.of(context).textTheme.caption.copyWith( + color: Colors.black.withOpacity(opacity), + ), + ); + } + + Text _buildTypings(List typings, BuildContext context, double opacity) { + return Text( + '${typings.map((u) => u.extraData.containsKey('name') ? u.extraData['name'] : u.id).join(',')} ${typings.length == 1 ? 'is' : 'are'} typing...', + maxLines: 1, + style: Theme.of(context).textTheme.caption.copyWith( + color: Colors.black.withOpacity(opacity), + ), + ); + } +} diff --git a/packages/dart_client/example/lib/connection_indicator.dart b/packages/dart_client/example/lib/connection_indicator.dart new file mode 100644 index 00000000..4fb81861 --- /dev/null +++ b/packages/dart_client/example/lib/connection_indicator.dart @@ -0,0 +1,100 @@ +import 'package:flutter/material.dart'; + +class ConnectionIndicator extends StatefulWidget { + final IndicatorController indicatorController; + + const ConnectionIndicator({ + Key key, + this.indicatorController, + }) : super(key: key); + + @override + _ConnectionIndicatorState createState() => _ConnectionIndicatorState(); +} + +class _ConnectionIndicatorState extends State { + double _height = 0; + String _text; + Color _color; + VoidCallback _listener; + + @override + Widget build(BuildContext context) { + return AnimatedContainer( + duration: Duration(milliseconds: 300), + height: _height, + child: Container( + width: double.infinity, + child: Material( + color: _color ?? Theme.of(context).snackBarTheme.backgroundColor, + child: Center( + child: Text(_text ?? ''), + ), + ), + ), + ); + } + + @override + void initState() { + super.initState(); + + _listener = () { + final values = widget.indicatorController.indicatorValues.value; + if (mounted) { + setState(() { + _height = 30; + _text = values.text; + _color = values.color; + }); + } + + if (values.duration != null) { + Future.delayed(values.duration, () { + if (mounted) { + setState(() { + _height = 0; + _text = ''; + }); + } + }); + } + }; + + widget.indicatorController.indicatorValues.addListener(_listener); + } + + @override + void dispose() { + widget.indicatorController.indicatorValues.removeListener(_listener); + super.dispose(); + } +} + +class IndicatorValues { + final String text; + final Color color; + final Duration duration; + + IndicatorValues({ + this.duration, + this.text, + this.color, + }); +} + +class IndicatorController { + ValueNotifier indicatorValues = ValueNotifier(null); + + void showIndicator({ + Duration duration, + Color color, + String text, + }) { + indicatorValues.value = IndicatorValues( + text: text, + color: color, + duration: duration, + ); + } +} diff --git a/packages/dart_client/example/lib/main.dart b/packages/dart_client/example/lib/main.dart new file mode 100644 index 00000000..de87783b --- /dev/null +++ b/packages/dart_client/example/lib/main.dart @@ -0,0 +1,94 @@ +import 'package:flutter/material.dart'; +import 'package:stream_chat/stream_chat.dart'; + +import 'channel_list_page.dart'; +import 'stream_chat.dart'; + +void main() async { + final client = Client( + "qk4nn7rpcn75", + logLevel: Level.INFO, + ); + + await client.setUser( + User(id: "wild-breeze-7"), + 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoid2lsZC1icmVlemUtNyJ9.VM2EX1EXOfgqa-bTH_3JzeY0T99ngWzWahSauP3dBMo', + ); + + runApp(StreamChat( + child: MyApp(), + client: client, + )); +} + +class MyApp extends StatefulWidget { + @override + _MyAppState createState() => _MyAppState(); +} + +class _MyAppState extends State { + @override + Widget build(BuildContext context) { + return MaterialApp( + debugShowCheckedModeBanner: false, + title: 'Stream Chat Example', + home: ChatLoader(), + theme: ThemeData( + scaffoldBackgroundColor: Color(0xfff1f1f3), + primaryColor: Color(0xfff1f1f3), + accentColor: Color(0xff006bff), + iconTheme: IconThemeData( + color: Color(0xff006bff), + ), + floatingActionButtonTheme: FloatingActionButtonThemeData( + foregroundColor: Color(0xff006bff), + ), + backgroundColor: Color(0xfff1f1f3), + canvasColor: Color(0xfff1f1f3), + ), + ); + } + + @override + void dispose() { + StreamChat.of(context).dispose(); + super.dispose(); + } +} + +class ChatLoader extends StatelessWidget { + @override + Widget build(BuildContext context) { + final streamChat = StreamChat.of(context); + return StreamBuilder( + stream: streamChat.userStream, + builder: (context, snapshot) { + if (snapshot.hasError) { + return Scaffold( + body: Center( + child: Text('${snapshot.error}'), + ), + ); + } else if (!snapshot.hasData) { + return Scaffold( + body: Center( + child: CircularProgressIndicator(), + ), + ); + } else { + return ChannelListPage( + filter: { + 'members': { + '\$in': [StreamChat.of(context).user.id], + } + }, + sort: [SortOption("last_message_at")], + pagination: PaginationParams( + limit: 20, + ), + ); + } + }, + ); + } +} diff --git a/packages/dart_client/example/lib/message_input.dart b/packages/dart_client/example/lib/message_input.dart new file mode 100644 index 00000000..243f1d31 --- /dev/null +++ b/packages/dart_client/example/lib/message_input.dart @@ -0,0 +1,137 @@ +import 'dart:ui'; + +import 'package:flutter/material.dart'; +import 'package:stream_chat/stream_chat.dart'; + +import 'stream_channel.dart'; + +class MessageInput extends StatefulWidget { + MessageInput({ + Key key, + this.onMessageSent, + this.parent, + }) : super(key: key); + + final void Function(Message) onMessageSent; + final Message parent; + + @override + _MessageInputState createState() => _MessageInputState(); +} + +class _MessageInputState extends State { + final _textController = TextEditingController(); + bool _messageIsPresent = false; + bool _typingStarted = false; + + @override + Widget build(BuildContext context) { + return Padding( + padding: const EdgeInsets.all(8.0), + child: Container( + width: MediaQuery.of(context).size.width, + padding: EdgeInsets.all(2), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(10.0), + gradient: _typingStarted + ? LinearGradient(colors: [Color(0xFF00AEFF), Color(0xFF0076FF)]) + : null, + ), + child: Container( + decoration: BoxDecoration( + color: Theme.of(context).canvasColor, + borderRadius: BorderRadius.circular(10.0), + ), + child: Container( + decoration: BoxDecoration( + color: Colors.black.withAlpha(5), + borderRadius: BorderRadius.circular(10.0), + border: Border.all(color: Colors.black.withOpacity(.2)), + ), + child: Flex( + direction: Axis.horizontal, + children: [ + Expanded( + child: TextField( + minLines: null, + maxLines: null, + onSubmitted: (_) { + _sendMessage(context); + }, + controller: _textController, + onChanged: (s) { + StreamChannel.of(context).channelClient.keyStroke(); + setState(() { + _messageIsPresent = s.trim().isNotEmpty; + }); + }, + onTap: () { + setState(() { + _typingStarted = true; + }); + }, + style: Theme.of(context).textTheme.body1, + autofocus: false, + decoration: InputDecoration( + hintText: 'Write a message', + prefixText: ' ', + border: InputBorder.none, + ), + ), + ), + AnimatedCrossFade( + crossFadeState: _messageIsPresent + ? CrossFadeState.showFirst + : CrossFadeState.showSecond, + firstChild: _buildSendButton(context), + secondChild: Container(), + duration: Duration(milliseconds: 300), + alignment: Alignment.center, + ), + ], + ), + ), + ), + ), + ); + } + + IconButton _buildSendButton(BuildContext context) { + return IconButton( + onPressed: () { + _sendMessage(context); + }, + icon: Icon( + Icons.send, + ), + ); + } + + void _sendMessage(BuildContext context) { + final text = _textController.text.trim(); + if (text.isEmpty) { + return; + } + + _textController.clear(); + setState(() { + _messageIsPresent = false; + _typingStarted = false; + }); + FocusScope.of(context).unfocus(); + + StreamChannel.of(context) + .channelClient + .sendMessage( + Message( + parentId: widget.parent?.id, + text: text, + ), + ) + .then((_) { + if (widget.onMessageSent != null) { + widget.onMessageSent(Message(text: text)); + } + }); + } +} diff --git a/packages/dart_client/example/lib/message_list_view.dart b/packages/dart_client/example/lib/message_list_view.dart new file mode 100644 index 00000000..af8608d6 --- /dev/null +++ b/packages/dart_client/example/lib/message_list_view.dart @@ -0,0 +1,280 @@ +import 'dart:async'; + +import 'package:flutter/material.dart'; +import 'package:flutter_widgets/flutter_widgets.dart'; +import 'package:stream_chat/stream_chat.dart'; + +import 'message_widget.dart'; +import 'stream_channel.dart'; + +typedef MessageBuilder = Widget Function(BuildContext, Message, int index); +typedef ParentMessageBuilder = Widget Function(BuildContext, Message); +typedef OnThreadSelectCallback = void Function(Message parent); + +class MessageListView extends StatefulWidget { + MessageListView({ + Key key, + MessageBuilder messageBuilder, + this.parentMessageBuilder, + this.parentMessage, + this.onThreadSelect, + }) : _messageBuilder = messageBuilder, + super(key: key); + + final MessageBuilder _messageBuilder; + final ParentMessageBuilder parentMessageBuilder; + final OnThreadSelectCallback onThreadSelect; + final Message parentMessage; + + @override + _MessageListViewState createState() => _MessageListViewState(); +} + +class _MessageListViewState extends State { + static const _newMessageLoadingOffset = 100; + final ScrollController _scrollController = ScrollController(); + bool _isBottom = true; + bool _topWasVisible = false; + List _messages = []; + List _newMessageList = []; + + @override + Widget build(BuildContext context) { + final streamChannel = StreamChannel.of(context); + + /// TODO: find a better solution when (https://github.com/flutter/flutter/issues/21023) is fixed + return NotificationListener( + onNotification: (_) { + if (_scrollController.offset < 150 && _newMessageList.isNotEmpty) { + setState(() { + _messages.insertAll(0, _newMessageList); + _newMessageList.clear(); + }); + } + return true; + }, + child: ListView.custom( + physics: AlwaysScrollableScrollPhysics(), + controller: _scrollController, + reverse: true, + childrenDelegate: SliverChildBuilderDelegate( + (context, i) { + if (i == _messages.length + 1) { + if (widget.parentMessage != null) { + if (widget.parentMessageBuilder != null) { + return widget.parentMessageBuilder( + context, widget.parentMessage); + } else { + return Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + MessageWidget( + key: ValueKey( + 'PARENT-MESSAGE-${widget.parentMessage.id}'), + previousMessage: null, + message: widget.parentMessage.copyWith(replyCount: 0), + nextMessage: null, + onThreadSelect: widget.onThreadSelect, + ), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 32), + child: Container( + padding: const EdgeInsets.all(8), + child: Text( + 'Start of a new thread', + textAlign: TextAlign.center, + ), + color: Theme.of(context).primaryColorLight, + ), + ), + ], + ); + } + } else { + return SizedBox(); + } + } + + if (i == _messages.length) { + return _buildLoadingIndicator(streamChannel); + } + final message = _messages[i]; + + if (widget._messageBuilder != null) { + return widget._messageBuilder(context, message, i); + } + + final previousMessage = + i < _messages.length - 1 ? _messages[i + 1] : null; + final nextMessage = i > 0 ? _messages[i - 1] : null; + + if (i == 0) { + return _buildBottomMessage( + streamChannel, + previousMessage, + message, + context, + ); + } + + if (i == _messages.length - 1) { + return _buildTopMessage( + message, + nextMessage, + streamChannel, + context, + ); + } + + return MessageWidget( + key: ValueKey('MESSAGE-${message.id}'), + previousMessage: previousMessage, + message: message, + nextMessage: nextMessage, + onThreadSelect: widget.onThreadSelect, + ); + }, + childCount: _messages.length + 2, + findChildIndexCallback: (key) { + final ValueKey valueKey = key; + final index = _messages + .indexWhere((m) => 'MESSAGE-${m.id}' == valueKey.value); + return index != -1 ? index : null; + }, + ), + ), + ); + } + + Container _buildLoadingIndicator(StreamChannelState streamChannel) { + return Container( + height: 50, + child: StreamBuilder( + stream: streamChannel.queryMessage, + initialData: false, + builder: (context, snapshot) { + if (snapshot.hasError) { + print((snapshot.error as Error).stackTrace.toString()); + return Center( + child: Text(snapshot.error.toString()), + ); + } + if (!snapshot.data) { + return Container(); + } + return Center( + child: Padding( + padding: const EdgeInsets.all(8.0), + child: CircularProgressIndicator(), + ), + ); + }), + ); + } + + Widget _buildTopMessage( + Message message, + Message nextMessage, + StreamChannelState streamChannelState, + BuildContext context, + ) { + return VisibilityDetector( + key: ValueKey('TOP-MESSAGE'), + child: MessageWidget( + key: ValueKey('MESSAGE-${message.id}'), + previousMessage: null, + message: message, + nextMessage: nextMessage, + onThreadSelect: widget.onThreadSelect, + ), + onVisibilityChanged: (visibility) { + final topIsVisible = visibility.visibleBounds != Rect.zero; + if (topIsVisible && !_topWasVisible) { + streamChannelState.queryMessages(); + } + _topWasVisible = topIsVisible; + }, + ); + } + + Widget _buildBottomMessage( + StreamChannelState channelBloc, + Message previousMessage, + Message message, + BuildContext context, + ) { + return VisibilityDetector( + key: ValueKey('BOTTOM-MESSAGE'), + onVisibilityChanged: (visibility) { + _isBottom = visibility.visibleBounds != Rect.zero; + if (_isBottom) { + if (channelBloc.channelClient.state.unreadCount > 0) { + channelBloc.channelClient.markRead(); + } + } + }, + child: MessageWidget( + key: ValueKey('MESSAGE-${message.id}'), + previousMessage: previousMessage, + message: message, + nextMessage: null, + onThreadSelect: widget.onThreadSelect, + ), + ); + } + + StreamSubscription _streamListener; + + @override + void initState() { + super.initState(); + + final streamChannel = StreamChannel.of(context); + if (streamChannel.channelClient.state.unreadCount > 0) { + streamChannel.channelClient.markRead(); + } + + Stream> stream; + + if (widget.parentMessage == null) { + stream = streamChannel.channelStateStream.map((c) => c.messages); + } else { + streamChannel.getReplies(widget.parentMessage.id); + stream = streamChannel.channelClient.state.threadsStream + .where((threads) => threads.containsKey(widget.parentMessage.id)) + .map((threads) => threads[widget.parentMessage.id]); + } + + _streamListener = stream.listen((newMessages) { + newMessages = newMessages.reversed.toList(); + if (_messages.isEmpty || newMessages.first.id != _messages.first.id) { + if (!_scrollController.hasClients || + _scrollController.offset < _newMessageLoadingOffset) { + setState(() { + _messages = newMessages; + }); + } else if (newMessages.first.user.id == + streamChannel.channelClient.client.state.user.id) { + _scrollController.jumpTo(0); + WidgetsBinding.instance.addPostFrameCallback((_) { + setState(() { + _messages = newMessages; + }); + }); + } else { + _newMessageList = newMessages; + } + } else { + setState(() { + _messages = newMessages; + }); + } + }); + } + + @override + void dispose() { + _streamListener.cancel(); + super.dispose(); + } +} diff --git a/packages/dart_client/example/lib/message_page.dart b/packages/dart_client/example/lib/message_page.dart new file mode 100644 index 00000000..3d3c8073 --- /dev/null +++ b/packages/dart_client/example/lib/message_page.dart @@ -0,0 +1,110 @@ +import 'package:animations/animations.dart'; +import 'package:flutter/material.dart'; +import 'package:stream_chat/stream_chat.dart'; + +import './channel_header.dart'; +import 'connection_indicator.dart'; +import 'message_input.dart'; +import 'message_list_view.dart'; +import 'stream_channel.dart'; +import 'stream_chat.dart'; + +class MessagePage extends StatefulWidget { + final PreferredSizeWidget _channelHeader; + + const MessagePage({ + Key key, + PreferredSizeWidget channelHeader, + this.parentMessage, + }) : _channelHeader = channelHeader, + super(key: key); + + final Message parentMessage; + + @override + _MessagePageState createState() => _MessagePageState(); +} + +class _MessagePageState extends State { + IndicatorController _indicatorController = IndicatorController(); + + @override + Widget build(BuildContext context) { + return Scaffold( + resizeToAvoidBottomInset: true, + appBar: widget._channelHeader ?? ChannelHeader(), + body: Column( + children: [ + ConnectionIndicator( + indicatorController: _indicatorController, + ), + Expanded( + child: MessageListView( + parentMessage: widget.parentMessage, + onThreadSelect: (message) { + Navigator.of(context).push( + PageRouteBuilder( + pageBuilder: (_, __, ___) => StreamChannel( + channelClient: StreamChannel.of(context).channelClient, + child: MessagePage( + parentMessage: message, + channelHeader: widget._channelHeader, + ), + ), + transitionsBuilder: ( + _, + animation, + secondaryAnimation, + child, + ) => + SharedAxisTransition( + child: child, + animation: animation, + secondaryAnimation: secondaryAnimation, + transitionType: SharedAxisTransitionType.horizontal, + ), + ), + ); + }, + ), + ), + MessageInput(), + ], + ), + ); + } + + @override + void initState() { + super.initState(); + + final streamChat = StreamChat.of(context); + streamChat.client.wsConnectionStatus.addListener(() { + if (streamChat.client.wsConnectionStatus.value == + ConnectionStatus.disconnected) { + _indicatorController.showIndicator( + duration: Duration(minutes: 1), + color: Colors.red, + text: 'Disconnected', + ); + } else if (streamChat.client.wsConnectionStatus.value == + ConnectionStatus.connecting) { + _indicatorController.showIndicator( + duration: Duration(minutes: 1), + color: Colors.yellow, + text: 'Reconnecting', + ); + } else if (streamChat.client.wsConnectionStatus.value == + ConnectionStatus.connected) { + _indicatorController.showIndicator( + duration: Duration(seconds: 5), + color: Colors.green, + text: 'Connected', + ); + + final streamChat = StreamChannel.of(context); + streamChat.queryMessages(); + } + }); + } +} diff --git a/packages/dart_client/example/lib/message_widget.dart b/packages/dart_client/example/lib/message_widget.dart new file mode 100644 index 00000000..aba9ced1 --- /dev/null +++ b/packages/dart_client/example/lib/message_widget.dart @@ -0,0 +1,353 @@ +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:chewie/chewie.dart'; +import 'package:date_format/date_format.dart'; +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_markdown/flutter_markdown.dart'; +import 'package:stream_chat/stream_chat.dart'; +import 'package:url_launcher/url_launcher.dart'; +import 'package:video_player/video_player.dart'; + +import 'message_list_view.dart'; +import 'stream_chat.dart'; +import 'user_avatar.dart'; + +class MessageWidget extends StatefulWidget { + const MessageWidget({ + Key key, + @required this.previousMessage, + @required this.message, + @required this.nextMessage, + this.onThreadSelect, + }) : super(key: key); + + final Message previousMessage; + final Message message; + final Message nextMessage; + final OnThreadSelectCallback onThreadSelect; + + @override + _MessageWidgetState createState() => _MessageWidgetState(); +} + +class _MessageWidgetState extends State + with AutomaticKeepAliveClientMixin { + final Map _videoControllers = {}; + final Map _chuwieControllers = {}; + + @override + Widget build(BuildContext context) { + super.build(context); + + final streamChat = StreamChat.of(context); + final currentUserId = streamChat.user.id; + final messageUserId = widget.message.user.id; + final previousUserId = widget.previousMessage?.user?.id; + final nextUserId = widget.nextMessage?.user?.id; + final isMyMessage = messageUserId == currentUserId; + final isLastUser = previousUserId == messageUserId; + final isNextUser = nextUserId == messageUserId; + final alignment = + isMyMessage ? Alignment.centerRight : Alignment.centerLeft; + + var row = [ + Column( + crossAxisAlignment: + isMyMessage ? CrossAxisAlignment.end : CrossAxisAlignment.start, + children: [ + _buildBubble(context, isMyMessage, isLastUser), + widget.message.replyCount > 0 + ? GestureDetector( + onTap: () { + if (widget.onThreadSelect != null) { + widget.onThreadSelect(widget.message); + } + }, + child: Padding( + padding: const EdgeInsets.symmetric(vertical: 2.0), + child: Row( + children: [ + Text( + 'Replies: ${widget.message.replyCount}', + style: Theme.of(context) + .textTheme + .subtitle + .copyWith(color: Colors.blue), + ), + Icon( + Icons.subdirectory_arrow_left, + color: Colors.black12, + ), + ], + ), + ), + ) + : Container(), + isNextUser ? Container() : _buildTimestamp(isMyMessage, alignment), + ], + ), + isNextUser + ? Container( + width: 40, + ) + : Padding( + padding: EdgeInsets.only( + left: isMyMessage ? 8.0 : 0, + right: isMyMessage ? 0 : 8.0, + ), + child: UserAvatar(user: widget.message.user), + ), + ]; + + if (!isMyMessage) { + row = row.reversed.toList(); + } + + return Container( + padding: const EdgeInsets.symmetric(horizontal: 10.0), + margin: EdgeInsets.only( + top: isLastUser ? 5 : 24, + bottom: widget.nextMessage == null ? 30 : 0, + ), + child: Row( + crossAxisAlignment: CrossAxisAlignment.end, + mainAxisAlignment: + isMyMessage ? MainAxisAlignment.end : MainAxisAlignment.start, + mainAxisSize: MainAxisSize.max, + children: row, + ), + ); + } + + Widget _buildBubble( + BuildContext context, + bool isMyMessage, + bool isLastUser, + ) { + var nOfAttachmentWidgets = 0; + + final column = Column( + crossAxisAlignment: + isMyMessage ? CrossAxisAlignment.end : CrossAxisAlignment.start, + children: widget.message.attachments.map((attachment) { + nOfAttachmentWidgets++; + + Widget attachmentWidget; + if (attachment.type == 'video') { + attachmentWidget = _buildVideo(attachment, isMyMessage, isLastUser); + } else if (attachment.type == 'image' || attachment.type == 'giphy') { + attachmentWidget = _buildImage(isMyMessage, isLastUser, attachment); + } + + if (attachmentWidget != null) { + final boxDecoration = _buildBoxDecoration(isMyMessage, isLastUser) + .copyWith(color: Color(0xffebebeb)); + return ClipRRect( + borderRadius: boxDecoration.borderRadius, + child: Container( + decoration: boxDecoration, + constraints: BoxConstraints.loose(Size.fromWidth(300)), + child: Stack( + children: [ + Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + attachmentWidget, + attachment.title != null + ? Container( + constraints: + BoxConstraints.loose(Size.fromHeight(70)), + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + attachment.title, + overflow: TextOverflow.ellipsis, + style: Theme.of(context) + .textTheme + .subtitle + .copyWith(color: Colors.blue), + ), + Text( + Uri.parse(attachment.thumbUrl) + .authority + .split('.') + .reversed + .take(2) + .toList() + .reversed + .join('.'), + overflow: TextOverflow.ellipsis, + style: + Theme.of(context).textTheme.caption, + ), + ], + ), + ), + color: Color(0xffebebeb), + ) + : Container(), + ], + ), + attachment.type == 'image' && attachment.titleLink != null + ? Positioned.fill( + child: Material( + color: Colors.transparent, + child: InkWell( + onTap: () => _launchURL(attachment.titleLink), + ), + ), + ) + : SizedBox.fromSize( + size: Size.zero, + ), + ], + ), + margin: EdgeInsets.only( + top: nOfAttachmentWidgets > 1 ? 5 : 0, + ), + ), + ); + } + + nOfAttachmentWidgets--; + return Container(); + }).toList(), + ); + + if (widget.message.text.trim().isNotEmpty) { + column.children.add(Container( + margin: EdgeInsets.only( + top: nOfAttachmentWidgets > 0 ? 5 : 0, + ), + decoration: _buildBoxDecoration( + isMyMessage, isLastUser || nOfAttachmentWidgets > 0), + padding: EdgeInsets.all(10), + constraints: BoxConstraints.loose(Size.fromWidth(300)), + child: MarkdownBody( + data: '${widget.message.text}', + onTapLink: (link) { + _launchURL(link); + }, + styleSheet: MarkdownStyleSheet.fromTheme(Theme.of(context)), + ), + )); + } + + return column; + } + + Widget _buildImage( + bool isMyMessage, + bool isLastUser, + Attachment attachment, + ) { + return CachedNetworkImage( + imageUrl: attachment.thumbUrl ?? attachment.imageUrl, + fit: BoxFit.cover, + ); + } + + Widget _buildVideo( + Attachment attachment, + bool isMyMessage, + bool isLastUser, + ) { + VideoPlayerController videoController; + if (_videoControllers.containsKey(attachment.assetUrl)) { + videoController = _videoControllers[attachment.assetUrl]; + } else { + videoController = VideoPlayerController.network(attachment.assetUrl); + _videoControllers[attachment.assetUrl] = videoController; + } + + ChewieController chewieController; + if (_chuwieControllers.containsKey(attachment.assetUrl)) { + chewieController = _chuwieControllers[attachment.assetUrl]; + } else { + chewieController = ChewieController( + videoPlayerController: videoController, + autoInitialize: true, + errorBuilder: (_, e) { + return Stack( + children: [ + Container( + decoration: BoxDecoration( + image: DecorationImage( + fit: BoxFit.cover, + image: CachedNetworkImageProvider( + attachment.thumbUrl, + ), + ), + ), + ), + Material( + color: Colors.transparent, + child: InkWell( + onTap: () => _launchURL(attachment.titleLink), + ), + ), + ], + ); + }); + _chuwieControllers[attachment.assetUrl] = chewieController; + } + + return Chewie( + key: ValueKey( + 'ATTACHMENT-${attachment.title}-${widget.message.id}'), + controller: chewieController, + ); + } + + Future _launchURL(String url) async { + if (await canLaunch(url)) { + await launch(url); + } else { + Scaffold.of(context).showSnackBar( + SnackBar( + content: Text('Cannot launch the url'), + ), + ); + } + } + + @override + void dispose() { + _videoControllers.values.forEach((element) { + element.dispose(); + }); + super.dispose(); + } + + Widget _buildTimestamp(bool isMyMessage, Alignment alignment) { + return Padding( + padding: const EdgeInsets.only(top: 5.0), + child: Text( + formatDate(widget.message.createdAt.toLocal(), [HH, ':', nn]), + ), + ); + } + + BoxDecoration _buildBoxDecoration(bool isMyMessage, bool isLastUser) { + return BoxDecoration( + border: isMyMessage ? null : Border.all(color: Colors.black.withAlpha(8)), + borderRadius: BorderRadius.only( + topLeft: Radius.circular((isMyMessage || !isLastUser) ? 16 : 2), + bottomLeft: Radius.circular(isMyMessage ? 16 : 2), + topRight: Radius.circular((isMyMessage && isLastUser) ? 2 : 16), + bottomRight: Radius.circular(isMyMessage ? 2 : 16), + ), + color: isMyMessage ? Color(0xffebebeb) : Colors.white, + ); + } + + @override + bool get wantKeepAlive { + return widget.message.attachments.isNotEmpty; + } +} diff --git a/packages/dart_client/example/lib/stream_channel.dart b/packages/dart_client/example/lib/stream_channel.dart new file mode 100644 index 00000000..40c082c1 --- /dev/null +++ b/packages/dart_client/example/lib/stream_channel.dart @@ -0,0 +1,128 @@ +import 'dart:async'; + +import 'package:flutter/material.dart'; +import 'package:rxdart/rxdart.dart'; +import 'package:stream_chat/stream_chat.dart'; + +class StreamChannel extends StatefulWidget { + StreamChannel({ + Key key, + @required this.child, + @required this.channelClient, + }) : super( + key: key, + ); + + final Widget child; + final Channel channelClient; + + static StreamChannelState of(BuildContext context) { + StreamChannelState streamChannelState; + + streamChannelState = context.findAncestorStateOfType(); + + if (streamChannelState == null) { + throw Exception( + 'You must have a StreamChannel widget at the top of your widget tree'); + } + + return streamChannelState; + } + + @override + StreamChannelState createState() => StreamChannelState(); +} + +class StreamChannelState extends State { + StreamChannelState(); + + Channel get channelClient => widget.channelClient; + + Channel get channel => widget.channelClient; + + Stream get channelStateStream => + widget.channelClient.state.channelStateStream; + + final BehaviorSubject _queryMessageController = BehaviorSubject(); + + Stream get queryMessage => _queryMessageController.stream; + + void queryMessages() { + _queryMessageController.add(true); + + String firstId; + if (channel.state.messages.isNotEmpty) { + firstId = channel.state.messages.first.id; + } + + widget.channelClient + .query( + messagesPagination: PaginationParams( + lessThan: firstId, + limit: 100, + ), + ) + .then((res) { + _queryMessageController.add(false); + }).catchError((e, stack) { + _queryMessageController.addError(e, stack); + }); + } + + Future getReplies(String parentId) async { + _queryMessageController.add(true); + + String firstId; + if (widget.channelClient.state.threads.containsKey(parentId)) { + firstId = widget.channelClient.state.threads[parentId].first.id; + } + + return widget.channelClient + .getReplies( + parentId, + PaginationParams( + lessThan: firstId, + limit: 100, + ), + ) + .then((res) { + _queryMessageController.add(false); + }).catchError((e, stack) { + _queryMessageController.addError(e, stack); + }); + } + + @override + void dispose() { + _queryMessageController.close(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + if (widget.channelClient == null) { + return Center( + child: CircularProgressIndicator(), + ); + } + return FutureBuilder( + future: widget.channelClient.initialized, + initialData: widget.channelClient.state != null, + builder: (context, snapshot) { + if (!snapshot.hasData) { + return Scaffold( + body: Center( + child: CircularProgressIndicator(), + ), + ); + } else if (snapshot.hasError) { + return Center( + child: Text(snapshot.error), + ); + } else { + return widget.child; + } + }, + ); + } +} diff --git a/packages/dart_client/example/lib/stream_chat.dart b/packages/dart_client/example/lib/stream_chat.dart new file mode 100644 index 00000000..f6b1db38 --- /dev/null +++ b/packages/dart_client/example/lib/stream_chat.dart @@ -0,0 +1,95 @@ +import 'dart:async'; + +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:rxdart/rxdart.dart'; +import 'package:stream_chat/stream_chat.dart'; + +class StreamChat extends InheritedWidget { + final Client client; + final List _subscriptions = []; + + StreamChat({ + Key key, + @required this.client, + @required Widget child, + }) : super( + key: key, + child: child, + ) { + _subscriptions.add(client.on(EventType.messageNew).listen((Event e) { + final index = channels.indexWhere((c) => c.cid == e.cid); + if (index > 0) { + final channel = channels.removeAt(index); + channels.insert(0, channel); + } + })); + } + + User get user => client.state.user; + + Stream get userStream => client.state.userStream; + + final List channels = []; + + final BehaviorSubject _queryChannelsLoadingController = + BehaviorSubject.seeded(false); + + Stream get queryChannelsLoading => + _queryChannelsLoadingController.stream; + + Future queryChannels({ + Map filter, + List sortOptions, + PaginationParams paginationParams, + Map options, + }) async { + if (_queryChannelsLoadingController.value) { + return; + } + _queryChannelsLoadingController.sink.add(true); + + try { + client.queryChannels( + filter: filter, + sort: sortOptions, + options: options, + paginationParams: paginationParams, + ); + } finally { + _queryChannelsLoadingController.sink.add(false); + } + } + + void clearChannels() { + channels.clear(); + } + + void dispose() { + client.dispose(); + _subscriptions.forEach((s) => s.cancel()); + _queryChannelsLoadingController.close(); + } + + @override + bool updateShouldNotify(InheritedWidget oldWidget) { + return true; + } + + static StreamChat of(BuildContext context, [bool listen = false]) { + StreamChat streamChat; + + if (listen) { + streamChat = context.dependOnInheritedWidgetOfExactType(); + } else { + streamChat = context.findAncestorWidgetOfExactType(); + } + + if (streamChat == null) { + throw Exception( + 'You must have a StreamChat widget at the top of your widget tree'); + } + + return streamChat; + } +} diff --git a/packages/dart_client/example/lib/user_avatar.dart b/packages/dart_client/example/lib/user_avatar.dart new file mode 100644 index 00000000..c815f363 --- /dev/null +++ b/packages/dart_client/example/lib/user_avatar.dart @@ -0,0 +1,29 @@ +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:flutter/material.dart'; +import 'package:stream_chat/stream_chat.dart'; + +class UserAvatar extends StatelessWidget { + const UserAvatar({ + Key key, + @required this.user, + this.radius = 16, + }) : super(key: key); + + final User user; + final double radius; + + @override + Widget build(BuildContext context) { + return CircleAvatar( + radius: this.radius, + backgroundImage: user.extraData.containsKey('image') + ? CachedNetworkImageProvider(user.extraData['image'] as String) + : null, + child: user.extraData.containsKey('image') + ? null + : Text(user?.extraData?.containsKey('name') ?? false + ? user.extraData['name'][0] + : ''), + ); + } +} diff --git a/packages/dart_client/example/pubspec.yaml b/packages/dart_client/example/pubspec.yaml new file mode 100644 index 00000000..59a8bb96 --- /dev/null +++ b/packages/dart_client/example/pubspec.yaml @@ -0,0 +1,33 @@ +name: stream_chat_example +description: example Flutter project using Stream Chat service + +version: 1.0.0+1 + +environment: + sdk: ">=2.1.0 <3.0.0" + +dependencies: + flutter: + sdk: flutter + flutter_widgets: ^0.1.11 + timeago: ^2.0.26 + jiffy: ^3.0.1 + date_format: ^1.0.8 + cached_network_image: ^2.0.0 + flutter_markdown: ^0.3.4 + url_launcher: ^5.4.2 + video_player: ^0.10.8+1 + chewie: ^0.9.10 + animations: ^1.0.0+5 + + stream_chat: + path: ../ + +dev_dependencies: + flutter_test: + sdk: flutter + build_runner: any + build_web_compilers: any + +flutter: + uses-material-design: true diff --git a/packages/dart_client/example/test/widget_test.dart b/packages/dart_client/example/test/widget_test.dart new file mode 100644 index 00000000..8d7438e9 --- /dev/null +++ b/packages/dart_client/example/test/widget_test.dart @@ -0,0 +1,29 @@ +// This is a basic Flutter widget test. +// +// To perform an interaction with a widget in your test, use the WidgetTester +// utility that Flutter provides. For example, you can send tap and scroll +// gestures. You can also use WidgetTester to find child widgets in the widget +// tree, read text, and verify that the values of widget properties are correct. + +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:stream_chat_example/main.dart'; + +void main() { + testWidgets('Counter increments smoke test', (WidgetTester tester) async { + // Build our app and trigger a frame. + await tester.pumpWidget(MyApp()); + + // Verify that our counter starts at 0. + expect(find.text('0'), findsOneWidget); + expect(find.text('1'), findsNothing); + + // Tap the '+' icon and trigger a frame. + await tester.tap(find.byIcon(Icons.add)); + await tester.pump(); + + // Verify that our counter has incremented. + expect(find.text('0'), findsNothing); + expect(find.text('1'), findsOneWidget); + }); +} diff --git a/packages/dart_client/example/web/icons/Icon-192.png b/packages/dart_client/example/web/icons/Icon-192.png new file mode 100644 index 0000000000000000000000000000000000000000..b749bfef07473333cf1dd31e9eed89862a5d52aa GIT binary patch literal 5292 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 literal 0 HcmV?d00001 diff --git a/packages/dart_client/example/web/icons/Icon-512.png b/packages/dart_client/example/web/icons/Icon-512.png new file mode 100644 index 0000000000000000000000000000000000000000..88cfd48dff1169879ba46840804b412fe02fefd6 GIT binary patch literal 8252 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 literal 0 HcmV?d00001 diff --git a/packages/dart_client/example/web/index.html b/packages/dart_client/example/web/index.html new file mode 100644 index 00000000..97221146 --- /dev/null +++ b/packages/dart_client/example/web/index.html @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + stream_chat + + + + + + diff --git a/packages/dart_client/example/web/manifest.json b/packages/dart_client/example/web/manifest.json new file mode 100644 index 00000000..bad373ca --- /dev/null +++ b/packages/dart_client/example/web/manifest.json @@ -0,0 +1,23 @@ +{ + "name": "stream_chat", + "short_name": "stream_chat", + "start_url": ".", + "display": "minimal-ui", + "background_color": "#0175C2", + "theme_color": "#0175C2", + "description": "A new Flutter project.", + "orientation": "portrait-primary", + "prefer_related_applications": false, + "icons": [ + { + "src": "icons/Icon-192.png", + "sizes": "192x192", + "type": "image/png" + }, + { + "src": "icons/Icon-512.png", + "sizes": "512x512", + "type": "image/png" + } + ] +} diff --git a/packages/dart_client/lib/src/api/channel.dart b/packages/dart_client/lib/src/api/channel.dart new file mode 100644 index 00000000..5a0dcbfa --- /dev/null +++ b/packages/dart_client/lib/src/api/channel.dart @@ -0,0 +1,1518 @@ +import 'dart:async'; +import 'dart:convert'; +import 'dart:math'; + +import 'package:dio/dio.dart'; +import 'package:logging/logging.dart'; +import 'package:rxdart/rxdart.dart'; +import 'package:stream_chat/src/api/retry_queue.dart'; +import 'package:stream_chat/src/event_type.dart'; +import 'package:stream_chat/src/models/channel_state.dart'; +import 'package:stream_chat/src/models/user.dart'; +import 'package:stream_chat/stream_chat.dart'; +import 'package:uuid/uuid.dart'; + +import '../client.dart'; +import '../models/event.dart'; +import '../models/member.dart'; +import '../models/message.dart'; +import 'requests.dart'; +import 'responses.dart'; + +/// This a the class that manages a specific channel. +class Channel { + /// Create a channel client instance. + Channel( + this._client, + this.type, + this._id, + this._extraData, + ) : _cid = _id != null ? '$type:$_id' : null { + _client.logger.info('New Channel instance not initialized created'); + } + + /// Create a channel client instance from a [ChannelState] object + Channel.fromState(this._client, ChannelState channelState) { + _cid = channelState.channel.cid; + _id = channelState.channel.id; + type = channelState.channel.type; + + state = ChannelClientState(this, channelState); + _initializedCompleter.complete(true); + _startCleaning(); + + _client.logger.info('New Channel instance initialized created'); + } + + /// This client state + ChannelClientState state; + + /// The channel type + String type; + + String _id; + String _cid; + Map _extraData; + + set extraData(Map extraData) { + if (_initializedCompleter.isCompleted) { + throw Exception( + 'Once the channel is initialized you should use channel.update to update channel data'); + } + _extraData = extraData; + } + + /// Returns true if the channel is muted + bool get isMuted => + _client.state.user?.channelMutes + ?.any((element) => element.channel.cid == cid) == + true; + + /// Returns true if the channel is muted as a stream + Stream get isMutedStream => _client.state.userStream?.map((event) => + event.channelMutes?.any((element) => element.channel.cid == cid) == true); + + /// True if the channel is a group + bool get isGroup => memberCount != 2; + + /// True if the channel is distinct + bool get isDistinct => id?.startsWith('!members') == true; + + /// Channel configuration + ChannelConfig get config => state?._channelState?.channel?.config; + + /// Channel configuration as a stream + Stream get configStream => + state?.channelStateStream?.map((cs) => cs.channel?.config); + + /// Channel user creator + User get createdBy => state?._channelState?.channel?.createdBy; + + /// Channel user creator as a stream + Stream get createdByStream => + state?.channelStateStream?.map((cs) => cs.channel?.createdBy); + + /// Channel frozen status + bool get frozen => state?._channelState?.channel?.frozen; + + /// Channel frozen status as a stream + Stream get frozenStream => + state?.channelStateStream?.map((cs) => cs.channel?.frozen); + + /// Channel creation date + DateTime get createdAt => state?._channelState?.channel?.createdAt; + + /// Channel creation date as a stream + Stream get createdAtStream => + state?.channelStateStream?.map((cs) => cs.channel?.createdAt); + + /// Channel last message date + DateTime get lastMessageAt => state?._channelState?.channel?.lastMessageAt; + + /// Channel last message date as a stream + Stream get lastMessageAtStream => + state?.channelStateStream?.map((cs) => cs.channel?.lastMessageAt); + + /// Channel updated date + DateTime get updatedAt => state?._channelState?.channel?.updatedAt; + + /// Channel updated date as a stream + Stream get updatedAtStream => + state?.channelStateStream?.map((cs) => cs.channel?.updatedAt); + + /// Channel deletion date + DateTime get deletedAt => state?._channelState?.channel?.deletedAt; + + /// Channel deletion date as a stream + Stream get deletedAtStream => + state?.channelStateStream?.map((cs) => cs.channel?.deletedAt); + + /// Channel member count + int get memberCount => state?._channelState?.channel?.memberCount; + + /// Channel member count as a stream + Stream get memberCountStream => + state?.channelStateStream?.map((cs) => cs.channel?.memberCount); + + /// Channel id + String get id => state?._channelState?.channel?.id ?? _id; + + /// Channel id as a stream + Stream get idStream => + state?.channelStateStream?.map((cs) => cs.channel?.id ?? _id); + + /// Channel cid + String get cid => state?._channelState?.channel?.cid ?? _cid; + + /// Channel team + String get team => state?._channelState?.channel?.team; + + /// Channel cid as a stream + Stream get cidStream => + state?.channelStateStream?.map((cs) => cs.channel?.cid ?? _cid); + + /// Channel extra data + Map get extraData => + state?._channelState?.channel?.extraData; + + /// Channel extra data as a stream + Stream> get extraDataStream => + state?.channelStateStream?.map((cs) => cs.channel?.extraData); + + /// The main Stream chat client + Client get client => _client; + final Client _client; + + String get _channelURL => '/channels/$type/$id'; + + final Completer _initializedCompleter = Completer(); + + /// True if this is initialized + /// Call [watch] to initialize the client or instantiate it using [Channel.fromState] + Future get initialized => _initializedCompleter.future; + + /// Send a message to this channel + Future sendMessage(Message message) async { + final messageId = message.id ?? Uuid().v4(); + final quotedMessage = state?.messages?.firstWhere( + (m) => m.id == message?.quotedMessageId, + orElse: () => null, + ); + final newMessage = message.copyWith( + createdAt: message.createdAt ?? DateTime.now(), + user: _client.state.user, + id: messageId, + quotedMessage: quotedMessage, + status: MessageSendingStatus.SENDING, + ); + + if (message.parentId != null && message.id == null) { + final parentMessage = + state.messages.firstWhere((m) => m.id == message.parentId); + + state?.addMessage(parentMessage.copyWith( + replyCount: parentMessage.replyCount + 1, + )); + } + + state?.addMessage(newMessage); + + try { + final response = await _client.post( + '$_channelURL/message', + data: { + 'message': message + .copyWith( + id: messageId, + ) + .toJson() + }, + ); + + final res = _client.decode(response.data, SendMessageResponse.fromJson); + + state?.addMessage(res.message); + + return res; + } catch (error) { + if (error is DioError && error.type != DioErrorType.RESPONSE) { + state?.retryQueue?.add([newMessage]); + } + rethrow; + } + } + + /// Send a file to this channel + Future sendFile(MultipartFile file) async { + final response = await _client.post( + '$_channelURL/file', + data: FormData.fromMap({'file': file}), + ); + return _client.decode(response.data, SendFileResponse.fromJson); + } + + /// Send an image to this channel + Future sendImage(MultipartFile file) async { + final response = await _client.post( + '$_channelURL/image', + data: FormData.fromMap({'file': file}), + ); + return _client.decode(response.data, SendImageResponse.fromJson); + } + + /// Delete a file from this channel + Future deleteFile(String url) async { + final response = await _client + .delete('$_channelURL/file', queryParameters: {'url': url}); + return _client.decode(response.data, EmptyResponse.fromJson); + } + + /// Delete an image from this channel + Future deleteImage(String url) async { + final response = await _client + .delete('$_channelURL/image', queryParameters: {'url': url}); + return _client.decode(response.data, EmptyResponse.fromJson); + } + + /// Send an event on this channel + Future sendEvent(Event event) { + _checkInitialized(); + return _client.post( + '$_channelURL/event', + data: {'event': event.toJson()}, + ).then((res) { + return _client.decode(res.data, EmptyResponse.fromJson); + }); + } + + /// Send a reaction to this channel + /// Set [enforceUnique] to true to remove the existing user reaction + Future sendReaction( + Message message, + String type, { + Map extraData = const {}, + bool enforceUnique = false, + }) async { + final messageId = message.id; + final data = Map.from(extraData) + ..addAll({ + 'type': type, + }); + + final res = await _client.post( + '/messages/$messageId/reaction', + data: { + 'reaction': data, + 'enforce_unique': enforceUnique, + }, + ); + return _client.decode(res.data, SendReactionResponse.fromJson); + } + + /// Delete a reaction from this channel + Future deleteReaction(Message message, Reaction reaction) { + _checkInitialized(); + + return client + .delete('/messages/${message.id}/reaction/${reaction.type}') + .then((res) => _client.decode(res.data, EmptyResponse.fromJson)); + } + + /// Edit the channel custom data + Future update( + Map channelData, [ + Message updateMessage, + ]) async { + final response = await _client.post(_channelURL, data: { + if (updateMessage != null) + 'message': updateMessage.copyWith(updatedAt: DateTime.now()).toJson(), + 'data': channelData, + }); + return _client.decode(response.data, UpdateChannelResponse.fromJson); + } + + /// Delete this channel. Messages are permanently removed. + Future delete() async { + final response = await _client.delete(_channelURL); + return _client.decode(response.data, EmptyResponse.fromJson); + } + + /// Removes all messages from the channel + Future truncate() async { + final response = await _client.post('$_channelURL/truncate'); + return _client.decode(response.data, EmptyResponse.fromJson); + } + + /// Accept invitation to the channel + Future acceptInvite([Message message]) async { + final res = await _client.post(_channelURL, + data: {'accept_invite': true, 'message': message?.toJson()}); + return _client.decode(res.data, AcceptInviteResponse.fromJson); + } + + /// Reject invitation to the channel + Future rejectInvite([Message message]) async { + final res = await _client.post(_channelURL, + data: {'reject_invite': true, 'message': message?.toJson()}); + return _client.decode(res.data, RejectInviteResponse.fromJson); + } + + /// Add members to the channel + Future addMembers( + List memberIds, [ + Message message, + ]) async { + final res = await _client.post(_channelURL, data: { + 'add_members': memberIds, + 'message': message?.toJson(), + }); + return _client.decode(res.data, AddMembersResponse.fromJson); + } + + /// Invite members to the channel + Future inviteMembers( + List memberIds, [ + Message message, + ]) async { + final res = await _client.post(_channelURL, data: { + 'invites': memberIds, + 'message': message?.toJson(), + }); + return _client.decode(res.data, InviteMembersResponse.fromJson); + } + + /// Remove members from the channel + Future removeMembers( + List memberIds, [ + Message message, + ]) async { + final res = await _client.post(_channelURL, data: { + 'remove_members': memberIds, + 'message': message?.toJson(), + }); + return _client.decode(res.data, RemoveMembersResponse.fromJson); + } + + /// Send action for a specific message of this channel + Future sendAction( + Message message, + Map formData, + ) async { + _checkInitialized(); + + final messageId = message.id; + final response = await _client.post('/messages/$messageId/action', data: { + 'id': id, + 'type': type, + 'form_data': formData, + 'message_id': messageId, + }); + + final res = _client.decode(response.data, SendActionResponse.fromJson); + + if (res.message != null) { + state.addMessage(res.message); + } else { + final oldIndex = state.messages?.indexWhere((m) => m.id == messageId); + + Message oldMessage; + if (oldIndex != null && oldIndex != -1) { + oldMessage = state.messages[oldIndex]; + state.updateChannelState(state._channelState.copyWith( + messages: state.messages..remove(oldMessage), + )); + } else { + oldMessage = state.threads.values + .expand((messages) => messages) + .firstWhere((m) => m.id == messageId, orElse: () => null); + if (oldMessage?.parentId != null) { + final parentMessage = state.messages.firstWhere( + (element) => element.id == oldMessage.parentId, + orElse: () => null, + ); + if (parentMessage != null) { + state.addMessage(parentMessage.copyWith( + replyCount: parentMessage.replyCount - 1)); + } + state.updateThreadInfo(oldMessage.parentId, + state.threads[oldMessage.parentId]..remove(oldMessage)); + } + } + + await _client.offlineStorage?.deleteMessages([messageId]); + } + + return res; + } + + /// Mark all channel messages as read + Future markRead() async { + _checkInitialized(); + state._unreadCountController.add(0); + final response = await _client.post('$_channelURL/read', data: {}); + return _client.decode(response.data, EmptyResponse.fromJson); + } + + /// Loads the initial channel state and watches for changes + Future watch([Map options = const {}]) async { + final watchOptions = Map.from({ + 'state': true, + 'watch': true, + 'presence': false, + }) + ..addAll(options); + + var response; + + try { + response = await query(options: watchOptions); + } catch (error, stackTrace) { + if (!_initializedCompleter.isCompleted) { + _initializedCompleter.completeError(error, stackTrace); + } + rethrow; + } + + if (state == null) { + _initState(response); + } + + return response; + } + + void _initState(ChannelState channelState) { + state = ChannelClientState(this, channelState); + client.state.channels[cid] = this; + if (!_initializedCompleter.isCompleted) { + _initializedCompleter.complete(true); + } + _startCleaning(); + } + + /// Stop watching the channel + Future stopWatching() async { + final response = await _client.post( + '$_channelURL/stop-watching', + data: {}, + ); + return _client.decode(response?.data, EmptyResponse.fromJson); + } + + /// List the message replies for a parent message + /// Set [preferOffline] to true to avoid the api call if the data is already in the offline storage + Future getReplies( + String parentId, + PaginationParams options, { + bool preferOffline = false, + }) async { + final cachedReplies = await _client.offlineStorage?.getReplies( + parentId, + lessThan: options?.lessThan, + ); + if (cachedReplies != null && cachedReplies.isNotEmpty) { + state?.updateThreadInfo(parentId, cachedReplies); + if (preferOffline) { + return QueryRepliesResponse()..messages = cachedReplies; + } + } + + final response = await _client.get('/messages/$parentId/replies', + queryParameters: options.toJson()); + + final repliesResponse = _client.decode( + response.data, + QueryRepliesResponse.fromJson, + ); + + state?.updateThreadInfo(parentId, repliesResponse.messages); + + return repliesResponse; + } + + /// List the reactions for a message in the channel + Future getReactions( + String messageID, + PaginationParams options, + ) async { + final response = await _client.get( + '/messages/$messageID/reactions', + queryParameters: options.toJson(), + ); + return _client.decode( + response.data, QueryReactionsResponse.fromJson); + } + + /// Retrieves a list of messages by ID + Future getMessagesById( + List messageIDs) async { + final response = await _client.get( + '$_channelURL/messages', + queryParameters: {'ids': messageIDs.join(',')}, + ); + + final res = _client.decode( + response.data, + GetMessagesByIdResponse.fromJson, + ); + + state?.updateChannelState(ChannelState(messages: res.messages)); + + return res; + } + + /// Retrieves a list of messages by ID + Future translateMessage( + String messageId, + String language, + ) async { + final response = await _client.post( + '/messages/$messageId/translate', + data: { + 'language': language, + }, + ); + return _client.decode( + response.data, + TranslateMessageResponse.fromJson, + ); + } + + /// Creates a new channel + Future create() async { + return query(options: { + 'watch': false, + 'state': false, + 'presence': false, + }); + } + + /// Query the API, get messages, members or other channel fields + /// Set [preferOffline] to true to avoid the api call if the data is already in the offline storage + Future query({ + Map options = const {}, + PaginationParams messagesPagination, + PaginationParams membersPagination, + PaginationParams watchersPagination, + bool preferOffline = false, + }) async { + var path = '/channels/$type'; + if (id != null) { + path = '$path/$id'; + } + path = '$path/query'; + + final payload = Map.from({ + 'state': true, + }) + ..addAll(options); + + if (_extraData != null) { + payload['data'] = _extraData; + } + + if (messagesPagination != null) { + payload['messages'] = messagesPagination.toJson(); + } + if (membersPagination != null) { + payload['members'] = membersPagination.toJson(); + } + if (watchersPagination != null) { + payload['watchers'] = watchersPagination.toJson(); + } + + if (preferOffline && cid != null) { + final updatedState = await _client.offlineStorage?.getChannel( + cid, + limit: messagesPagination?.limit, + messageLessThan: messagesPagination?.lessThan, + messageGreaterThan: messagesPagination?.greaterThan, + ); + if (updatedState != null && updatedState.messages.isNotEmpty) { + if (state == null) { + _initState(updatedState); + } else { + state?.updateChannelState(updatedState); + } + return updatedState; + } + } + + final response = await _client.post(path, data: payload); + final updatedState = _client.decode(response.data, ChannelState.fromJson); + + if (_id == null) { + _id = updatedState.channel.id; + _cid = updatedState.channel.cid; + } + + state?.updateChannelState(updatedState); + return updatedState; + } + + /// Query channel members + Future queryMembers({ + Map filter, + List sort, + PaginationParams pagination, + }) async { + final payload = { + 'sort': sort, + 'filter_conditions': filter, + 'type': type, + }; + + if (pagination != null) { + payload.addAll(pagination.toJson()); + } + + if (id != null) { + payload['id'] = id; + } else if (state?.members?.isNotEmpty == true) { + payload['members'] = state.members; + } + + final rawRes = await _client.get('/members', queryParameters: { + 'payload': jsonEncode(payload), + }); + final response = _client.decode(rawRes.data, QueryMembersResponse.fromJson); + return response; + } + + /// Mutes the channel + Future mute({Duration expiration}) async { + final response = await _client.post('/moderation/mute/channel', data: { + 'channel_cid': cid, + if (expiration != null) 'expiration': expiration.inMilliseconds, + }); + return _client.decode(response.data, EmptyResponse.fromJson); + } + + /// Unmutes the channel + Future unmute() async { + final response = await _client.post('/moderation/unmute/channel', data: { + 'channel_cid': cid, + }); + return _client.decode(response.data, EmptyResponse.fromJson); + } + + /// Bans a user from the channel + Future banUser( + String userID, + Map options, + ) async { + _checkInitialized(); + final opts = Map.from(options) + ..addAll({ + 'type': type, + 'id': id, + }); + return _client.banUser(userID, opts); + } + + /// Remove the ban for a user in the channel + Future unbanUser(String userID) async { + _checkInitialized(); + return _client.unbanUser(userID, { + 'type': type, + 'id': id, + }); + } + + /// Shadow bans a user from the channel + Future shadowBan( + String userID, + Map options, + ) async { + _checkInitialized(); + final opts = Map.from(options) + ..addAll({ + 'type': type, + 'id': id, + }); + return _client.shadowBan(userID, opts); + } + + /// Remove the shadow ban for a user in the channel + Future removeShadowBan(String userID) async { + _checkInitialized(); + return _client.removeShadowBan(userID, { + 'type': type, + 'id': id, + }); + } + + /// Hides the channel from [Client.queryChannels] for the user until a message is added + /// If [clearHistory] is set to true - all messages will be removed for the user + Future hide({bool clearHistory = false}) async { + _checkInitialized(); + final response = await _client + .post('$_channelURL/hide', data: {'clear_history': clearHistory}); + + if (clearHistory == true) { + state.truncate(); + await _client.offlineStorage?.deleteChannelsMessages([_cid]); + } + + return _client.decode(response.data, EmptyResponse.fromJson); + } + + /// Removes the hidden status for the channel + Future show() async { + _checkInitialized(); + final response = await _client.post('$_channelURL/show'); + return _client.decode(response.data, EmptyResponse.fromJson); + } + + /// Stream of [Event] coming from websocket connection specific for the channel + /// Pass an eventType as parameter in order to filter just a type of event + Stream on([ + String eventType, + String eventType2, + String eventType3, + String eventType4, + ]) { + return _client + .on( + eventType, + eventType2, + eventType3, + eventType4, + ) + .where((e) => e.cid == cid); + } + + DateTime _lastTypingEvent; + + /// First of the [EventType.typingStart] and [EventType.typingStop] events based on the users keystrokes. + /// Call this on every keystroke. + Future keyStroke([String parentId]) async { + if (config?.typingEvents == false) { + return; + } + + client.logger.info('start typing'); + final now = DateTime.now(); + + if (_lastTypingEvent == null || + now.difference(_lastTypingEvent).inSeconds >= 2) { + _lastTypingEvent = now; + await sendEvent(Event( + type: EventType.typingStart, + parentId: parentId, + )); + } + } + + /// Sets last typing to null and sends the typing.stop event + Future stopTyping([String parentId]) async { + if (config?.typingEvents == false) { + return; + } + + client.logger.info('stop typing'); + _lastTypingEvent = null; + await sendEvent(Event( + type: EventType.typingStop, + parentId: parentId, + )); + } + + Timer _cleaningTimer; + + void _startCleaning() { + if (config?.typingEvents == false) { + return; + } + + _cleaningTimer = Timer.periodic(Duration(milliseconds: 500), (_) { + final now = DateTime.now(); + + if (_lastTypingEvent != null && + now.difference(_lastTypingEvent).inSeconds > 1) { + stopTyping(); + } + + state._clean(); + }); + } + + /// Call this method to dispose the channel client + void dispose() { + _cleaningTimer.cancel(); + state.dispose(); + } + + void _checkInitialized() { + if (!_initializedCompleter.isCompleted) { + throw Exception( + "Channel $cid hasn't been initialized yet. Make sure to call .watch() or to instantiate the client using [Channel.fromState]"); + } + } +} + +/// The class that handles the state of the channel listening to the events +class ChannelClientState { + final _subscriptions = []; + + /// Creates a new instance listening to events and updating the state + ChannelClientState(this._channel, ChannelState channelState) { + retryQueue = RetryQueue( + channel: _channel, + logger: Logger('RETRY QUEUE ${_channel.cid}'), + ); + + _checkExpiredAttachmentMessages(channelState); + + _channelStateController = BehaviorSubject.seeded(channelState); + + _listenTypingEvents(); + + _listenMessageNew(); + + _listenMessageDeleted(); + + _listenMessageUpdated(); + + _listenReactions(); + + _listenReactionDeleted(); + + _listenReadEvents(); + + _listenChannelTruncated(); + + _listenChannelUpdated(); + + _listenMemberAdded(); + + _listenMemberRemoved(); + + _computeInitialUnread(); + + _channel._client.offlineStorage + ?.getChannelThreads(_channel.cid) + ?.then((threads) { + _threads = threads; + retryFailedMessages(); + }); + } + + void _computeInitialUnread() { + final userRead = channelState?.read?.firstWhere( + (r) => r.user.id == _channel._client.state?.user?.id, + orElse: () => null, + ); + if (userRead != null) { + _unreadCountController.add(userRead.unreadMessages ?? 0); + } + } + + void _checkExpiredAttachmentMessages(ChannelState channelState) { + final expiredAttachmentMessagesId = channelState.messages + ?.where((m) => + !_updatedMessagesIds.contains(m.id) && + m.attachments?.isNotEmpty == true && + m.attachments?.any((e) { + final url = e.imageUrl ?? e.assetUrl; + if (url == null || !url.contains('stream-io-cdn.com')) { + return false; + } + final expiration = + DateTime.parse(Uri.parse(url).queryParameters['Expires']); + return expiration.isBefore(DateTime.now()); + }) == + true) + ?.map((e) => e.id) + ?.toList(); + if (expiredAttachmentMessagesId?.isNotEmpty == true) { + _channel.getMessagesById(expiredAttachmentMessagesId); + _updatedMessagesIds.addAll(expiredAttachmentMessagesId); + } + } + + void _listenMemberAdded() { + _subscriptions.add(_channel.on(EventType.memberAdded).listen((Event e) { + final member = e.member; + updateChannelState(channelState.copyWith( + members: [ + ...channelState.members, + member, + ], + )); + })); + } + + void _listenMemberRemoved() { + _subscriptions.add(_channel.on(EventType.memberRemoved).listen((Event e) { + final user = e.user; + updateChannelState(channelState.copyWith( + members: List.from( + channelState.members..removeWhere((m) => m.userId == user.id)), + )); + })); + } + + void _listenChannelUpdated() { + _subscriptions.add(_channel.on(EventType.channelUpdated).listen((Event e) { + final channel = e.channel; + updateChannelState(channelState.copyWith( + channel: channel, + members: channel.members, + )); + })); + } + + void _listenChannelTruncated() { + _subscriptions.add(_channel + .on(EventType.channelTruncated, EventType.notificationChannelTruncated) + .listen((event) async { + final channel = event.channel; + await _channel._client.offlineStorage + ?.deleteChannelsMessages([channel.cid]); + truncate(); + })); + } + + /// Flag which indicates if [ChannelClientState] contain latest/recent messages or not. + /// This flag should be managed by UI sdks. + /// When false, any new message (received by WebSocket event - [EventType.messageNew]) will not + /// be pushed on to message list. + bool get isUpToDate => _isUpToDateController.value; + + set isUpToDate(bool isUpToDate) => _isUpToDateController.add(isUpToDate); + + /// [isUpToDate] flag count as a stream + Stream get isUpToDateStream => _isUpToDateController.stream; + + final BehaviorSubject _isUpToDateController = + BehaviorSubject.seeded(true); + + /// The retry queue associated to this channel + RetryQueue retryQueue; + + /// Retry failed message + Future retryFailedMessages() async { + final failedMessages = + [...messages, ...threads.values.expand((v) => v)] + .where((message) => + message.status != null && + message.status != MessageSendingStatus.SENT && + message.createdAt.isBefore(DateTime.now().subtract(Duration( + seconds: 1, + )))) + .toList(); + + retryQueue.add(failedMessages); + } + + void _listenReactionDeleted() { + _subscriptions.add(_channel.on(EventType.reactionDeleted).listen((event) { + final reaction = event.reaction; + final message = event.message; + _removeMessageReaction(message, reaction); + })); + } + + void _removeMessageReaction(Message message, Reaction reaction) { + if (message.parentId == null || message.showInChannel == true) { + _channelState = _channelState.copyWith( + messages: _channelState?.messages?.map((m) { + if (m.id == message.id) { + return _removeReactionFromMessage(m, reaction); + } + return m; + })?.toList(), + ); + } + + if (message.parentId != null) { + final newThreads = threads; + if (newThreads.containsKey(message.parentId)) { + newThreads[message.parentId] = newThreads[message.parentId].map((m) { + if (m.id == message.id) { + return _removeReactionFromMessage(m, reaction); + } + return m; + }).toList(); + _threads = newThreads; + } + } + } + + void _listenReactions() { + _subscriptions.add(_channel + .on( + EventType.reactionNew, + ) + .listen((event) { + final message = event.message; + _addMessageReaction(message, event.reaction); + })); + } + + void _addMessageReaction(Message message, Reaction reaction) { + if (message.parentId == null || message.showInChannel == true) { + _channelState = _channelState.copyWith( + messages: _channelState.messages.map((m) { + if (message.id == m.id) { + return _addReactionToMessage(m, reaction); + } + return m; + }).toList(), + ); + } + + if (message.parentId != null) { + final newThreads = threads; + if (newThreads.containsKey(message.parentId)) { + newThreads[message.parentId] = newThreads[message.parentId].map((m) { + if (message.id == m.id) { + return _addReactionToMessage(m, reaction); + } + return m; + }).toList(); + _threads = newThreads; + } + } + } + + void _listenMessageUpdated() { + _subscriptions.add(_channel + .on( + EventType.messageUpdated, + EventType.reactionUpdated, + ) + .listen((event) { + final message = event.message; + addMessage(message.copyWith( + ownReactions: message.latestReactions + .where( + (element) => element.user?.id == _channel._client.state.user.id) + .toList(), + )); + })); + } + + void _listenMessageDeleted() { + _subscriptions.add(_channel.on(EventType.messageDeleted).listen((event) { + final message = event.message; + addMessage(message); + })); + } + + void _listenMessageNew() { + _subscriptions.add(_channel + .on( + EventType.messageNew, + EventType.notificationMessageNew, + ) + .listen((event) { + final message = event.message; + if (isUpToDate || + (message.parentId != null && message.showInChannel != true)) { + addMessage(message); + } + + if (_countMessageAsUnread(message)) { + _unreadCountController.add(_unreadCountController.value + 1); + } + })); + } + + /// Add a message to this channel + void addMessage(Message message) { + if (message.parentId == null || message.showInChannel == true) { + final newMessages = List.from(_channelState.messages); + + final oldIndex = newMessages.indexWhere((m) => m.id == message.id); + if (oldIndex != -1) { + newMessages[oldIndex] = newMessages[oldIndex].copyWith( + text: message.text, + type: message.type, + attachments: message.attachments, + mentionedUsers: message.mentionedUsers, + reactionCounts: message.reactionCounts, + reactionScores: message.reactionScores, + latestReactions: message.latestReactions, + ownReactions: message.ownReactions, + parentId: message.parentId, + quotedMessageId: message.quotedMessageId, + quotedMessage: message.quotedMessage, + replyCount: message.replyCount, + showInChannel: message.showInChannel, + command: message.command, + silent: message.silent, + createdAt: message.createdAt, + updatedAt: message.updatedAt, + deletedAt: message.deletedAt, + user: message.user, + status: message.status, + threadParticipants: message.threadParticipants, + extraData: message.extraData, + ); + } else { + newMessages.add(message); + } + + _channelState = _channelState.copyWith( + messages: newMessages, + channel: _channelState.channel.copyWith( + lastMessageAt: message.createdAt, + ), + ); + } + + if (message.parentId != null) { + updateThreadInfo(message.parentId, [message]); + } + } + + void _listenReadEvents() { + if (_channel.config?.readEvents == false) { + return; + } + + _subscriptions.add(_channel + .on( + EventType.messageRead, + EventType.notificationMarkRead, + ) + .listen((event) { + final readList = List.from(_channelState?.read ?? []); + final userReadIndex = read?.indexWhere((r) => r.user.id == event.user.id); + + if (userReadIndex != null && userReadIndex != -1) { + final userRead = readList.removeAt(userReadIndex); + if (userRead.user?.id == _channel._client.state.user.id) { + _unreadCountController.add(0); + } + readList.add(Read( + user: event.user, + lastRead: event.createdAt, + )); + _channelState = _channelState.copyWith(read: readList); + } + })); + } + + Message _addReactionToMessage(Message message, Reaction reaction) { + final newMessage = message.copyWith( + latestReactions: message.latestReactions..add(reaction), + reactionCounts: { + ...message.reactionCounts ?? {}, + reaction.type: (message.reactionCounts == null + ? 0 + : message.reactionCounts[reaction.type] ?? 0) + + 1, + }, + reactionScores: { + ...message.reactionScores ?? {}, + reaction.type: (message.reactionScores == null + ? 0 + : message.reactionScores[reaction.type] ?? 0) + + reaction.score, + }, + ); + + if (reaction.user.id == _channel.client.state.user.id) { + return newMessage.copyWith( + ownReactions: message.ownReactions..add(reaction), + ); + } + + return newMessage; + } + + Message _removeReactionFromMessage(Message message, Reaction reaction) { + final newMessage = message.copyWith( + latestReactions: message.latestReactions + ..removeWhere( + (r) => r.type == reaction.type && r.userId == reaction.userId), + reactionCounts: { + ...message.reactionCounts, + reaction.type: (message.reactionCounts[reaction.type] ?? 0) - 1, + }, + reactionScores: { + ...message.reactionScores ?? {}, + reaction.type: max( + (message.reactionScores == null + ? 0 + : message.reactionScores[reaction.type] ?? 0) - + reaction.score, + 0), + }, + ); + + newMessage.reactionCounts.removeWhere((_, v) => v <= 0); + + if (reaction.user.id == _channel.client.state.user.id) { + return newMessage.copyWith( + ownReactions: message.ownReactions + ..removeWhere((r) => r.type == reaction.type), + ); + } + + return newMessage; + } + + /// Channel message list + List get messages => _channelState.messages; + + /// Channel message list as a stream + Stream> get messagesStream => + channelStateStream.map((cs) => cs.messages); + + /// Get channel last message + Message get lastMessage => _channelState.messages?.isNotEmpty == true + ? _channelState.messages.last + : null; + + /// Get channel last message + Stream get lastMessageStream => messagesStream + .map((event) => event?.isNotEmpty == true ? event.last : null); + + /// Channel members list + List get members => _channelState.members + .map((e) => e.copyWith(user: _channel.client.state.users[e.user.id])) + .toList(); + + /// Channel members list as a stream + Stream> get membersStream => CombineLatestStream.combine2< + List, Map, List>( + channelStateStream.map((cs) => cs.members), + _channel.client.state.usersStream, + (members, users) { + return members + .map((e) => e.copyWith(user: users[e.user.id])) + .toList(); + }, + ); + + /// Channel watcher count + int get watcherCount => _channelState.watcherCount; + + /// Channel watcher count as a stream + Stream get watcherCountStream => + channelStateStream.map((cs) => cs.watcherCount); + + /// Channel watchers list + List get watchers => _channelState.watchers + .map((e) => _channel.client.state.users[e.id] ?? e) + .toList(); + + /// Channel watchers list as a stream + Stream> get watchersStream => + CombineLatestStream.combine2, Map, List>( + channelStateStream.map((cs) => cs.watchers), + _channel.client.state.usersStream, + (watchers, users) { + return watchers.map((e) => users[e.id] ?? e).toList(); + }, + ); + + /// Channel read list + List get read => _channelState.read; + + /// Channel read list as a stream + Stream> get readStream => channelStateStream.map((cs) => cs.read); + + final BehaviorSubject _unreadCountController = BehaviorSubject.seeded(0); + + /// Unread count getter as a stream + Stream get unreadCountStream => _unreadCountController.stream; + + /// Unread count getter + int get unreadCount => _unreadCountController.value; + + bool _countMessageAsUnread(Message message) { + final userId = _channel.client.state?.user?.id; + final userIsMuted = _channel.client.state.user.mutes.firstWhere( + (m) => m.user?.id == message.user.id, + orElse: () => null, + ) != + null; + return message.silent != true && + message.shadowed != true && + message.user.id != userId && + !userIsMuted; + } + + /// Update threads with updated information about messages + void updateThreadInfo(String parentId, List messages) { + final newThreads = Map>.from(threads); + + if (newThreads.containsKey(parentId)) { + newThreads[parentId] = [ + ...newThreads[parentId] + ?.where( + (newMessage) => !messages.any((m) => m.id == newMessage.id)) + ?.toList() ?? + [], + ...messages, + ]; + + newThreads[parentId].sort(_sortByCreatedAt); + } else { + newThreads[parentId] = messages; + } + + _threads = newThreads; + } + + /// Delete all channel messages + void truncate() { + _channelState = _channelState.copyWith( + messages: [], + ); + } + + final List _updatedMessagesIds = []; + + /// Update channelState with updated information + void updateChannelState(ChannelState updatedState) { + final newMessages = [ + ...updatedState?.messages ?? [], + ..._channelState?.messages + ?.where((m) => + updatedState.messages + ?.any((newMessage) => newMessage.id == m.id) != + true) + ?.toList() ?? + [], + ]; + + newMessages.sort(_sortByCreatedAt); + + final newWatchers = [ + ...updatedState?.watchers ?? [], + ..._channelState?.watchers + ?.where((w) => + updatedState.watchers + ?.any((newWatcher) => newWatcher.id == w.id) != + true) + ?.toList() ?? + [], + ]; + + final newMembers = [ + ...updatedState?.members ?? [], + ]; + + final newReads = [ + ...updatedState?.read ?? [], + ..._channelState?.read + ?.where((r) => + updatedState.read + ?.any((newRead) => newRead.user.id == r.user.id) != + true) + ?.toList() ?? + [], + ]; + + _checkExpiredAttachmentMessages(updatedState); + + _channelState = _channelState.copyWith( + messages: newMessages, + channel: _channelState.channel?.copyWith( + lastMessageAt: updatedState.channel?.lastMessageAt, + createdAt: updatedState.channel?.createdAt, + type: updatedState.channel?.type, + extraData: updatedState.channel?.extraData, + updatedAt: updatedState.channel?.updatedAt, + id: updatedState.channel?.id, + createdBy: updatedState.channel?.createdBy, + config: updatedState.channel?.config, + deletedAt: updatedState.channel?.deletedAt, + cid: updatedState.channel?.cid, + frozen: updatedState.channel?.frozen, + memberCount: updatedState.channel?.memberCount, + ), + watchers: newWatchers, + watcherCount: updatedState.watcherCount, + members: newMembers, + read: newReads, + ); + } + + int _sortByCreatedAt(a, b) { + if (a.createdAt == null) { + return 1; + } + + if (b.createdAt == null) { + return -1; + } + + return a.createdAt.compareTo(b.createdAt); + } + + /// The channel state related to this client + ChannelState get _channelState => _channelStateController.value; + + /// The channel state related to this client as a stream + Stream get channelStateStream => _channelStateController.stream; + + /// The channel state related to this client + ChannelState get channelState => _channelStateController.value; + BehaviorSubject _channelStateController; + + set _channelState(ChannelState v) { + _channelStateController.add(v); + _channel._client.offlineStorage?.updateChannelState(v); + } + + /// The channel threads related to this channel + Map> get threads => _threadsController.value; + + /// The channel threads related to this channel as a stream + Stream>> get threadsStream => + _threadsController.stream; + final BehaviorSubject>> _threadsController = + BehaviorSubject.seeded({}); + + set _threads(Map> v) { + _channel._client.offlineStorage?.updateMessages( + v.values.expand((v) => v).toList(), + _channel.cid, + ); + _threadsController.add(v); + } + + /// Channel related typing users last value + List get typingEvents => _typingEventsController.value; + + /// Channel related typing users stream + Stream> get typingEventsStream => _typingEventsController.stream; + final BehaviorSubject> _typingEventsController = + BehaviorSubject.seeded([]); + + final Channel _channel; + final Map _typings = {}; + + void _listenTypingEvents() { + if (_channel.config?.typingEvents == false) { + return; + } + + _subscriptions.add(_channel.on(EventType.typingStart).listen((event) { + if (event.user.id != _channel.client.state.user.id) { + _typings[event.user] = DateTime.now(); + _typingEventsController.add(_typings.keys.toList()); + } + })); + + _subscriptions.add(_channel.on(EventType.typingStop).listen((event) { + if (event.user.id != _channel.client.state.user.id) { + _typings.remove(event.user); + _typingEventsController.add(_typings.keys.toList()); + } + })); + } + + void _clean() { + final now = DateTime.now(); + _typings.forEach((user, lastTypingEvent) { + if (now.difference(lastTypingEvent).inSeconds > 7) { + _channel.client.handleEvent( + Event( + type: EventType.typingStop, + user: user, + cid: _channel.cid, + ), + ); + } + }); + _typingEventsController.add(_typings.keys.toList()); + } + + /// Call this method to dispose this object + void dispose() { + _unreadCountController.close(); + retryQueue.dispose(); + _subscriptions.forEach((s) => s.cancel()); + _channelStateController.close(); + _isUpToDateController.close(); + _threadsController.close(); + _typingEventsController.close(); + } +} diff --git a/packages/dart_client/lib/src/api/connection_status.dart b/packages/dart_client/lib/src/api/connection_status.dart new file mode 100644 index 00000000..28a8e8d4 --- /dev/null +++ b/packages/dart_client/lib/src/api/connection_status.dart @@ -0,0 +1,11 @@ +/// Used to notify the WS connection status +enum ConnectionStatus { + /// WS is connected and everything is good + connected, + + /// WS is connecting (usually reconnecting) + connecting, + + /// WS is disconnected and it's not reconnecting + disconnected, +} diff --git a/packages/dart_client/lib/src/api/requests.dart b/packages/dart_client/lib/src/api/requests.dart new file mode 100644 index 00000000..fdf1f34f --- /dev/null +++ b/packages/dart_client/lib/src/api/requests.dart @@ -0,0 +1,97 @@ +import 'package:json_annotation/json_annotation.dart'; + +part 'requests.g.dart'; + +/// Sorting options +@JsonSerializable(createFactory: false) +class SortOption { + /// Ascending order + static const ASC = 1; + + /// Descending order + static const DESC = -1; + + /// A sorting field name + final String field; + + /// A sorting direction + final int direction; + + /// Creates a new SortOption instance + /// + /// For example: + /// ```dart + /// // Sort channels by the last message date: + /// final sorting = SortOption("last_message_at") + /// ``` + const SortOption(this.field, {this.direction = DESC}); + + /// Serialize model to json + Map toJson() => _$SortOptionToJson(this); +} + +/// Pagination options. +@JsonSerializable(createFactory: false, includeIfNull: false) +class PaginationParams { + /// The amount of items requested from the APIs. + final int limit; + + /// The offset of requesting items. + final int offset; + + /// Filter on ids greater than the given value. + @JsonKey(name: 'id_gt') + final String greaterThan; + + /// Filter on ids greater than or equal to the given value. + @JsonKey(name: 'id_gte') + final String greaterThanOrEqual; + + /// Filter on ids smaller than the given value. + @JsonKey(name: 'id_lt') + final String lessThan; + + /// Filter on ids smaller than or equal to the given value. + @JsonKey(name: 'id_lte') + final String lessThanOrEqual; + + /// Creates a new PaginationParams instance + /// + /// For example: + /// ```dart + /// // limit to 50 + /// final paginationParams = PaginationParams(limit: 50); + /// + /// // limit to 50 with offset + /// final paginationParams = PaginationParams(limit: 50, offset: 50); + /// ``` + const PaginationParams({ + this.limit = 10, + this.offset, + this.greaterThan, + this.greaterThanOrEqual, + this.lessThan, + this.lessThanOrEqual, + }); + + /// Serialize model to json + Map toJson() => _$PaginationParamsToJson(this); + + /// Creates a copy of [PaginationParams] with specified attributes overridden. + PaginationParams copyWith({ + int limit, + int offset, + String greaterThan, + String greaterThanOrEqual, + String lessThan, + String lessThanOrEqual, + }) => + PaginationParams( + limit: limit ?? this.limit, + offset: offset ?? this.offset, + greaterThan: greaterThan ?? this.greaterThan, + greaterThanOrEqual: greaterThanOrEqual ?? this.greaterThanOrEqual, + lessThan: lessThan ?? this.lessThan, + lessThanOrEqual: lessThanOrEqual ?? this.lessThanOrEqual, + ); +} diff --git a/packages/dart_client/lib/src/api/requests.g.dart b/packages/dart_client/lib/src/api/requests.g.dart new file mode 100644 index 00000000..ef790776 --- /dev/null +++ b/packages/dart_client/lib/src/api/requests.g.dart @@ -0,0 +1,31 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'requests.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +Map _$SortOptionToJson(SortOption instance) => + { + 'field': instance.field, + 'direction': instance.direction, + }; + +Map _$PaginationParamsToJson(PaginationParams instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('limit', instance.limit); + writeNotNull('offset', instance.offset); + writeNotNull('id_gt', instance.greaterThan); + writeNotNull('id_gte', instance.greaterThanOrEqual); + writeNotNull('id_lt', instance.lessThan); + writeNotNull('id_lte', instance.lessThanOrEqual); + return val; +} diff --git a/packages/dart_client/lib/src/api/responses.dart b/packages/dart_client/lib/src/api/responses.dart new file mode 100644 index 00000000..919a875b --- /dev/null +++ b/packages/dart_client/lib/src/api/responses.dart @@ -0,0 +1,375 @@ +import 'package:json_annotation/json_annotation.dart'; +import 'package:stream_chat/src/client.dart'; +import 'package:stream_chat/src/models/device.dart'; +import 'package:stream_chat/src/models/event.dart'; + +import '../models/channel_model.dart'; +import '../models/channel_state.dart'; +import '../models/member.dart'; +import '../models/message.dart'; +import '../models/reaction.dart'; +import '../models/read.dart'; +import '../models/user.dart'; + +part 'responses.g.dart'; + +class _BaseResponse { + String duration; +} + +/// Model response for [Client.resync] api call +@JsonSerializable(createToJson: false) +class SyncResponse extends _BaseResponse { + /// The list of events + List events; + + /// Create a new instance from a json + static SyncResponse fromJson(Map json) => + _$SyncResponseFromJson(json); +} + +/// Model response for [Client.queryChannels] api call +@JsonSerializable(createToJson: false) +class QueryChannelsResponse extends _BaseResponse { + /// List of channels state returned by the query + List channels; + + /// Create a new instance from a json + static QueryChannelsResponse fromJson(Map json) => + _$QueryChannelsResponseFromJson(json); +} + +/// Model response for [Client.queryChannels] api call +@JsonSerializable(createToJson: false) +class TranslateMessageResponse extends _BaseResponse { + /// List of channels state returned by the query + TranslatedMessage message; + + /// Create a new instance from a json + static TranslateMessageResponse fromJson(Map json) => + _$TranslateMessageResponseFromJson(json); +} + +/// Model response for [Client.queryChannels] api call +@JsonSerializable(createToJson: false) +class QueryMembersResponse extends _BaseResponse { + /// List of channels state returned by the query + List members; + + /// Create a new instance from a json + static QueryMembersResponse fromJson(Map json) => + _$QueryMembersResponseFromJson(json); +} + +/// Model response for [Client.queryUsers] api call +@JsonSerializable(createToJson: false) +class QueryUsersResponse extends _BaseResponse { + /// List of users returned by the query + List users; + + /// Create a new instance from a json + static QueryUsersResponse fromJson(Map json) => + _$QueryUsersResponseFromJson(json); +} + +/// Model response for [channel.getReactions] api call +@JsonSerializable(createToJson: false) +class QueryReactionsResponse extends _BaseResponse { + /// List of reactions returned by the query + List reactions; + + /// Create a new instance from a json + static QueryReactionsResponse fromJson(Map json) => + _$QueryReactionsResponseFromJson(json); +} + +/// Model response for [Channel.getReplies] api call +@JsonSerializable(createToJson: false) +class QueryRepliesResponse extends _BaseResponse { + /// List of messages returned by the api call + List messages; + + /// Create a new instance from a json + static QueryRepliesResponse fromJson(Map json) => + _$QueryRepliesResponseFromJson(json); +} + +/// Model response for [Client.getDevices] api call +@JsonSerializable(createToJson: false) +class ListDevicesResponse extends _BaseResponse { + /// List of user devices + List devices; + + /// Create a new instance from a json + static ListDevicesResponse fromJson(Map json) => + _$ListDevicesResponseFromJson(json); +} + +/// Model response for [Channel.sendFile] api call +@JsonSerializable(createToJson: false) +class SendFileResponse extends _BaseResponse { + /// The url of the uploaded file + String file; + + /// Create a new instance from a json + static SendFileResponse fromJson(Map json) => + _$SendFileResponseFromJson(json); +} + +/// Model response for [Channel.sendImage] api call +@JsonSerializable(createToJson: false) +class SendImageResponse extends _BaseResponse { + /// The url of the uploaded file + String file; + + /// Create a new instance from a json + static SendImageResponse fromJson(Map json) => + _$SendImageResponseFromJson(json); +} + +/// Model response for [Channel.sendReaction] api call +@JsonSerializable(createToJson: false) +class SendReactionResponse extends _BaseResponse { + /// Message returned by the api call + Message message; + + /// The reaction created by the api call + Reaction reaction; + + /// Create a new instance from a json + static SendReactionResponse fromJson(Map json) => + _$SendReactionResponseFromJson(json); +} + +/// Model response for [Client.setGuestUser] api call +@JsonSerializable(createToJson: false) +class SetGuestUserResponse extends _BaseResponse { + /// Guest user access token + String accessToken; + + /// Guest user + User user; + + /// Create a new instance from a json + static SetGuestUserResponse fromJson(Map json) => + _$SetGuestUserResponseFromJson(json); +} + +/// Model response for [Client.updateUser] api call +@JsonSerializable(createToJson: false) +class UpdateUsersResponse extends _BaseResponse { + /// Updated users + Map users; + + /// Create a new instance from a json + static UpdateUsersResponse fromJson(Map json) => + _$UpdateUsersResponseFromJson(json); +} + +/// Model response for [Client.updateMessage] api call +@JsonSerializable(createToJson: false) +class UpdateMessageResponse extends _BaseResponse { + /// Message returned by the api call + Message message; + + /// Create a new instance from a json + static UpdateMessageResponse fromJson(Map json) => + _$UpdateMessageResponseFromJson(json); +} + +/// Model response for [Channel.sendMessage] api call +@JsonSerializable(createToJson: false) +class SendMessageResponse extends _BaseResponse { + /// Message returned by the api call + Message message; + + /// Create a new instance from a json + static SendMessageResponse fromJson(Map json) => + _$SendMessageResponseFromJson(json); +} + +/// Model response for [Client.getMessage] api call +@JsonSerializable(createToJson: false) +class GetMessageResponse extends _BaseResponse { + /// Message returned by the api call + Message message; + + /// Channel of the message + ChannelModel channel; + + /// Create a new instance from a json + static GetMessageResponse fromJson(Map json) { + final res = _$GetMessageResponseFromJson(json); + final jsonChannel = res.message?.extraData?.remove('channel'); + if (jsonChannel != null) { + res.channel = ChannelModel.fromJson(jsonChannel); + } + return res; + } +} + +/// Model response for [Client.search] api call +@JsonSerializable(createToJson: false) +class SearchMessagesResponse extends _BaseResponse { + /// List of messages returned by the api call + List results; + + /// Create a new instance from a json + static SearchMessagesResponse fromJson(Map json) => + _$SearchMessagesResponseFromJson(json); +} + +/// Model response for [Channel.getMessagesById] api call +@JsonSerializable(createToJson: false) +class GetMessagesByIdResponse extends _BaseResponse { + /// Message returned by the api call + List messages; + + /// Create a new instance from a json + static GetMessagesByIdResponse fromJson(Map json) => + _$GetMessagesByIdResponseFromJson(json); +} + +/// Model response for [Channel.update] api call +@JsonSerializable(createToJson: false) +class UpdateChannelResponse extends _BaseResponse { + /// Updated channel + ChannelModel channel; + + /// Channel members + List members; + + /// Message returned by the api call + Message message; + + /// Create a new instance from a json + static UpdateChannelResponse fromJson(Map json) => + _$UpdateChannelResponseFromJson(json); +} + +/// Model response for [Channel.inviteMembers] api call +@JsonSerializable(createToJson: false) +class InviteMembersResponse extends _BaseResponse { + /// Updated channel + ChannelModel channel; + + /// Channel members + List members; + + /// Message returned by the api call + Message message; + + /// Create a new instance from a json + static InviteMembersResponse fromJson(Map json) => + _$InviteMembersResponseFromJson(json); +} + +/// Model response for [Channel.removeMembers] api call +@JsonSerializable(createToJson: false) +class RemoveMembersResponse extends _BaseResponse { + /// Updated channel + ChannelModel channel; + + /// Channel members + List members; + + /// Message returned by the api call + Message message; + + /// Create a new instance from a json + static RemoveMembersResponse fromJson(Map json) => + _$RemoveMembersResponseFromJson(json); +} + +/// Model response for [Channel.sendAction] api call +@JsonSerializable(createToJson: false) +class SendActionResponse extends _BaseResponse { + /// Message returned by the api call + Message message; + + /// Create a new instance from a json + static SendActionResponse fromJson(Map json) => + _$SendActionResponseFromJson(json); +} + +/// Model response for [Channel.addMembers] api call +@JsonSerializable(createToJson: false) +class AddMembersResponse extends _BaseResponse { + /// Updated channel + ChannelModel channel; + + /// Channel members + List members; + + /// Message returned by the api call + Message message; + + /// Create a new instance from a json + static AddMembersResponse fromJson(Map json) => + _$AddMembersResponseFromJson(json); +} + +/// Model response for [Channel.acceptInvite] api call +@JsonSerializable(createToJson: false) +class AcceptInviteResponse extends _BaseResponse { + /// Updated channel + ChannelModel channel; + + /// Channel members + List members; + + /// Message returned by the api call + Message message; + + /// Create a new instance from a json + static AcceptInviteResponse fromJson(Map json) => + _$AcceptInviteResponseFromJson(json); +} + +/// Model response for [Channel.rejectInvite] api call +@JsonSerializable(createToJson: false) +class RejectInviteResponse extends _BaseResponse { + /// Updated channel + ChannelModel channel; + + /// Channel members + List members; + + /// Message returned by the api call + Message message; + + /// Create a new instance from a json + static RejectInviteResponse fromJson(Map json) => + _$RejectInviteResponseFromJson(json); +} + +/// Model response for empty responses +@JsonSerializable(createToJson: false) +class EmptyResponse extends _BaseResponse { + /// Create a new instance from a json + static EmptyResponse fromJson(Map json) => + _$EmptyResponseFromJson(json); +} + +/// Model response for [Channel.query] api call +@JsonSerializable(createToJson: false) +class ChannelStateResponse extends _BaseResponse { + /// Updated channel + ChannelModel channel; + + /// List of messages returned by the api call + List messages; + + /// Channel members + List members; + + /// Number of users watching the channel + int watcherCount; + + /// List of read states + List read; + + /// Create a new instance from a json + static ChannelStateResponse fromJson(Map json) => + _$ChannelStateResponseFromJson(json); +} diff --git a/packages/dart_client/lib/src/api/responses.g.dart b/packages/dart_client/lib/src/api/responses.g.dart new file mode 100644 index 00000000..db5fba9e --- /dev/null +++ b/packages/dart_client/lib/src/api/responses.g.dart @@ -0,0 +1,382 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'responses.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +SyncResponse _$SyncResponseFromJson(Map json) { + return SyncResponse() + ..duration = json['duration'] as String + ..events = (json['events'] as List) + ?.map((e) => e == null + ? null + : Event.fromJson((e as Map)?.map( + (k, e) => MapEntry(k as String, e), + ))) + ?.toList(); +} + +QueryChannelsResponse _$QueryChannelsResponseFromJson(Map json) { + return QueryChannelsResponse() + ..duration = json['duration'] as String + ..channels = (json['channels'] as List) + ?.map((e) => e == null ? null : ChannelState.fromJson(e as Map)) + ?.toList(); +} + +TranslateMessageResponse _$TranslateMessageResponseFromJson(Map json) { + return TranslateMessageResponse() + ..duration = json['duration'] as String + ..message = json['message'] == null + ? null + : TranslatedMessage.fromJson((json['message'] as Map)?.map( + (k, e) => MapEntry(k as String, e), + )); +} + +QueryMembersResponse _$QueryMembersResponseFromJson(Map json) { + return QueryMembersResponse() + ..duration = json['duration'] as String + ..members = (json['members'] as List) + ?.map((e) => e == null + ? null + : Member.fromJson((e as Map)?.map( + (k, e) => MapEntry(k as String, e), + ))) + ?.toList(); +} + +QueryUsersResponse _$QueryUsersResponseFromJson(Map json) { + return QueryUsersResponse() + ..duration = json['duration'] as String + ..users = (json['users'] as List) + ?.map((e) => e == null + ? null + : User.fromJson((e as Map)?.map( + (k, e) => MapEntry(k as String, e), + ))) + ?.toList(); +} + +QueryReactionsResponse _$QueryReactionsResponseFromJson(Map json) { + return QueryReactionsResponse() + ..duration = json['duration'] as String + ..reactions = (json['reactions'] as List) + ?.map((e) => e == null + ? null + : Reaction.fromJson((e as Map)?.map( + (k, e) => MapEntry(k as String, e), + ))) + ?.toList(); +} + +QueryRepliesResponse _$QueryRepliesResponseFromJson(Map json) { + return QueryRepliesResponse() + ..duration = json['duration'] as String + ..messages = (json['messages'] as List) + ?.map((e) => e == null + ? null + : Message.fromJson((e as Map)?.map( + (k, e) => MapEntry(k as String, e), + ))) + ?.toList(); +} + +ListDevicesResponse _$ListDevicesResponseFromJson(Map json) { + return ListDevicesResponse() + ..duration = json['duration'] as String + ..devices = (json['devices'] as List) + ?.map((e) => e == null + ? null + : Device.fromJson((e as Map)?.map( + (k, e) => MapEntry(k as String, e), + ))) + ?.toList(); +} + +SendFileResponse _$SendFileResponseFromJson(Map json) { + return SendFileResponse() + ..duration = json['duration'] as String + ..file = json['file'] as String; +} + +SendImageResponse _$SendImageResponseFromJson(Map json) { + return SendImageResponse() + ..duration = json['duration'] as String + ..file = json['file'] as String; +} + +SendReactionResponse _$SendReactionResponseFromJson(Map json) { + return SendReactionResponse() + ..duration = json['duration'] as String + ..message = json['message'] == null + ? null + : Message.fromJson((json['message'] as Map)?.map( + (k, e) => MapEntry(k as String, e), + )) + ..reaction = json['reaction'] == null + ? null + : Reaction.fromJson((json['reaction'] as Map)?.map( + (k, e) => MapEntry(k as String, e), + )); +} + +SetGuestUserResponse _$SetGuestUserResponseFromJson(Map json) { + return SetGuestUserResponse() + ..duration = json['duration'] as String + ..accessToken = json['access_token'] as String + ..user = json['user'] == null + ? null + : User.fromJson((json['user'] as Map)?.map( + (k, e) => MapEntry(k as String, e), + )); +} + +UpdateUsersResponse _$UpdateUsersResponseFromJson(Map json) { + return UpdateUsersResponse() + ..duration = json['duration'] as String + ..users = (json['users'] as Map)?.map( + (k, e) => MapEntry( + k as String, + e == null + ? null + : User.fromJson((e as Map)?.map( + (k, e) => MapEntry(k as String, e), + ))), + ); +} + +UpdateMessageResponse _$UpdateMessageResponseFromJson(Map json) { + return UpdateMessageResponse() + ..duration = json['duration'] as String + ..message = json['message'] == null + ? null + : Message.fromJson((json['message'] as Map)?.map( + (k, e) => MapEntry(k as String, e), + )); +} + +SendMessageResponse _$SendMessageResponseFromJson(Map json) { + return SendMessageResponse() + ..duration = json['duration'] as String + ..message = json['message'] == null + ? null + : Message.fromJson((json['message'] as Map)?.map( + (k, e) => MapEntry(k as String, e), + )); +} + +GetMessageResponse _$GetMessageResponseFromJson(Map json) { + return GetMessageResponse() + ..duration = json['duration'] as String + ..message = json['message'] == null + ? null + : Message.fromJson((json['message'] as Map)?.map( + (k, e) => MapEntry(k as String, e), + )) + ..channel = json['channel'] == null + ? null + : ChannelModel.fromJson((json['channel'] as Map)?.map( + (k, e) => MapEntry(k as String, e), + )); +} + +SearchMessagesResponse _$SearchMessagesResponseFromJson(Map json) { + return SearchMessagesResponse() + ..duration = json['duration'] as String + ..results = (json['results'] as List) + ?.map((e) => e == null ? null : GetMessageResponse.fromJson(e as Map)) + ?.toList(); +} + +GetMessagesByIdResponse _$GetMessagesByIdResponseFromJson(Map json) { + return GetMessagesByIdResponse() + ..duration = json['duration'] as String + ..messages = (json['messages'] as List) + ?.map((e) => e == null + ? null + : Message.fromJson((e as Map)?.map( + (k, e) => MapEntry(k as String, e), + ))) + ?.toList(); +} + +UpdateChannelResponse _$UpdateChannelResponseFromJson(Map json) { + return UpdateChannelResponse() + ..duration = json['duration'] as String + ..channel = json['channel'] == null + ? null + : ChannelModel.fromJson((json['channel'] as Map)?.map( + (k, e) => MapEntry(k as String, e), + )) + ..members = (json['members'] as List) + ?.map((e) => e == null + ? null + : Member.fromJson((e as Map)?.map( + (k, e) => MapEntry(k as String, e), + ))) + ?.toList() + ..message = json['message'] == null + ? null + : Message.fromJson((json['message'] as Map)?.map( + (k, e) => MapEntry(k as String, e), + )); +} + +InviteMembersResponse _$InviteMembersResponseFromJson(Map json) { + return InviteMembersResponse() + ..duration = json['duration'] as String + ..channel = json['channel'] == null + ? null + : ChannelModel.fromJson((json['channel'] as Map)?.map( + (k, e) => MapEntry(k as String, e), + )) + ..members = (json['members'] as List) + ?.map((e) => e == null + ? null + : Member.fromJson((e as Map)?.map( + (k, e) => MapEntry(k as String, e), + ))) + ?.toList() + ..message = json['message'] == null + ? null + : Message.fromJson((json['message'] as Map)?.map( + (k, e) => MapEntry(k as String, e), + )); +} + +RemoveMembersResponse _$RemoveMembersResponseFromJson(Map json) { + return RemoveMembersResponse() + ..duration = json['duration'] as String + ..channel = json['channel'] == null + ? null + : ChannelModel.fromJson((json['channel'] as Map)?.map( + (k, e) => MapEntry(k as String, e), + )) + ..members = (json['members'] as List) + ?.map((e) => e == null + ? null + : Member.fromJson((e as Map)?.map( + (k, e) => MapEntry(k as String, e), + ))) + ?.toList() + ..message = json['message'] == null + ? null + : Message.fromJson((json['message'] as Map)?.map( + (k, e) => MapEntry(k as String, e), + )); +} + +SendActionResponse _$SendActionResponseFromJson(Map json) { + return SendActionResponse() + ..duration = json['duration'] as String + ..message = json['message'] == null + ? null + : Message.fromJson((json['message'] as Map)?.map( + (k, e) => MapEntry(k as String, e), + )); +} + +AddMembersResponse _$AddMembersResponseFromJson(Map json) { + return AddMembersResponse() + ..duration = json['duration'] as String + ..channel = json['channel'] == null + ? null + : ChannelModel.fromJson((json['channel'] as Map)?.map( + (k, e) => MapEntry(k as String, e), + )) + ..members = (json['members'] as List) + ?.map((e) => e == null + ? null + : Member.fromJson((e as Map)?.map( + (k, e) => MapEntry(k as String, e), + ))) + ?.toList() + ..message = json['message'] == null + ? null + : Message.fromJson((json['message'] as Map)?.map( + (k, e) => MapEntry(k as String, e), + )); +} + +AcceptInviteResponse _$AcceptInviteResponseFromJson(Map json) { + return AcceptInviteResponse() + ..duration = json['duration'] as String + ..channel = json['channel'] == null + ? null + : ChannelModel.fromJson((json['channel'] as Map)?.map( + (k, e) => MapEntry(k as String, e), + )) + ..members = (json['members'] as List) + ?.map((e) => e == null + ? null + : Member.fromJson((e as Map)?.map( + (k, e) => MapEntry(k as String, e), + ))) + ?.toList() + ..message = json['message'] == null + ? null + : Message.fromJson((json['message'] as Map)?.map( + (k, e) => MapEntry(k as String, e), + )); +} + +RejectInviteResponse _$RejectInviteResponseFromJson(Map json) { + return RejectInviteResponse() + ..duration = json['duration'] as String + ..channel = json['channel'] == null + ? null + : ChannelModel.fromJson((json['channel'] as Map)?.map( + (k, e) => MapEntry(k as String, e), + )) + ..members = (json['members'] as List) + ?.map((e) => e == null + ? null + : Member.fromJson((e as Map)?.map( + (k, e) => MapEntry(k as String, e), + ))) + ?.toList() + ..message = json['message'] == null + ? null + : Message.fromJson((json['message'] as Map)?.map( + (k, e) => MapEntry(k as String, e), + )); +} + +EmptyResponse _$EmptyResponseFromJson(Map json) { + return EmptyResponse()..duration = json['duration'] as String; +} + +ChannelStateResponse _$ChannelStateResponseFromJson(Map json) { + return ChannelStateResponse() + ..duration = json['duration'] as String + ..channel = json['channel'] == null + ? null + : ChannelModel.fromJson((json['channel'] as Map)?.map( + (k, e) => MapEntry(k as String, e), + )) + ..messages = (json['messages'] as List) + ?.map((e) => e == null + ? null + : Message.fromJson((e as Map)?.map( + (k, e) => MapEntry(k as String, e), + ))) + ?.toList() + ..members = (json['members'] as List) + ?.map((e) => e == null + ? null + : Member.fromJson((e as Map)?.map( + (k, e) => MapEntry(k as String, e), + ))) + ?.toList() + ..watcherCount = json['watcher_count'] as int + ..read = (json['read'] as List) + ?.map((e) => e == null + ? null + : Read.fromJson((e as Map)?.map( + (k, e) => MapEntry(k as String, e), + ))) + ?.toList(); +} diff --git a/packages/dart_client/lib/src/api/retry_policy.dart b/packages/dart_client/lib/src/api/retry_policy.dart new file mode 100644 index 00000000..43af3b8e --- /dev/null +++ b/packages/dart_client/lib/src/api/retry_policy.dart @@ -0,0 +1,37 @@ +import 'package:flutter/foundation.dart'; +import 'package:stream_chat/src/client.dart'; +import 'package:stream_chat/src/exceptions.dart'; + +/// The retry options +class RetryPolicy { + /// Instantiate a new RetryPolicy + RetryPolicy({ + @required this.shouldRetry, + @required this.retryTimeout, + this.attempt, + }); + + /// The number of attempts tried so far + int attempt = 0; + + /// This function evaluates if we should retry the failure + final bool Function(Client client, int attempt, ApiError apiError) + shouldRetry; + + /// In the case that we want to retry a failed request the retryTimeout method is called to determine the timeout + final Duration Function(Client client, int attempt, ApiError apiError) + retryTimeout; + + /// Creates a copy of [RetryPolicy] with specified attributes overridden. + RetryPolicy copyWith({ + bool Function(Client client, int attempt, ApiError apiError) shouldRetry, + Duration Function(Client client, int attempt, ApiError apiError) + retryTimeout, + int attempt, + }) => + RetryPolicy( + retryTimeout: retryTimeout ?? this.retryTimeout, + shouldRetry: shouldRetry ?? this.shouldRetry, + attempt: attempt ?? this.attempt, + ); +} diff --git a/packages/dart_client/lib/src/api/retry_queue.dart b/packages/dart_client/lib/src/api/retry_queue.dart new file mode 100644 index 00000000..12e8377a --- /dev/null +++ b/packages/dart_client/lib/src/api/retry_queue.dart @@ -0,0 +1,202 @@ +import 'dart:async'; + +import 'package:collection/collection.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/foundation.dart'; +import 'package:logging/logging.dart'; +import 'package:stream_chat/src/api/channel.dart'; +import 'package:stream_chat/src/api/retry_policy.dart'; +import 'package:stream_chat/src/event_type.dart'; +import 'package:stream_chat/src/exceptions.dart'; +import 'package:stream_chat/src/models/message.dart'; +import 'package:stream_chat/stream_chat.dart'; + +/// The retry queue associated to a channel +class RetryQueue { + /// The channel of this queue + final Channel channel; + + /// The logger associated to this queue + final Logger logger; + + /// Instantiate a new RetryQueue object + RetryQueue({ + @required this.channel, + this.logger, + }) { + _retryPolicy = channel.client.retryPolicy; + + _listenConnectionRecovered(); + + _listenFailedEvents(); + } + + final _subscriptions = []; + + void _listenConnectionRecovered() { + _subscriptions + .add(channel.client.on(EventType.connectionRecovered).listen((event) { + if (!_isRetrying && event.online) { + _startRetrying(); + } + })); + } + + final HeapPriorityQueue _messageQueue = HeapPriorityQueue(_byDate); + bool _isRetrying = false; + RetryPolicy _retryPolicy; + + /// Add a list of messages + void add(List messages) { + final messageList = _messageQueue.toList(); + _messageQueue.addAll(messages + .where((element) => !messageList.any((m) => m.id == element.id))); + + if (_messageQueue.isNotEmpty && !_isRetrying) { + _startRetrying(); + } + } + + Future _startRetrying() async { + logger?.info('start retrying'); + _isRetrying = true; + final retryPolicy = _retryPolicy.copyWith(attempt: 0); + + while (_messageQueue.isNotEmpty) { + final message = _messageQueue.first; + try { + logger?.info('retry attempt ${retryPolicy.attempt}'); + await _sendMessage(message); + logger?.info('message sent - removing it from the queue'); + _messageQueue.remove(message); + logger?.info('now ${_messageQueue.length} messages in the queue'); + retryPolicy.attempt = 0; + } catch (error) { + ApiError apiError; + if (error is DioError) { + if (error.type == DioErrorType.RESPONSE) { + _messageQueue.remove(message); + return; + } + apiError = ApiError( + error.response?.data, + error.response?.statusCode, + ); + } else if (error is ApiError) { + apiError = error; + if (apiError.status?.toString()?.startsWith('4') == true) { + _messageQueue.remove(message); + return; + } + } + + if (!retryPolicy.shouldRetry( + channel.client, + retryPolicy.attempt, + apiError, + )) { + _messageQueue.toList().forEach(_sendFailedEvent); + _isRetrying = false; + return; + } + + retryPolicy.attempt++; + final timeout = retryPolicy.retryTimeout( + channel.client, + retryPolicy.attempt, + apiError, + ); + await Future.delayed(timeout); + } + } + _isRetrying = false; + } + + void _sendFailedEvent(Message message) { + final newStatus = message.status == MessageSendingStatus.SENDING + ? MessageSendingStatus.FAILED + : (message.status == MessageSendingStatus.UPDATING + ? MessageSendingStatus.FAILED_UPDATE + : MessageSendingStatus.FAILED_DELETE); + channel.state.addMessage(message.copyWith( + status: newStatus, + )); + } + + Future _sendMessage(Message message) async { + if (message.status == MessageSendingStatus.FAILED_UPDATE || + message.status == MessageSendingStatus.UPDATING) { + await channel.client.updateMessage( + message, + channel.cid, + ); + } else if (message.status == MessageSendingStatus.FAILED || + message.status == MessageSendingStatus.SENDING) { + await channel.sendMessage( + message, + ); + } else if (message.status == MessageSendingStatus.FAILED_DELETE || + message.status == MessageSendingStatus.DELETING) { + await channel.client.deleteMessage( + message, + channel.cid, + ); + } + } + + void _listenFailedEvents() { + _subscriptions.add(channel.on().listen((event) { + final messageList = _messageQueue.toList(); + if (event.message != null) { + final messageIndex = + messageList.indexWhere((m) => m.id == event.message.id); + if (messageIndex == -1 && + [ + MessageSendingStatus.FAILED_UPDATE, + MessageSendingStatus.FAILED, + MessageSendingStatus.FAILED_DELETE, + ].contains(event.message.status)) { + logger?.info('add message from events'); + add([event.message]); + } else if (messageIndex != -1 && + [ + MessageSendingStatus.SENT, + null, + ].contains(event.message.status)) { + _messageQueue.remove(messageList[messageIndex]); + } + } + })); + } + + /// Call this method to dispose this object + void dispose() { + _messageQueue.clear(); + _subscriptions.forEach((s) => s.cancel()); + } + + static int _byDate(Message m1, Message m2) { + final date1 = _getMessageDate(m1); + final date2 = _getMessageDate(m2); + + return date1.compareTo(date2); + } + + static DateTime _getMessageDate(Message m1) { + switch (m1.status) { + case MessageSendingStatus.FAILED_DELETE: + case MessageSendingStatus.DELETING: + return m1.deletedAt; + + case MessageSendingStatus.FAILED: + case MessageSendingStatus.SENDING: + return m1.createdAt; + + case MessageSendingStatus.FAILED_UPDATE: + case MessageSendingStatus.UPDATING: + return m1.updatedAt; + default: + return null; + } + } +} diff --git a/packages/dart_client/lib/src/api/web_socket_channel_html.dart b/packages/dart_client/lib/src/api/web_socket_channel_html.dart new file mode 100644 index 00000000..9ddd83e5 --- /dev/null +++ b/packages/dart_client/lib/src/api/web_socket_channel_html.dart @@ -0,0 +1,7 @@ +import 'package:web_socket_channel/html.dart'; +import 'package:web_socket_channel/web_socket_channel.dart'; + +/// Html version of websocket implementation +/// Used in Flutter web version +WebSocketChannel connectWebSocket(String url, {Iterable protocols}) => + HtmlWebSocketChannel.connect(url, protocols: protocols); diff --git a/packages/dart_client/lib/src/api/web_socket_channel_io.dart b/packages/dart_client/lib/src/api/web_socket_channel_io.dart new file mode 100644 index 00000000..ed37ba7f --- /dev/null +++ b/packages/dart_client/lib/src/api/web_socket_channel_io.dart @@ -0,0 +1,7 @@ +import 'package:web_socket_channel/io.dart'; +import 'package:web_socket_channel/web_socket_channel.dart'; + +/// IO version of websocket implementation +/// Used in Flutter mobile version +WebSocketChannel connectWebSocket(String url, {Iterable protocols}) => + IOWebSocketChannel.connect(url, protocols: protocols); diff --git a/packages/dart_client/lib/src/api/web_socket_channel_stub.dart b/packages/dart_client/lib/src/api/web_socket_channel_stub.dart new file mode 100644 index 00000000..7e2e47bd --- /dev/null +++ b/packages/dart_client/lib/src/api/web_socket_channel_stub.dart @@ -0,0 +1,9 @@ +import 'package:web_socket_channel/web_socket_channel.dart'; + +/// Stub version of websocket implementation +/// Used just for conditional library import +WebSocketChannel connectWebSocket(String url, + {Iterable protocols, + Map headers, + Duration pingInterval}) => + throw UnimplementedError(); diff --git a/packages/dart_client/lib/src/api/websocket.dart b/packages/dart_client/lib/src/api/websocket.dart new file mode 100644 index 00000000..7d904a12 --- /dev/null +++ b/packages/dart_client/lib/src/api/websocket.dart @@ -0,0 +1,295 @@ +import 'dart:async'; +import 'dart:convert'; +import 'dart:math'; + +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:logging/logging.dart'; +import 'package:web_socket_channel/web_socket_channel.dart'; + +import '../models/event.dart'; +import '../models/user.dart'; +import 'connection_status.dart'; +import 'web_socket_channel_stub.dart' + if (dart.library.html) 'web_socket_channel_html.dart' + if (dart.library.io) 'web_socket_channel_io.dart'; + +typedef EventHandler = void Function(Event); +typedef ConnectWebSocket = WebSocketChannel Function(String url, + {Iterable protocols}); + +// TODO: parse error even +// TODO: if parsing an error into an event fails we should not hide the original error +/// A WebSocket connection that reconnects upon failure. +class WebSocket { + /// Creates a new websocket + /// To connect the WS call [connect] + WebSocket({ + @required this.baseUrl, + this.user, + this.connectParams, + this.connectPayload, + this.handler, + this.logger, + this.connectFunc = connectWebSocket, + this.reconnectionMonitorInterval = 1, + this.healthCheckInterval = 20, + this.reconnectionMonitorTimeout = 40, + }) { + final qs = Map.from(connectParams); + + final data = Map.from(connectPayload); + + data['user_details'] = user.toJson(); + qs['json'] = json.encode(data); + + if (baseUrl.startsWith('https')) { + _path = baseUrl.replaceFirst('https://', ''); + _path = Uri.https(_path, 'connect', qs) + .toString() + .replaceFirst('https', 'wss'); + } else if (baseUrl.startsWith('http')) { + _path = baseUrl.replaceFirst('http://', ''); + _path = + Uri.http(_path, 'connect', qs).toString().replaceFirst('http', 'ws'); + } else { + _path = Uri.https(baseUrl, 'connect', qs) + .toString() + .replaceFirst('https', 'wss'); + } + } + + /// WS base url + final String baseUrl; + + /// User performing the WS connection + final User user; + + /// Querystring connection parameters + final Map connectParams; + + /// WS connection payload + final Map connectPayload; + + /// Functions that will be called every time a new event is received from the connection + final EventHandler handler; + + /// A WS specific logger instance + final Logger logger; + + /// Connection function + /// Used only for testing purpose + @visibleForTesting + final ConnectWebSocket connectFunc; + + /// Interval of the reconnection monitor timer + /// This checks that it received a new event in the last [reconnectionMonitorTimeout] seconds, + /// otherwise it considers the connection unhealthy and reconnects the WS + final int reconnectionMonitorInterval; + + /// Interval of the health event sending timer + /// This sends a health event every [healthCheckInterval] seconds in order to + /// make the server aware that the client is still listening + final int healthCheckInterval; + + /// The timeout that uses the reconnection monitor timer to consider the connection unhealthy + final int reconnectionMonitorTimeout; + + /// This notifies of connection status changes + final ValueNotifier connectionStatus = + ValueNotifier(ConnectionStatus.disconnected); + + String _path; + int _retryAttempt = 1; + WebSocketChannel _channel; + Timer _healthCheck, _reconnectionMonitor; + DateTime _lastEventAt; + bool _manuallyClosed = false, _connecting = false, _reconnecting = false; + + Event _decodeEvent(String source) { + return Event.fromJson(json.decode(source)); + } + + Completer _connectionCompleter = Completer(); + + /// Connect the WS using the parameters passed in the constructor + Future connect() { + _manuallyClosed = false; + + if (_connecting) { + logger.severe('already connecting'); + return null; + } + + _connecting = true; + connectionStatus.value = ConnectionStatus.connecting; + + logger.info('connecting to $_path'); + + _channel = connectFunc(_path); + _channel.stream.listen( + (data) { + final jsonData = json.decode(data); + if (jsonData['error'] != null) { + return _onConnectionError(jsonData['error']); + } + _onData(data); + }, + onError: (error, stacktrace) { + _onConnectionError(error, stacktrace); + }, + onDone: () { + _onDone(); + }, + ); + return _connectionCompleter.future; + } + + void _onDone() { + _connecting = false; + if (_manuallyClosed) { + return; + } + + logger.info( + 'connection closed | closeCode: ${_channel.closeCode} | closedReason: ${_channel.closeReason}'); + + if (!_reconnecting) { + _reconnect(); + } + } + + void _onData(data) { + final event = _decodeEvent(data); + logger.info('received new event: $data'); + + if (_lastEventAt == null) { + logger.info('connection estabilished'); + _connecting = false; + _reconnecting = false; + _lastEventAt = DateTime.now(); + + connectionStatus.value = ConnectionStatus.connected; + _retryAttempt = 1; + + if (!_connectionCompleter.isCompleted) { + _connectionCompleter.complete(event); + } + + _startReconnectionMonitor(); + _startHealthCheck(); + } + + handler(event); + _lastEventAt = DateTime.now(); + } + + Future _onConnectionError(error, [stacktrace]) async { + logger.severe('error connecting'); + logger.severe(error); + if (stacktrace != null) { + logger.severe(stacktrace); + } + _connecting = false; + + if (!_reconnecting) { + connectionStatus.value = ConnectionStatus.disconnected; + } + + if (!_connectionCompleter.isCompleted) { + _cancelTimers(); + _connectionCompleter.completeError(error, stacktrace); + } else if (!_reconnecting) { + return _reconnect(); + } + } + + void _startReconnectionMonitor() { + final reconnectionTimer = (_) { + final now = DateTime.now(); + if (_lastEventAt != null && + now.difference(_lastEventAt).inSeconds > reconnectionMonitorTimeout) { + _channel.sink.close(); + } + }; + + _reconnectionMonitor = Timer.periodic( + Duration(seconds: reconnectionMonitorInterval), + reconnectionTimer, + ); + + reconnectionTimer(_reconnectionMonitor); + } + + void _reconnectTimer() async { + if (!_reconnecting) { + return; + } + if (_connecting) { + logger.info('already connecting'); + return; + } + + logger.info('reconnecting..'); + + _cancelTimers(); + + try { + await connect(); + } catch (e) {} + await Future.delayed( + Duration(seconds: min(_retryAttempt * 5, 25)), + () { + _reconnectTimer(); + _retryAttempt++; + }, + ); + } + + Future _reconnect() async { + logger.info('reconnect'); + if (!_reconnecting) { + _reconnecting = true; + connectionStatus.value = ConnectionStatus.connecting; + } + + _reconnectTimer(); + } + + void _cancelTimers() { + _lastEventAt = null; + if (_healthCheck != null) { + _healthCheck.cancel(); + } + if (_reconnectionMonitor != null) { + _reconnectionMonitor.cancel(); + } + } + + void _startHealthCheck() { + logger.info('start health check monitor'); + + final healthCheckTimer = (_) { + logger.info('sending health.check'); + _channel.sink.add("{'type': 'health.check'}"); + }; + + _healthCheck = Timer.periodic( + Duration(seconds: healthCheckInterval), + healthCheckTimer, + ); + + healthCheckTimer(_healthCheck); + } + + /// Disconnects the WS and releases eventual resources + Future disconnect() { + logger.info('disconnecting'); + _connectionCompleter = Completer(); + _cancelTimers(); + _manuallyClosed = true; + connectionStatus.value = ConnectionStatus.disconnected; + connectionStatus.dispose(); + return _channel.sink.close(); + } +} diff --git a/packages/dart_client/lib/src/client.dart b/packages/dart_client/lib/src/client.dart new file mode 100644 index 00000000..0952447a --- /dev/null +++ b/packages/dart_client/lib/src/client.dart @@ -0,0 +1,1388 @@ +import 'dart:async'; +import 'dart:convert'; +import 'dart:io'; + +import 'package:dio/dio.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:logging/logging.dart'; +import 'package:rxdart/rxdart.dart'; +import 'package:shared_preferences/shared_preferences.dart'; +import 'package:stream_chat/src/api/retry_policy.dart'; +import 'package:stream_chat/src/event_type.dart'; +import 'package:stream_chat/src/models/channel_model.dart'; +import 'package:stream_chat/src/models/own_user.dart'; +import 'package:stream_chat/version.dart'; +import 'package:uuid/uuid.dart'; + +import 'api/channel.dart'; +import 'api/connection_status.dart'; +import 'api/requests.dart'; +import 'api/responses.dart'; +import 'api/websocket.dart'; +import 'db/offline_storage.dart'; +import 'exceptions.dart'; +import 'models/event.dart'; +import 'models/message.dart'; +import 'models/user.dart'; + +typedef LogHandlerFunction = void Function(LogRecord record); +typedef DecoderFunction = T Function(Map); +typedef TokenProvider = Future Function(String userId); + +/// The key used to save the userId to sharedPreferences +const String KEY_USER_ID = 'KEY_USER_ID'; + +/// The key used to save the token to sharedPreferences +const String KEY_TOKEN = 'KEY_TOKEN'; + +/// The key used to save the apiKey to sharedPreferences +const String KEY_API_KEY = 'KEY_API_KEY'; + +/// The official Dart client for Stream Chat, +/// a service for building chat applications. +/// This library can be used on any Dart project and on both mobile and web apps with Flutter. +/// You can sign up for a Stream account at https://getstream.io/chat/ +/// +/// The Chat client will manage API call, event handling and manage the +/// websocket connection to Stream Chat servers. +/// +/// ```dart +/// final client = Client("stream-chat-api-key"); +/// ``` +class Client { + /// Create a client instance with default options. + /// You should only create the client once and re-use it across your application. + Client( + this.apiKey, { + this.tokenProvider, + this.baseURL = _defaultBaseURL, + this.logLevel = Level.WARNING, + this.logHandlerFunction, + this.persistenceEnabled = true, + Duration connectTimeout = const Duration(seconds: 6), + Duration receiveTimeout = const Duration(seconds: 6), + Dio httpClient, + this.showLocalNotification, + this.backgroundKeepAlive = const Duration(minutes: 1), + RetryPolicy retryPolicy, + }) { + WidgetsFlutterBinding.ensureInitialized(); + + _retryPolicy ??= RetryPolicy( + retryTimeout: (Client client, int attempt, ApiError error) => + Duration(seconds: 1 * attempt), + shouldRetry: (Client client, int attempt, ApiError error) => attempt < 5, + ); + + state = ClientState(this); + + _setupLogger(); + _setupDio(httpClient, receiveTimeout, connectTimeout); + + logger.info('instantiating new client'); + } + + OfflineStorage _offlineStorage; + + /// If true chat data will persist on disk + final bool persistenceEnabled; + + RetryPolicy _retryPolicy; + + bool _synced = false; + + /// The retry policy options getter + RetryPolicy get retryPolicy => _retryPolicy; + + /// Method used to show a local notification while the app is in background + /// Switching to another application will not disconnect the client immediately + /// So, use this method to show the notification when receiving a new message via events + final void Function(Message, ChannelModel) showLocalNotification; + + /// The amount of time that will pass before disconnecting the client in the background + final Duration backgroundKeepAlive; + + /// Client offline database + OfflineStorage get offlineStorage => _offlineStorage; + + /// This client state + ClientState state; + + /// By default the Chat Client will write all messages with level Warn or Error to stdout. + /// During development you might want to enable more logging information, you can change the default log level when constructing the client. + /// + /// ```dart + /// final client = Client("stream-chat-api-key", logLevel: Level.INFO); + /// ``` + final Level logLevel; + + /// Client specific logger instance. + /// Refer to the class [Logger] to learn more about the specific implementation. + final Logger logger = Logger.detached('📡'); + + /// A function that has a parameter of type [LogRecord]. + /// This is called on every new log record. + /// By default the client will use the handler returned by [_getDefaultLogHandler]. + /// Setting it you can handle the log messages directly instead of have them written to stdout, + /// this is very convenient if you use an error tracking tool or if you want to centralize your logs into one facility. + /// + /// ```dart + /// myLogHandlerFunction = (LogRecord record) { + /// // do something with the record (ie. send it to Sentry or Fabric) + /// } + /// + /// final client = Client("stream-chat-api-key", logHandlerFunction: myLogHandlerFunction); + ///``` + LogHandlerFunction logHandlerFunction; + + /// Your project Stream Chat api key. + /// Find your API keys here https://getstream.io/dashboard/ + String apiKey; + + /// Your project Stream Chat base url. + final String baseURL; + + /// A function in which you send a request to your own backend to get a Stream Chat API token. + /// The token will be the return value of the function. + /// It's used by the client to refresh the token once expired or to set the user without a predefined token using [setUserWithProvider]. + final TokenProvider tokenProvider; + + /// [Dio] httpClient + /// It's be chosen because it's easy to use and supports interesting features out of the box + /// (Interceptors, Global configuration, FormData, File downloading etc.) + @visibleForTesting + Dio httpClient = Dio(); + + static const _defaultBaseURL = 'chat-us-east-1.stream-io-api.com'; + static const _tokenExpiredErrorCode = 40; + VoidCallback _connectionStatusListener; + + final BehaviorSubject _controller = BehaviorSubject(); + + /// Stream of [Event] coming from websocket connection + /// Listen to this or use the [on] method to filter specific event types + Stream get stream => _controller.stream; + + /// This notifies the connection status of the websocket connection. + /// Listen to this to get notified when the websocket tries to reconnect. + final ValueNotifier wsConnectionStatus = + ValueNotifier(ConnectionStatus.disconnected); + + /// The current user token + String token; + + /// The id of the current websocket connection + String get connectionId => _connectionId; + + bool _anonymous = false; + String _connectionId; + WebSocket _ws; + + bool get _hasConnectionId => _connectionId != null; + + void _setupDio( + Dio httpClient, + Duration receiveTimeout, + Duration connectTimeout, + ) { + logger.info('http client setup'); + + this.httpClient = httpClient ?? Dio(); + + String url; + if (!baseURL.startsWith('https') && !baseURL.startsWith('http')) { + url = Uri.https(baseURL, '').toString(); + } else { + url = baseURL; + } + + this.httpClient.options.baseUrl = url; + this.httpClient.options.receiveTimeout = receiveTimeout.inMilliseconds; + this.httpClient.options.connectTimeout = connectTimeout.inMilliseconds; + this.httpClient.interceptors.add( + InterceptorsWrapper( + onRequest: (options) async { + options.queryParameters.addAll(_commonQueryParams); + options.headers.addAll(_httpHeaders); + + if (_connectionId != null && + (options.data is Map || options.data == null)) { + options.data = { + 'connection_id': _connectionId, + ...(options.data ?? {}), + }; + } + + var stringData = options.data.toString(); + + if (options.data is FormData) { + final multiPart = (options.data as FormData).files[0]?.value; + stringData = + '${multiPart?.filename} - ${multiPart?.contentType}'; + } + + logger.info(''' + + method: ${options.method} + url: ${options.uri} + headers: ${options.headers} + data: $stringData + + '''); + + return options; + }, + onError: _tokenExpiredInterceptor, + ), + ); + } + + Future _tokenExpiredInterceptor(DioError err) async { + final apiError = ApiError( + err.response?.data, + err.response?.statusCode, + ); + + if (apiError.code == _tokenExpiredErrorCode) { + logger.info('token expired'); + + if (tokenProvider != null) { + httpClient.lock(); + final userId = state.user.id; + + _ws.connectionStatus.removeListener(_connectionStatusListener); + + await _disconnect(); + + final newToken = await tokenProvider(userId); + await Future.delayed(Duration(seconds: 4)); + token = newToken; + + httpClient.unlock(); + + await setUser(User(id: userId), newToken); + + try { + return await httpClient.request( + err.request.path, + cancelToken: err.request.cancelToken, + data: err.request.data, + onReceiveProgress: err.request.onReceiveProgress, + onSendProgress: err.request.onSendProgress, + queryParameters: err.request.queryParameters, + options: err.request, + ); + } catch (err) { + return err; + } + } + } + + return err; + } + + LogHandlerFunction _getDefaultLogHandler() { + final levelEmojiMapper = { + Level.INFO.name: 'ℹ️', + Level.WARNING.name: '⚠️', + Level.SEVERE.name: '🚨', + }; + return (LogRecord record) { + print( + '(${record.time}) ${levelEmojiMapper[record.level.name] ?? record.level.name} ${record.loggerName} ${record.message}'); + if (record.stackTrace != null) { + print(record.stackTrace); + } + }; + } + + Logger _detachedLogger( + String name, + ) { + return Logger.detached(name) + ..level = logLevel + ..onRecord.listen(logHandlerFunction ?? _getDefaultLogHandler()); + } + + void _setupLogger() { + logger.level = logLevel; + + logHandlerFunction ??= _getDefaultLogHandler(); + + logger.onRecord.listen(logHandlerFunction); + + logger.info('logger setup'); + } + + /// Call this function to dispose the client + void dispose() async { + await _offlineStorage?.disconnect(); + await _disconnect(); + httpClient.close(); + await _controller.close(); + state.channels.values.forEach((c) => c.dispose()); + state.dispose(); + } + + Map get _httpHeaders => { + 'Authorization': token, + 'stream-auth-type': _authType, + 'x-stream-client': _userAgent, + 'Content-Encoding': 'gzip', + }; + + /// Set the current user, this triggers a connection to the API. + /// It returns a [Future] that resolves when the connection is setup. + Future setUser(User user, String token) async { + if (_connectCompleter != null && !_connectCompleter.isCompleted) { + logger.warning('Already connecting'); + throw Exception('Already connecting'); + } + + _connectCompleter = Completer(); + + logger.info('set user'); + state.user = OwnUser.fromJson(user.toJson()); + this.token = token; + _anonymous = false; + + final sharedPreferences = await SharedPreferences.getInstance(); + await sharedPreferences.setString(KEY_USER_ID, user.id); + await sharedPreferences.setString(KEY_TOKEN, token); + await sharedPreferences.setString(KEY_API_KEY, apiKey); + + return connect().then((event) { + _connectCompleter.complete(event); + return event; + }).catchError((e, s) { + _connectCompleter.completeError(e, s); + throw e; + }); + } + + /// Set the current user using the [tokenProvider] to fetch the token. + /// It returns a [Future] that resolves when the connection is setup. + Future setUserWithProvider(User user) async { + if (tokenProvider == null) { + throw Exception(''' + TokenProvider must be provided in the constructor in order to use `setUserWithProvider` method. + Use `setUser` providing a token. + '''); + } + final token = await tokenProvider(user.id); + return setUser(user, token); + } + + /// Stream of [Event] coming from websocket connection + /// Pass an eventType as parameter in order to filter just a type of event + Stream on([ + String eventType, + String eventType2, + String eventType3, + String eventType4, + ]) => + stream.where((event) => + eventType == null || + (event.type != null && + (event.type == eventType || + event.type == eventType2 || + event.type == eventType3 || + event.type == eventType4))); + + /// Method called to add a new event to the [_controller]. + void handleEvent(Event event) async { + logger.info('handle new event: ${event.toJson()}'); + if (event.connectionId != null) { + _connectionId = event.connectionId; + } + + if (!event.isLocal) { + if (_synced && event.createdAt != null) { + await _offlineStorage?.updateConnectionInfo(event); + await _offlineStorage?.updateLastSyncAt(event.createdAt); + } + } + + if (event.user != null) { + state._updateUser(event.user); + } + + if (event.me != null) { + state.user = event.me; + } + _controller.add(event); + } + + Completer _connectCompleter; + + /// Connect the client websocket + Future connect() async { + logger.info('connecting'); + if (wsConnectionStatus.value == ConnectionStatus.connecting) { + logger.warning('Already connecting'); + throw Exception('Already connecting'); + } + + if (wsConnectionStatus.value == ConnectionStatus.connected) { + logger.warning('Already connected'); + throw Exception('Already connected'); + } + + wsConnectionStatus.value = ConnectionStatus.connecting; + + if (persistenceEnabled && _offlineStorage == null) { + _offlineStorage = + await connectDatabase(state.user, _detachedLogger('💽')); + } + + _ws = WebSocket( + baseUrl: baseURL, + user: state.user, + connectParams: { + 'api_key': apiKey, + 'authorization': token, + 'stream-auth-type': _authType, + 'x-stream-client': _userAgent, + }, + connectPayload: { + 'user_id': state.user.id, + 'server_determines_connection_id': true, + }, + handler: handleEvent, + logger: _detachedLogger('🔌'), + ); + + _connectionStatusListener = () async { + final value = _ws.connectionStatus.value; + wsConnectionStatus.value = value; + handleEvent(Event( + type: EventType.connectionChanged, + online: value == ConnectionStatus.connected, + )); + + if (value == ConnectionStatus.connected && + state.channels?.isNotEmpty == true) { + queryChannels(filter: { + 'cid': { + '\$in': state.channels.keys.toList(), + }, + }).then( + (_) async { + await resync(); + handleEvent(Event( + type: EventType.connectionRecovered, + online: true, + )); + }, + ); + } else { + _synced = false; + } + }; + + _ws.connectionStatus.addListener(_connectionStatusListener); + + var event = await _offlineStorage?.getConnectionInfo(); + + await _ws.connect().then((e) async { + await _offlineStorage?.updateConnectionInfo(e); + event = e; + await resync(); + }).catchError((err, stacktrace) { + logger.severe('error connecting ws', err, stacktrace); + if (err is Map) { + throw err; + } + }); + + return event; + } + + /// Get the events missed while offline to sync the offline storage + Future resync([List cids]) async { + final lastSyncAt = await offlineStorage?.getLastSyncAt(); + + if (lastSyncAt == null) { + _synced = true; + return; + } + + cids ??= await offlineStorage?.getChannelCids(); + + if (cids?.isEmpty == true) { + return; + } + + try { + final rawRes = await post('/sync', data: { + 'channel_cids': cids, + 'last_sync_at': lastSyncAt.toUtc().toIso8601String(), + }); + logger.fine('rawRes: $rawRes'); + + final res = decode( + rawRes.data, + SyncResponse.fromJson, + ); + + res.events.sort((a, b) => a.createdAt.compareTo(b.createdAt)); + + res.events.forEach((element) { + logger.fine('element.type: ${element.type}'); + logger.fine('element.message.text: ${element.message?.text}'); + }); + + res.events.forEach((event) { + handleEvent(event); + }); + + await _offlineStorage?.updateLastSyncAt(DateTime.now()); + _synced = true; + } catch (error) { + logger.severe('Error during resync $error'); + } + } + + String _asMap(sort) { + return sort?.map((s) => s.toJson().toString())?.join(''); + } + + final _queryChannelsStreams = >>{}; + + /// Requests channels with a given query. + Future> queryChannels({ + Map filter, + List sort, + Map options, + PaginationParams paginationParams = const PaginationParams(limit: 10), + int messageLimit, + bool onlyOffline = false, + bool waitForConnect = true, + }) async { + if (waitForConnect) { + if (_connectCompleter != null && !_connectCompleter.isCompleted) { + logger.info('awaiting connection completer'); + await _connectCompleter.future; + } + if (wsConnectionStatus.value != ConnectionStatus.connected) { + throw Exception( + 'You cannot use queryChannels without an active connection. Call setUser to connect the client.'); + } + } + + final hash = base64.encode(utf8.encode( + '$filter${_asMap(sort)}$options${paginationParams?.toJson()}$messageLimit$onlyOffline')); + if (_queryChannelsStreams.containsKey(hash)) { + return _queryChannelsStreams[hash]; + } + + final newQueryChannelsStream = _doQueryChannels( + filter: filter, + sort: sort, + options: options, + paginationParams: paginationParams, + messageLimit: messageLimit, + onlyOffline: onlyOffline, + ).whenComplete(() { + _queryChannelsStreams.remove(hash); + }); + + _queryChannelsStreams[hash] = newQueryChannelsStream; + + return newQueryChannelsStream; + } + + Future> _doQueryChannels({ + @required Map filter, + @required List sort, + @required Map options, + @required int messageLimit, + PaginationParams paginationParams = const PaginationParams(limit: 10), + bool onlyOffline = false, + }) async { + logger.info('Query channel start'); + final defaultOptions = { + 'state': true, + 'watch': true, + 'presence': false, + }; + + var payload = { + 'filter_conditions': filter, + 'sort': sort, + }; + + if (messageLimit != null) { + payload['message_limit'] = messageLimit; + } + + payload.addAll(defaultOptions); + + if (options != null) { + payload.addAll(options); + } + + if (paginationParams != null) { + payload.addAll(paginationParams.toJson()); + } + + if (onlyOffline) { + return _queryChannelsOffline( + filter: filter, + sort: sort, + paginationParams: paginationParams, + ); + } + + try { + final response = await get( + '/channels', + queryParameters: { + 'payload': jsonEncode(payload), + }, + ); + + final res = decode( + response.data, + QueryChannelsResponse.fromJson, + ); + + final users = res.channels + ?.expand((channel) => channel.members.map((member) => member.user)) + ?.toList(); + + if (users != null) { + state._updateUsers(users); + } + + logger.info('Got ${res.channels?.length} channels from api'); + + if (res.channels?.isEmpty != false && + (paginationParams?.offset ?? 0) == 0) { + logger.warning('''We could not find any channel for this query. + Please make sure to take a look at the Flutter tutorial: https://getstream.io/chat/flutter/tutorial + If your application already has users and channels, you might need to adjust your query channel as explained in the docs https://getstream.io/chat/docs/query_channels/?language=dart'''); + } + + final newChannels = Map.from(state.channels ?? {}); + final channels = []; + + if (res.channels != null) { + for (final channelState in res.channels) { + final channel = newChannels[channelState.channel.cid]; + if (channel != null) { + channel.state?.updateChannelState(channelState); + channels.add(channel); + } else { + final newChannel = Channel.fromState(this, channelState); + await _offlineStorage + ?.updateChannelState(newChannel.state.channelState); + newChannel.state?.updateChannelState(channelState); + newChannels[newChannel.cid] = newChannel; + channels.add(newChannel); + } + } + } + + state.channels = newChannels; + + await _offlineStorage?.updateChannelQueries( + filter, + res.channels.map((c) => c.channel.cid).toList(), + paginationParams?.offset == null || paginationParams.offset == 0, + ); + + return channels; + } catch (e) { + if (!persistenceEnabled) { + rethrow; + } + return _queryChannelsOffline( + filter: filter, + sort: sort, + paginationParams: paginationParams, + ); + } + } + + _parseError(DioError error) { + if (error.type == DioErrorType.RESPONSE) { + final apiError = + ApiError(error.response?.data, error.response?.statusCode); + logger.severe('apiError: ${apiError.toString()}'); + return apiError; + } + + return error; + } + + Future> _queryChannelsOffline({ + @required Map filter, + @required List sort, + PaginationParams paginationParams = const PaginationParams(limit: 10), + }) async { + final offlineChannels = await _offlineStorage?.getChannelStates( + filter: filter, + sort: sort, + paginationParams: paginationParams, + ) ?? + []; + final newChannels = Map.from(state.channels ?? {}); + logger.info('Got ${offlineChannels.length} channels from storage'); + final channels = offlineChannels.map((channelState) { + final channel = newChannels[channelState.channel.cid]; + if (channel != null) { + channel.state?.updateChannelState(channelState); + return channel; + } else { + final newChannel = Channel.fromState(this, channelState); + _offlineStorage?.updateChannelState(newChannel.state.channelState); + newChannels[newChannel.cid] = newChannel; + return newChannel; + } + }).toList(); + + if (channels.isNotEmpty) { + state.channels = newChannels; + } + return channels; + } + + /// Handy method to make http GET request with error parsing. + Future> get( + String path, { + Map queryParameters, + }) async { + try { + final response = await httpClient.get( + path, + queryParameters: queryParameters, + ); + return response; + } on DioError catch (error) { + throw _parseError(error); + } + } + + /// Handy method to make http POST request with error parsing. + Future> post( + String path, { + dynamic data, + }) async { + try { + final response = await httpClient.post(path, data: data); + return response; + } on DioError catch (error) { + throw _parseError(error); + } + } + + /// Handy method to make http DELETE request with error parsing. + Future> delete( + String path, { + Map queryParameters, + }) async { + try { + final response = await httpClient.delete(path, + queryParameters: queryParameters); + return response; + } on DioError catch (error) { + throw _parseError(error); + } + } + + /// Handy method to make http PATCH request with error parsing. + Future> patch( + String path, { + Map queryParameters, + dynamic data, + }) async { + try { + final response = await httpClient.patch( + path, + queryParameters: queryParameters, + data: data, + ); + return response; + } on DioError catch (error) { + throw _parseError(error); + } + } + + /// Handy method to make http PUT request with error parsing. + Future> put( + String path, { + Map queryParameters, + dynamic data, + }) async { + try { + final response = await httpClient.put( + path, + queryParameters: queryParameters, + data: data, + ); + return response; + } on DioError catch (error) { + throw _parseError(error); + } + } + + /// Used to log errors and stacktrace in case of bad json deserialization + T decode(String j, DecoderFunction decoderFunction) { + try { + if (j == null) { + return null; + } + return decoderFunction(json.decode(j)); + } catch (error, stacktrace) { + logger.severe('Error decoding response', error, stacktrace); + rethrow; + } + } + + String get _authType => _anonymous ? 'anonymous' : 'jwt'; + + // TODO: get the right version of the lib from the build toolchain + String get _userAgent => 'stream-chat-dart-client-$PACKAGE_VERSION'; + + Map get _commonQueryParams => { + 'user_id': state.user?.id, + 'api_key': apiKey, + 'connection_id': _connectionId, + }; + + /// Set the current user with an anonymous id, this triggers a connection to the API. + /// It returns a [Future] that resolves when the connection is setup. + Future setAnonymousUser() async { + if (_connectCompleter != null && !_connectCompleter.isCompleted) { + logger.warning('Already connecting'); + throw Exception('Already connecting'); + } + + _connectCompleter = Completer(); + + _anonymous = true; + final uuid = Uuid(); + state.user = OwnUser(id: uuid.v4()); + + return connect().then((event) { + _connectCompleter.complete(event); + return event; + }).catchError((e, s) { + _connectCompleter.completeError(e, s); + throw e; + }); + } + + /// Set the current user as guest, this triggers a connection to the API. + /// It returns a [Future] that resolves when the connection is setup. + Future setGuestUser(User user) async { + _anonymous = true; + final response = await post('/guest', data: {'user': user.toJson()}) + .then((res) => decode( + res.data, SetGuestUserResponse.fromJson)) + .whenComplete(() => _anonymous = false); + return setUser( + response.user, + response.accessToken, + ); + } + + /// Closes the websocket connection and resets the client + /// If [flushOfflineStorage] is true the client deletes all offline user's data + /// If [clearUser] is true the client unsets the current user + Future disconnect({ + bool flushOfflineStorage = false, + bool clearUser = false, + }) async { + logger.info( + 'Disconnecting flushOfflineStorage: $flushOfflineStorage; clearUser: $clearUser'); + + await _offlineStorage?.disconnect(flush: flushOfflineStorage); + _offlineStorage = null; + + if (clearUser == true) { + state.dispose(); + state = ClientState(this); + } + + await _disconnect(); + } + + Future _disconnect() async { + logger.info('Client disconnecting'); + + await _ws?.disconnect(); + } + + /// Requests users with a given query. + Future queryUsers({ + Map filter, + List sort, + Map options, + PaginationParams pagination, + }) async { + final defaultOptions = { + 'presence': _hasConnectionId, + }; + + final payload = { + 'filter_conditions': filter ?? {}, + 'sort': sort, + }; + + payload.addAll(defaultOptions); + + if (pagination != null) { + payload.addAll(pagination.toJson()); + } + + if (options != null) { + payload.addAll(options); + } + + final rawRes = await get( + '/users', + queryParameters: { + 'payload': jsonEncode(payload), + }, + ); + + final response = decode( + rawRes.data, + QueryUsersResponse.fromJson, + ); + + state?._updateUsers(response.users); + + return response; + } + + /// A message search. + Future search( + Map filters, + List sort, + String query, + PaginationParams paginationParams, { + Map messageFilters, + }) async { + final payload = { + 'filter_conditions': filters, + if (messageFilters != null) ...{ + 'message_filter_conditions': messageFilters, + }, + 'query': query, + 'sort': sort, + }; + + if (paginationParams != null) { + payload.addAll(paginationParams.toJson()); + } + + final response = await get('/search', + queryParameters: {'payload': json.encode(payload)}); + return decode( + response.data, SearchMessagesResponse.fromJson); + } + + /// Add a device for Push Notifications. + Future addDevice(String id, String pushProvider) async { + final response = await post('/devices', data: { + 'id': id, + 'push_provider': pushProvider, + }); + return decode(response.data, EmptyResponse.fromJson); + } + + /// Gets a list of user devices. + Future getDevices() async { + final response = await get('/devices'); + return decode( + response.data, ListDevicesResponse.fromJson); + } + + /// Remove a user's device. + Future removeDevice(String id) async { + final response = await delete('/devices', queryParameters: { + 'id': id, + }); + return decode(response.data, EmptyResponse.fromJson); + } + + /// Get a development token + String devToken(String userId) { + final payload = json.encode({'user_id': userId}); + final payloadBytes = utf8.encode(payload); + final payloadB64 = base64.encode(payloadBytes); + return 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.$payloadB64.devtoken'; + } + + /// Returns a channel client with the given type, id and custom data. + Channel channel( + String type, { + String id, + Map extraData, + }) { + if (type != null && + id != null && + state.channels?.containsKey('$type:$id') == true) { + return state.channels['$type:$id']; + } + + return Channel(this, type, id, extraData); + } + + /// Update or Create the given user object. + Future updateUser(User user) async { + return updateUsers([user]); + } + + /// Batch update a list of users + Future updateUsers(List users) async { + final response = await post('/users', data: { + 'users': users.asMap().map((_, u) => MapEntry(u.id, u.toJson())), + }); + return decode( + response.data, + UpdateUsersResponse.fromJson, + ); + } + + /// Bans a user from all channels + Future banUser( + String targetUserID, [ + Map options = const {}, + ]) async { + final data = Map.from(options) + ..addAll({ + 'target_user_id': targetUserID, + }); + final response = await post( + '/moderation/ban', + data: data, + ); + return decode(response.data, EmptyResponse.fromJson); + } + + /// Remove global ban for a user + Future unbanUser( + String targetUserID, [ + Map options = const {}, + ]) async { + final data = Map.from(options) + ..addAll({ + 'target_user_id': targetUserID, + }); + final response = await delete( + '/moderation/ban', + queryParameters: data, + ); + return decode(response.data, EmptyResponse.fromJson); + } + + /// Shadow bans a user + Future shadowBan( + String targetID, [ + Map options = const {}, + ]) async { + return banUser(targetID, { + 'shadow': true, + ...options, + }); + } + + /// Removes shadow ban from a user + Future removeShadowBan( + String targetID, [ + Map options = const {}, + ]) async { + return unbanUser(targetID, { + 'shadow': true, + ...options, + }); + } + + /// Mutes a user + Future muteUser(String targetID) async { + final response = await post('/moderation/mute', data: { + 'target_id': targetID, + }); + return decode(response.data, EmptyResponse.fromJson); + } + + /// Unmutes a user + Future unmuteUser(String targetID) async { + final response = await post('/moderation/unmute', data: { + 'target_id': targetID, + }); + return decode(response.data, EmptyResponse.fromJson); + } + + /// Flag a message + Future flagMessage(String messageID) async { + final response = await post('/moderation/flag', data: { + 'target_message_id': messageID, + }); + return decode(response.data, EmptyResponse.fromJson); + } + + /// Unflag a message + Future unflagMessage(String messageId) async { + final response = await post('/moderation/unflag', data: { + 'target_message_id': messageId, + }); + return decode(response.data, EmptyResponse.fromJson); + } + + /// Flag a user + Future flagUser(String userId) async { + final response = await post('/moderation/flag', data: { + 'target_user_id': userId, + }); + return decode(response.data, EmptyResponse.fromJson); + } + + /// Unflag a message + Future unflagUser(String userId) async { + final response = await post('/moderation/unflag', data: { + 'target_user_id': userId, + }); + return decode(response.data, EmptyResponse.fromJson); + } + + /// Mark all channels for this user as read + Future markAllRead() async { + final response = await post('/channels/read'); + return decode(response.data, EmptyResponse.fromJson); + } + + /// Update the given message + Future updateMessage( + Message message, [ + String cid, + ]) async { + message = message.copyWith( + status: MessageSendingStatus.UPDATING, + updatedAt: message.updatedAt ?? DateTime.now(), + ); + + final channel = state?.channels != null ? state?.channels[cid] : null; + channel?.state?.addMessage(message); + + return post('/messages/${message.id}', data: {'message': message}) + .then((res) { + final updateMessageResponse = decode( + res?.data, + UpdateMessageResponse.fromJson, + ); + + channel?.state?.addMessage(updateMessageResponse?.message?.copyWith( + ownReactions: message.ownReactions, + )); + + return updateMessageResponse; + }).catchError((error) { + if (error is DioError && + error.type != DioErrorType.RESPONSE && + state?.channels != null) { + channel?.state?.retryQueue?.add([message]); + } + throw error; + }); + } + + /// Deletes the given message + Future deleteMessage(Message message, [String cid]) async { + if (message.status == MessageSendingStatus.FAILED) { + state.channels[cid].state.addMessage(message.copyWith( + type: 'deleted', + status: MessageSendingStatus.SENT, + )); + return EmptyResponse(); + } + + try { + message = message.copyWith( + type: 'deleted', + status: MessageSendingStatus.DELETING, + deletedAt: message.deletedAt ?? DateTime.now(), + ); + + if (state?.channels != null) { + state.channels[cid]?.state?.addMessage(message); + } + + final response = await delete('/messages/${message.id}'); + + if (state?.channels != null) { + state.channels[cid]?.state + ?.addMessage(message.copyWith(status: MessageSendingStatus.SENT)); + } + + return decode(response.data, EmptyResponse.fromJson); + } catch (error) { + if (error is DioError && + error.type != DioErrorType.RESPONSE && + state?.channels != null) { + state.channels[cid]?.state?.retryQueue?.add([message]); + } + rethrow; + } + } + + /// Get a message by id + Future getMessage(String messageId) async { + final response = await get('/messages/$messageId'); + return decode(response.data, GetMessageResponse.fromJson); + } +} + +/// The class that handles the state of the channel listening to the events +class ClientState { + final _subscriptions = []; + + /// Creates a new instance listening to events and updating the state + ClientState(this._client) { + _subscriptions.addAll([ + _client + .on() + .where((event) => event.me != null) + .map((e) => e.me) + .listen((user) { + _userController.add(user); + if (user.totalUnreadCount != null) { + _totalUnreadCountController.add(user.totalUnreadCount); + } + + if (user.unreadChannels != null) { + _unreadChannelsController.add(user.unreadChannels); + } + }), + _client + .on() + .where((event) => event.unreadChannels != null) + .map((e) => e.unreadChannels) + .listen((unreadChannels) { + _unreadChannelsController.add(unreadChannels); + }), + _client + .on() + .where((event) => event.totalUnreadCount != null) + .map((e) => e.totalUnreadCount) + .listen((totalUnreadCount) { + _totalUnreadCountController.add(totalUnreadCount); + }), + ]); + + _listenChannelDeleted(); + + _listenChannelHidden(); + + _listenUserUpdated(); + } + + void _listenChannelHidden() { + _subscriptions.add(_client.on(EventType.channelHidden).listen((event) { + _client._offlineStorage?.deleteChannels([event.cid]); + if (channels != null) { + channels = channels..removeWhere((cid, ch) => cid == event.cid); + } + })); + } + + void _listenUserUpdated() { + _subscriptions.add(_client.on(EventType.userUpdated).listen((event) { + if (event.user.id == user.id) { + user = OwnUser.fromJson(event.user.toJson()); + } + _updateUser(event.user); + })); + } + + void _listenChannelDeleted() { + _subscriptions.add(_client + .on( + EventType.channelDeleted, + EventType.notificationRemovedFromChannel, + EventType.notificationChannelDeleted, + ) + .listen((Event event) async { + final eventChannel = event.channel; + await _client._offlineStorage?.deleteChannels([eventChannel.cid]); + if (channels != null) { + channels = channels..remove(eventChannel.cid); + } + })); + } + + final Client _client; + + /// Update user information + set user(OwnUser user) { + _userController.add(user); + } + + void _updateUsers(List users) { + users?.forEach(_updateUser); + } + + void _updateUser(User user) { + final newUsers = { + ...users ?? {}, + user.id: user, + }; + _usersController.add(newUsers); + } + + /// The current user + OwnUser get user => _userController.value; + + /// The current user as a stream + Stream get userStream => _userController.stream; + + /// The current user + Map get users => _usersController.value; + + /// The current user as a stream + Stream> get usersStream => _usersController.stream; + + /// The current unread channels count + int get unreadChannels => _unreadChannelsController.value; + + /// The current unread channels count as a stream + Stream get unreadChannelsStream => _unreadChannelsController.stream; + + /// The current total unread messages count + int get totalUnreadCount => _totalUnreadCountController.value; + + /// The current total unread messages count as a stream + Stream get totalUnreadCountStream => _totalUnreadCountController.stream; + + /// The current list of channels in memory as a stream + Stream> get channelsStream => _channelsController.stream; + + /// The current list of channels in memory + Map get channels => _channelsController.value; + + set channels(Map v) { + _channelsController.add(v); + } + + final BehaviorSubject> _channelsController = + BehaviorSubject.seeded({}); + final BehaviorSubject _userController = BehaviorSubject(); + final BehaviorSubject> _usersController = + BehaviorSubject.seeded({}); + final BehaviorSubject _unreadChannelsController = BehaviorSubject(); + final BehaviorSubject _totalUnreadCountController = BehaviorSubject(); + + /// Call this method to dispose this object + void dispose() { + _subscriptions.forEach((s) => s.cancel()); + _userController.close(); + _unreadChannelsController.close(); + _totalUnreadCountController.close(); + channels.values.forEach((c) => c.dispose()); + _channelsController.close(); + } +} diff --git a/packages/dart_client/lib/src/db/models.part.dart b/packages/dart_client/lib/src/db/models.part.dart new file mode 100644 index 00000000..98fced53 --- /dev/null +++ b/packages/dart_client/lib/src/db/models.part.dart @@ -0,0 +1,258 @@ +part of 'offline_storage.dart'; + +@DataClassName('ChannelQuery') +class _ChannelQueries extends Table { + TextColumn get queryHash => text()(); + + TextColumn get channelCid => text()(); + + @override + Set get primaryKey => { + queryHash, + channelCid, + }; +} + +class _Channels extends Table { + TextColumn get id => text()(); + + TextColumn get type => text()(); + + TextColumn get cid => text()(); + + TextColumn get config => text()(); + + BoolColumn get frozen => boolean().withDefault(Constant(false))(); + + DateTimeColumn get lastMessageAt => dateTime().nullable()(); + + DateTimeColumn get createdAt => dateTime().nullable()(); + + DateTimeColumn get updatedAt => dateTime().nullable()(); + + DateTimeColumn get deletedAt => dateTime().nullable()(); + + IntColumn get memberCount => integer().nullable()(); + + TextColumn get extraData => text().nullable().map(_ExtraDataConverter())(); + + TextColumn get createdBy => text().nullable()(); + + @override + Set get primaryKey => {cid}; +} + +class _ConnectionEvent extends Table { + IntColumn get id => integer()(); + + TextColumn get ownUser => text().nullable().map(_ExtraDataConverter())(); + + IntColumn get totalUnreadCount => integer().nullable()(); + + IntColumn get unreadChannels => integer().nullable()(); + + DateTimeColumn get lastEventAt => dateTime().nullable()(); + + DateTimeColumn get lastSyncAt => dateTime().nullable()(); + + @override + Set get primaryKey => {id}; +} + +class _Users extends Table { + TextColumn get id => text()(); + + TextColumn get role => text().nullable()(); + + DateTimeColumn get createdAt => dateTime().nullable()(); + + DateTimeColumn get updatedAt => dateTime().nullable()(); + + DateTimeColumn get lastActive => dateTime().nullable()(); + + BoolColumn get online => boolean().nullable()(); + + BoolColumn get banned => boolean().nullable()(); + + TextColumn get extraData => text().nullable().map(_ExtraDataConverter())(); + + @override + Set get primaryKey => {id}; +} + +class _Reads extends Table { + DateTimeColumn get lastRead => dateTime()(); + + TextColumn get userId => text()(); + + TextColumn get channelCid => text()(); + + IntColumn get unreadMessages => integer().nullable()(); + + @override + Set get primaryKey => { + userId, + channelCid, + }; +} + +class _Reactions extends Table { + TextColumn get messageId => text()(); + + TextColumn get type => text()(); + + DateTimeColumn get createdAt => dateTime()(); + + IntColumn get score => integer().nullable()(); + + TextColumn get userId => text()(); + + TextColumn get extraData => text().nullable().map(_ExtraDataConverter())(); + + @override + Set get primaryKey => { + messageId, + type, + userId, + }; +} + +class _Messages extends Table { + TextColumn get id => text()(); + + TextColumn get messageText => text().nullable()(); + + TextColumn get attachmentJson => text().nullable()(); + + IntColumn get status => + integer().map(_MessageSendingStatusConverter()).nullable()(); + + TextColumn get type => text().nullable()(); + + List mentionedUsers; + + TextColumn get reactionCounts => + text().nullable().map(_ExtraDataConverter())(); + + TextColumn get reactionScores => + text().nullable().map(_ExtraDataConverter())(); + + TextColumn get parentId => text().nullable()(); + + TextColumn get quotedMessageId => text().nullable()(); + + IntColumn get replyCount => integer().nullable()(); + + BoolColumn get showInChannel => boolean().nullable()(); + + BoolColumn get shadowed => boolean().nullable()(); + + TextColumn get command => text().nullable()(); + + DateTimeColumn get createdAt => dateTime()(); + + DateTimeColumn get updatedAt => dateTime().nullable()(); + + DateTimeColumn get deletedAt => dateTime().nullable()(); + + TextColumn get userId => text().nullable()(); + + TextColumn get channelCid => text().nullable()(); + + TextColumn get extraData => text().nullable().map(_ExtraDataConverter())(); + + @override + Set get primaryKey => {id}; +} + +class _Members extends Table { + TextColumn get userId => text()(); + + TextColumn get channelCid => text()(); + + TextColumn get role => text().nullable()(); + + DateTimeColumn get inviteAcceptedAt => dateTime().nullable()(); + + DateTimeColumn get inviteRejectedAt => dateTime().nullable()(); + + BoolColumn get invited => boolean().nullable()(); + + BoolColumn get banned => boolean().nullable()(); + + BoolColumn get shadowBanned => boolean().nullable()(); + + BoolColumn get isModerator => boolean().nullable()(); + + DateTimeColumn get createdAt => dateTime()(); + + DateTimeColumn get updatedAt => dateTime().nullable()(); + + @override + Set get primaryKey => { + userId, + channelCid, + }; +} + +class _ExtraDataConverter extends TypeConverter, String> { + @override + Map mapToDart(fromDb) { + if (fromDb == null) { + return null; + } + return Map.from(jsonDecode(fromDb) ?? {}); + } + + @override + String mapToSql(value) { + return jsonEncode(value); + } +} + +class _MessageSendingStatusConverter + extends TypeConverter { + @override + MessageSendingStatus mapToDart(int fromDb) { + switch (fromDb) { + case 0: + return MessageSendingStatus.SENDING; + case 1: + return MessageSendingStatus.SENT; + case 2: + return MessageSendingStatus.FAILED; + case 3: + return MessageSendingStatus.UPDATING; + case 4: + return MessageSendingStatus.FAILED_UPDATE; + case 5: + return MessageSendingStatus.DELETING; + case 6: + return MessageSendingStatus.FAILED_DELETE; + default: + return null; + } + } + + @override + int mapToSql(MessageSendingStatus value) { + switch (value) { + case MessageSendingStatus.SENDING: + return 0; + case MessageSendingStatus.SENT: + return 1; + case MessageSendingStatus.FAILED: + return 2; + case MessageSendingStatus.UPDATING: + return 3; + case MessageSendingStatus.FAILED_UPDATE: + return 4; + case MessageSendingStatus.DELETING: + return 5; + case MessageSendingStatus.FAILED_DELETE: + return 6; + default: + return null; + } + } +} diff --git a/packages/dart_client/lib/src/db/offline_storage.dart b/packages/dart_client/lib/src/db/offline_storage.dart new file mode 100644 index 00000000..b132ae02 --- /dev/null +++ b/packages/dart_client/lib/src/db/offline_storage.dart @@ -0,0 +1,841 @@ +import 'dart:convert'; + +import 'package:flutter/material.dart' show WidgetsFlutterBinding; +import 'package:logging/logging.dart'; +import 'package:moor/isolate.dart'; +import 'package:moor/moor.dart'; +import 'package:stream_chat/src/db/shared/shared_db.dart'; +import 'package:stream_chat/src/models/event.dart'; +import 'package:stream_chat/src/models/own_user.dart'; + +import '../api/requests.dart'; +import '../models/attachment.dart'; +import '../models/channel_config.dart'; +import '../models/channel_model.dart'; +import '../models/channel_state.dart'; +import '../models/member.dart'; +import '../models/message.dart'; +import '../models/reaction.dart'; +import '../models/read.dart'; +import '../models/user.dart'; + +part 'models.part.dart'; + +part 'offline_storage.g.dart'; + +/// Gets a new instance of the database running on a background isolate +Future connectDatabase(User user, Logger logger) async { + logger.info('Connecting on background isolate'); + WidgetsFlutterBinding.ensureInitialized(); + return SharedDB.constructOfflineStorage( + userId: user.id, + logger: logger, + ); +} + +LazyDatabase _openConnection(String userId) { + moorRuntimeOptions.dontWarnAboutMultipleDatabases = true; + return LazyDatabase(() async { + return await SharedDB.constructDatabase('db_$userId.sqlite'); + }); +} + +/// Offline database used for caching channel queries and state +@UseMoor(tables: [ + _ConnectionEvent, + _Channels, + _Users, + _Messages, + _Reads, + _Members, + _ChannelQueries, + _Reactions, +]) +class OfflineStorage extends _$OfflineStorage { + /// Creates a new database instance + OfflineStorage.connect( + DatabaseConnection connection, + this._userId, + this._isolate, + this._logger, + ) : super.connect(connection); + + /// Instantiate a new OfflineStorage + OfflineStorage( + this._userId, + this._logger, + ) : _isolate = null, + super(_openConnection(_userId)) { + _logger.info('Connecting on standard isolate'); + } + + final String _userId; + final MoorIsolate _isolate; + final Logger _logger; + + // you should bump this number whenever you change or add a table definition. Migrations + // are covered later in this readme. + @override + int get schemaVersion => 8; + + @override + MigrationStrategy get migration => MigrationStrategy( + onUpgrade: (openingDetails, before, after) async { + if (before != after) { + final m = createMigrator(); + for (final table in allTables) { + await m.deleteTable(table.actualTableName); + await m.createTable(table); + } + } + }, + ); + + /// Closes the database instance + /// If [flush] is true, the database data will be deleted + Future disconnect({bool flush = false}) async { + _logger.info('Disconnecting'); + if (flush) { + _logger.info('Flushing'); + await batch((batch) { + allTables.forEach((table) { + delete(table).go(); + }); + }); + } + + await _isolate?.shutdownAll(); + + await close(); + } + + /// Get stored replies by messageId + Future> getReplies( + String parentId, { + String lessThan, + }) async { + final offlineList = await Future.wait(await (select(messages).join([ + innerJoin(users, messages.userId.equalsExp(users.id)), + ]) + ..where(messages.parentId.equals(parentId)) + ..orderBy([ + OrderingTerm.asc(messages.createdAt), + ])) + .map(_messageFromJoinRow) + .get()); + if (lessThan != null) { + final lessThanIndex = offlineList.indexWhere((m) => m.id == lessThan); + offlineList.removeRange(lessThanIndex, offlineList.length); + } + + return offlineList; + } + + /// Get stored connection event + Future getConnectionInfo() async { + return select(connectionEvent).map((row) { + return Event( + me: row.ownUser != null ? OwnUser.fromJson(row.ownUser) : null, + totalUnreadCount: row.totalUnreadCount, + unreadChannels: row.unreadChannels, + ); + }).getSingle(); + } + + /// Get stored lastSyncAt + Future getLastSyncAt() async { + return select(connectionEvent).getSingle().then((r) => r?.lastSyncAt); + } + + /// Update stored connection event + Future updateConnectionInfo(Event event) async { + final connectionInfo = await select(connectionEvent).getSingle(); + + return into(connectionEvent).insert( + _ConnectionEventData( + id: 1, + lastSyncAt: connectionInfo?.lastSyncAt, + lastEventAt: event.createdAt ?? connectionInfo?.lastEventAt, + totalUnreadCount: + event.totalUnreadCount ?? connectionInfo?.totalUnreadCount, + ownUser: event.me?.toJson() ?? connectionInfo?.ownUser, + unreadChannels: event.unreadChannels ?? connectionInfo?.unreadChannels, + ), + mode: InsertMode.insertOrReplace, + ); + } + + /// Update stored lastSyncAt + Future updateLastSyncAt(DateTime lastSyncAt) async { + return await (update(connectionEvent)..where((r) => r.id.equals(1))).write( + _ConnectionEventCompanion( + id: Value(1), + lastSyncAt: Value(lastSyncAt), + ), + ); + } + + /// Get the channel cids saved in the offline storage + Future> getChannelCids() async { + return (select(channels) + ..orderBy([(c) => OrderingTerm.desc(c.lastMessageAt)]) + ..limit(250)) + .map((c) => c.cid) + .get(); + } + + /// Get channel data by cid + Future getChannel( + String cid, { + int limit, + String messageLessThan, + String messageGreaterThan, + }) async { + return await (select(channels)..where((c) => c.cid.equals(cid))).join([ + leftOuterJoin(users, channels.createdBy.equalsExp(users.id)), + ]).map((row) { + return _channelFromRow( + row.readTable(channels), + row.readTable(users), + limit: limit, + messageLessThan: messageLessThan, + messageGreaterThan: messageGreaterThan, + ); + }).getSingle(); + } + + /// Get list of channels by filter, sort and paginationParams + Future> getChannelStates({ + Map filter, + List sort = const [], + PaginationParams paginationParams, + }) async { + _logger.info('Get channel states'); + final hash = _computeHash(filter); + final cachedChannels = await Future.wait(await (select(channelQueries) + ..where((c) => c.queryHash.equals(hash))) + .get() + .then((channelQueries) { + final cids = channelQueries.map((c) => c.channelCid).toList(); + final query = select(channels)..where((c) => c.cid.isIn(cids)); + + sort = sort + ?.where((s) => ChannelModel.topLevelFields.contains(s.field)) + ?.toList(); + + if (sort != null && sort.isNotEmpty) { + query.orderBy(sort.map((s) { + final orderExpression = CustomExpression('channels.${s.field}'); + return (c) => OrderingTerm( + expression: orderExpression, + mode: s.direction == 1 ? OrderingMode.asc : OrderingMode.desc, + ); + }).toList()); + } + + if (paginationParams != null) { + query.limit( + paginationParams.limit ?? 10, + offset: paginationParams.offset, + ); + } + + return query.join([ + leftOuterJoin(users, channels.createdBy.equalsExp(users.id)), + ]).map((row) async { + final userRow = row.readTable(users); + final channelRow = row.readTable(channels); + + return _channelFromRow(channelRow, userRow); + }).get(); + })); + + _logger.info('Got ${cachedChannels.length} channels'); + + if (sort?.isEmpty != false && cachedChannels?.isNotEmpty == true) { + cachedChannels + .sort((a, b) => b.channel.updatedAt.compareTo(a.channel.updatedAt)); + cachedChannels.sort((a, b) { + final dateA = a.channel.lastMessageAt ?? a.channel.createdAt; + final dateB = b.channel.lastMessageAt ?? b.channel.createdAt; + return dateB.compareTo(dateA); + }); + } + + return cachedChannels; + } + + /// Update list of channel queries + /// If [clearQueryCache] is true before the insert + /// the list of matching rows will be deleted + Future updateChannelQueries( + Map filter, + List cids, + bool clearQueryCache, + ) async { + final hash = _computeHash(filter); + if (clearQueryCache) { + await (delete(channelQueries) + ..where( + (_ChannelQueries query) => query.queryHash.equals(hash), + )) + .go(); + } + + return batch((batch) { + batch.insertAll( + channelQueries, + cids.map((cid) { + return ChannelQuery( + queryHash: hash, + channelCid: cid, + ); + }).toList(), + mode: InsertMode.insertOrReplace, + ); + }); + } + + /// Remove a message by message id + Future deleteMessages(List messageIds) { + return batch((batch) { + batch.deleteWhere<_Reactions, _Reaction>( + reactions, + (r) => r.messageId.isIn(messageIds), + ); + batch.deleteWhere<_Messages, _Message>( + messages, + (m) => m.id.isIn(messageIds), + ); + }); + } + + /// Remove a message by message id + Future deleteChannelsMessages(List cids) async { + final messageIds = await (select(messages) + ..where((m) => m.channelCid.isIn(cids))) + .map((m) => m.id) + .get(); + return batch((batch) { + batch.deleteWhere<_Reactions, _Reaction>( + reactions, + (r) => r.messageId.isIn(messageIds), + ); + batch.deleteWhere<_Messages, _Message>( + messages, + (m) => m.id.isIn(messageIds), + ); + }); + } + + /// Remove a channel by cid + Future deleteChannels(List cids) async { + await deleteChannelsMessages(cids); + return batch((batch) { + batch.deleteWhere<_Members, _Member>( + members, + (m) => m.channelCid.isIn(cids), + ); + batch.deleteWhere<_Reads, _Read>( + reads, + (r) => r.channelCid.isIn(cids), + ); + batch.deleteWhere<_Channels, _Channel>( + channels, + (c) => c.cid.isIn(cids), + ); + }); + } + + /// Update messages data from a list + Future updateMessages( + List newMessages, + String cid, + ) { + return batch((batch) { + batch.insertAll( + messages, + newMessages.map( + (m) { + return _Message( + id: m.id, + attachmentJson: m.attachments != null + ? jsonEncode(m.attachments.map((a) => a.toJson()).toList()) + : null, + channelCid: cid, + type: m.type, + parentId: m.parentId, + quotedMessageId: m.quotedMessageId, + command: m.command, + createdAt: m.createdAt, + shadowed: m.shadowed, + showInChannel: m.showInChannel, + replyCount: m.replyCount, + reactionScores: m.reactionScores, + reactionCounts: m.reactionCounts, + status: m.status, + updatedAt: m.updatedAt, + extraData: m.extraData, + userId: m.user.id, + deletedAt: m.deletedAt, + messageText: m.text, + ); + }, + ).toList(), + mode: InsertMode.insertOrReplace, + ); + }); + } + + /// Update single channel state + Future updateChannelState(ChannelState channelState) async { + await updateChannelStates([channelState]); + } + + /// Update list of channel states + Future updateChannelStates(List channelStates) async { + channelStates.forEach((cs) { + updateMessages( + cs.messages, + cs.channel.cid, + ); + }); + + await batch((batch) { + _updateReactions(batch, channelStates); + + _updateUsers(batch, channelStates); + + _updateReads(channelStates, batch); + + _updateMembers(channelStates, batch); + + _updateChannels(batch, channelStates); + }); + } + + /// Get the info about channel threads + Future>> getChannelThreads(String cid) async { + final rowMessages = await Future.wait(await (select(messages).join([ + leftOuterJoin(users, messages.userId.equalsExp(users.id)), + ]) + ..where(messages.channelCid.equals(cid)) + ..where(isNotNull(messages.parentId)) + ..orderBy([ + OrderingTerm.asc(messages.createdAt), + ])) + .map(_messageFromJoinRow) + .get()); + + final threads = >{}; + rowMessages.forEach((message) { + if (threads.containsKey(message.parentId)) { + threads[message.parentId].add(message); + } else { + threads[message.parentId] = [message]; + } + }); + + return threads; + } + + Future _channelFromRow( + _Channel channelRow, + _User userRow, { + int limit, + String messageLessThan, + String messageGreaterThan, + }) async { + final rowMessages = await _getChannelMessages( + channelRow, + limit: limit, + lessThan: messageLessThan, + greaterThan: messageGreaterThan, + ); + final rowReads = await _getChannelReads(channelRow); + final rowMembers = await _getChannelMembers(channelRow); + + return ChannelState( + members: rowMembers, + read: rowReads, + messages: rowMessages, + channel: ChannelModel( + id: channelRow.id, + type: channelRow.type, + frozen: channelRow.frozen, + createdAt: channelRow.createdAt, + updatedAt: channelRow.updatedAt, + memberCount: channelRow.memberCount, + cid: channelRow.cid, + lastMessageAt: channelRow.lastMessageAt, + deletedAt: channelRow.deletedAt, + extraData: channelRow.extraData, + config: ChannelConfig.fromJson(jsonDecode(channelRow.config)), + createdBy: userRow != null ? _userFromUserRow(userRow) : null, + ), + ); + } + + String _computeHash(Map filter) { + if (filter == null) { + return 'allchannels'; + } + final hash = base64Encode(utf8.encode('filter: ${jsonEncode(filter)}')); + return hash; + } + + Future _getMessageById(String id) async { + if (id == null || id.isEmpty) return null; + final message = await Future.wait(await (select(messages).join([ + leftOuterJoin(users, messages.userId.equalsExp(users.id)), + ]) + ..where(messages.id.equals(id))) + .map(_messageFromJoinRow) + .get()); + return message.first; + } + + Future> _getChannelMessages( + _Channel channelRow, { + int limit, + String lessThan, + String greaterThan, + }) async { + final rowMessages = await Future.wait(await (select(messages).join([ + leftOuterJoin(users, messages.userId.equalsExp(users.id)), + ]) + ..where(messages.channelCid.equals(channelRow.cid)) + ..where( + isNull(messages.parentId) | messages.showInChannel.equals(true)) + ..orderBy([ + OrderingTerm.asc(messages.createdAt), + ])) + .map(_messageFromJoinRow) + .get()); + + if (lessThan != null) { + final lessThanIndex = rowMessages.indexWhere((m) => m.id == lessThan); + if (lessThanIndex != -1) { + rowMessages.removeRange(lessThanIndex, rowMessages.length); + } + } + if (greaterThan != null) { + final greaterThanIndex = + rowMessages.indexWhere((m) => m.id == greaterThan); + if (greaterThanIndex != -1) { + rowMessages.removeRange(0, greaterThanIndex); + } + } + if (limit != null) { + return rowMessages.take(limit).toList(); + } + return rowMessages; + } + + Future _messageFromJoinRow(row) async { + final messageRow = row.readTable(messages); + final userRow = row.readTable(users); + + final latestReactions = await _getLatestReactions(messageRow); + final ownReactions = await _getOwnReactions(messageRow); + final quotedMessage = await _getMessageById(messageRow.quotedMessageId); + + return Message( + shadowed: messageRow.shadowed, + latestReactions: latestReactions, + ownReactions: ownReactions, + attachments: messageRow.attachmentJson != null + ? List>.from( + jsonDecode(messageRow.attachmentJson)) + .map((j) => Attachment.fromJson(j)) + .toList() + : null, + createdAt: messageRow.createdAt, + extraData: messageRow.extraData, + updatedAt: messageRow.updatedAt, + id: messageRow.id, + type: messageRow.type, + status: messageRow.status, + command: messageRow.command, + parentId: messageRow.parentId, + quotedMessageId: messageRow.quotedMessageId, + quotedMessage: quotedMessage, + reactionCounts: messageRow.reactionCounts, + reactionScores: messageRow.reactionScores, + replyCount: messageRow.replyCount, + showInChannel: messageRow.showInChannel, + text: messageRow.messageText, + user: _userFromUserRow(userRow), + deletedAt: messageRow.deletedAt, + ); + } + + Future> _getLatestReactions(_Message messageRow) async { + return await (select(reactions).join([ + leftOuterJoin(users, reactions.userId.equalsExp(users.id)), + ]) + ..where(reactions.messageId.equals(messageRow.id)) + ..orderBy([OrderingTerm.asc(reactions.createdAt)])) + .map((row) { + final r = row.readTable(reactions); + final u = row.readTable(users); + return _reactionFromRow(r, u); + }).get(); + } + + Reaction _reactionFromRow(_Reaction r, _User u) { + return Reaction( + extraData: r.extraData, + type: r.type, + createdAt: r.createdAt, + userId: r.userId, + user: _userFromUserRow(u), + messageId: r.messageId, + score: r.score, + ); + } + + Future> _getOwnReactions(_Message messageRow) async { + return await (select(reactions).join([ + leftOuterJoin(users, reactions.userId.equalsExp(users.id)), + ]) + ..where(reactions.userId.equals(_userId)) + ..where(reactions.messageId.equals(messageRow.id)) + ..orderBy([OrderingTerm.asc(reactions.createdAt)])) + .map((row) { + final r = row.readTable(reactions); + final u = row.readTable(users); + return _reactionFromRow(r, u); + }).get(); + } + + Future> _getChannelReads(_Channel channelRow) async { + final rowReads = await (select(reads).join([ + leftOuterJoin(users, reads.userId.equalsExp(users.id)), + ]) + ..where(reads.channelCid.equals(channelRow.cid)) + ..orderBy([ + OrderingTerm.asc(reads.lastRead), + ])) + .map((row) { + final userRow = row.readTable(users); + final readRow = row.readTable(reads); + return Read( + user: _userFromUserRow(userRow), + lastRead: readRow.lastRead, + unreadMessages: readRow.unreadMessages, + ); + }).get(); + return rowReads; + } + + Future> _getChannelMembers(_Channel channelRow) async { + final rowMembers = await (select(members).join([ + leftOuterJoin(users, members.userId.equalsExp(users.id)), + ]) + ..where(members.channelCid.equals(channelRow.cid)) + ..orderBy([ + OrderingTerm.asc(members.createdAt), + ])) + .map((row) { + final userRow = row.readTable(users); + final memberRow = row.readTable(members); + return Member( + user: _userFromUserRow(userRow), + userId: userRow.id, + banned: memberRow.banned, + shadowBanned: memberRow.shadowBanned, + updatedAt: memberRow.updatedAt, + createdAt: memberRow.createdAt, + role: memberRow.role, + inviteAcceptedAt: memberRow.inviteAcceptedAt, + invited: memberRow.invited, + inviteRejectedAt: memberRow.inviteRejectedAt, + isModerator: memberRow.isModerator, + ); + }).get(); + return rowMembers; + } + + User _userFromUserRow(_User userRow) { + return User( + updatedAt: userRow.updatedAt, + role: userRow.role, + online: userRow.online, + lastActive: userRow.lastActive, + extraData: userRow.extraData, + banned: userRow.banned, + createdAt: userRow.createdAt, + id: userRow.id, + ); + } + + void _updateChannels(Batch batch, List channelStates) { + batch.insertAll( + channels, + channelStates.map((cs) { + final channel = cs.channel; + return _channelDataFromChannelModel(channel); + }).toList(), + mode: InsertMode.insertOrReplace, + ); + } + + void _updateMembers(List channelStates, Batch batch) async { + await (delete(members) + ..where((tbl) => + tbl.channelCid.isIn(channelStates.map((e) => e.channel.cid)))) + .go(); + final newMembers = channelStates + .map((cs) => cs.members.map((m) => _Member( + userId: m.user.id, + banned: m.banned, + shadowBanned: m.shadowBanned, + channelCid: cs.channel.cid, + createdAt: m.createdAt, + isModerator: m.isModerator, + inviteRejectedAt: m.inviteRejectedAt, + invited: m.invited, + inviteAcceptedAt: m.inviteAcceptedAt, + role: m.role, + updatedAt: m.updatedAt, + ))) + .where((v) => v != null) + .expand((v) => v); + if (newMembers != null && newMembers.isNotEmpty) { + batch.insertAll( + members, + newMembers.toList(), + mode: InsertMode.insertOrReplace, + ); + } + } + + void _updateReads(List channelStates, Batch batch) { + final newReads = channelStates + .map((cs) => cs.read?.map((r) => _Read( + lastRead: r.lastRead, + userId: r.user.id, + channelCid: cs.channel.cid, + unreadMessages: r.unreadMessages, + ))) + .where((v) => v != null) + .expand((v) => v); + + if (newReads != null && newReads.isNotEmpty) { + batch.insertAll( + reads, + newReads.toList(), + mode: InsertMode.insertOrReplace, + ); + } + } + + void _updateUsers(Batch batch, List channelStates) { + batch.insertAll( + users, + channelStates + .map((cs) => [ + if (cs.channel.createdBy != null) + _userDataFromUser(cs.channel.createdBy), + if (cs.messages != null) + ...cs.messages + .map((m) => [ + _userDataFromUser(m.user), + if (m.latestReactions != null) + ...m.latestReactions + .where((r) => r.user != null) + .map((r) => _userDataFromUser(r.user)), + if (m.ownReactions != null) + ...m.ownReactions + .where((r) => r.user != null) + .map((r) => _userDataFromUser(r.user)), + ]) + .expand((v) => v), + if (cs.read != null) + ...cs.read.map((r) => _userDataFromUser(r.user)), + if (cs.members != null) + ...cs.members.map((m) => _userDataFromUser(m.user)), + ]) + .expand((v) => v) + .toList(), + mode: InsertMode.insertOrReplace, + ); + } + + void _updateReactions(Batch batch, List channelStates) { + batch.deleteWhere<_Reactions, _Reaction>( + reactions, + (r) => r.messageId.isIn(channelStates + .map((cs) => cs.messages.map((m) => m.id)) + .expand((v) => v)), + ); + final newReactions = channelStates + .map((cs) => cs.messages.map((m) { + final ownReactions = + m.ownReactions?.where((e) => e.userId != null)?.map( + (r) => _reactionDataFromReaction(m, r), + ) ?? + []; + final latestReactions = + m.latestReactions?.where((e) => e.userId != null)?.map( + (r) => _reactionDataFromReaction(m, r), + ) ?? + []; + return [ + ...ownReactions, + ...latestReactions, + ]; + }).expand((v) => v)) + .expand((v) => v); + + if (newReactions.isNotEmpty) { + batch.insertAll( + reactions, + newReactions.toList(), + mode: InsertMode.insertOrReplace, + ); + } + } + + _Reaction _reactionDataFromReaction(Message m, Reaction r) { + return _Reaction( + messageId: m.id, + type: r.type, + extraData: r.extraData, + score: r.score, + createdAt: r.createdAt, + userId: r.userId, + ); + } + + _User _userDataFromUser(User user) { + return _User( + id: user.id, + createdAt: user.createdAt, + banned: user.banned, + extraData: user.extraData, + lastActive: user.lastActive, + online: user.online, + role: user.role, + updatedAt: user.updatedAt, + ); + } + + _Channel _channelDataFromChannelModel(ChannelModel channel) { + return _Channel( + id: channel.id, + config: jsonEncode(channel.config?.toJson() ?? {}), + type: channel.type, + frozen: channel.frozen, + createdAt: channel.createdAt, + updatedAt: channel.updatedAt, + memberCount: channel.memberCount, + cid: channel.cid, + lastMessageAt: channel.lastMessageAt, + deletedAt: channel.deletedAt, + extraData: channel.extraData, + createdBy: channel.createdBy?.id, + ); + } +} diff --git a/packages/dart_client/lib/src/db/offline_storage.g.dart b/packages/dart_client/lib/src/db/offline_storage.g.dart new file mode 100644 index 00000000..a87ecb92 --- /dev/null +++ b/packages/dart_client/lib/src/db/offline_storage.g.dart @@ -0,0 +1,4160 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'offline_storage.dart'; + +// ************************************************************************** +// MoorGenerator +// ************************************************************************** + +// ignore_for_file: unnecessary_brace_in_string_interps, unnecessary_this +class _ConnectionEventData extends DataClass + implements Insertable<_ConnectionEventData> { + final int id; + final Map ownUser; + final int totalUnreadCount; + final int unreadChannels; + final DateTime lastEventAt; + final DateTime lastSyncAt; + _ConnectionEventData( + {@required this.id, + this.ownUser, + this.totalUnreadCount, + this.unreadChannels, + this.lastEventAt, + this.lastSyncAt}); + factory _ConnectionEventData.fromData( + Map data, GeneratedDatabase db, + {String prefix}) { + final effectivePrefix = prefix ?? ''; + final intType = db.typeSystem.forDartType(); + final stringType = db.typeSystem.forDartType(); + final dateTimeType = db.typeSystem.forDartType(); + return _ConnectionEventData( + id: intType.mapFromDatabaseResponse(data['${effectivePrefix}id']), + ownUser: $_ConnectionEventTable.$converter0.mapToDart(stringType + .mapFromDatabaseResponse(data['${effectivePrefix}own_user'])), + totalUnreadCount: intType.mapFromDatabaseResponse( + data['${effectivePrefix}total_unread_count']), + unreadChannels: intType + .mapFromDatabaseResponse(data['${effectivePrefix}unread_channels']), + lastEventAt: dateTimeType + .mapFromDatabaseResponse(data['${effectivePrefix}last_event_at']), + lastSyncAt: dateTimeType + .mapFromDatabaseResponse(data['${effectivePrefix}last_sync_at']), + ); + } + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (!nullToAbsent || id != null) { + map['id'] = Variable(id); + } + if (!nullToAbsent || ownUser != null) { + final converter = $_ConnectionEventTable.$converter0; + map['own_user'] = Variable(converter.mapToSql(ownUser)); + } + if (!nullToAbsent || totalUnreadCount != null) { + map['total_unread_count'] = Variable(totalUnreadCount); + } + if (!nullToAbsent || unreadChannels != null) { + map['unread_channels'] = Variable(unreadChannels); + } + if (!nullToAbsent || lastEventAt != null) { + map['last_event_at'] = Variable(lastEventAt); + } + if (!nullToAbsent || lastSyncAt != null) { + map['last_sync_at'] = Variable(lastSyncAt); + } + return map; + } + + _ConnectionEventCompanion toCompanion(bool nullToAbsent) { + return _ConnectionEventCompanion( + id: id == null && nullToAbsent ? const Value.absent() : Value(id), + ownUser: ownUser == null && nullToAbsent + ? const Value.absent() + : Value(ownUser), + totalUnreadCount: totalUnreadCount == null && nullToAbsent + ? const Value.absent() + : Value(totalUnreadCount), + unreadChannels: unreadChannels == null && nullToAbsent + ? const Value.absent() + : Value(unreadChannels), + lastEventAt: lastEventAt == null && nullToAbsent + ? const Value.absent() + : Value(lastEventAt), + lastSyncAt: lastSyncAt == null && nullToAbsent + ? const Value.absent() + : Value(lastSyncAt), + ); + } + + factory _ConnectionEventData.fromJson(Map json, + {ValueSerializer serializer}) { + serializer ??= moorRuntimeOptions.defaultSerializer; + return _ConnectionEventData( + id: serializer.fromJson(json['id']), + ownUser: serializer.fromJson>(json['ownUser']), + totalUnreadCount: serializer.fromJson(json['totalUnreadCount']), + unreadChannels: serializer.fromJson(json['unreadChannels']), + lastEventAt: serializer.fromJson(json['lastEventAt']), + lastSyncAt: serializer.fromJson(json['lastSyncAt']), + ); + } + @override + Map toJson({ValueSerializer serializer}) { + serializer ??= moorRuntimeOptions.defaultSerializer; + return { + 'id': serializer.toJson(id), + 'ownUser': serializer.toJson>(ownUser), + 'totalUnreadCount': serializer.toJson(totalUnreadCount), + 'unreadChannels': serializer.toJson(unreadChannels), + 'lastEventAt': serializer.toJson(lastEventAt), + 'lastSyncAt': serializer.toJson(lastSyncAt), + }; + } + + _ConnectionEventData copyWith( + {int id, + Map ownUser, + int totalUnreadCount, + int unreadChannels, + DateTime lastEventAt, + DateTime lastSyncAt}) => + _ConnectionEventData( + id: id ?? this.id, + ownUser: ownUser ?? this.ownUser, + totalUnreadCount: totalUnreadCount ?? this.totalUnreadCount, + unreadChannels: unreadChannels ?? this.unreadChannels, + lastEventAt: lastEventAt ?? this.lastEventAt, + lastSyncAt: lastSyncAt ?? this.lastSyncAt, + ); + @override + String toString() { + return (StringBuffer('_ConnectionEventData(') + ..write('id: $id, ') + ..write('ownUser: $ownUser, ') + ..write('totalUnreadCount: $totalUnreadCount, ') + ..write('unreadChannels: $unreadChannels, ') + ..write('lastEventAt: $lastEventAt, ') + ..write('lastSyncAt: $lastSyncAt') + ..write(')')) + .toString(); + } + + @override + int get hashCode => $mrjf($mrjc( + id.hashCode, + $mrjc( + ownUser.hashCode, + $mrjc( + totalUnreadCount.hashCode, + $mrjc(unreadChannels.hashCode, + $mrjc(lastEventAt.hashCode, lastSyncAt.hashCode)))))); + @override + bool operator ==(dynamic other) => + identical(this, other) || + (other is _ConnectionEventData && + other.id == this.id && + other.ownUser == this.ownUser && + other.totalUnreadCount == this.totalUnreadCount && + other.unreadChannels == this.unreadChannels && + other.lastEventAt == this.lastEventAt && + other.lastSyncAt == this.lastSyncAt); +} + +class _ConnectionEventCompanion extends UpdateCompanion<_ConnectionEventData> { + final Value id; + final Value> ownUser; + final Value totalUnreadCount; + final Value unreadChannels; + final Value lastEventAt; + final Value lastSyncAt; + const _ConnectionEventCompanion({ + this.id = const Value.absent(), + this.ownUser = const Value.absent(), + this.totalUnreadCount = const Value.absent(), + this.unreadChannels = const Value.absent(), + this.lastEventAt = const Value.absent(), + this.lastSyncAt = const Value.absent(), + }); + _ConnectionEventCompanion.insert({ + this.id = const Value.absent(), + this.ownUser = const Value.absent(), + this.totalUnreadCount = const Value.absent(), + this.unreadChannels = const Value.absent(), + this.lastEventAt = const Value.absent(), + this.lastSyncAt = const Value.absent(), + }); + static Insertable<_ConnectionEventData> custom({ + Expression id, + Expression ownUser, + Expression totalUnreadCount, + Expression unreadChannels, + Expression lastEventAt, + Expression lastSyncAt, + }) { + return RawValuesInsertable({ + if (id != null) 'id': id, + if (ownUser != null) 'own_user': ownUser, + if (totalUnreadCount != null) 'total_unread_count': totalUnreadCount, + if (unreadChannels != null) 'unread_channels': unreadChannels, + if (lastEventAt != null) 'last_event_at': lastEventAt, + if (lastSyncAt != null) 'last_sync_at': lastSyncAt, + }); + } + + _ConnectionEventCompanion copyWith( + {Value id, + Value> ownUser, + Value totalUnreadCount, + Value unreadChannels, + Value lastEventAt, + Value lastSyncAt}) { + return _ConnectionEventCompanion( + id: id ?? this.id, + ownUser: ownUser ?? this.ownUser, + totalUnreadCount: totalUnreadCount ?? this.totalUnreadCount, + unreadChannels: unreadChannels ?? this.unreadChannels, + lastEventAt: lastEventAt ?? this.lastEventAt, + lastSyncAt: lastSyncAt ?? this.lastSyncAt, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (id.present) { + map['id'] = Variable(id.value); + } + if (ownUser.present) { + final converter = $_ConnectionEventTable.$converter0; + map['own_user'] = Variable(converter.mapToSql(ownUser.value)); + } + if (totalUnreadCount.present) { + map['total_unread_count'] = Variable(totalUnreadCount.value); + } + if (unreadChannels.present) { + map['unread_channels'] = Variable(unreadChannels.value); + } + if (lastEventAt.present) { + map['last_event_at'] = Variable(lastEventAt.value); + } + if (lastSyncAt.present) { + map['last_sync_at'] = Variable(lastSyncAt.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('_ConnectionEventCompanion(') + ..write('id: $id, ') + ..write('ownUser: $ownUser, ') + ..write('totalUnreadCount: $totalUnreadCount, ') + ..write('unreadChannels: $unreadChannels, ') + ..write('lastEventAt: $lastEventAt, ') + ..write('lastSyncAt: $lastSyncAt') + ..write(')')) + .toString(); + } +} + +class $_ConnectionEventTable extends _ConnectionEvent + with TableInfo<$_ConnectionEventTable, _ConnectionEventData> { + final GeneratedDatabase _db; + final String _alias; + $_ConnectionEventTable(this._db, [this._alias]); + final VerificationMeta _idMeta = const VerificationMeta('id'); + GeneratedIntColumn _id; + @override + GeneratedIntColumn get id => _id ??= _constructId(); + GeneratedIntColumn _constructId() { + return GeneratedIntColumn( + 'id', + $tableName, + false, + ); + } + + final VerificationMeta _ownUserMeta = const VerificationMeta('ownUser'); + GeneratedTextColumn _ownUser; + @override + GeneratedTextColumn get ownUser => _ownUser ??= _constructOwnUser(); + GeneratedTextColumn _constructOwnUser() { + return GeneratedTextColumn( + 'own_user', + $tableName, + true, + ); + } + + final VerificationMeta _totalUnreadCountMeta = + const VerificationMeta('totalUnreadCount'); + GeneratedIntColumn _totalUnreadCount; + @override + GeneratedIntColumn get totalUnreadCount => + _totalUnreadCount ??= _constructTotalUnreadCount(); + GeneratedIntColumn _constructTotalUnreadCount() { + return GeneratedIntColumn( + 'total_unread_count', + $tableName, + true, + ); + } + + final VerificationMeta _unreadChannelsMeta = + const VerificationMeta('unreadChannels'); + GeneratedIntColumn _unreadChannels; + @override + GeneratedIntColumn get unreadChannels => + _unreadChannels ??= _constructUnreadChannels(); + GeneratedIntColumn _constructUnreadChannels() { + return GeneratedIntColumn( + 'unread_channels', + $tableName, + true, + ); + } + + final VerificationMeta _lastEventAtMeta = + const VerificationMeta('lastEventAt'); + GeneratedDateTimeColumn _lastEventAt; + @override + GeneratedDateTimeColumn get lastEventAt => + _lastEventAt ??= _constructLastEventAt(); + GeneratedDateTimeColumn _constructLastEventAt() { + return GeneratedDateTimeColumn( + 'last_event_at', + $tableName, + true, + ); + } + + final VerificationMeta _lastSyncAtMeta = const VerificationMeta('lastSyncAt'); + GeneratedDateTimeColumn _lastSyncAt; + @override + GeneratedDateTimeColumn get lastSyncAt => + _lastSyncAt ??= _constructLastSyncAt(); + GeneratedDateTimeColumn _constructLastSyncAt() { + return GeneratedDateTimeColumn( + 'last_sync_at', + $tableName, + true, + ); + } + + @override + List get $columns => + [id, ownUser, totalUnreadCount, unreadChannels, lastEventAt, lastSyncAt]; + @override + $_ConnectionEventTable get asDslTable => this; + @override + String get $tableName => _alias ?? 'connection_event'; + @override + final String actualTableName = 'connection_event'; + @override + VerificationContext validateIntegrity( + Insertable<_ConnectionEventData> instance, + {bool isInserting = false}) { + final context = VerificationContext(); + final data = instance.toColumns(true); + if (data.containsKey('id')) { + context.handle(_idMeta, id.isAcceptableOrUnknown(data['id'], _idMeta)); + } + context.handle(_ownUserMeta, const VerificationResult.success()); + if (data.containsKey('total_unread_count')) { + context.handle( + _totalUnreadCountMeta, + totalUnreadCount.isAcceptableOrUnknown( + data['total_unread_count'], _totalUnreadCountMeta)); + } + if (data.containsKey('unread_channels')) { + context.handle( + _unreadChannelsMeta, + unreadChannels.isAcceptableOrUnknown( + data['unread_channels'], _unreadChannelsMeta)); + } + if (data.containsKey('last_event_at')) { + context.handle( + _lastEventAtMeta, + lastEventAt.isAcceptableOrUnknown( + data['last_event_at'], _lastEventAtMeta)); + } + if (data.containsKey('last_sync_at')) { + context.handle( + _lastSyncAtMeta, + lastSyncAt.isAcceptableOrUnknown( + data['last_sync_at'], _lastSyncAtMeta)); + } + return context; + } + + @override + Set get $primaryKey => {id}; + @override + _ConnectionEventData map(Map data, {String tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : null; + return _ConnectionEventData.fromData(data, _db, prefix: effectivePrefix); + } + + @override + $_ConnectionEventTable createAlias(String alias) { + return $_ConnectionEventTable(_db, alias); + } + + static TypeConverter, String> $converter0 = + _ExtraDataConverter(); +} + +class _Channel extends DataClass implements Insertable<_Channel> { + final String id; + final String type; + final String cid; + final String config; + final bool frozen; + final DateTime lastMessageAt; + final DateTime createdAt; + final DateTime updatedAt; + final DateTime deletedAt; + final int memberCount; + final Map extraData; + final String createdBy; + _Channel( + {@required this.id, + @required this.type, + @required this.cid, + @required this.config, + @required this.frozen, + this.lastMessageAt, + this.createdAt, + this.updatedAt, + this.deletedAt, + this.memberCount, + this.extraData, + this.createdBy}); + factory _Channel.fromData(Map data, GeneratedDatabase db, + {String prefix}) { + final effectivePrefix = prefix ?? ''; + final stringType = db.typeSystem.forDartType(); + final boolType = db.typeSystem.forDartType(); + final dateTimeType = db.typeSystem.forDartType(); + final intType = db.typeSystem.forDartType(); + return _Channel( + id: stringType.mapFromDatabaseResponse(data['${effectivePrefix}id']), + type: stringType.mapFromDatabaseResponse(data['${effectivePrefix}type']), + cid: stringType.mapFromDatabaseResponse(data['${effectivePrefix}cid']), + config: + stringType.mapFromDatabaseResponse(data['${effectivePrefix}config']), + frozen: + boolType.mapFromDatabaseResponse(data['${effectivePrefix}frozen']), + lastMessageAt: dateTimeType + .mapFromDatabaseResponse(data['${effectivePrefix}last_message_at']), + createdAt: dateTimeType + .mapFromDatabaseResponse(data['${effectivePrefix}created_at']), + updatedAt: dateTimeType + .mapFromDatabaseResponse(data['${effectivePrefix}updated_at']), + deletedAt: dateTimeType + .mapFromDatabaseResponse(data['${effectivePrefix}deleted_at']), + memberCount: intType + .mapFromDatabaseResponse(data['${effectivePrefix}member_count']), + extraData: $_ChannelsTable.$converter0.mapToDart(stringType + .mapFromDatabaseResponse(data['${effectivePrefix}extra_data'])), + createdBy: stringType + .mapFromDatabaseResponse(data['${effectivePrefix}created_by']), + ); + } + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (!nullToAbsent || id != null) { + map['id'] = Variable(id); + } + if (!nullToAbsent || type != null) { + map['type'] = Variable(type); + } + if (!nullToAbsent || cid != null) { + map['cid'] = Variable(cid); + } + if (!nullToAbsent || config != null) { + map['config'] = Variable(config); + } + if (!nullToAbsent || frozen != null) { + map['frozen'] = Variable(frozen); + } + if (!nullToAbsent || lastMessageAt != null) { + map['last_message_at'] = Variable(lastMessageAt); + } + if (!nullToAbsent || createdAt != null) { + map['created_at'] = Variable(createdAt); + } + if (!nullToAbsent || updatedAt != null) { + map['updated_at'] = Variable(updatedAt); + } + if (!nullToAbsent || deletedAt != null) { + map['deleted_at'] = Variable(deletedAt); + } + if (!nullToAbsent || memberCount != null) { + map['member_count'] = Variable(memberCount); + } + if (!nullToAbsent || extraData != null) { + final converter = $_ChannelsTable.$converter0; + map['extra_data'] = Variable(converter.mapToSql(extraData)); + } + if (!nullToAbsent || createdBy != null) { + map['created_by'] = Variable(createdBy); + } + return map; + } + + _ChannelsCompanion toCompanion(bool nullToAbsent) { + return _ChannelsCompanion( + id: id == null && nullToAbsent ? const Value.absent() : Value(id), + type: type == null && nullToAbsent ? const Value.absent() : Value(type), + cid: cid == null && nullToAbsent ? const Value.absent() : Value(cid), + config: + config == null && nullToAbsent ? const Value.absent() : Value(config), + frozen: + frozen == null && nullToAbsent ? const Value.absent() : Value(frozen), + lastMessageAt: lastMessageAt == null && nullToAbsent + ? const Value.absent() + : Value(lastMessageAt), + createdAt: createdAt == null && nullToAbsent + ? const Value.absent() + : Value(createdAt), + updatedAt: updatedAt == null && nullToAbsent + ? const Value.absent() + : Value(updatedAt), + deletedAt: deletedAt == null && nullToAbsent + ? const Value.absent() + : Value(deletedAt), + memberCount: memberCount == null && nullToAbsent + ? const Value.absent() + : Value(memberCount), + extraData: extraData == null && nullToAbsent + ? const Value.absent() + : Value(extraData), + createdBy: createdBy == null && nullToAbsent + ? const Value.absent() + : Value(createdBy), + ); + } + + factory _Channel.fromJson(Map json, + {ValueSerializer serializer}) { + serializer ??= moorRuntimeOptions.defaultSerializer; + return _Channel( + id: serializer.fromJson(json['id']), + type: serializer.fromJson(json['type']), + cid: serializer.fromJson(json['cid']), + config: serializer.fromJson(json['config']), + frozen: serializer.fromJson(json['frozen']), + lastMessageAt: serializer.fromJson(json['lastMessageAt']), + createdAt: serializer.fromJson(json['createdAt']), + updatedAt: serializer.fromJson(json['updatedAt']), + deletedAt: serializer.fromJson(json['deletedAt']), + memberCount: serializer.fromJson(json['memberCount']), + extraData: serializer.fromJson>(json['extraData']), + createdBy: serializer.fromJson(json['createdBy']), + ); + } + @override + Map toJson({ValueSerializer serializer}) { + serializer ??= moorRuntimeOptions.defaultSerializer; + return { + 'id': serializer.toJson(id), + 'type': serializer.toJson(type), + 'cid': serializer.toJson(cid), + 'config': serializer.toJson(config), + 'frozen': serializer.toJson(frozen), + 'lastMessageAt': serializer.toJson(lastMessageAt), + 'createdAt': serializer.toJson(createdAt), + 'updatedAt': serializer.toJson(updatedAt), + 'deletedAt': serializer.toJson(deletedAt), + 'memberCount': serializer.toJson(memberCount), + 'extraData': serializer.toJson>(extraData), + 'createdBy': serializer.toJson(createdBy), + }; + } + + _Channel copyWith( + {String id, + String type, + String cid, + String config, + bool frozen, + DateTime lastMessageAt, + DateTime createdAt, + DateTime updatedAt, + DateTime deletedAt, + int memberCount, + Map extraData, + String createdBy}) => + _Channel( + id: id ?? this.id, + type: type ?? this.type, + cid: cid ?? this.cid, + config: config ?? this.config, + frozen: frozen ?? this.frozen, + lastMessageAt: lastMessageAt ?? this.lastMessageAt, + createdAt: createdAt ?? this.createdAt, + updatedAt: updatedAt ?? this.updatedAt, + deletedAt: deletedAt ?? this.deletedAt, + memberCount: memberCount ?? this.memberCount, + extraData: extraData ?? this.extraData, + createdBy: createdBy ?? this.createdBy, + ); + @override + String toString() { + return (StringBuffer('_Channel(') + ..write('id: $id, ') + ..write('type: $type, ') + ..write('cid: $cid, ') + ..write('config: $config, ') + ..write('frozen: $frozen, ') + ..write('lastMessageAt: $lastMessageAt, ') + ..write('createdAt: $createdAt, ') + ..write('updatedAt: $updatedAt, ') + ..write('deletedAt: $deletedAt, ') + ..write('memberCount: $memberCount, ') + ..write('extraData: $extraData, ') + ..write('createdBy: $createdBy') + ..write(')')) + .toString(); + } + + @override + int get hashCode => $mrjf($mrjc( + id.hashCode, + $mrjc( + type.hashCode, + $mrjc( + cid.hashCode, + $mrjc( + config.hashCode, + $mrjc( + frozen.hashCode, + $mrjc( + lastMessageAt.hashCode, + $mrjc( + createdAt.hashCode, + $mrjc( + updatedAt.hashCode, + $mrjc( + deletedAt.hashCode, + $mrjc( + memberCount.hashCode, + $mrjc(extraData.hashCode, + createdBy.hashCode)))))))))))); + @override + bool operator ==(dynamic other) => + identical(this, other) || + (other is _Channel && + other.id == this.id && + other.type == this.type && + other.cid == this.cid && + other.config == this.config && + other.frozen == this.frozen && + other.lastMessageAt == this.lastMessageAt && + other.createdAt == this.createdAt && + other.updatedAt == this.updatedAt && + other.deletedAt == this.deletedAt && + other.memberCount == this.memberCount && + other.extraData == this.extraData && + other.createdBy == this.createdBy); +} + +class _ChannelsCompanion extends UpdateCompanion<_Channel> { + final Value id; + final Value type; + final Value cid; + final Value config; + final Value frozen; + final Value lastMessageAt; + final Value createdAt; + final Value updatedAt; + final Value deletedAt; + final Value memberCount; + final Value> extraData; + final Value createdBy; + const _ChannelsCompanion({ + this.id = const Value.absent(), + this.type = const Value.absent(), + this.cid = const Value.absent(), + this.config = const Value.absent(), + this.frozen = const Value.absent(), + this.lastMessageAt = const Value.absent(), + this.createdAt = const Value.absent(), + this.updatedAt = const Value.absent(), + this.deletedAt = const Value.absent(), + this.memberCount = const Value.absent(), + this.extraData = const Value.absent(), + this.createdBy = const Value.absent(), + }); + _ChannelsCompanion.insert({ + @required String id, + @required String type, + @required String cid, + @required String config, + this.frozen = const Value.absent(), + this.lastMessageAt = const Value.absent(), + this.createdAt = const Value.absent(), + this.updatedAt = const Value.absent(), + this.deletedAt = const Value.absent(), + this.memberCount = const Value.absent(), + this.extraData = const Value.absent(), + this.createdBy = const Value.absent(), + }) : id = Value(id), + type = Value(type), + cid = Value(cid), + config = Value(config); + static Insertable<_Channel> custom({ + Expression id, + Expression type, + Expression cid, + Expression config, + Expression frozen, + Expression lastMessageAt, + Expression createdAt, + Expression updatedAt, + Expression deletedAt, + Expression memberCount, + Expression extraData, + Expression createdBy, + }) { + return RawValuesInsertable({ + if (id != null) 'id': id, + if (type != null) 'type': type, + if (cid != null) 'cid': cid, + if (config != null) 'config': config, + if (frozen != null) 'frozen': frozen, + if (lastMessageAt != null) 'last_message_at': lastMessageAt, + if (createdAt != null) 'created_at': createdAt, + if (updatedAt != null) 'updated_at': updatedAt, + if (deletedAt != null) 'deleted_at': deletedAt, + if (memberCount != null) 'member_count': memberCount, + if (extraData != null) 'extra_data': extraData, + if (createdBy != null) 'created_by': createdBy, + }); + } + + _ChannelsCompanion copyWith( + {Value id, + Value type, + Value cid, + Value config, + Value frozen, + Value lastMessageAt, + Value createdAt, + Value updatedAt, + Value deletedAt, + Value memberCount, + Value> extraData, + Value createdBy}) { + return _ChannelsCompanion( + id: id ?? this.id, + type: type ?? this.type, + cid: cid ?? this.cid, + config: config ?? this.config, + frozen: frozen ?? this.frozen, + lastMessageAt: lastMessageAt ?? this.lastMessageAt, + createdAt: createdAt ?? this.createdAt, + updatedAt: updatedAt ?? this.updatedAt, + deletedAt: deletedAt ?? this.deletedAt, + memberCount: memberCount ?? this.memberCount, + extraData: extraData ?? this.extraData, + createdBy: createdBy ?? this.createdBy, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (id.present) { + map['id'] = Variable(id.value); + } + if (type.present) { + map['type'] = Variable(type.value); + } + if (cid.present) { + map['cid'] = Variable(cid.value); + } + if (config.present) { + map['config'] = Variable(config.value); + } + if (frozen.present) { + map['frozen'] = Variable(frozen.value); + } + if (lastMessageAt.present) { + map['last_message_at'] = Variable(lastMessageAt.value); + } + if (createdAt.present) { + map['created_at'] = Variable(createdAt.value); + } + if (updatedAt.present) { + map['updated_at'] = Variable(updatedAt.value); + } + if (deletedAt.present) { + map['deleted_at'] = Variable(deletedAt.value); + } + if (memberCount.present) { + map['member_count'] = Variable(memberCount.value); + } + if (extraData.present) { + final converter = $_ChannelsTable.$converter0; + map['extra_data'] = Variable(converter.mapToSql(extraData.value)); + } + if (createdBy.present) { + map['created_by'] = Variable(createdBy.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('_ChannelsCompanion(') + ..write('id: $id, ') + ..write('type: $type, ') + ..write('cid: $cid, ') + ..write('config: $config, ') + ..write('frozen: $frozen, ') + ..write('lastMessageAt: $lastMessageAt, ') + ..write('createdAt: $createdAt, ') + ..write('updatedAt: $updatedAt, ') + ..write('deletedAt: $deletedAt, ') + ..write('memberCount: $memberCount, ') + ..write('extraData: $extraData, ') + ..write('createdBy: $createdBy') + ..write(')')) + .toString(); + } +} + +class $_ChannelsTable extends _Channels + with TableInfo<$_ChannelsTable, _Channel> { + final GeneratedDatabase _db; + final String _alias; + $_ChannelsTable(this._db, [this._alias]); + final VerificationMeta _idMeta = const VerificationMeta('id'); + GeneratedTextColumn _id; + @override + GeneratedTextColumn get id => _id ??= _constructId(); + GeneratedTextColumn _constructId() { + return GeneratedTextColumn( + 'id', + $tableName, + false, + ); + } + + final VerificationMeta _typeMeta = const VerificationMeta('type'); + GeneratedTextColumn _type; + @override + GeneratedTextColumn get type => _type ??= _constructType(); + GeneratedTextColumn _constructType() { + return GeneratedTextColumn( + 'type', + $tableName, + false, + ); + } + + final VerificationMeta _cidMeta = const VerificationMeta('cid'); + GeneratedTextColumn _cid; + @override + GeneratedTextColumn get cid => _cid ??= _constructCid(); + GeneratedTextColumn _constructCid() { + return GeneratedTextColumn( + 'cid', + $tableName, + false, + ); + } + + final VerificationMeta _configMeta = const VerificationMeta('config'); + GeneratedTextColumn _config; + @override + GeneratedTextColumn get config => _config ??= _constructConfig(); + GeneratedTextColumn _constructConfig() { + return GeneratedTextColumn( + 'config', + $tableName, + false, + ); + } + + final VerificationMeta _frozenMeta = const VerificationMeta('frozen'); + GeneratedBoolColumn _frozen; + @override + GeneratedBoolColumn get frozen => _frozen ??= _constructFrozen(); + GeneratedBoolColumn _constructFrozen() { + return GeneratedBoolColumn('frozen', $tableName, false, + defaultValue: Constant(false)); + } + + final VerificationMeta _lastMessageAtMeta = + const VerificationMeta('lastMessageAt'); + GeneratedDateTimeColumn _lastMessageAt; + @override + GeneratedDateTimeColumn get lastMessageAt => + _lastMessageAt ??= _constructLastMessageAt(); + GeneratedDateTimeColumn _constructLastMessageAt() { + return GeneratedDateTimeColumn( + 'last_message_at', + $tableName, + true, + ); + } + + final VerificationMeta _createdAtMeta = const VerificationMeta('createdAt'); + GeneratedDateTimeColumn _createdAt; + @override + GeneratedDateTimeColumn get createdAt => _createdAt ??= _constructCreatedAt(); + GeneratedDateTimeColumn _constructCreatedAt() { + return GeneratedDateTimeColumn( + 'created_at', + $tableName, + true, + ); + } + + final VerificationMeta _updatedAtMeta = const VerificationMeta('updatedAt'); + GeneratedDateTimeColumn _updatedAt; + @override + GeneratedDateTimeColumn get updatedAt => _updatedAt ??= _constructUpdatedAt(); + GeneratedDateTimeColumn _constructUpdatedAt() { + return GeneratedDateTimeColumn( + 'updated_at', + $tableName, + true, + ); + } + + final VerificationMeta _deletedAtMeta = const VerificationMeta('deletedAt'); + GeneratedDateTimeColumn _deletedAt; + @override + GeneratedDateTimeColumn get deletedAt => _deletedAt ??= _constructDeletedAt(); + GeneratedDateTimeColumn _constructDeletedAt() { + return GeneratedDateTimeColumn( + 'deleted_at', + $tableName, + true, + ); + } + + final VerificationMeta _memberCountMeta = + const VerificationMeta('memberCount'); + GeneratedIntColumn _memberCount; + @override + GeneratedIntColumn get memberCount => + _memberCount ??= _constructMemberCount(); + GeneratedIntColumn _constructMemberCount() { + return GeneratedIntColumn( + 'member_count', + $tableName, + true, + ); + } + + final VerificationMeta _extraDataMeta = const VerificationMeta('extraData'); + GeneratedTextColumn _extraData; + @override + GeneratedTextColumn get extraData => _extraData ??= _constructExtraData(); + GeneratedTextColumn _constructExtraData() { + return GeneratedTextColumn( + 'extra_data', + $tableName, + true, + ); + } + + final VerificationMeta _createdByMeta = const VerificationMeta('createdBy'); + GeneratedTextColumn _createdBy; + @override + GeneratedTextColumn get createdBy => _createdBy ??= _constructCreatedBy(); + GeneratedTextColumn _constructCreatedBy() { + return GeneratedTextColumn( + 'created_by', + $tableName, + true, + ); + } + + @override + List get $columns => [ + id, + type, + cid, + config, + frozen, + lastMessageAt, + createdAt, + updatedAt, + deletedAt, + memberCount, + extraData, + createdBy + ]; + @override + $_ChannelsTable get asDslTable => this; + @override + String get $tableName => _alias ?? 'channels'; + @override + final String actualTableName = 'channels'; + @override + VerificationContext validateIntegrity(Insertable<_Channel> instance, + {bool isInserting = false}) { + final context = VerificationContext(); + final data = instance.toColumns(true); + if (data.containsKey('id')) { + context.handle(_idMeta, id.isAcceptableOrUnknown(data['id'], _idMeta)); + } else if (isInserting) { + context.missing(_idMeta); + } + if (data.containsKey('type')) { + context.handle( + _typeMeta, type.isAcceptableOrUnknown(data['type'], _typeMeta)); + } else if (isInserting) { + context.missing(_typeMeta); + } + if (data.containsKey('cid')) { + context.handle( + _cidMeta, cid.isAcceptableOrUnknown(data['cid'], _cidMeta)); + } else if (isInserting) { + context.missing(_cidMeta); + } + if (data.containsKey('config')) { + context.handle(_configMeta, + config.isAcceptableOrUnknown(data['config'], _configMeta)); + } else if (isInserting) { + context.missing(_configMeta); + } + if (data.containsKey('frozen')) { + context.handle(_frozenMeta, + frozen.isAcceptableOrUnknown(data['frozen'], _frozenMeta)); + } + if (data.containsKey('last_message_at')) { + context.handle( + _lastMessageAtMeta, + lastMessageAt.isAcceptableOrUnknown( + data['last_message_at'], _lastMessageAtMeta)); + } + if (data.containsKey('created_at')) { + context.handle(_createdAtMeta, + createdAt.isAcceptableOrUnknown(data['created_at'], _createdAtMeta)); + } + if (data.containsKey('updated_at')) { + context.handle(_updatedAtMeta, + updatedAt.isAcceptableOrUnknown(data['updated_at'], _updatedAtMeta)); + } + if (data.containsKey('deleted_at')) { + context.handle(_deletedAtMeta, + deletedAt.isAcceptableOrUnknown(data['deleted_at'], _deletedAtMeta)); + } + if (data.containsKey('member_count')) { + context.handle( + _memberCountMeta, + memberCount.isAcceptableOrUnknown( + data['member_count'], _memberCountMeta)); + } + context.handle(_extraDataMeta, const VerificationResult.success()); + if (data.containsKey('created_by')) { + context.handle(_createdByMeta, + createdBy.isAcceptableOrUnknown(data['created_by'], _createdByMeta)); + } + return context; + } + + @override + Set get $primaryKey => {cid}; + @override + _Channel map(Map data, {String tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : null; + return _Channel.fromData(data, _db, prefix: effectivePrefix); + } + + @override + $_ChannelsTable createAlias(String alias) { + return $_ChannelsTable(_db, alias); + } + + static TypeConverter, String> $converter0 = + _ExtraDataConverter(); +} + +class _User extends DataClass implements Insertable<_User> { + final String id; + final String role; + final DateTime createdAt; + final DateTime updatedAt; + final DateTime lastActive; + final bool online; + final bool banned; + final Map extraData; + _User( + {@required this.id, + this.role, + this.createdAt, + this.updatedAt, + this.lastActive, + this.online, + this.banned, + this.extraData}); + factory _User.fromData(Map data, GeneratedDatabase db, + {String prefix}) { + final effectivePrefix = prefix ?? ''; + final stringType = db.typeSystem.forDartType(); + final dateTimeType = db.typeSystem.forDartType(); + final boolType = db.typeSystem.forDartType(); + return _User( + id: stringType.mapFromDatabaseResponse(data['${effectivePrefix}id']), + role: stringType.mapFromDatabaseResponse(data['${effectivePrefix}role']), + createdAt: dateTimeType + .mapFromDatabaseResponse(data['${effectivePrefix}created_at']), + updatedAt: dateTimeType + .mapFromDatabaseResponse(data['${effectivePrefix}updated_at']), + lastActive: dateTimeType + .mapFromDatabaseResponse(data['${effectivePrefix}last_active']), + online: + boolType.mapFromDatabaseResponse(data['${effectivePrefix}online']), + banned: + boolType.mapFromDatabaseResponse(data['${effectivePrefix}banned']), + extraData: $_UsersTable.$converter0.mapToDart(stringType + .mapFromDatabaseResponse(data['${effectivePrefix}extra_data'])), + ); + } + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (!nullToAbsent || id != null) { + map['id'] = Variable(id); + } + if (!nullToAbsent || role != null) { + map['role'] = Variable(role); + } + if (!nullToAbsent || createdAt != null) { + map['created_at'] = Variable(createdAt); + } + if (!nullToAbsent || updatedAt != null) { + map['updated_at'] = Variable(updatedAt); + } + if (!nullToAbsent || lastActive != null) { + map['last_active'] = Variable(lastActive); + } + if (!nullToAbsent || online != null) { + map['online'] = Variable(online); + } + if (!nullToAbsent || banned != null) { + map['banned'] = Variable(banned); + } + if (!nullToAbsent || extraData != null) { + final converter = $_UsersTable.$converter0; + map['extra_data'] = Variable(converter.mapToSql(extraData)); + } + return map; + } + + _UsersCompanion toCompanion(bool nullToAbsent) { + return _UsersCompanion( + id: id == null && nullToAbsent ? const Value.absent() : Value(id), + role: role == null && nullToAbsent ? const Value.absent() : Value(role), + createdAt: createdAt == null && nullToAbsent + ? const Value.absent() + : Value(createdAt), + updatedAt: updatedAt == null && nullToAbsent + ? const Value.absent() + : Value(updatedAt), + lastActive: lastActive == null && nullToAbsent + ? const Value.absent() + : Value(lastActive), + online: + online == null && nullToAbsent ? const Value.absent() : Value(online), + banned: + banned == null && nullToAbsent ? const Value.absent() : Value(banned), + extraData: extraData == null && nullToAbsent + ? const Value.absent() + : Value(extraData), + ); + } + + factory _User.fromJson(Map json, + {ValueSerializer serializer}) { + serializer ??= moorRuntimeOptions.defaultSerializer; + return _User( + id: serializer.fromJson(json['id']), + role: serializer.fromJson(json['role']), + createdAt: serializer.fromJson(json['createdAt']), + updatedAt: serializer.fromJson(json['updatedAt']), + lastActive: serializer.fromJson(json['lastActive']), + online: serializer.fromJson(json['online']), + banned: serializer.fromJson(json['banned']), + extraData: serializer.fromJson>(json['extraData']), + ); + } + @override + Map toJson({ValueSerializer serializer}) { + serializer ??= moorRuntimeOptions.defaultSerializer; + return { + 'id': serializer.toJson(id), + 'role': serializer.toJson(role), + 'createdAt': serializer.toJson(createdAt), + 'updatedAt': serializer.toJson(updatedAt), + 'lastActive': serializer.toJson(lastActive), + 'online': serializer.toJson(online), + 'banned': serializer.toJson(banned), + 'extraData': serializer.toJson>(extraData), + }; + } + + _User copyWith( + {String id, + String role, + DateTime createdAt, + DateTime updatedAt, + DateTime lastActive, + bool online, + bool banned, + Map extraData}) => + _User( + id: id ?? this.id, + role: role ?? this.role, + createdAt: createdAt ?? this.createdAt, + updatedAt: updatedAt ?? this.updatedAt, + lastActive: lastActive ?? this.lastActive, + online: online ?? this.online, + banned: banned ?? this.banned, + extraData: extraData ?? this.extraData, + ); + @override + String toString() { + return (StringBuffer('_User(') + ..write('id: $id, ') + ..write('role: $role, ') + ..write('createdAt: $createdAt, ') + ..write('updatedAt: $updatedAt, ') + ..write('lastActive: $lastActive, ') + ..write('online: $online, ') + ..write('banned: $banned, ') + ..write('extraData: $extraData') + ..write(')')) + .toString(); + } + + @override + int get hashCode => $mrjf($mrjc( + id.hashCode, + $mrjc( + role.hashCode, + $mrjc( + createdAt.hashCode, + $mrjc( + updatedAt.hashCode, + $mrjc( + lastActive.hashCode, + $mrjc(online.hashCode, + $mrjc(banned.hashCode, extraData.hashCode)))))))); + @override + bool operator ==(dynamic other) => + identical(this, other) || + (other is _User && + other.id == this.id && + other.role == this.role && + other.createdAt == this.createdAt && + other.updatedAt == this.updatedAt && + other.lastActive == this.lastActive && + other.online == this.online && + other.banned == this.banned && + other.extraData == this.extraData); +} + +class _UsersCompanion extends UpdateCompanion<_User> { + final Value id; + final Value role; + final Value createdAt; + final Value updatedAt; + final Value lastActive; + final Value online; + final Value banned; + final Value> extraData; + const _UsersCompanion({ + this.id = const Value.absent(), + this.role = const Value.absent(), + this.createdAt = const Value.absent(), + this.updatedAt = const Value.absent(), + this.lastActive = const Value.absent(), + this.online = const Value.absent(), + this.banned = const Value.absent(), + this.extraData = const Value.absent(), + }); + _UsersCompanion.insert({ + @required String id, + this.role = const Value.absent(), + this.createdAt = const Value.absent(), + this.updatedAt = const Value.absent(), + this.lastActive = const Value.absent(), + this.online = const Value.absent(), + this.banned = const Value.absent(), + this.extraData = const Value.absent(), + }) : id = Value(id); + static Insertable<_User> custom({ + Expression id, + Expression role, + Expression createdAt, + Expression updatedAt, + Expression lastActive, + Expression online, + Expression banned, + Expression extraData, + }) { + return RawValuesInsertable({ + if (id != null) 'id': id, + if (role != null) 'role': role, + if (createdAt != null) 'created_at': createdAt, + if (updatedAt != null) 'updated_at': updatedAt, + if (lastActive != null) 'last_active': lastActive, + if (online != null) 'online': online, + if (banned != null) 'banned': banned, + if (extraData != null) 'extra_data': extraData, + }); + } + + _UsersCompanion copyWith( + {Value id, + Value role, + Value createdAt, + Value updatedAt, + Value lastActive, + Value online, + Value banned, + Value> extraData}) { + return _UsersCompanion( + id: id ?? this.id, + role: role ?? this.role, + createdAt: createdAt ?? this.createdAt, + updatedAt: updatedAt ?? this.updatedAt, + lastActive: lastActive ?? this.lastActive, + online: online ?? this.online, + banned: banned ?? this.banned, + extraData: extraData ?? this.extraData, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (id.present) { + map['id'] = Variable(id.value); + } + if (role.present) { + map['role'] = Variable(role.value); + } + if (createdAt.present) { + map['created_at'] = Variable(createdAt.value); + } + if (updatedAt.present) { + map['updated_at'] = Variable(updatedAt.value); + } + if (lastActive.present) { + map['last_active'] = Variable(lastActive.value); + } + if (online.present) { + map['online'] = Variable(online.value); + } + if (banned.present) { + map['banned'] = Variable(banned.value); + } + if (extraData.present) { + final converter = $_UsersTable.$converter0; + map['extra_data'] = Variable(converter.mapToSql(extraData.value)); + } + return map; + } + + @override + String toString() { + return (StringBuffer('_UsersCompanion(') + ..write('id: $id, ') + ..write('role: $role, ') + ..write('createdAt: $createdAt, ') + ..write('updatedAt: $updatedAt, ') + ..write('lastActive: $lastActive, ') + ..write('online: $online, ') + ..write('banned: $banned, ') + ..write('extraData: $extraData') + ..write(')')) + .toString(); + } +} + +class $_UsersTable extends _Users with TableInfo<$_UsersTable, _User> { + final GeneratedDatabase _db; + final String _alias; + $_UsersTable(this._db, [this._alias]); + final VerificationMeta _idMeta = const VerificationMeta('id'); + GeneratedTextColumn _id; + @override + GeneratedTextColumn get id => _id ??= _constructId(); + GeneratedTextColumn _constructId() { + return GeneratedTextColumn( + 'id', + $tableName, + false, + ); + } + + final VerificationMeta _roleMeta = const VerificationMeta('role'); + GeneratedTextColumn _role; + @override + GeneratedTextColumn get role => _role ??= _constructRole(); + GeneratedTextColumn _constructRole() { + return GeneratedTextColumn( + 'role', + $tableName, + true, + ); + } + + final VerificationMeta _createdAtMeta = const VerificationMeta('createdAt'); + GeneratedDateTimeColumn _createdAt; + @override + GeneratedDateTimeColumn get createdAt => _createdAt ??= _constructCreatedAt(); + GeneratedDateTimeColumn _constructCreatedAt() { + return GeneratedDateTimeColumn( + 'created_at', + $tableName, + true, + ); + } + + final VerificationMeta _updatedAtMeta = const VerificationMeta('updatedAt'); + GeneratedDateTimeColumn _updatedAt; + @override + GeneratedDateTimeColumn get updatedAt => _updatedAt ??= _constructUpdatedAt(); + GeneratedDateTimeColumn _constructUpdatedAt() { + return GeneratedDateTimeColumn( + 'updated_at', + $tableName, + true, + ); + } + + final VerificationMeta _lastActiveMeta = const VerificationMeta('lastActive'); + GeneratedDateTimeColumn _lastActive; + @override + GeneratedDateTimeColumn get lastActive => + _lastActive ??= _constructLastActive(); + GeneratedDateTimeColumn _constructLastActive() { + return GeneratedDateTimeColumn( + 'last_active', + $tableName, + true, + ); + } + + final VerificationMeta _onlineMeta = const VerificationMeta('online'); + GeneratedBoolColumn _online; + @override + GeneratedBoolColumn get online => _online ??= _constructOnline(); + GeneratedBoolColumn _constructOnline() { + return GeneratedBoolColumn( + 'online', + $tableName, + true, + ); + } + + final VerificationMeta _bannedMeta = const VerificationMeta('banned'); + GeneratedBoolColumn _banned; + @override + GeneratedBoolColumn get banned => _banned ??= _constructBanned(); + GeneratedBoolColumn _constructBanned() { + return GeneratedBoolColumn( + 'banned', + $tableName, + true, + ); + } + + final VerificationMeta _extraDataMeta = const VerificationMeta('extraData'); + GeneratedTextColumn _extraData; + @override + GeneratedTextColumn get extraData => _extraData ??= _constructExtraData(); + GeneratedTextColumn _constructExtraData() { + return GeneratedTextColumn( + 'extra_data', + $tableName, + true, + ); + } + + @override + List get $columns => + [id, role, createdAt, updatedAt, lastActive, online, banned, extraData]; + @override + $_UsersTable get asDslTable => this; + @override + String get $tableName => _alias ?? 'users'; + @override + final String actualTableName = 'users'; + @override + VerificationContext validateIntegrity(Insertable<_User> instance, + {bool isInserting = false}) { + final context = VerificationContext(); + final data = instance.toColumns(true); + if (data.containsKey('id')) { + context.handle(_idMeta, id.isAcceptableOrUnknown(data['id'], _idMeta)); + } else if (isInserting) { + context.missing(_idMeta); + } + if (data.containsKey('role')) { + context.handle( + _roleMeta, role.isAcceptableOrUnknown(data['role'], _roleMeta)); + } + if (data.containsKey('created_at')) { + context.handle(_createdAtMeta, + createdAt.isAcceptableOrUnknown(data['created_at'], _createdAtMeta)); + } + if (data.containsKey('updated_at')) { + context.handle(_updatedAtMeta, + updatedAt.isAcceptableOrUnknown(data['updated_at'], _updatedAtMeta)); + } + if (data.containsKey('last_active')) { + context.handle( + _lastActiveMeta, + lastActive.isAcceptableOrUnknown( + data['last_active'], _lastActiveMeta)); + } + if (data.containsKey('online')) { + context.handle(_onlineMeta, + online.isAcceptableOrUnknown(data['online'], _onlineMeta)); + } + if (data.containsKey('banned')) { + context.handle(_bannedMeta, + banned.isAcceptableOrUnknown(data['banned'], _bannedMeta)); + } + context.handle(_extraDataMeta, const VerificationResult.success()); + return context; + } + + @override + Set get $primaryKey => {id}; + @override + _User map(Map data, {String tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : null; + return _User.fromData(data, _db, prefix: effectivePrefix); + } + + @override + $_UsersTable createAlias(String alias) { + return $_UsersTable(_db, alias); + } + + static TypeConverter, String> $converter0 = + _ExtraDataConverter(); +} + +class _Message extends DataClass implements Insertable<_Message> { + final String id; + final String messageText; + final String attachmentJson; + final MessageSendingStatus status; + final String type; + final Map reactionCounts; + final Map reactionScores; + final String parentId; + final String quotedMessageId; + final int replyCount; + final bool showInChannel; + final bool shadowed; + final String command; + final DateTime createdAt; + final DateTime updatedAt; + final DateTime deletedAt; + final String userId; + final String channelCid; + final Map extraData; + _Message( + {@required this.id, + this.messageText, + this.attachmentJson, + this.status, + this.type, + this.reactionCounts, + this.reactionScores, + this.parentId, + this.quotedMessageId, + this.replyCount, + this.showInChannel, + this.shadowed, + this.command, + @required this.createdAt, + this.updatedAt, + this.deletedAt, + this.userId, + this.channelCid, + this.extraData}); + factory _Message.fromData(Map data, GeneratedDatabase db, + {String prefix}) { + final effectivePrefix = prefix ?? ''; + final stringType = db.typeSystem.forDartType(); + final intType = db.typeSystem.forDartType(); + final boolType = db.typeSystem.forDartType(); + final dateTimeType = db.typeSystem.forDartType(); + return _Message( + id: stringType.mapFromDatabaseResponse(data['${effectivePrefix}id']), + messageText: stringType + .mapFromDatabaseResponse(data['${effectivePrefix}message_text']), + attachmentJson: stringType + .mapFromDatabaseResponse(data['${effectivePrefix}attachment_json']), + status: $_MessagesTable.$converter0.mapToDart( + intType.mapFromDatabaseResponse(data['${effectivePrefix}status'])), + type: stringType.mapFromDatabaseResponse(data['${effectivePrefix}type']), + reactionCounts: $_MessagesTable.$converter1.mapToDart(stringType + .mapFromDatabaseResponse(data['${effectivePrefix}reaction_counts'])), + reactionScores: $_MessagesTable.$converter2.mapToDart(stringType + .mapFromDatabaseResponse(data['${effectivePrefix}reaction_scores'])), + parentId: stringType + .mapFromDatabaseResponse(data['${effectivePrefix}parent_id']), + quotedMessageId: stringType + .mapFromDatabaseResponse(data['${effectivePrefix}quoted_message_id']), + replyCount: intType + .mapFromDatabaseResponse(data['${effectivePrefix}reply_count']), + showInChannel: boolType + .mapFromDatabaseResponse(data['${effectivePrefix}show_in_channel']), + shadowed: + boolType.mapFromDatabaseResponse(data['${effectivePrefix}shadowed']), + command: + stringType.mapFromDatabaseResponse(data['${effectivePrefix}command']), + createdAt: dateTimeType + .mapFromDatabaseResponse(data['${effectivePrefix}created_at']), + updatedAt: dateTimeType + .mapFromDatabaseResponse(data['${effectivePrefix}updated_at']), + deletedAt: dateTimeType + .mapFromDatabaseResponse(data['${effectivePrefix}deleted_at']), + userId: + stringType.mapFromDatabaseResponse(data['${effectivePrefix}user_id']), + channelCid: stringType + .mapFromDatabaseResponse(data['${effectivePrefix}channel_cid']), + extraData: $_MessagesTable.$converter3.mapToDart(stringType + .mapFromDatabaseResponse(data['${effectivePrefix}extra_data'])), + ); + } + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (!nullToAbsent || id != null) { + map['id'] = Variable(id); + } + if (!nullToAbsent || messageText != null) { + map['message_text'] = Variable(messageText); + } + if (!nullToAbsent || attachmentJson != null) { + map['attachment_json'] = Variable(attachmentJson); + } + if (!nullToAbsent || status != null) { + final converter = $_MessagesTable.$converter0; + map['status'] = Variable(converter.mapToSql(status)); + } + if (!nullToAbsent || type != null) { + map['type'] = Variable(type); + } + if (!nullToAbsent || reactionCounts != null) { + final converter = $_MessagesTable.$converter1; + map['reaction_counts'] = + Variable(converter.mapToSql(reactionCounts)); + } + if (!nullToAbsent || reactionScores != null) { + final converter = $_MessagesTable.$converter2; + map['reaction_scores'] = + Variable(converter.mapToSql(reactionScores)); + } + if (!nullToAbsent || parentId != null) { + map['parent_id'] = Variable(parentId); + } + if (!nullToAbsent || quotedMessageId != null) { + map['quoted_message_id'] = Variable(quotedMessageId); + } + if (!nullToAbsent || replyCount != null) { + map['reply_count'] = Variable(replyCount); + } + if (!nullToAbsent || showInChannel != null) { + map['show_in_channel'] = Variable(showInChannel); + } + if (!nullToAbsent || shadowed != null) { + map['shadowed'] = Variable(shadowed); + } + if (!nullToAbsent || command != null) { + map['command'] = Variable(command); + } + if (!nullToAbsent || createdAt != null) { + map['created_at'] = Variable(createdAt); + } + if (!nullToAbsent || updatedAt != null) { + map['updated_at'] = Variable(updatedAt); + } + if (!nullToAbsent || deletedAt != null) { + map['deleted_at'] = Variable(deletedAt); + } + if (!nullToAbsent || userId != null) { + map['user_id'] = Variable(userId); + } + if (!nullToAbsent || channelCid != null) { + map['channel_cid'] = Variable(channelCid); + } + if (!nullToAbsent || extraData != null) { + final converter = $_MessagesTable.$converter3; + map['extra_data'] = Variable(converter.mapToSql(extraData)); + } + return map; + } + + _MessagesCompanion toCompanion(bool nullToAbsent) { + return _MessagesCompanion( + id: id == null && nullToAbsent ? const Value.absent() : Value(id), + messageText: messageText == null && nullToAbsent + ? const Value.absent() + : Value(messageText), + attachmentJson: attachmentJson == null && nullToAbsent + ? const Value.absent() + : Value(attachmentJson), + status: + status == null && nullToAbsent ? const Value.absent() : Value(status), + type: type == null && nullToAbsent ? const Value.absent() : Value(type), + reactionCounts: reactionCounts == null && nullToAbsent + ? const Value.absent() + : Value(reactionCounts), + reactionScores: reactionScores == null && nullToAbsent + ? const Value.absent() + : Value(reactionScores), + parentId: parentId == null && nullToAbsent + ? const Value.absent() + : Value(parentId), + quotedMessageId: quotedMessageId == null && nullToAbsent + ? const Value.absent() + : Value(quotedMessageId), + replyCount: replyCount == null && nullToAbsent + ? const Value.absent() + : Value(replyCount), + showInChannel: showInChannel == null && nullToAbsent + ? const Value.absent() + : Value(showInChannel), + shadowed: shadowed == null && nullToAbsent + ? const Value.absent() + : Value(shadowed), + command: command == null && nullToAbsent + ? const Value.absent() + : Value(command), + createdAt: createdAt == null && nullToAbsent + ? const Value.absent() + : Value(createdAt), + updatedAt: updatedAt == null && nullToAbsent + ? const Value.absent() + : Value(updatedAt), + deletedAt: deletedAt == null && nullToAbsent + ? const Value.absent() + : Value(deletedAt), + userId: + userId == null && nullToAbsent ? const Value.absent() : Value(userId), + channelCid: channelCid == null && nullToAbsent + ? const Value.absent() + : Value(channelCid), + extraData: extraData == null && nullToAbsent + ? const Value.absent() + : Value(extraData), + ); + } + + factory _Message.fromJson(Map json, + {ValueSerializer serializer}) { + serializer ??= moorRuntimeOptions.defaultSerializer; + return _Message( + id: serializer.fromJson(json['id']), + messageText: serializer.fromJson(json['messageText']), + attachmentJson: serializer.fromJson(json['attachmentJson']), + status: serializer.fromJson(json['status']), + type: serializer.fromJson(json['type']), + reactionCounts: + serializer.fromJson>(json['reactionCounts']), + reactionScores: + serializer.fromJson>(json['reactionScores']), + parentId: serializer.fromJson(json['parentId']), + quotedMessageId: serializer.fromJson(json['quotedMessageId']), + replyCount: serializer.fromJson(json['replyCount']), + showInChannel: serializer.fromJson(json['showInChannel']), + shadowed: serializer.fromJson(json['shadowed']), + command: serializer.fromJson(json['command']), + createdAt: serializer.fromJson(json['createdAt']), + updatedAt: serializer.fromJson(json['updatedAt']), + deletedAt: serializer.fromJson(json['deletedAt']), + userId: serializer.fromJson(json['userId']), + channelCid: serializer.fromJson(json['channelCid']), + extraData: serializer.fromJson>(json['extraData']), + ); + } + @override + Map toJson({ValueSerializer serializer}) { + serializer ??= moorRuntimeOptions.defaultSerializer; + return { + 'id': serializer.toJson(id), + 'messageText': serializer.toJson(messageText), + 'attachmentJson': serializer.toJson(attachmentJson), + 'status': serializer.toJson(status), + 'type': serializer.toJson(type), + 'reactionCounts': serializer.toJson>(reactionCounts), + 'reactionScores': serializer.toJson>(reactionScores), + 'parentId': serializer.toJson(parentId), + 'quotedMessageId': serializer.toJson(quotedMessageId), + 'replyCount': serializer.toJson(replyCount), + 'showInChannel': serializer.toJson(showInChannel), + 'shadowed': serializer.toJson(shadowed), + 'command': serializer.toJson(command), + 'createdAt': serializer.toJson(createdAt), + 'updatedAt': serializer.toJson(updatedAt), + 'deletedAt': serializer.toJson(deletedAt), + 'userId': serializer.toJson(userId), + 'channelCid': serializer.toJson(channelCid), + 'extraData': serializer.toJson>(extraData), + }; + } + + _Message copyWith( + {String id, + String messageText, + String attachmentJson, + MessageSendingStatus status, + String type, + Map reactionCounts, + Map reactionScores, + String parentId, + String quotedMessageId, + int replyCount, + bool showInChannel, + bool shadowed, + String command, + DateTime createdAt, + DateTime updatedAt, + DateTime deletedAt, + String userId, + String channelCid, + Map extraData}) => + _Message( + id: id ?? this.id, + messageText: messageText ?? this.messageText, + attachmentJson: attachmentJson ?? this.attachmentJson, + status: status ?? this.status, + type: type ?? this.type, + reactionCounts: reactionCounts ?? this.reactionCounts, + reactionScores: reactionScores ?? this.reactionScores, + parentId: parentId ?? this.parentId, + quotedMessageId: quotedMessageId ?? this.quotedMessageId, + replyCount: replyCount ?? this.replyCount, + showInChannel: showInChannel ?? this.showInChannel, + shadowed: shadowed ?? this.shadowed, + command: command ?? this.command, + createdAt: createdAt ?? this.createdAt, + updatedAt: updatedAt ?? this.updatedAt, + deletedAt: deletedAt ?? this.deletedAt, + userId: userId ?? this.userId, + channelCid: channelCid ?? this.channelCid, + extraData: extraData ?? this.extraData, + ); + @override + String toString() { + return (StringBuffer('_Message(') + ..write('id: $id, ') + ..write('messageText: $messageText, ') + ..write('attachmentJson: $attachmentJson, ') + ..write('status: $status, ') + ..write('type: $type, ') + ..write('reactionCounts: $reactionCounts, ') + ..write('reactionScores: $reactionScores, ') + ..write('parentId: $parentId, ') + ..write('quotedMessageId: $quotedMessageId, ') + ..write('replyCount: $replyCount, ') + ..write('showInChannel: $showInChannel, ') + ..write('shadowed: $shadowed, ') + ..write('command: $command, ') + ..write('createdAt: $createdAt, ') + ..write('updatedAt: $updatedAt, ') + ..write('deletedAt: $deletedAt, ') + ..write('userId: $userId, ') + ..write('channelCid: $channelCid, ') + ..write('extraData: $extraData') + ..write(')')) + .toString(); + } + + @override + int get hashCode => $mrjf($mrjc( + id.hashCode, + $mrjc( + messageText.hashCode, + $mrjc( + attachmentJson.hashCode, + $mrjc( + status.hashCode, + $mrjc( + type.hashCode, + $mrjc( + reactionCounts.hashCode, + $mrjc( + reactionScores.hashCode, + $mrjc( + parentId.hashCode, + $mrjc( + quotedMessageId.hashCode, + $mrjc( + replyCount.hashCode, + $mrjc( + showInChannel.hashCode, + $mrjc( + shadowed.hashCode, + $mrjc( + command.hashCode, + $mrjc( + createdAt.hashCode, + $mrjc( + updatedAt + .hashCode, + $mrjc( + deletedAt + .hashCode, + $mrjc( + userId + .hashCode, + $mrjc( + channelCid + .hashCode, + extraData + .hashCode))))))))))))))))))); + @override + bool operator ==(dynamic other) => + identical(this, other) || + (other is _Message && + other.id == this.id && + other.messageText == this.messageText && + other.attachmentJson == this.attachmentJson && + other.status == this.status && + other.type == this.type && + other.reactionCounts == this.reactionCounts && + other.reactionScores == this.reactionScores && + other.parentId == this.parentId && + other.quotedMessageId == this.quotedMessageId && + other.replyCount == this.replyCount && + other.showInChannel == this.showInChannel && + other.shadowed == this.shadowed && + other.command == this.command && + other.createdAt == this.createdAt && + other.updatedAt == this.updatedAt && + other.deletedAt == this.deletedAt && + other.userId == this.userId && + other.channelCid == this.channelCid && + other.extraData == this.extraData); +} + +class _MessagesCompanion extends UpdateCompanion<_Message> { + final Value id; + final Value messageText; + final Value attachmentJson; + final Value status; + final Value type; + final Value> reactionCounts; + final Value> reactionScores; + final Value parentId; + final Value quotedMessageId; + final Value replyCount; + final Value showInChannel; + final Value shadowed; + final Value command; + final Value createdAt; + final Value updatedAt; + final Value deletedAt; + final Value userId; + final Value channelCid; + final Value> extraData; + const _MessagesCompanion({ + this.id = const Value.absent(), + this.messageText = const Value.absent(), + this.attachmentJson = const Value.absent(), + this.status = const Value.absent(), + this.type = const Value.absent(), + this.reactionCounts = const Value.absent(), + this.reactionScores = const Value.absent(), + this.parentId = const Value.absent(), + this.quotedMessageId = const Value.absent(), + this.replyCount = const Value.absent(), + this.showInChannel = const Value.absent(), + this.shadowed = const Value.absent(), + this.command = const Value.absent(), + this.createdAt = const Value.absent(), + this.updatedAt = const Value.absent(), + this.deletedAt = const Value.absent(), + this.userId = const Value.absent(), + this.channelCid = const Value.absent(), + this.extraData = const Value.absent(), + }); + _MessagesCompanion.insert({ + @required String id, + this.messageText = const Value.absent(), + this.attachmentJson = const Value.absent(), + this.status = const Value.absent(), + this.type = const Value.absent(), + this.reactionCounts = const Value.absent(), + this.reactionScores = const Value.absent(), + this.parentId = const Value.absent(), + this.quotedMessageId = const Value.absent(), + this.replyCount = const Value.absent(), + this.showInChannel = const Value.absent(), + this.shadowed = const Value.absent(), + this.command = const Value.absent(), + @required DateTime createdAt, + this.updatedAt = const Value.absent(), + this.deletedAt = const Value.absent(), + this.userId = const Value.absent(), + this.channelCid = const Value.absent(), + this.extraData = const Value.absent(), + }) : id = Value(id), + createdAt = Value(createdAt); + static Insertable<_Message> custom({ + Expression id, + Expression messageText, + Expression attachmentJson, + Expression status, + Expression type, + Expression reactionCounts, + Expression reactionScores, + Expression parentId, + Expression quotedMessageId, + Expression replyCount, + Expression showInChannel, + Expression shadowed, + Expression command, + Expression createdAt, + Expression updatedAt, + Expression deletedAt, + Expression userId, + Expression channelCid, + Expression extraData, + }) { + return RawValuesInsertable({ + if (id != null) 'id': id, + if (messageText != null) 'message_text': messageText, + if (attachmentJson != null) 'attachment_json': attachmentJson, + if (status != null) 'status': status, + if (type != null) 'type': type, + if (reactionCounts != null) 'reaction_counts': reactionCounts, + if (reactionScores != null) 'reaction_scores': reactionScores, + if (parentId != null) 'parent_id': parentId, + if (quotedMessageId != null) 'quoted_message_id': quotedMessageId, + if (replyCount != null) 'reply_count': replyCount, + if (showInChannel != null) 'show_in_channel': showInChannel, + if (shadowed != null) 'shadowed': shadowed, + if (command != null) 'command': command, + if (createdAt != null) 'created_at': createdAt, + if (updatedAt != null) 'updated_at': updatedAt, + if (deletedAt != null) 'deleted_at': deletedAt, + if (userId != null) 'user_id': userId, + if (channelCid != null) 'channel_cid': channelCid, + if (extraData != null) 'extra_data': extraData, + }); + } + + _MessagesCompanion copyWith( + {Value id, + Value messageText, + Value attachmentJson, + Value status, + Value type, + Value> reactionCounts, + Value> reactionScores, + Value parentId, + Value quotedMessageId, + Value replyCount, + Value showInChannel, + Value shadowed, + Value command, + Value createdAt, + Value updatedAt, + Value deletedAt, + Value userId, + Value channelCid, + Value> extraData}) { + return _MessagesCompanion( + id: id ?? this.id, + messageText: messageText ?? this.messageText, + attachmentJson: attachmentJson ?? this.attachmentJson, + status: status ?? this.status, + type: type ?? this.type, + reactionCounts: reactionCounts ?? this.reactionCounts, + reactionScores: reactionScores ?? this.reactionScores, + parentId: parentId ?? this.parentId, + quotedMessageId: quotedMessageId ?? this.quotedMessageId, + replyCount: replyCount ?? this.replyCount, + showInChannel: showInChannel ?? this.showInChannel, + shadowed: shadowed ?? this.shadowed, + command: command ?? this.command, + createdAt: createdAt ?? this.createdAt, + updatedAt: updatedAt ?? this.updatedAt, + deletedAt: deletedAt ?? this.deletedAt, + userId: userId ?? this.userId, + channelCid: channelCid ?? this.channelCid, + extraData: extraData ?? this.extraData, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (id.present) { + map['id'] = Variable(id.value); + } + if (messageText.present) { + map['message_text'] = Variable(messageText.value); + } + if (attachmentJson.present) { + map['attachment_json'] = Variable(attachmentJson.value); + } + if (status.present) { + final converter = $_MessagesTable.$converter0; + map['status'] = Variable(converter.mapToSql(status.value)); + } + if (type.present) { + map['type'] = Variable(type.value); + } + if (reactionCounts.present) { + final converter = $_MessagesTable.$converter1; + map['reaction_counts'] = + Variable(converter.mapToSql(reactionCounts.value)); + } + if (reactionScores.present) { + final converter = $_MessagesTable.$converter2; + map['reaction_scores'] = + Variable(converter.mapToSql(reactionScores.value)); + } + if (parentId.present) { + map['parent_id'] = Variable(parentId.value); + } + if (quotedMessageId.present) { + map['quoted_message_id'] = Variable(quotedMessageId.value); + } + if (replyCount.present) { + map['reply_count'] = Variable(replyCount.value); + } + if (showInChannel.present) { + map['show_in_channel'] = Variable(showInChannel.value); + } + if (shadowed.present) { + map['shadowed'] = Variable(shadowed.value); + } + if (command.present) { + map['command'] = Variable(command.value); + } + if (createdAt.present) { + map['created_at'] = Variable(createdAt.value); + } + if (updatedAt.present) { + map['updated_at'] = Variable(updatedAt.value); + } + if (deletedAt.present) { + map['deleted_at'] = Variable(deletedAt.value); + } + if (userId.present) { + map['user_id'] = Variable(userId.value); + } + if (channelCid.present) { + map['channel_cid'] = Variable(channelCid.value); + } + if (extraData.present) { + final converter = $_MessagesTable.$converter3; + map['extra_data'] = Variable(converter.mapToSql(extraData.value)); + } + return map; + } + + @override + String toString() { + return (StringBuffer('_MessagesCompanion(') + ..write('id: $id, ') + ..write('messageText: $messageText, ') + ..write('attachmentJson: $attachmentJson, ') + ..write('status: $status, ') + ..write('type: $type, ') + ..write('reactionCounts: $reactionCounts, ') + ..write('reactionScores: $reactionScores, ') + ..write('parentId: $parentId, ') + ..write('quotedMessageId: $quotedMessageId, ') + ..write('replyCount: $replyCount, ') + ..write('showInChannel: $showInChannel, ') + ..write('shadowed: $shadowed, ') + ..write('command: $command, ') + ..write('createdAt: $createdAt, ') + ..write('updatedAt: $updatedAt, ') + ..write('deletedAt: $deletedAt, ') + ..write('userId: $userId, ') + ..write('channelCid: $channelCid, ') + ..write('extraData: $extraData') + ..write(')')) + .toString(); + } +} + +class $_MessagesTable extends _Messages + with TableInfo<$_MessagesTable, _Message> { + final GeneratedDatabase _db; + final String _alias; + $_MessagesTable(this._db, [this._alias]); + final VerificationMeta _idMeta = const VerificationMeta('id'); + GeneratedTextColumn _id; + @override + GeneratedTextColumn get id => _id ??= _constructId(); + GeneratedTextColumn _constructId() { + return GeneratedTextColumn( + 'id', + $tableName, + false, + ); + } + + final VerificationMeta _messageTextMeta = + const VerificationMeta('messageText'); + GeneratedTextColumn _messageText; + @override + GeneratedTextColumn get messageText => + _messageText ??= _constructMessageText(); + GeneratedTextColumn _constructMessageText() { + return GeneratedTextColumn( + 'message_text', + $tableName, + true, + ); + } + + final VerificationMeta _attachmentJsonMeta = + const VerificationMeta('attachmentJson'); + GeneratedTextColumn _attachmentJson; + @override + GeneratedTextColumn get attachmentJson => + _attachmentJson ??= _constructAttachmentJson(); + GeneratedTextColumn _constructAttachmentJson() { + return GeneratedTextColumn( + 'attachment_json', + $tableName, + true, + ); + } + + final VerificationMeta _statusMeta = const VerificationMeta('status'); + GeneratedIntColumn _status; + @override + GeneratedIntColumn get status => _status ??= _constructStatus(); + GeneratedIntColumn _constructStatus() { + return GeneratedIntColumn( + 'status', + $tableName, + true, + ); + } + + final VerificationMeta _typeMeta = const VerificationMeta('type'); + GeneratedTextColumn _type; + @override + GeneratedTextColumn get type => _type ??= _constructType(); + GeneratedTextColumn _constructType() { + return GeneratedTextColumn( + 'type', + $tableName, + true, + ); + } + + final VerificationMeta _reactionCountsMeta = + const VerificationMeta('reactionCounts'); + GeneratedTextColumn _reactionCounts; + @override + GeneratedTextColumn get reactionCounts => + _reactionCounts ??= _constructReactionCounts(); + GeneratedTextColumn _constructReactionCounts() { + return GeneratedTextColumn( + 'reaction_counts', + $tableName, + true, + ); + } + + final VerificationMeta _reactionScoresMeta = + const VerificationMeta('reactionScores'); + GeneratedTextColumn _reactionScores; + @override + GeneratedTextColumn get reactionScores => + _reactionScores ??= _constructReactionScores(); + GeneratedTextColumn _constructReactionScores() { + return GeneratedTextColumn( + 'reaction_scores', + $tableName, + true, + ); + } + + final VerificationMeta _parentIdMeta = const VerificationMeta('parentId'); + GeneratedTextColumn _parentId; + @override + GeneratedTextColumn get parentId => _parentId ??= _constructParentId(); + GeneratedTextColumn _constructParentId() { + return GeneratedTextColumn( + 'parent_id', + $tableName, + true, + ); + } + + final VerificationMeta _quotedMessageIdMeta = + const VerificationMeta('quotedMessageId'); + GeneratedTextColumn _quotedMessageId; + @override + GeneratedTextColumn get quotedMessageId => + _quotedMessageId ??= _constructQuotedMessageId(); + GeneratedTextColumn _constructQuotedMessageId() { + return GeneratedTextColumn( + 'quoted_message_id', + $tableName, + true, + ); + } + + final VerificationMeta _replyCountMeta = const VerificationMeta('replyCount'); + GeneratedIntColumn _replyCount; + @override + GeneratedIntColumn get replyCount => _replyCount ??= _constructReplyCount(); + GeneratedIntColumn _constructReplyCount() { + return GeneratedIntColumn( + 'reply_count', + $tableName, + true, + ); + } + + final VerificationMeta _showInChannelMeta = + const VerificationMeta('showInChannel'); + GeneratedBoolColumn _showInChannel; + @override + GeneratedBoolColumn get showInChannel => + _showInChannel ??= _constructShowInChannel(); + GeneratedBoolColumn _constructShowInChannel() { + return GeneratedBoolColumn( + 'show_in_channel', + $tableName, + true, + ); + } + + final VerificationMeta _shadowedMeta = const VerificationMeta('shadowed'); + GeneratedBoolColumn _shadowed; + @override + GeneratedBoolColumn get shadowed => _shadowed ??= _constructShadowed(); + GeneratedBoolColumn _constructShadowed() { + return GeneratedBoolColumn( + 'shadowed', + $tableName, + true, + ); + } + + final VerificationMeta _commandMeta = const VerificationMeta('command'); + GeneratedTextColumn _command; + @override + GeneratedTextColumn get command => _command ??= _constructCommand(); + GeneratedTextColumn _constructCommand() { + return GeneratedTextColumn( + 'command', + $tableName, + true, + ); + } + + final VerificationMeta _createdAtMeta = const VerificationMeta('createdAt'); + GeneratedDateTimeColumn _createdAt; + @override + GeneratedDateTimeColumn get createdAt => _createdAt ??= _constructCreatedAt(); + GeneratedDateTimeColumn _constructCreatedAt() { + return GeneratedDateTimeColumn( + 'created_at', + $tableName, + false, + ); + } + + final VerificationMeta _updatedAtMeta = const VerificationMeta('updatedAt'); + GeneratedDateTimeColumn _updatedAt; + @override + GeneratedDateTimeColumn get updatedAt => _updatedAt ??= _constructUpdatedAt(); + GeneratedDateTimeColumn _constructUpdatedAt() { + return GeneratedDateTimeColumn( + 'updated_at', + $tableName, + true, + ); + } + + final VerificationMeta _deletedAtMeta = const VerificationMeta('deletedAt'); + GeneratedDateTimeColumn _deletedAt; + @override + GeneratedDateTimeColumn get deletedAt => _deletedAt ??= _constructDeletedAt(); + GeneratedDateTimeColumn _constructDeletedAt() { + return GeneratedDateTimeColumn( + 'deleted_at', + $tableName, + true, + ); + } + + final VerificationMeta _userIdMeta = const VerificationMeta('userId'); + GeneratedTextColumn _userId; + @override + GeneratedTextColumn get userId => _userId ??= _constructUserId(); + GeneratedTextColumn _constructUserId() { + return GeneratedTextColumn( + 'user_id', + $tableName, + true, + ); + } + + final VerificationMeta _channelCidMeta = const VerificationMeta('channelCid'); + GeneratedTextColumn _channelCid; + @override + GeneratedTextColumn get channelCid => _channelCid ??= _constructChannelCid(); + GeneratedTextColumn _constructChannelCid() { + return GeneratedTextColumn( + 'channel_cid', + $tableName, + true, + ); + } + + final VerificationMeta _extraDataMeta = const VerificationMeta('extraData'); + GeneratedTextColumn _extraData; + @override + GeneratedTextColumn get extraData => _extraData ??= _constructExtraData(); + GeneratedTextColumn _constructExtraData() { + return GeneratedTextColumn( + 'extra_data', + $tableName, + true, + ); + } + + @override + List get $columns => [ + id, + messageText, + attachmentJson, + status, + type, + reactionCounts, + reactionScores, + parentId, + quotedMessageId, + replyCount, + showInChannel, + shadowed, + command, + createdAt, + updatedAt, + deletedAt, + userId, + channelCid, + extraData + ]; + @override + $_MessagesTable get asDslTable => this; + @override + String get $tableName => _alias ?? 'messages'; + @override + final String actualTableName = 'messages'; + @override + VerificationContext validateIntegrity(Insertable<_Message> instance, + {bool isInserting = false}) { + final context = VerificationContext(); + final data = instance.toColumns(true); + if (data.containsKey('id')) { + context.handle(_idMeta, id.isAcceptableOrUnknown(data['id'], _idMeta)); + } else if (isInserting) { + context.missing(_idMeta); + } + if (data.containsKey('message_text')) { + context.handle( + _messageTextMeta, + messageText.isAcceptableOrUnknown( + data['message_text'], _messageTextMeta)); + } + if (data.containsKey('attachment_json')) { + context.handle( + _attachmentJsonMeta, + attachmentJson.isAcceptableOrUnknown( + data['attachment_json'], _attachmentJsonMeta)); + } + context.handle(_statusMeta, const VerificationResult.success()); + if (data.containsKey('type')) { + context.handle( + _typeMeta, type.isAcceptableOrUnknown(data['type'], _typeMeta)); + } + context.handle(_reactionCountsMeta, const VerificationResult.success()); + context.handle(_reactionScoresMeta, const VerificationResult.success()); + if (data.containsKey('parent_id')) { + context.handle(_parentIdMeta, + parentId.isAcceptableOrUnknown(data['parent_id'], _parentIdMeta)); + } + if (data.containsKey('quoted_message_id')) { + context.handle( + _quotedMessageIdMeta, + quotedMessageId.isAcceptableOrUnknown( + data['quoted_message_id'], _quotedMessageIdMeta)); + } + if (data.containsKey('reply_count')) { + context.handle( + _replyCountMeta, + replyCount.isAcceptableOrUnknown( + data['reply_count'], _replyCountMeta)); + } + if (data.containsKey('show_in_channel')) { + context.handle( + _showInChannelMeta, + showInChannel.isAcceptableOrUnknown( + data['show_in_channel'], _showInChannelMeta)); + } + if (data.containsKey('shadowed')) { + context.handle(_shadowedMeta, + shadowed.isAcceptableOrUnknown(data['shadowed'], _shadowedMeta)); + } + if (data.containsKey('command')) { + context.handle(_commandMeta, + command.isAcceptableOrUnknown(data['command'], _commandMeta)); + } + if (data.containsKey('created_at')) { + context.handle(_createdAtMeta, + createdAt.isAcceptableOrUnknown(data['created_at'], _createdAtMeta)); + } else if (isInserting) { + context.missing(_createdAtMeta); + } + if (data.containsKey('updated_at')) { + context.handle(_updatedAtMeta, + updatedAt.isAcceptableOrUnknown(data['updated_at'], _updatedAtMeta)); + } + if (data.containsKey('deleted_at')) { + context.handle(_deletedAtMeta, + deletedAt.isAcceptableOrUnknown(data['deleted_at'], _deletedAtMeta)); + } + if (data.containsKey('user_id')) { + context.handle(_userIdMeta, + userId.isAcceptableOrUnknown(data['user_id'], _userIdMeta)); + } + if (data.containsKey('channel_cid')) { + context.handle( + _channelCidMeta, + channelCid.isAcceptableOrUnknown( + data['channel_cid'], _channelCidMeta)); + } + context.handle(_extraDataMeta, const VerificationResult.success()); + return context; + } + + @override + Set get $primaryKey => {id}; + @override + _Message map(Map data, {String tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : null; + return _Message.fromData(data, _db, prefix: effectivePrefix); + } + + @override + $_MessagesTable createAlias(String alias) { + return $_MessagesTable(_db, alias); + } + + static TypeConverter $converter0 = + _MessageSendingStatusConverter(); + static TypeConverter, String> $converter1 = + _ExtraDataConverter(); + static TypeConverter, String> $converter2 = + _ExtraDataConverter(); + static TypeConverter, String> $converter3 = + _ExtraDataConverter(); +} + +class _Read extends DataClass implements Insertable<_Read> { + final DateTime lastRead; + final String userId; + final String channelCid; + final int unreadMessages; + _Read( + {@required this.lastRead, + @required this.userId, + @required this.channelCid, + this.unreadMessages}); + factory _Read.fromData(Map data, GeneratedDatabase db, + {String prefix}) { + final effectivePrefix = prefix ?? ''; + final dateTimeType = db.typeSystem.forDartType(); + final stringType = db.typeSystem.forDartType(); + final intType = db.typeSystem.forDartType(); + return _Read( + lastRead: dateTimeType + .mapFromDatabaseResponse(data['${effectivePrefix}last_read']), + userId: + stringType.mapFromDatabaseResponse(data['${effectivePrefix}user_id']), + channelCid: stringType + .mapFromDatabaseResponse(data['${effectivePrefix}channel_cid']), + unreadMessages: intType + .mapFromDatabaseResponse(data['${effectivePrefix}unread_messages']), + ); + } + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (!nullToAbsent || lastRead != null) { + map['last_read'] = Variable(lastRead); + } + if (!nullToAbsent || userId != null) { + map['user_id'] = Variable(userId); + } + if (!nullToAbsent || channelCid != null) { + map['channel_cid'] = Variable(channelCid); + } + if (!nullToAbsent || unreadMessages != null) { + map['unread_messages'] = Variable(unreadMessages); + } + return map; + } + + _ReadsCompanion toCompanion(bool nullToAbsent) { + return _ReadsCompanion( + lastRead: lastRead == null && nullToAbsent + ? const Value.absent() + : Value(lastRead), + userId: + userId == null && nullToAbsent ? const Value.absent() : Value(userId), + channelCid: channelCid == null && nullToAbsent + ? const Value.absent() + : Value(channelCid), + unreadMessages: unreadMessages == null && nullToAbsent + ? const Value.absent() + : Value(unreadMessages), + ); + } + + factory _Read.fromJson(Map json, + {ValueSerializer serializer}) { + serializer ??= moorRuntimeOptions.defaultSerializer; + return _Read( + lastRead: serializer.fromJson(json['lastRead']), + userId: serializer.fromJson(json['userId']), + channelCid: serializer.fromJson(json['channelCid']), + unreadMessages: serializer.fromJson(json['unreadMessages']), + ); + } + @override + Map toJson({ValueSerializer serializer}) { + serializer ??= moorRuntimeOptions.defaultSerializer; + return { + 'lastRead': serializer.toJson(lastRead), + 'userId': serializer.toJson(userId), + 'channelCid': serializer.toJson(channelCid), + 'unreadMessages': serializer.toJson(unreadMessages), + }; + } + + _Read copyWith( + {DateTime lastRead, + String userId, + String channelCid, + int unreadMessages}) => + _Read( + lastRead: lastRead ?? this.lastRead, + userId: userId ?? this.userId, + channelCid: channelCid ?? this.channelCid, + unreadMessages: unreadMessages ?? this.unreadMessages, + ); + @override + String toString() { + return (StringBuffer('_Read(') + ..write('lastRead: $lastRead, ') + ..write('userId: $userId, ') + ..write('channelCid: $channelCid, ') + ..write('unreadMessages: $unreadMessages') + ..write(')')) + .toString(); + } + + @override + int get hashCode => $mrjf($mrjc( + lastRead.hashCode, + $mrjc(userId.hashCode, + $mrjc(channelCid.hashCode, unreadMessages.hashCode)))); + @override + bool operator ==(dynamic other) => + identical(this, other) || + (other is _Read && + other.lastRead == this.lastRead && + other.userId == this.userId && + other.channelCid == this.channelCid && + other.unreadMessages == this.unreadMessages); +} + +class _ReadsCompanion extends UpdateCompanion<_Read> { + final Value lastRead; + final Value userId; + final Value channelCid; + final Value unreadMessages; + const _ReadsCompanion({ + this.lastRead = const Value.absent(), + this.userId = const Value.absent(), + this.channelCid = const Value.absent(), + this.unreadMessages = const Value.absent(), + }); + _ReadsCompanion.insert({ + @required DateTime lastRead, + @required String userId, + @required String channelCid, + this.unreadMessages = const Value.absent(), + }) : lastRead = Value(lastRead), + userId = Value(userId), + channelCid = Value(channelCid); + static Insertable<_Read> custom({ + Expression lastRead, + Expression userId, + Expression channelCid, + Expression unreadMessages, + }) { + return RawValuesInsertable({ + if (lastRead != null) 'last_read': lastRead, + if (userId != null) 'user_id': userId, + if (channelCid != null) 'channel_cid': channelCid, + if (unreadMessages != null) 'unread_messages': unreadMessages, + }); + } + + _ReadsCompanion copyWith( + {Value lastRead, + Value userId, + Value channelCid, + Value unreadMessages}) { + return _ReadsCompanion( + lastRead: lastRead ?? this.lastRead, + userId: userId ?? this.userId, + channelCid: channelCid ?? this.channelCid, + unreadMessages: unreadMessages ?? this.unreadMessages, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (lastRead.present) { + map['last_read'] = Variable(lastRead.value); + } + if (userId.present) { + map['user_id'] = Variable(userId.value); + } + if (channelCid.present) { + map['channel_cid'] = Variable(channelCid.value); + } + if (unreadMessages.present) { + map['unread_messages'] = Variable(unreadMessages.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('_ReadsCompanion(') + ..write('lastRead: $lastRead, ') + ..write('userId: $userId, ') + ..write('channelCid: $channelCid, ') + ..write('unreadMessages: $unreadMessages') + ..write(')')) + .toString(); + } +} + +class $_ReadsTable extends _Reads with TableInfo<$_ReadsTable, _Read> { + final GeneratedDatabase _db; + final String _alias; + $_ReadsTable(this._db, [this._alias]); + final VerificationMeta _lastReadMeta = const VerificationMeta('lastRead'); + GeneratedDateTimeColumn _lastRead; + @override + GeneratedDateTimeColumn get lastRead => _lastRead ??= _constructLastRead(); + GeneratedDateTimeColumn _constructLastRead() { + return GeneratedDateTimeColumn( + 'last_read', + $tableName, + false, + ); + } + + final VerificationMeta _userIdMeta = const VerificationMeta('userId'); + GeneratedTextColumn _userId; + @override + GeneratedTextColumn get userId => _userId ??= _constructUserId(); + GeneratedTextColumn _constructUserId() { + return GeneratedTextColumn( + 'user_id', + $tableName, + false, + ); + } + + final VerificationMeta _channelCidMeta = const VerificationMeta('channelCid'); + GeneratedTextColumn _channelCid; + @override + GeneratedTextColumn get channelCid => _channelCid ??= _constructChannelCid(); + GeneratedTextColumn _constructChannelCid() { + return GeneratedTextColumn( + 'channel_cid', + $tableName, + false, + ); + } + + final VerificationMeta _unreadMessagesMeta = + const VerificationMeta('unreadMessages'); + GeneratedIntColumn _unreadMessages; + @override + GeneratedIntColumn get unreadMessages => + _unreadMessages ??= _constructUnreadMessages(); + GeneratedIntColumn _constructUnreadMessages() { + return GeneratedIntColumn( + 'unread_messages', + $tableName, + true, + ); + } + + @override + List get $columns => + [lastRead, userId, channelCid, unreadMessages]; + @override + $_ReadsTable get asDslTable => this; + @override + String get $tableName => _alias ?? 'reads'; + @override + final String actualTableName = 'reads'; + @override + VerificationContext validateIntegrity(Insertable<_Read> instance, + {bool isInserting = false}) { + final context = VerificationContext(); + final data = instance.toColumns(true); + if (data.containsKey('last_read')) { + context.handle(_lastReadMeta, + lastRead.isAcceptableOrUnknown(data['last_read'], _lastReadMeta)); + } else if (isInserting) { + context.missing(_lastReadMeta); + } + if (data.containsKey('user_id')) { + context.handle(_userIdMeta, + userId.isAcceptableOrUnknown(data['user_id'], _userIdMeta)); + } else if (isInserting) { + context.missing(_userIdMeta); + } + if (data.containsKey('channel_cid')) { + context.handle( + _channelCidMeta, + channelCid.isAcceptableOrUnknown( + data['channel_cid'], _channelCidMeta)); + } else if (isInserting) { + context.missing(_channelCidMeta); + } + if (data.containsKey('unread_messages')) { + context.handle( + _unreadMessagesMeta, + unreadMessages.isAcceptableOrUnknown( + data['unread_messages'], _unreadMessagesMeta)); + } + return context; + } + + @override + Set get $primaryKey => {userId, channelCid}; + @override + _Read map(Map data, {String tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : null; + return _Read.fromData(data, _db, prefix: effectivePrefix); + } + + @override + $_ReadsTable createAlias(String alias) { + return $_ReadsTable(_db, alias); + } +} + +class _Member extends DataClass implements Insertable<_Member> { + final String userId; + final String channelCid; + final String role; + final DateTime inviteAcceptedAt; + final DateTime inviteRejectedAt; + final bool invited; + final bool banned; + final bool shadowBanned; + final bool isModerator; + final DateTime createdAt; + final DateTime updatedAt; + _Member( + {@required this.userId, + @required this.channelCid, + this.role, + this.inviteAcceptedAt, + this.inviteRejectedAt, + this.invited, + this.banned, + this.shadowBanned, + this.isModerator, + @required this.createdAt, + this.updatedAt}); + factory _Member.fromData(Map data, GeneratedDatabase db, + {String prefix}) { + final effectivePrefix = prefix ?? ''; + final stringType = db.typeSystem.forDartType(); + final dateTimeType = db.typeSystem.forDartType(); + final boolType = db.typeSystem.forDartType(); + return _Member( + userId: + stringType.mapFromDatabaseResponse(data['${effectivePrefix}user_id']), + channelCid: stringType + .mapFromDatabaseResponse(data['${effectivePrefix}channel_cid']), + role: stringType.mapFromDatabaseResponse(data['${effectivePrefix}role']), + inviteAcceptedAt: dateTimeType.mapFromDatabaseResponse( + data['${effectivePrefix}invite_accepted_at']), + inviteRejectedAt: dateTimeType.mapFromDatabaseResponse( + data['${effectivePrefix}invite_rejected_at']), + invited: + boolType.mapFromDatabaseResponse(data['${effectivePrefix}invited']), + banned: + boolType.mapFromDatabaseResponse(data['${effectivePrefix}banned']), + shadowBanned: boolType + .mapFromDatabaseResponse(data['${effectivePrefix}shadow_banned']), + isModerator: boolType + .mapFromDatabaseResponse(data['${effectivePrefix}is_moderator']), + createdAt: dateTimeType + .mapFromDatabaseResponse(data['${effectivePrefix}created_at']), + updatedAt: dateTimeType + .mapFromDatabaseResponse(data['${effectivePrefix}updated_at']), + ); + } + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (!nullToAbsent || userId != null) { + map['user_id'] = Variable(userId); + } + if (!nullToAbsent || channelCid != null) { + map['channel_cid'] = Variable(channelCid); + } + if (!nullToAbsent || role != null) { + map['role'] = Variable(role); + } + if (!nullToAbsent || inviteAcceptedAt != null) { + map['invite_accepted_at'] = Variable(inviteAcceptedAt); + } + if (!nullToAbsent || inviteRejectedAt != null) { + map['invite_rejected_at'] = Variable(inviteRejectedAt); + } + if (!nullToAbsent || invited != null) { + map['invited'] = Variable(invited); + } + if (!nullToAbsent || banned != null) { + map['banned'] = Variable(banned); + } + if (!nullToAbsent || shadowBanned != null) { + map['shadow_banned'] = Variable(shadowBanned); + } + if (!nullToAbsent || isModerator != null) { + map['is_moderator'] = Variable(isModerator); + } + if (!nullToAbsent || createdAt != null) { + map['created_at'] = Variable(createdAt); + } + if (!nullToAbsent || updatedAt != null) { + map['updated_at'] = Variable(updatedAt); + } + return map; + } + + _MembersCompanion toCompanion(bool nullToAbsent) { + return _MembersCompanion( + userId: + userId == null && nullToAbsent ? const Value.absent() : Value(userId), + channelCid: channelCid == null && nullToAbsent + ? const Value.absent() + : Value(channelCid), + role: role == null && nullToAbsent ? const Value.absent() : Value(role), + inviteAcceptedAt: inviteAcceptedAt == null && nullToAbsent + ? const Value.absent() + : Value(inviteAcceptedAt), + inviteRejectedAt: inviteRejectedAt == null && nullToAbsent + ? const Value.absent() + : Value(inviteRejectedAt), + invited: invited == null && nullToAbsent + ? const Value.absent() + : Value(invited), + banned: + banned == null && nullToAbsent ? const Value.absent() : Value(banned), + shadowBanned: shadowBanned == null && nullToAbsent + ? const Value.absent() + : Value(shadowBanned), + isModerator: isModerator == null && nullToAbsent + ? const Value.absent() + : Value(isModerator), + createdAt: createdAt == null && nullToAbsent + ? const Value.absent() + : Value(createdAt), + updatedAt: updatedAt == null && nullToAbsent + ? const Value.absent() + : Value(updatedAt), + ); + } + + factory _Member.fromJson(Map json, + {ValueSerializer serializer}) { + serializer ??= moorRuntimeOptions.defaultSerializer; + return _Member( + userId: serializer.fromJson(json['userId']), + channelCid: serializer.fromJson(json['channelCid']), + role: serializer.fromJson(json['role']), + inviteAcceptedAt: serializer.fromJson(json['inviteAcceptedAt']), + inviteRejectedAt: serializer.fromJson(json['inviteRejectedAt']), + invited: serializer.fromJson(json['invited']), + banned: serializer.fromJson(json['banned']), + shadowBanned: serializer.fromJson(json['shadowBanned']), + isModerator: serializer.fromJson(json['isModerator']), + createdAt: serializer.fromJson(json['createdAt']), + updatedAt: serializer.fromJson(json['updatedAt']), + ); + } + @override + Map toJson({ValueSerializer serializer}) { + serializer ??= moorRuntimeOptions.defaultSerializer; + return { + 'userId': serializer.toJson(userId), + 'channelCid': serializer.toJson(channelCid), + 'role': serializer.toJson(role), + 'inviteAcceptedAt': serializer.toJson(inviteAcceptedAt), + 'inviteRejectedAt': serializer.toJson(inviteRejectedAt), + 'invited': serializer.toJson(invited), + 'banned': serializer.toJson(banned), + 'shadowBanned': serializer.toJson(shadowBanned), + 'isModerator': serializer.toJson(isModerator), + 'createdAt': serializer.toJson(createdAt), + 'updatedAt': serializer.toJson(updatedAt), + }; + } + + _Member copyWith( + {String userId, + String channelCid, + String role, + DateTime inviteAcceptedAt, + DateTime inviteRejectedAt, + bool invited, + bool banned, + bool shadowBanned, + bool isModerator, + DateTime createdAt, + DateTime updatedAt}) => + _Member( + userId: userId ?? this.userId, + channelCid: channelCid ?? this.channelCid, + role: role ?? this.role, + inviteAcceptedAt: inviteAcceptedAt ?? this.inviteAcceptedAt, + inviteRejectedAt: inviteRejectedAt ?? this.inviteRejectedAt, + invited: invited ?? this.invited, + banned: banned ?? this.banned, + shadowBanned: shadowBanned ?? this.shadowBanned, + isModerator: isModerator ?? this.isModerator, + createdAt: createdAt ?? this.createdAt, + updatedAt: updatedAt ?? this.updatedAt, + ); + @override + String toString() { + return (StringBuffer('_Member(') + ..write('userId: $userId, ') + ..write('channelCid: $channelCid, ') + ..write('role: $role, ') + ..write('inviteAcceptedAt: $inviteAcceptedAt, ') + ..write('inviteRejectedAt: $inviteRejectedAt, ') + ..write('invited: $invited, ') + ..write('banned: $banned, ') + ..write('shadowBanned: $shadowBanned, ') + ..write('isModerator: $isModerator, ') + ..write('createdAt: $createdAt, ') + ..write('updatedAt: $updatedAt') + ..write(')')) + .toString(); + } + + @override + int get hashCode => $mrjf($mrjc( + userId.hashCode, + $mrjc( + channelCid.hashCode, + $mrjc( + role.hashCode, + $mrjc( + inviteAcceptedAt.hashCode, + $mrjc( + inviteRejectedAt.hashCode, + $mrjc( + invited.hashCode, + $mrjc( + banned.hashCode, + $mrjc( + shadowBanned.hashCode, + $mrjc( + isModerator.hashCode, + $mrjc(createdAt.hashCode, + updatedAt.hashCode))))))))))); + @override + bool operator ==(dynamic other) => + identical(this, other) || + (other is _Member && + other.userId == this.userId && + other.channelCid == this.channelCid && + other.role == this.role && + other.inviteAcceptedAt == this.inviteAcceptedAt && + other.inviteRejectedAt == this.inviteRejectedAt && + other.invited == this.invited && + other.banned == this.banned && + other.shadowBanned == this.shadowBanned && + other.isModerator == this.isModerator && + other.createdAt == this.createdAt && + other.updatedAt == this.updatedAt); +} + +class _MembersCompanion extends UpdateCompanion<_Member> { + final Value userId; + final Value channelCid; + final Value role; + final Value inviteAcceptedAt; + final Value inviteRejectedAt; + final Value invited; + final Value banned; + final Value shadowBanned; + final Value isModerator; + final Value createdAt; + final Value updatedAt; + const _MembersCompanion({ + this.userId = const Value.absent(), + this.channelCid = const Value.absent(), + this.role = const Value.absent(), + this.inviteAcceptedAt = const Value.absent(), + this.inviteRejectedAt = const Value.absent(), + this.invited = const Value.absent(), + this.banned = const Value.absent(), + this.shadowBanned = const Value.absent(), + this.isModerator = const Value.absent(), + this.createdAt = const Value.absent(), + this.updatedAt = const Value.absent(), + }); + _MembersCompanion.insert({ + @required String userId, + @required String channelCid, + this.role = const Value.absent(), + this.inviteAcceptedAt = const Value.absent(), + this.inviteRejectedAt = const Value.absent(), + this.invited = const Value.absent(), + this.banned = const Value.absent(), + this.shadowBanned = const Value.absent(), + this.isModerator = const Value.absent(), + @required DateTime createdAt, + this.updatedAt = const Value.absent(), + }) : userId = Value(userId), + channelCid = Value(channelCid), + createdAt = Value(createdAt); + static Insertable<_Member> custom({ + Expression userId, + Expression channelCid, + Expression role, + Expression inviteAcceptedAt, + Expression inviteRejectedAt, + Expression invited, + Expression banned, + Expression shadowBanned, + Expression isModerator, + Expression createdAt, + Expression updatedAt, + }) { + return RawValuesInsertable({ + if (userId != null) 'user_id': userId, + if (channelCid != null) 'channel_cid': channelCid, + if (role != null) 'role': role, + if (inviteAcceptedAt != null) 'invite_accepted_at': inviteAcceptedAt, + if (inviteRejectedAt != null) 'invite_rejected_at': inviteRejectedAt, + if (invited != null) 'invited': invited, + if (banned != null) 'banned': banned, + if (shadowBanned != null) 'shadow_banned': shadowBanned, + if (isModerator != null) 'is_moderator': isModerator, + if (createdAt != null) 'created_at': createdAt, + if (updatedAt != null) 'updated_at': updatedAt, + }); + } + + _MembersCompanion copyWith( + {Value userId, + Value channelCid, + Value role, + Value inviteAcceptedAt, + Value inviteRejectedAt, + Value invited, + Value banned, + Value shadowBanned, + Value isModerator, + Value createdAt, + Value updatedAt}) { + return _MembersCompanion( + userId: userId ?? this.userId, + channelCid: channelCid ?? this.channelCid, + role: role ?? this.role, + inviteAcceptedAt: inviteAcceptedAt ?? this.inviteAcceptedAt, + inviteRejectedAt: inviteRejectedAt ?? this.inviteRejectedAt, + invited: invited ?? this.invited, + banned: banned ?? this.banned, + shadowBanned: shadowBanned ?? this.shadowBanned, + isModerator: isModerator ?? this.isModerator, + createdAt: createdAt ?? this.createdAt, + updatedAt: updatedAt ?? this.updatedAt, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (userId.present) { + map['user_id'] = Variable(userId.value); + } + if (channelCid.present) { + map['channel_cid'] = Variable(channelCid.value); + } + if (role.present) { + map['role'] = Variable(role.value); + } + if (inviteAcceptedAt.present) { + map['invite_accepted_at'] = Variable(inviteAcceptedAt.value); + } + if (inviteRejectedAt.present) { + map['invite_rejected_at'] = Variable(inviteRejectedAt.value); + } + if (invited.present) { + map['invited'] = Variable(invited.value); + } + if (banned.present) { + map['banned'] = Variable(banned.value); + } + if (shadowBanned.present) { + map['shadow_banned'] = Variable(shadowBanned.value); + } + if (isModerator.present) { + map['is_moderator'] = Variable(isModerator.value); + } + if (createdAt.present) { + map['created_at'] = Variable(createdAt.value); + } + if (updatedAt.present) { + map['updated_at'] = Variable(updatedAt.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('_MembersCompanion(') + ..write('userId: $userId, ') + ..write('channelCid: $channelCid, ') + ..write('role: $role, ') + ..write('inviteAcceptedAt: $inviteAcceptedAt, ') + ..write('inviteRejectedAt: $inviteRejectedAt, ') + ..write('invited: $invited, ') + ..write('banned: $banned, ') + ..write('shadowBanned: $shadowBanned, ') + ..write('isModerator: $isModerator, ') + ..write('createdAt: $createdAt, ') + ..write('updatedAt: $updatedAt') + ..write(')')) + .toString(); + } +} + +class $_MembersTable extends _Members with TableInfo<$_MembersTable, _Member> { + final GeneratedDatabase _db; + final String _alias; + $_MembersTable(this._db, [this._alias]); + final VerificationMeta _userIdMeta = const VerificationMeta('userId'); + GeneratedTextColumn _userId; + @override + GeneratedTextColumn get userId => _userId ??= _constructUserId(); + GeneratedTextColumn _constructUserId() { + return GeneratedTextColumn( + 'user_id', + $tableName, + false, + ); + } + + final VerificationMeta _channelCidMeta = const VerificationMeta('channelCid'); + GeneratedTextColumn _channelCid; + @override + GeneratedTextColumn get channelCid => _channelCid ??= _constructChannelCid(); + GeneratedTextColumn _constructChannelCid() { + return GeneratedTextColumn( + 'channel_cid', + $tableName, + false, + ); + } + + final VerificationMeta _roleMeta = const VerificationMeta('role'); + GeneratedTextColumn _role; + @override + GeneratedTextColumn get role => _role ??= _constructRole(); + GeneratedTextColumn _constructRole() { + return GeneratedTextColumn( + 'role', + $tableName, + true, + ); + } + + final VerificationMeta _inviteAcceptedAtMeta = + const VerificationMeta('inviteAcceptedAt'); + GeneratedDateTimeColumn _inviteAcceptedAt; + @override + GeneratedDateTimeColumn get inviteAcceptedAt => + _inviteAcceptedAt ??= _constructInviteAcceptedAt(); + GeneratedDateTimeColumn _constructInviteAcceptedAt() { + return GeneratedDateTimeColumn( + 'invite_accepted_at', + $tableName, + true, + ); + } + + final VerificationMeta _inviteRejectedAtMeta = + const VerificationMeta('inviteRejectedAt'); + GeneratedDateTimeColumn _inviteRejectedAt; + @override + GeneratedDateTimeColumn get inviteRejectedAt => + _inviteRejectedAt ??= _constructInviteRejectedAt(); + GeneratedDateTimeColumn _constructInviteRejectedAt() { + return GeneratedDateTimeColumn( + 'invite_rejected_at', + $tableName, + true, + ); + } + + final VerificationMeta _invitedMeta = const VerificationMeta('invited'); + GeneratedBoolColumn _invited; + @override + GeneratedBoolColumn get invited => _invited ??= _constructInvited(); + GeneratedBoolColumn _constructInvited() { + return GeneratedBoolColumn( + 'invited', + $tableName, + true, + ); + } + + final VerificationMeta _bannedMeta = const VerificationMeta('banned'); + GeneratedBoolColumn _banned; + @override + GeneratedBoolColumn get banned => _banned ??= _constructBanned(); + GeneratedBoolColumn _constructBanned() { + return GeneratedBoolColumn( + 'banned', + $tableName, + true, + ); + } + + final VerificationMeta _shadowBannedMeta = + const VerificationMeta('shadowBanned'); + GeneratedBoolColumn _shadowBanned; + @override + GeneratedBoolColumn get shadowBanned => + _shadowBanned ??= _constructShadowBanned(); + GeneratedBoolColumn _constructShadowBanned() { + return GeneratedBoolColumn( + 'shadow_banned', + $tableName, + true, + ); + } + + final VerificationMeta _isModeratorMeta = + const VerificationMeta('isModerator'); + GeneratedBoolColumn _isModerator; + @override + GeneratedBoolColumn get isModerator => + _isModerator ??= _constructIsModerator(); + GeneratedBoolColumn _constructIsModerator() { + return GeneratedBoolColumn( + 'is_moderator', + $tableName, + true, + ); + } + + final VerificationMeta _createdAtMeta = const VerificationMeta('createdAt'); + GeneratedDateTimeColumn _createdAt; + @override + GeneratedDateTimeColumn get createdAt => _createdAt ??= _constructCreatedAt(); + GeneratedDateTimeColumn _constructCreatedAt() { + return GeneratedDateTimeColumn( + 'created_at', + $tableName, + false, + ); + } + + final VerificationMeta _updatedAtMeta = const VerificationMeta('updatedAt'); + GeneratedDateTimeColumn _updatedAt; + @override + GeneratedDateTimeColumn get updatedAt => _updatedAt ??= _constructUpdatedAt(); + GeneratedDateTimeColumn _constructUpdatedAt() { + return GeneratedDateTimeColumn( + 'updated_at', + $tableName, + true, + ); + } + + @override + List get $columns => [ + userId, + channelCid, + role, + inviteAcceptedAt, + inviteRejectedAt, + invited, + banned, + shadowBanned, + isModerator, + createdAt, + updatedAt + ]; + @override + $_MembersTable get asDslTable => this; + @override + String get $tableName => _alias ?? 'members'; + @override + final String actualTableName = 'members'; + @override + VerificationContext validateIntegrity(Insertable<_Member> instance, + {bool isInserting = false}) { + final context = VerificationContext(); + final data = instance.toColumns(true); + if (data.containsKey('user_id')) { + context.handle(_userIdMeta, + userId.isAcceptableOrUnknown(data['user_id'], _userIdMeta)); + } else if (isInserting) { + context.missing(_userIdMeta); + } + if (data.containsKey('channel_cid')) { + context.handle( + _channelCidMeta, + channelCid.isAcceptableOrUnknown( + data['channel_cid'], _channelCidMeta)); + } else if (isInserting) { + context.missing(_channelCidMeta); + } + if (data.containsKey('role')) { + context.handle( + _roleMeta, role.isAcceptableOrUnknown(data['role'], _roleMeta)); + } + if (data.containsKey('invite_accepted_at')) { + context.handle( + _inviteAcceptedAtMeta, + inviteAcceptedAt.isAcceptableOrUnknown( + data['invite_accepted_at'], _inviteAcceptedAtMeta)); + } + if (data.containsKey('invite_rejected_at')) { + context.handle( + _inviteRejectedAtMeta, + inviteRejectedAt.isAcceptableOrUnknown( + data['invite_rejected_at'], _inviteRejectedAtMeta)); + } + if (data.containsKey('invited')) { + context.handle(_invitedMeta, + invited.isAcceptableOrUnknown(data['invited'], _invitedMeta)); + } + if (data.containsKey('banned')) { + context.handle(_bannedMeta, + banned.isAcceptableOrUnknown(data['banned'], _bannedMeta)); + } + if (data.containsKey('shadow_banned')) { + context.handle( + _shadowBannedMeta, + shadowBanned.isAcceptableOrUnknown( + data['shadow_banned'], _shadowBannedMeta)); + } + if (data.containsKey('is_moderator')) { + context.handle( + _isModeratorMeta, + isModerator.isAcceptableOrUnknown( + data['is_moderator'], _isModeratorMeta)); + } + if (data.containsKey('created_at')) { + context.handle(_createdAtMeta, + createdAt.isAcceptableOrUnknown(data['created_at'], _createdAtMeta)); + } else if (isInserting) { + context.missing(_createdAtMeta); + } + if (data.containsKey('updated_at')) { + context.handle(_updatedAtMeta, + updatedAt.isAcceptableOrUnknown(data['updated_at'], _updatedAtMeta)); + } + return context; + } + + @override + Set get $primaryKey => {userId, channelCid}; + @override + _Member map(Map data, {String tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : null; + return _Member.fromData(data, _db, prefix: effectivePrefix); + } + + @override + $_MembersTable createAlias(String alias) { + return $_MembersTable(_db, alias); + } +} + +class ChannelQuery extends DataClass implements Insertable { + final String queryHash; + final String channelCid; + ChannelQuery({@required this.queryHash, @required this.channelCid}); + factory ChannelQuery.fromData(Map data, GeneratedDatabase db, + {String prefix}) { + final effectivePrefix = prefix ?? ''; + final stringType = db.typeSystem.forDartType(); + return ChannelQuery( + queryHash: stringType + .mapFromDatabaseResponse(data['${effectivePrefix}query_hash']), + channelCid: stringType + .mapFromDatabaseResponse(data['${effectivePrefix}channel_cid']), + ); + } + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (!nullToAbsent || queryHash != null) { + map['query_hash'] = Variable(queryHash); + } + if (!nullToAbsent || channelCid != null) { + map['channel_cid'] = Variable(channelCid); + } + return map; + } + + _ChannelQueriesCompanion toCompanion(bool nullToAbsent) { + return _ChannelQueriesCompanion( + queryHash: queryHash == null && nullToAbsent + ? const Value.absent() + : Value(queryHash), + channelCid: channelCid == null && nullToAbsent + ? const Value.absent() + : Value(channelCid), + ); + } + + factory ChannelQuery.fromJson(Map json, + {ValueSerializer serializer}) { + serializer ??= moorRuntimeOptions.defaultSerializer; + return ChannelQuery( + queryHash: serializer.fromJson(json['queryHash']), + channelCid: serializer.fromJson(json['channelCid']), + ); + } + @override + Map toJson({ValueSerializer serializer}) { + serializer ??= moorRuntimeOptions.defaultSerializer; + return { + 'queryHash': serializer.toJson(queryHash), + 'channelCid': serializer.toJson(channelCid), + }; + } + + ChannelQuery copyWith({String queryHash, String channelCid}) => ChannelQuery( + queryHash: queryHash ?? this.queryHash, + channelCid: channelCid ?? this.channelCid, + ); + @override + String toString() { + return (StringBuffer('ChannelQuery(') + ..write('queryHash: $queryHash, ') + ..write('channelCid: $channelCid') + ..write(')')) + .toString(); + } + + @override + int get hashCode => $mrjf($mrjc(queryHash.hashCode, channelCid.hashCode)); + @override + bool operator ==(dynamic other) => + identical(this, other) || + (other is ChannelQuery && + other.queryHash == this.queryHash && + other.channelCid == this.channelCid); +} + +class _ChannelQueriesCompanion extends UpdateCompanion { + final Value queryHash; + final Value channelCid; + const _ChannelQueriesCompanion({ + this.queryHash = const Value.absent(), + this.channelCid = const Value.absent(), + }); + _ChannelQueriesCompanion.insert({ + @required String queryHash, + @required String channelCid, + }) : queryHash = Value(queryHash), + channelCid = Value(channelCid); + static Insertable custom({ + Expression queryHash, + Expression channelCid, + }) { + return RawValuesInsertable({ + if (queryHash != null) 'query_hash': queryHash, + if (channelCid != null) 'channel_cid': channelCid, + }); + } + + _ChannelQueriesCompanion copyWith( + {Value queryHash, Value channelCid}) { + return _ChannelQueriesCompanion( + queryHash: queryHash ?? this.queryHash, + channelCid: channelCid ?? this.channelCid, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (queryHash.present) { + map['query_hash'] = Variable(queryHash.value); + } + if (channelCid.present) { + map['channel_cid'] = Variable(channelCid.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('_ChannelQueriesCompanion(') + ..write('queryHash: $queryHash, ') + ..write('channelCid: $channelCid') + ..write(')')) + .toString(); + } +} + +class $_ChannelQueriesTable extends _ChannelQueries + with TableInfo<$_ChannelQueriesTable, ChannelQuery> { + final GeneratedDatabase _db; + final String _alias; + $_ChannelQueriesTable(this._db, [this._alias]); + final VerificationMeta _queryHashMeta = const VerificationMeta('queryHash'); + GeneratedTextColumn _queryHash; + @override + GeneratedTextColumn get queryHash => _queryHash ??= _constructQueryHash(); + GeneratedTextColumn _constructQueryHash() { + return GeneratedTextColumn( + 'query_hash', + $tableName, + false, + ); + } + + final VerificationMeta _channelCidMeta = const VerificationMeta('channelCid'); + GeneratedTextColumn _channelCid; + @override + GeneratedTextColumn get channelCid => _channelCid ??= _constructChannelCid(); + GeneratedTextColumn _constructChannelCid() { + return GeneratedTextColumn( + 'channel_cid', + $tableName, + false, + ); + } + + @override + List get $columns => [queryHash, channelCid]; + @override + $_ChannelQueriesTable get asDslTable => this; + @override + String get $tableName => _alias ?? 'channel_queries'; + @override + final String actualTableName = 'channel_queries'; + @override + VerificationContext validateIntegrity(Insertable instance, + {bool isInserting = false}) { + final context = VerificationContext(); + final data = instance.toColumns(true); + if (data.containsKey('query_hash')) { + context.handle(_queryHashMeta, + queryHash.isAcceptableOrUnknown(data['query_hash'], _queryHashMeta)); + } else if (isInserting) { + context.missing(_queryHashMeta); + } + if (data.containsKey('channel_cid')) { + context.handle( + _channelCidMeta, + channelCid.isAcceptableOrUnknown( + data['channel_cid'], _channelCidMeta)); + } else if (isInserting) { + context.missing(_channelCidMeta); + } + return context; + } + + @override + Set get $primaryKey => {queryHash, channelCid}; + @override + ChannelQuery map(Map data, {String tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : null; + return ChannelQuery.fromData(data, _db, prefix: effectivePrefix); + } + + @override + $_ChannelQueriesTable createAlias(String alias) { + return $_ChannelQueriesTable(_db, alias); + } +} + +class _Reaction extends DataClass implements Insertable<_Reaction> { + final String messageId; + final String type; + final DateTime createdAt; + final int score; + final String userId; + final Map extraData; + _Reaction( + {@required this.messageId, + @required this.type, + @required this.createdAt, + this.score, + @required this.userId, + this.extraData}); + factory _Reaction.fromData(Map data, GeneratedDatabase db, + {String prefix}) { + final effectivePrefix = prefix ?? ''; + final stringType = db.typeSystem.forDartType(); + final dateTimeType = db.typeSystem.forDartType(); + final intType = db.typeSystem.forDartType(); + return _Reaction( + messageId: stringType + .mapFromDatabaseResponse(data['${effectivePrefix}message_id']), + type: stringType.mapFromDatabaseResponse(data['${effectivePrefix}type']), + createdAt: dateTimeType + .mapFromDatabaseResponse(data['${effectivePrefix}created_at']), + score: intType.mapFromDatabaseResponse(data['${effectivePrefix}score']), + userId: + stringType.mapFromDatabaseResponse(data['${effectivePrefix}user_id']), + extraData: $_ReactionsTable.$converter0.mapToDart(stringType + .mapFromDatabaseResponse(data['${effectivePrefix}extra_data'])), + ); + } + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (!nullToAbsent || messageId != null) { + map['message_id'] = Variable(messageId); + } + if (!nullToAbsent || type != null) { + map['type'] = Variable(type); + } + if (!nullToAbsent || createdAt != null) { + map['created_at'] = Variable(createdAt); + } + if (!nullToAbsent || score != null) { + map['score'] = Variable(score); + } + if (!nullToAbsent || userId != null) { + map['user_id'] = Variable(userId); + } + if (!nullToAbsent || extraData != null) { + final converter = $_ReactionsTable.$converter0; + map['extra_data'] = Variable(converter.mapToSql(extraData)); + } + return map; + } + + _ReactionsCompanion toCompanion(bool nullToAbsent) { + return _ReactionsCompanion( + messageId: messageId == null && nullToAbsent + ? const Value.absent() + : Value(messageId), + type: type == null && nullToAbsent ? const Value.absent() : Value(type), + createdAt: createdAt == null && nullToAbsent + ? const Value.absent() + : Value(createdAt), + score: + score == null && nullToAbsent ? const Value.absent() : Value(score), + userId: + userId == null && nullToAbsent ? const Value.absent() : Value(userId), + extraData: extraData == null && nullToAbsent + ? const Value.absent() + : Value(extraData), + ); + } + + factory _Reaction.fromJson(Map json, + {ValueSerializer serializer}) { + serializer ??= moorRuntimeOptions.defaultSerializer; + return _Reaction( + messageId: serializer.fromJson(json['messageId']), + type: serializer.fromJson(json['type']), + createdAt: serializer.fromJson(json['createdAt']), + score: serializer.fromJson(json['score']), + userId: serializer.fromJson(json['userId']), + extraData: serializer.fromJson>(json['extraData']), + ); + } + @override + Map toJson({ValueSerializer serializer}) { + serializer ??= moorRuntimeOptions.defaultSerializer; + return { + 'messageId': serializer.toJson(messageId), + 'type': serializer.toJson(type), + 'createdAt': serializer.toJson(createdAt), + 'score': serializer.toJson(score), + 'userId': serializer.toJson(userId), + 'extraData': serializer.toJson>(extraData), + }; + } + + _Reaction copyWith( + {String messageId, + String type, + DateTime createdAt, + int score, + String userId, + Map extraData}) => + _Reaction( + messageId: messageId ?? this.messageId, + type: type ?? this.type, + createdAt: createdAt ?? this.createdAt, + score: score ?? this.score, + userId: userId ?? this.userId, + extraData: extraData ?? this.extraData, + ); + @override + String toString() { + return (StringBuffer('_Reaction(') + ..write('messageId: $messageId, ') + ..write('type: $type, ') + ..write('createdAt: $createdAt, ') + ..write('score: $score, ') + ..write('userId: $userId, ') + ..write('extraData: $extraData') + ..write(')')) + .toString(); + } + + @override + int get hashCode => $mrjf($mrjc( + messageId.hashCode, + $mrjc( + type.hashCode, + $mrjc( + createdAt.hashCode, + $mrjc(score.hashCode, + $mrjc(userId.hashCode, extraData.hashCode)))))); + @override + bool operator ==(dynamic other) => + identical(this, other) || + (other is _Reaction && + other.messageId == this.messageId && + other.type == this.type && + other.createdAt == this.createdAt && + other.score == this.score && + other.userId == this.userId && + other.extraData == this.extraData); +} + +class _ReactionsCompanion extends UpdateCompanion<_Reaction> { + final Value messageId; + final Value type; + final Value createdAt; + final Value score; + final Value userId; + final Value> extraData; + const _ReactionsCompanion({ + this.messageId = const Value.absent(), + this.type = const Value.absent(), + this.createdAt = const Value.absent(), + this.score = const Value.absent(), + this.userId = const Value.absent(), + this.extraData = const Value.absent(), + }); + _ReactionsCompanion.insert({ + @required String messageId, + @required String type, + @required DateTime createdAt, + this.score = const Value.absent(), + @required String userId, + this.extraData = const Value.absent(), + }) : messageId = Value(messageId), + type = Value(type), + createdAt = Value(createdAt), + userId = Value(userId); + static Insertable<_Reaction> custom({ + Expression messageId, + Expression type, + Expression createdAt, + Expression score, + Expression userId, + Expression extraData, + }) { + return RawValuesInsertable({ + if (messageId != null) 'message_id': messageId, + if (type != null) 'type': type, + if (createdAt != null) 'created_at': createdAt, + if (score != null) 'score': score, + if (userId != null) 'user_id': userId, + if (extraData != null) 'extra_data': extraData, + }); + } + + _ReactionsCompanion copyWith( + {Value messageId, + Value type, + Value createdAt, + Value score, + Value userId, + Value> extraData}) { + return _ReactionsCompanion( + messageId: messageId ?? this.messageId, + type: type ?? this.type, + createdAt: createdAt ?? this.createdAt, + score: score ?? this.score, + userId: userId ?? this.userId, + extraData: extraData ?? this.extraData, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (messageId.present) { + map['message_id'] = Variable(messageId.value); + } + if (type.present) { + map['type'] = Variable(type.value); + } + if (createdAt.present) { + map['created_at'] = Variable(createdAt.value); + } + if (score.present) { + map['score'] = Variable(score.value); + } + if (userId.present) { + map['user_id'] = Variable(userId.value); + } + if (extraData.present) { + final converter = $_ReactionsTable.$converter0; + map['extra_data'] = Variable(converter.mapToSql(extraData.value)); + } + return map; + } + + @override + String toString() { + return (StringBuffer('_ReactionsCompanion(') + ..write('messageId: $messageId, ') + ..write('type: $type, ') + ..write('createdAt: $createdAt, ') + ..write('score: $score, ') + ..write('userId: $userId, ') + ..write('extraData: $extraData') + ..write(')')) + .toString(); + } +} + +class $_ReactionsTable extends _Reactions + with TableInfo<$_ReactionsTable, _Reaction> { + final GeneratedDatabase _db; + final String _alias; + $_ReactionsTable(this._db, [this._alias]); + final VerificationMeta _messageIdMeta = const VerificationMeta('messageId'); + GeneratedTextColumn _messageId; + @override + GeneratedTextColumn get messageId => _messageId ??= _constructMessageId(); + GeneratedTextColumn _constructMessageId() { + return GeneratedTextColumn( + 'message_id', + $tableName, + false, + ); + } + + final VerificationMeta _typeMeta = const VerificationMeta('type'); + GeneratedTextColumn _type; + @override + GeneratedTextColumn get type => _type ??= _constructType(); + GeneratedTextColumn _constructType() { + return GeneratedTextColumn( + 'type', + $tableName, + false, + ); + } + + final VerificationMeta _createdAtMeta = const VerificationMeta('createdAt'); + GeneratedDateTimeColumn _createdAt; + @override + GeneratedDateTimeColumn get createdAt => _createdAt ??= _constructCreatedAt(); + GeneratedDateTimeColumn _constructCreatedAt() { + return GeneratedDateTimeColumn( + 'created_at', + $tableName, + false, + ); + } + + final VerificationMeta _scoreMeta = const VerificationMeta('score'); + GeneratedIntColumn _score; + @override + GeneratedIntColumn get score => _score ??= _constructScore(); + GeneratedIntColumn _constructScore() { + return GeneratedIntColumn( + 'score', + $tableName, + true, + ); + } + + final VerificationMeta _userIdMeta = const VerificationMeta('userId'); + GeneratedTextColumn _userId; + @override + GeneratedTextColumn get userId => _userId ??= _constructUserId(); + GeneratedTextColumn _constructUserId() { + return GeneratedTextColumn( + 'user_id', + $tableName, + false, + ); + } + + final VerificationMeta _extraDataMeta = const VerificationMeta('extraData'); + GeneratedTextColumn _extraData; + @override + GeneratedTextColumn get extraData => _extraData ??= _constructExtraData(); + GeneratedTextColumn _constructExtraData() { + return GeneratedTextColumn( + 'extra_data', + $tableName, + true, + ); + } + + @override + List get $columns => + [messageId, type, createdAt, score, userId, extraData]; + @override + $_ReactionsTable get asDslTable => this; + @override + String get $tableName => _alias ?? 'reactions'; + @override + final String actualTableName = 'reactions'; + @override + VerificationContext validateIntegrity(Insertable<_Reaction> instance, + {bool isInserting = false}) { + final context = VerificationContext(); + final data = instance.toColumns(true); + if (data.containsKey('message_id')) { + context.handle(_messageIdMeta, + messageId.isAcceptableOrUnknown(data['message_id'], _messageIdMeta)); + } else if (isInserting) { + context.missing(_messageIdMeta); + } + if (data.containsKey('type')) { + context.handle( + _typeMeta, type.isAcceptableOrUnknown(data['type'], _typeMeta)); + } else if (isInserting) { + context.missing(_typeMeta); + } + if (data.containsKey('created_at')) { + context.handle(_createdAtMeta, + createdAt.isAcceptableOrUnknown(data['created_at'], _createdAtMeta)); + } else if (isInserting) { + context.missing(_createdAtMeta); + } + if (data.containsKey('score')) { + context.handle( + _scoreMeta, score.isAcceptableOrUnknown(data['score'], _scoreMeta)); + } + if (data.containsKey('user_id')) { + context.handle(_userIdMeta, + userId.isAcceptableOrUnknown(data['user_id'], _userIdMeta)); + } else if (isInserting) { + context.missing(_userIdMeta); + } + context.handle(_extraDataMeta, const VerificationResult.success()); + return context; + } + + @override + Set get $primaryKey => {messageId, type, userId}; + @override + _Reaction map(Map data, {String tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : null; + return _Reaction.fromData(data, _db, prefix: effectivePrefix); + } + + @override + $_ReactionsTable createAlias(String alias) { + return $_ReactionsTable(_db, alias); + } + + static TypeConverter, String> $converter0 = + _ExtraDataConverter(); +} + +abstract class _$OfflineStorage extends GeneratedDatabase { + _$OfflineStorage(QueryExecutor e) : super(SqlTypeSystem.defaultInstance, e); + _$OfflineStorage.connect(DatabaseConnection c) : super.connect(c); + $_ConnectionEventTable _connectionEvent; + $_ConnectionEventTable get connectionEvent => + _connectionEvent ??= $_ConnectionEventTable(this); + $_ChannelsTable _channels; + $_ChannelsTable get channels => _channels ??= $_ChannelsTable(this); + $_UsersTable _users; + $_UsersTable get users => _users ??= $_UsersTable(this); + $_MessagesTable _messages; + $_MessagesTable get messages => _messages ??= $_MessagesTable(this); + $_ReadsTable _reads; + $_ReadsTable get reads => _reads ??= $_ReadsTable(this); + $_MembersTable _members; + $_MembersTable get members => _members ??= $_MembersTable(this); + $_ChannelQueriesTable _channelQueries; + $_ChannelQueriesTable get channelQueries => + _channelQueries ??= $_ChannelQueriesTable(this); + $_ReactionsTable _reactions; + $_ReactionsTable get reactions => _reactions ??= $_ReactionsTable(this); + @override + Iterable get allTables => allSchemaEntities.whereType(); + @override + List get allSchemaEntities => [ + connectionEvent, + channels, + users, + messages, + reads, + members, + channelQueries, + reactions + ]; +} diff --git a/packages/dart_client/lib/src/db/shared/native_db.dart b/packages/dart_client/lib/src/db/shared/native_db.dart new file mode 100644 index 00000000..38a1923e --- /dev/null +++ b/packages/dart_client/lib/src/db/shared/native_db.dart @@ -0,0 +1,64 @@ +import 'dart:io'; +import 'dart:isolate'; +import 'package:flutter/material.dart'; +import 'package:moor/ffi.dart'; +import 'package:moor/isolate.dart'; +import 'package:moor/moor.dart'; +import 'package:path/path.dart'; +import 'package:path_provider/path_provider.dart'; +import 'package:stream_chat/src/db/offline_storage.dart'; + +class SharedDB { + static constructDatabase(dbName) async { + final dir = await getApplicationDocumentsDirectory(); + final path = join(dir.path, dbName); + final file = File(path); + return VmDatabase(file); + } + + static Future createMoorIsolate(String userId) async { + WidgetsFlutterBinding.ensureInitialized(); + final dir = await getApplicationDocumentsDirectory(); + final path = join(dir.path, 'db_$userId.sqlite'); + + final receivePort = ReceivePort(); + await Isolate.spawn( + startBackground, + _IsolateStartRequest(receivePort.sendPort, path), + ); + + return (await receivePort.first as MoorIsolate); + } + + static void startBackground(_IsolateStartRequest request) { + final executor = LazyDatabase(() async { + return VmDatabase(File(request.targetPath)); + }); + final moorIsolate = MoorIsolate.inCurrent( + () => DatabaseConnection.fromExecutor(executor), + ); + request.sendMoorIsolate.send(moorIsolate); + } + + static Future constructOfflineStorage({ + userId, + logger, + }) async { + logger.info('Connecting on background isolate'); + final isolate = await createMoorIsolate(userId); + final connection = await isolate.connect(); + return OfflineStorage.connect( + connection, + userId, + isolate, + logger, + ); + } +} + +class _IsolateStartRequest { + final SendPort sendMoorIsolate; + final String targetPath; + + _IsolateStartRequest(this.sendMoorIsolate, this.targetPath); +} diff --git a/packages/dart_client/lib/src/db/shared/shared_db.dart b/packages/dart_client/lib/src/db/shared/shared_db.dart new file mode 100644 index 00000000..25120fcf --- /dev/null +++ b/packages/dart_client/lib/src/db/shared/shared_db.dart @@ -0,0 +1,3 @@ +export 'unsupported_db.dart' + if (dart.library.io) 'native_db.dart' // implementation using dart:io + if (dart.library.html) 'web_db.dart'; diff --git a/packages/dart_client/lib/src/db/shared/unsupported_db.dart b/packages/dart_client/lib/src/db/shared/unsupported_db.dart new file mode 100644 index 00000000..9d4ef84f --- /dev/null +++ b/packages/dart_client/lib/src/db/shared/unsupported_db.dart @@ -0,0 +1,12 @@ +class SharedDB { + static constructDatabase(dbName) async { + print('Unsupported Platform'); + return null; + } + + static createMoorIsolate(userId) {} + + static startBackground(request) {} + + static constructOfflineStorage({userId, logger}) {} +} diff --git a/packages/dart_client/lib/src/db/shared/web_db.dart b/packages/dart_client/lib/src/db/shared/web_db.dart new file mode 100644 index 00000000..bd579280 --- /dev/null +++ b/packages/dart_client/lib/src/db/shared/web_db.dart @@ -0,0 +1,18 @@ +import 'package:moor/moor_web.dart'; +import 'package:stream_chat/src/db/offline_storage.dart'; + +class SharedDB { + static constructDatabase(dbName) async { + return WebDatabase(dbName); + } + + static Future constructOfflineStorage({ + userId, + logger, + }) async { + return OfflineStorage( + userId, + logger, + ); + } +} diff --git a/packages/dart_client/lib/src/event_type.dart b/packages/dart_client/lib/src/event_type.dart new file mode 100644 index 00000000..fd93af2a --- /dev/null +++ b/packages/dart_client/lib/src/event_type.dart @@ -0,0 +1,94 @@ +/// This class defines some basic event types +class EventType { + /// Indicates any type of events + static const String any = '*'; + + /// Event sent when a user starts typing a message + static const String typingStart = 'typing.start'; + + /// Event sent when a user stops typing a message + static const String typingStop = 'typing.stop'; + + /// Event sent when receiving a new message + static const String messageNew = 'message.new'; + + /// Event sent when receiving a new message + static const String notificationMessageNew = 'notification.message_new'; + + /// Event sent when the unread count changes + static const String notificationMarkRead = 'notification.mark_read'; + + /// Event sent when deleting a new message + static const String messageDeleted = 'message.deleted'; + + /// Event sent when receiving a new reaction + static const String reactionNew = 'reaction.new'; + + /// Event sent when deleting a reaction + static const String reactionDeleted = 'reaction.deleted'; + + /// Event sent when updating a reaction + static const String reactionUpdated = 'reaction.updated'; + + /// Event sent when updating a message + static const String messageUpdated = 'message.updated'; + + /// Event sent when reading a message + static const String messageRead = 'message.read'; + + /// Event sent when a channel is deleted + static const String channelDeleted = 'channel.deleted'; + + /// Event sent when a channel is deleted + static const String notificationChannelDeleted = + 'notification.channel_deleted'; + + /// Event sent when a channel is truncated + static const String channelTruncated = 'channel.truncated'; + + /// Event sent when a channel is truncated + static const String notificationChannelTruncated = + 'notification.channel_truncated'; + + /// Event sent when the user is added to a channel + static const String notificationAddedToChannel = + 'notification.added_to_channel'; + + /// Event sent when the user is removed to a channel + static const String notificationRemovedFromChannel = + 'notification.removed_from_channel'; + + /// Event sent when a channel is updated + static const String channelUpdated = 'channel.updated'; + + /// Event sent when a user is updated + static const String userUpdated = 'user.updated'; + + /// Event sent when a member is added to a channel + static const String memberAdded = 'member.added'; + + /// Event sent when a member is removed to a channel + static const String memberRemoved = 'member.removed'; + + /// Event sent when a channel is hidden + static const String channelHidden = 'channel.hidden'; + + /// Event sent when a channel is visible + static const String channelVisible = 'channel.visible'; + + /// Event sent when the connection status changes + static const String connectionChanged = 'connection.changed'; + + /// Event sent when the connection is recovered + static const String connectionRecovered = 'connection.recovered'; + + /// Event sent when the user is accepts an invite + static const String notificationInviteAccepted = + 'notification.invite_accepted'; + + /// Event sent when the user is invited + static const String notificationInvited = 'notification.invited'; + + /// Event sent when the user's mutes list is updated + static const String notificationMutesUpdated = 'notification.mutes_updated'; +} diff --git a/packages/dart_client/lib/src/exceptions.dart b/packages/dart_client/lib/src/exceptions.dart new file mode 100644 index 00000000..9ba27e79 --- /dev/null +++ b/packages/dart_client/lib/src/exceptions.dart @@ -0,0 +1,54 @@ +import 'dart:convert'; + +/// Exception related to api calls +class ApiError extends Error { + /// Raw body of the response + final String body; + + /// Json parsed body + final Map jsonData; + + /// Http status code of the response + final int status; + + /// Stream specific error code + int get code => _code; + int _code; + + static Map _decode(String body) { + try { + if (body == null) { + return null; + } + return json.decode(body); + } on FormatException { + return null; + } + } + + /// Creates a new ApiError instance using the response body and status code + ApiError(this.body, this.status) : jsonData = _decode(body) { + if (jsonData != null && jsonData.containsKey('code')) { + _code = jsonData['code']; + } + } + + @override + bool operator ==(Object other) => + identical(this, other) || + other is ApiError && + runtimeType == other.runtimeType && + body == other.body && + jsonData == other.jsonData && + status == other.status && + _code == other._code; + + @override + int get hashCode => + body.hashCode ^ jsonData.hashCode ^ status.hashCode ^ _code.hashCode; + + @override + String toString() { + return 'ApiError{body: $body, jsonData: $jsonData, status: $status, code: $_code}'; + } +} diff --git a/packages/dart_client/lib/src/models/action.dart b/packages/dart_client/lib/src/models/action.dart new file mode 100644 index 00000000..34bb8f7e --- /dev/null +++ b/packages/dart_client/lib/src/models/action.dart @@ -0,0 +1,31 @@ +import 'package:json_annotation/json_annotation.dart'; + +part 'action.g.dart'; + +/// The class that contains the information about an action +@JsonSerializable() +class Action { + /// The name of the action + final String name; + + /// The style of the action + final String style; + + /// The test of the action + final String text; + + /// The type of the action + final String type; + + /// The value of the action + final String value; + + /// Constructor used for json serialization + Action({this.name, this.style, this.text, this.type, this.value}); + + /// Create a new instance from a json + factory Action.fromJson(Map json) => _$ActionFromJson(json); + + /// Serialize to json + Map toJson() => _$ActionToJson(this); +} diff --git a/packages/dart_client/lib/src/models/action.g.dart b/packages/dart_client/lib/src/models/action.g.dart new file mode 100644 index 00000000..3c567843 --- /dev/null +++ b/packages/dart_client/lib/src/models/action.g.dart @@ -0,0 +1,25 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'action.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +Action _$ActionFromJson(Map json) { + return Action( + name: json['name'] as String, + style: json['style'] as String, + text: json['text'] as String, + type: json['type'] as String, + value: json['value'] as String, + ); +} + +Map _$ActionToJson(Action instance) => { + 'name': instance.name, + 'style': instance.style, + 'text': instance.text, + 'type': instance.type, + 'value': instance.value, + }; diff --git a/packages/dart_client/lib/src/models/attachment.dart b/packages/dart_client/lib/src/models/attachment.dart new file mode 100644 index 00000000..8546fb9d --- /dev/null +++ b/packages/dart_client/lib/src/models/attachment.dart @@ -0,0 +1,207 @@ +// ignore_for_file: public_member_api_docs + +import 'package:json_annotation/json_annotation.dart'; + +import 'action.dart'; +import 'serialization.dart'; + +part 'attachment.g.dart'; + +/// The class that contains the information about an attachment +@JsonSerializable(includeIfNull: false) +class Attachment { + ///The attachment type based on the URL resource. This can be: audio, image or video + final String type; + + ///The link to which the attachment message points to. + final String titleLink; + + /// The attachment title + final String title; + + /// The URL to the attached file thumbnail. You can use this to represent the attached link. + final String thumbUrl; + + /// The attachment text. It will be displayed in the channel next to the original message. + final String text; + + /// Optional text that appears above the attachment block + final String pretext; + + /// The original URL that was used to scrape this attachment. + final String ogScrapeUrl; + + /// The URL to the attached image. This is present for URL pointing to an image article (eg. Unsplash) + final String imageUrl; + final String footerIcon; + final String footer; + final dynamic fields; + final String fallback; + final String color; + + /// The name of the author. + final String authorName; + final String authorLink; + final String authorIcon; + + /// The URL to the audio, video or image related to the URL. + final String assetUrl; + + /// Actions from a command + final List actions; + + final Uri localUri; + + /// Map of custom channel extraData + @JsonKey(includeIfNull: false) + final Map extraData; + + /// Known top level fields. + /// Useful for [Serialization] methods. + static const topLevelFields = [ + 'type', + 'title_link', + 'title', + 'thumb_url', + 'text', + 'pretext', + 'og_scrape_url', + 'image_url', + 'footer_icon', + 'footer', + 'fields', + 'fallback', + 'color', + 'author_name', + 'author_link', + 'author_icon', + 'asset_url', + 'actions', + ]; + + /// Constructor used for json serialization + Attachment({ + this.type, + this.titleLink, + this.title, + this.thumbUrl, + this.text, + this.pretext, + this.ogScrapeUrl, + this.imageUrl, + this.footerIcon, + this.footer, + this.fields, + this.fallback, + this.color, + this.authorName, + this.authorLink, + this.authorIcon, + this.assetUrl, + this.actions, + this.extraData, + this.localUri, + }); + + /// Create a new instance from a json + factory Attachment.fromJson(Map json) { + return _$AttachmentFromJson( + Serialization.moveToExtraDataFromRoot(json, topLevelFields)); + } + + /// Serialize to json + Map toJson() => Serialization.moveFromExtraDataToRoot( + _$AttachmentToJson(this), topLevelFields); + + Attachment copyWith({ + String type, + String titleLink, + String title, + String thumbUrl, + String text, + String pretext, + String ogScrapeUrl, + String imageUrl, + String footerIcon, + String footer, + dynamic fields, + String fallback, + String color, + String authorName, + String authorLink, + String authorIcon, + String assetUrl, + List actions, + Uri localUri, + Map extraData, + }) => + Attachment( + type: type ?? this.type, + titleLink: titleLink ?? this.titleLink, + title: title ?? this.title, + thumbUrl: thumbUrl ?? this.thumbUrl, + text: text ?? this.text, + pretext: pretext ?? this.pretext, + ogScrapeUrl: ogScrapeUrl ?? this.ogScrapeUrl, + imageUrl: imageUrl ?? this.imageUrl, + footerIcon: footerIcon ?? this.footerIcon, + footer: footer ?? this.footer, + fields: fields ?? this.fields, + fallback: fallback ?? this.fallback, + color: color ?? this.color, + authorName: authorName ?? this.authorName, + authorLink: authorLink ?? this.authorLink, + authorIcon: authorIcon ?? this.authorIcon, + assetUrl: assetUrl ?? this.assetUrl, + actions: actions ?? this.actions, + localUri: localUri ?? this.localUri, + extraData: extraData ?? this.extraData, + ); + + @override + bool operator ==(Object other) => + identical(this, other) || + other is Attachment && + runtimeType == other.runtimeType && + type == other.type && + titleLink == other.titleLink && + title == other.title && + thumbUrl == other.thumbUrl && + text == other.text && + pretext == other.pretext && + ogScrapeUrl == other.ogScrapeUrl && + imageUrl == other.imageUrl && + footerIcon == other.footerIcon && + footer == other.footer && + fields == other.fields && + fallback == other.fallback && + color == other.color && + authorName == other.authorName && + authorLink == other.authorLink && + authorIcon == other.authorIcon && + assetUrl == other.assetUrl && + actions == other.actions && + extraData == other.extraData; + + @override + int get hashCode => + type.hashCode ^ + titleLink.hashCode ^ + title.hashCode ^ + thumbUrl.hashCode ^ + text.hashCode ^ + pretext.hashCode ^ + ogScrapeUrl.hashCode ^ + imageUrl.hashCode ^ + footerIcon.hashCode ^ + footer.hashCode ^ + fields.hashCode ^ + fallback.hashCode ^ + color.hashCode ^ + authorName.hashCode ^ + authorLink.hashCode ^ + authorIcon.hashCode ^ + assetUrl.hashCode ^ + actions.hashCode ^ + extraData.hashCode; +} diff --git a/packages/dart_client/lib/src/models/attachment.g.dart b/packages/dart_client/lib/src/models/attachment.g.dart new file mode 100644 index 00000000..db276d69 --- /dev/null +++ b/packages/dart_client/lib/src/models/attachment.g.dart @@ -0,0 +1,74 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'attachment.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +Attachment _$AttachmentFromJson(Map json) { + return Attachment( + type: json['type'] as String, + titleLink: json['title_link'] as String, + title: json['title'] as String, + thumbUrl: json['thumb_url'] as String, + text: json['text'] as String, + pretext: json['pretext'] as String, + ogScrapeUrl: json['og_scrape_url'] as String, + imageUrl: json['image_url'] as String, + footerIcon: json['footer_icon'] as String, + footer: json['footer'] as String, + fields: json['fields'], + fallback: json['fallback'] as String, + color: json['color'] as String, + authorName: json['author_name'] as String, + authorLink: json['author_link'] as String, + authorIcon: json['author_icon'] as String, + assetUrl: json['asset_url'] as String, + actions: (json['actions'] as List) + ?.map((e) => e == null + ? null + : Action.fromJson((e as Map)?.map( + (k, e) => MapEntry(k as String, e), + ))) + ?.toList(), + extraData: (json['extra_data'] as Map)?.map( + (k, e) => MapEntry(k as String, e), + ), + localUri: json['local_uri'] == null + ? null + : Uri.parse(json['local_uri'] as String), + ); +} + +Map _$AttachmentToJson(Attachment instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('type', instance.type); + writeNotNull('title_link', instance.titleLink); + writeNotNull('title', instance.title); + writeNotNull('thumb_url', instance.thumbUrl); + writeNotNull('text', instance.text); + writeNotNull('pretext', instance.pretext); + writeNotNull('og_scrape_url', instance.ogScrapeUrl); + writeNotNull('image_url', instance.imageUrl); + writeNotNull('footer_icon', instance.footerIcon); + writeNotNull('footer', instance.footer); + writeNotNull('fields', instance.fields); + writeNotNull('fallback', instance.fallback); + writeNotNull('color', instance.color); + writeNotNull('author_name', instance.authorName); + writeNotNull('author_link', instance.authorLink); + writeNotNull('author_icon', instance.authorIcon); + writeNotNull('asset_url', instance.assetUrl); + writeNotNull('actions', instance.actions?.map((e) => e?.toJson())?.toList()); + writeNotNull('local_uri', instance.localUri?.toString()); + writeNotNull('extra_data', instance.extraData); + return val; +} diff --git a/packages/dart_client/lib/src/models/channel_config.dart b/packages/dart_client/lib/src/models/channel_config.dart new file mode 100644 index 00000000..e455930f --- /dev/null +++ b/packages/dart_client/lib/src/models/channel_config.dart @@ -0,0 +1,84 @@ +import 'package:json_annotation/json_annotation.dart'; + +import 'command.dart'; + +part 'channel_config.g.dart'; + +/// The class that contains the information about the configuration of a channel +@JsonSerializable() +class ChannelConfig { + /// Moderation configuration + final String automod; + + /// List of available commands + final List commands; + + /// True if the channel should send connect events + final bool connectEvents; + + /// Date of channel creation + final DateTime createdAt; + + /// Date of last channel update + final DateTime updatedAt; + + /// Max channel message length + final int maxMessageLength; + + /// Duration of message retention + final String messageRetention; + + /// True if users can be muted + final bool mutes; + + /// Name of the channel + final String name; + + /// True if reaction are active for this channel + final bool reactions; + + /// True if readEvents are active for this channel + final bool readEvents; + + /// True if reply message are active for this channel + final bool replies; + + /// True if it's possible to perform a search in this channel + final bool search; + + /// True if typing events should be sent for this channel + final bool typingEvents; + + /// True if it's possible to upload files to this channel + final bool uploads; + + /// True if urls appears as attachments + final bool urlEnrichment; + + /// Constructor used for json serialization + ChannelConfig({ + this.automod, + this.commands, + this.connectEvents, + this.createdAt, + this.updatedAt, + this.maxMessageLength, + this.messageRetention, + this.mutes, + this.name, + this.reactions, + this.readEvents, + this.replies, + this.search, + this.typingEvents, + this.uploads, + this.urlEnrichment, + }); + + /// Create a new instance from a json + factory ChannelConfig.fromJson(Map json) => + _$ChannelConfigFromJson(json); + + /// Serialize to json + Map toJson() => _$ChannelConfigToJson(this); +} diff --git a/packages/dart_client/lib/src/models/channel_config.g.dart b/packages/dart_client/lib/src/models/channel_config.g.dart new file mode 100644 index 00000000..e8152c80 --- /dev/null +++ b/packages/dart_client/lib/src/models/channel_config.g.dart @@ -0,0 +1,58 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'channel_config.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +ChannelConfig _$ChannelConfigFromJson(Map json) { + return ChannelConfig( + automod: json['automod'] as String, + commands: (json['commands'] as List) + ?.map((e) => e == null + ? null + : Command.fromJson((e as Map)?.map( + (k, e) => MapEntry(k as String, e), + ))) + ?.toList(), + connectEvents: json['connect_events'] as bool, + createdAt: json['created_at'] == null + ? null + : DateTime.parse(json['created_at'] as String), + updatedAt: json['updated_at'] == null + ? null + : DateTime.parse(json['updated_at'] as String), + maxMessageLength: json['max_message_length'] as int, + messageRetention: json['message_retention'] as String, + mutes: json['mutes'] as bool, + name: json['name'] as String, + reactions: json['reactions'] as bool, + readEvents: json['read_events'] as bool, + replies: json['replies'] as bool, + search: json['search'] as bool, + typingEvents: json['typing_events'] as bool, + uploads: json['uploads'] as bool, + urlEnrichment: json['url_enrichment'] as bool, + ); +} + +Map _$ChannelConfigToJson(ChannelConfig instance) => + { + 'automod': instance.automod, + 'commands': instance.commands?.map((e) => e?.toJson())?.toList(), + 'connect_events': instance.connectEvents, + 'created_at': instance.createdAt?.toIso8601String(), + 'updated_at': instance.updatedAt?.toIso8601String(), + 'max_message_length': instance.maxMessageLength, + 'message_retention': instance.messageRetention, + 'mutes': instance.mutes, + 'name': instance.name, + 'reactions': instance.reactions, + 'read_events': instance.readEvents, + 'replies': instance.replies, + 'search': instance.search, + 'typing_events': instance.typingEvents, + 'uploads': instance.uploads, + 'url_enrichment': instance.urlEnrichment, + }; diff --git a/packages/dart_client/lib/src/models/channel_model.dart b/packages/dart_client/lib/src/models/channel_model.dart new file mode 100644 index 00000000..10f65e0b --- /dev/null +++ b/packages/dart_client/lib/src/models/channel_model.dart @@ -0,0 +1,145 @@ +import 'package:json_annotation/json_annotation.dart'; + +import 'channel_config.dart'; +import 'serialization.dart'; +import 'user.dart'; + +part 'channel_model.g.dart'; + +/// The class that contains the information about a channel +@JsonSerializable() +class ChannelModel { + /// The id of this channel + final String id; + + /// The type of this channel + final String type; + + /// The cid of this channel + @JsonKey(includeIfNull: false, toJson: Serialization.readOnly) + final String cid; + + /// The channel configuration data + @JsonKey(includeIfNull: false, toJson: Serialization.readOnly) + final ChannelConfig config; + + /// The user that created this channel + @JsonKey(includeIfNull: false, toJson: Serialization.readOnly) + final User createdBy; + + /// True if this channel is frozen + @JsonKey(includeIfNull: false) + final bool frozen; + + /// The date of the last message + @JsonKey(includeIfNull: false, toJson: Serialization.readOnly) + final DateTime lastMessageAt; + + /// The date of channel creation + @JsonKey(includeIfNull: false, toJson: Serialization.readOnly) + final DateTime createdAt; + + /// The date of the last channel update + @JsonKey(includeIfNull: false, toJson: Serialization.readOnly) + final DateTime updatedAt; + + /// The date of channel deletion + @JsonKey(includeIfNull: false, toJson: Serialization.readOnly) + final DateTime deletedAt; + + /// The count of this channel members + @JsonKey(includeIfNull: false, toJson: Serialization.readOnly) + final int memberCount; + + /// Map of custom channel extraData + @JsonKey(includeIfNull: false) + final Map extraData; + + /// The team the channel belongs to + @JsonKey(includeIfNull: false, toJson: Serialization.readOnly) + final String team; + + /// Known top level fields. + /// Useful for [Serialization] methods. + static const topLevelFields = [ + 'id', + 'type', + 'cid', + 'config', + 'created_by', + 'frozen', + 'last_message_at', + 'created_at', + 'updated_at', + 'deleted_at', + 'member_count', + 'team', + ]; + + /// Constructor used for json serialization + ChannelModel({ + this.id, + this.type, + this.cid, + this.config, + this.createdBy, + this.frozen, + this.lastMessageAt, + this.createdAt, + this.updatedAt, + this.deletedAt, + this.memberCount, + this.extraData, + this.team, + }); + + /// Shortcut for channel name + String get name => + extraData?.containsKey('name') == true ? extraData['name'] : cid; + + /// Create a new instance from a json + factory ChannelModel.fromJson(Map json) { + return _$ChannelModelFromJson( + Serialization.moveToExtraDataFromRoot(json, topLevelFields)); + } + + /// Serialize to json + Map toJson() { + return Serialization.moveFromExtraDataToRoot( + _$ChannelModelToJson(this), + topLevelFields, + ); + } + + /// Creates a copy of [ChannelModel] with specified attributes overridden. + ChannelModel copyWith({ + String id, + String type, + String cid, + ChannelConfig config, + User createdBy, + bool frozen, + DateTime lastMessageAt, + DateTime createdAt, + DateTime updatedAt, + DateTime deletedAt, + int memberCount, + Map extraData, + String team, + }) => + ChannelModel( + id: id ?? this.id, + type: type ?? this.type, + cid: cid ?? this.cid, + config: config ?? this.config, + createdBy: createdBy ?? this.createdBy, + frozen: frozen ?? this.frozen, + lastMessageAt: lastMessageAt ?? this.lastMessageAt, + createdAt: createdAt ?? this.createdAt, + updatedAt: updatedAt ?? this.updatedAt, + deletedAt: deletedAt ?? this.deletedAt, + memberCount: memberCount ?? this.memberCount, + extraData: extraData ?? this.extraData, + team: team ?? this.team, + ); +} diff --git a/packages/dart_client/lib/src/models/channel_model.g.dart b/packages/dart_client/lib/src/models/channel_model.g.dart new file mode 100644 index 00000000..4f535f46 --- /dev/null +++ b/packages/dart_client/lib/src/models/channel_model.g.dart @@ -0,0 +1,69 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'channel_model.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +ChannelModel _$ChannelModelFromJson(Map json) { + return ChannelModel( + id: json['id'] as String, + type: json['type'] as String, + cid: json['cid'] as String, + config: json['config'] == null + ? null + : ChannelConfig.fromJson((json['config'] as Map)?.map( + (k, e) => MapEntry(k as String, e), + )), + createdBy: json['created_by'] == null + ? null + : User.fromJson((json['created_by'] as Map)?.map( + (k, e) => MapEntry(k as String, e), + )), + frozen: json['frozen'] as bool, + lastMessageAt: json['last_message_at'] == null + ? null + : DateTime.parse(json['last_message_at'] as String), + createdAt: json['created_at'] == null + ? null + : DateTime.parse(json['created_at'] as String), + updatedAt: json['updated_at'] == null + ? null + : DateTime.parse(json['updated_at'] as String), + deletedAt: json['deleted_at'] == null + ? null + : DateTime.parse(json['deleted_at'] as String), + memberCount: json['member_count'] as int, + extraData: (json['extra_data'] as Map)?.map( + (k, e) => MapEntry(k as String, e), + ), + team: json['team'] as String, + ); +} + +Map _$ChannelModelToJson(ChannelModel instance) { + final val = { + 'id': instance.id, + 'type': instance.type, + }; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('cid', readonly(instance.cid)); + writeNotNull('config', readonly(instance.config)); + writeNotNull('created_by', readonly(instance.createdBy)); + writeNotNull('frozen', instance.frozen); + writeNotNull('last_message_at', readonly(instance.lastMessageAt)); + writeNotNull('created_at', readonly(instance.createdAt)); + writeNotNull('updated_at', readonly(instance.updatedAt)); + writeNotNull('deleted_at', readonly(instance.deletedAt)); + writeNotNull('member_count', readonly(instance.memberCount)); + writeNotNull('extra_data', instance.extraData); + writeNotNull('team', readonly(instance.team)); + return val; +} diff --git a/packages/dart_client/lib/src/models/channel_state.dart b/packages/dart_client/lib/src/models/channel_state.dart new file mode 100644 index 00000000..59e7a4f1 --- /dev/null +++ b/packages/dart_client/lib/src/models/channel_state.dart @@ -0,0 +1,66 @@ +import 'package:json_annotation/json_annotation.dart'; + +import '../models/read.dart'; +import '../models/user.dart'; +import 'channel_model.dart'; +import 'member.dart'; +import 'message.dart'; + +part 'channel_state.g.dart'; + +/// The class that contains the information about a command +@JsonSerializable() +class ChannelState { + /// The channel to which this state belongs + final ChannelModel channel; + + /// A paginated list of channel messages + final List messages; + + /// A paginated list of channel members + final List members; + + /// The count of users watching the channel + final int watcherCount; + + /// A paginated list of users watching the channel + final List watchers; + + /// The list of channel reads + final List read; + + /// Constructor used for json serialization + ChannelState({ + this.channel, + this.messages = const [], + this.members = const [], + this.watcherCount, + this.watchers = const [], + this.read = const [], + }); + + /// Create a new instance from a json + static ChannelState fromJson(Map json) => + _$ChannelStateFromJson(json); + + /// Serialize to json + Map toJson() => _$ChannelStateToJson(this); + + /// Creates a copy of [ChannelState] with specified attributes overridden. + ChannelState copyWith({ + ChannelModel channel, + List messages, + List members, + int watcherCount, + List watchers, + List read, + }) => + ChannelState( + channel: channel ?? this.channel, + messages: messages ?? this.messages, + members: members ?? this.members, + watcherCount: watcherCount ?? this.watcherCount, + watchers: watchers ?? this.watchers, + read: read ?? this.read, + ); +} diff --git a/packages/dart_client/lib/src/models/channel_state.g.dart b/packages/dart_client/lib/src/models/channel_state.g.dart new file mode 100644 index 00000000..d053768e --- /dev/null +++ b/packages/dart_client/lib/src/models/channel_state.g.dart @@ -0,0 +1,56 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'channel_state.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +ChannelState _$ChannelStateFromJson(Map json) { + return ChannelState( + channel: json['channel'] == null + ? null + : ChannelModel.fromJson((json['channel'] as Map)?.map( + (k, e) => MapEntry(k as String, e), + )), + messages: (json['messages'] as List) + ?.map((e) => e == null + ? null + : Message.fromJson((e as Map)?.map( + (k, e) => MapEntry(k as String, e), + ))) + ?.toList(), + members: (json['members'] as List) + ?.map((e) => e == null + ? null + : Member.fromJson((e as Map)?.map( + (k, e) => MapEntry(k as String, e), + ))) + ?.toList(), + watcherCount: json['watcher_count'] as int, + watchers: (json['watchers'] as List) + ?.map((e) => e == null + ? null + : User.fromJson((e as Map)?.map( + (k, e) => MapEntry(k as String, e), + ))) + ?.toList(), + read: (json['read'] as List) + ?.map((e) => e == null + ? null + : Read.fromJson((e as Map)?.map( + (k, e) => MapEntry(k as String, e), + ))) + ?.toList(), + ); +} + +Map _$ChannelStateToJson(ChannelState instance) => + { + 'channel': instance.channel?.toJson(), + 'messages': instance.messages?.map((e) => e?.toJson())?.toList(), + 'members': instance.members?.map((e) => e?.toJson())?.toList(), + 'watcher_count': instance.watcherCount, + 'watchers': instance.watchers?.map((e) => e?.toJson())?.toList(), + 'read': instance.read?.map((e) => e?.toJson())?.toList(), + }; diff --git a/packages/dart_client/lib/src/models/command.dart b/packages/dart_client/lib/src/models/command.dart new file mode 100644 index 00000000..420f2195 --- /dev/null +++ b/packages/dart_client/lib/src/models/command.dart @@ -0,0 +1,30 @@ +import 'package:json_annotation/json_annotation.dart'; + +part 'command.g.dart'; + +/// The class that contains the information about a command +@JsonSerializable() +class Command { + /// The name of the command + final String name; + + /// The description explaining the command + final String description; + + /// The arguments of the command + final String args; + + /// Constructor used for json serialization + Command({ + this.name, + this.description, + this.args, + }); + + /// Create a new instance from a json + factory Command.fromJson(Map json) => + _$CommandFromJson(json); + + /// Serialize to json + Map toJson() => _$CommandToJson(this); +} diff --git a/packages/dart_client/lib/src/models/command.g.dart b/packages/dart_client/lib/src/models/command.g.dart new file mode 100644 index 00000000..f32e8e8a --- /dev/null +++ b/packages/dart_client/lib/src/models/command.g.dart @@ -0,0 +1,21 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'command.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +Command _$CommandFromJson(Map json) { + return Command( + name: json['name'] as String, + description: json['description'] as String, + args: json['args'] as String, + ); +} + +Map _$CommandToJson(Command instance) => { + 'name': instance.name, + 'description': instance.description, + 'args': instance.args, + }; diff --git a/packages/dart_client/lib/src/models/device.dart b/packages/dart_client/lib/src/models/device.dart new file mode 100644 index 00000000..97247222 --- /dev/null +++ b/packages/dart_client/lib/src/models/device.dart @@ -0,0 +1,25 @@ +import 'package:json_annotation/json_annotation.dart'; + +part 'device.g.dart'; + +/// The class that contains the information about a device +@JsonSerializable() +class Device { + /// The id of the device + final String id; + + /// The notification push provider + final String pushProvider; + + /// Constructor used for json serialization + Device({ + this.id, + this.pushProvider, + }); + + /// Create a new instance from a json + factory Device.fromJson(Map json) => _$DeviceFromJson(json); + + /// Serialize to json + Map toJson() => _$DeviceToJson(this); +} diff --git a/packages/dart_client/lib/src/models/device.g.dart b/packages/dart_client/lib/src/models/device.g.dart new file mode 100644 index 00000000..bac60856 --- /dev/null +++ b/packages/dart_client/lib/src/models/device.g.dart @@ -0,0 +1,19 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'device.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +Device _$DeviceFromJson(Map json) { + return Device( + id: json['id'] as String, + pushProvider: json['push_provider'] as String, + ); +} + +Map _$DeviceToJson(Device instance) => { + 'id': instance.id, + 'push_provider': instance.pushProvider, + }; diff --git a/packages/dart_client/lib/src/models/event.dart b/packages/dart_client/lib/src/models/event.dart new file mode 100644 index 00000000..20537185 --- /dev/null +++ b/packages/dart_client/lib/src/models/event.dart @@ -0,0 +1,183 @@ +import 'package:json_annotation/json_annotation.dart'; +import 'package:stream_chat/src/models/channel_model.dart'; +import 'package:stream_chat/src/models/message.dart'; +import 'package:stream_chat/src/models/serialization.dart'; +import 'package:stream_chat/stream_chat.dart'; + +import '../event_type.dart'; +import 'member.dart'; +import 'own_user.dart'; +import 'reaction.dart'; +import 'user.dart'; + +part 'event.g.dart'; + +/// The class that contains the information about an event +@JsonSerializable() +class Event { + /// The type of the event + /// [EventType] contains some predefined constant types + final String type; + + /// The channel cid to which the event belongs + final String cid; + + /// The channel id to which the event belongs + final String channelId; + + /// The channel type to which the event belongs + final String channelType; + + /// The connection id in which the event has been sent + final String connectionId; + + /// The date of creation of the event + final DateTime createdAt; + + /// User object of the health check user + final OwnUser me; + + /// User object of the current user + final User user; + + /// The message sent with the event + final Message message; + + /// The channel sent with the event + final EventChannel channel; + + /// The member sent with the event + final Member member; + + /// The reaction sent with the event + final Reaction reaction; + + /// The number of unread messages for current user + final int totalUnreadCount; + + /// User total unread channels + final int unreadChannels; + + /// Online status + final bool online; + + /// The id of the parent message of a thread + final String parentId; + + /// True if the event is generated by this client + bool isLocal; + + /// Map of custom channel extraData + @JsonKey(includeIfNull: false) + final Map extraData; + + /// Constructor used for json serialization + Event({ + this.type, + this.cid, + this.connectionId, + this.createdAt, + this.me, + this.user, + this.message, + this.totalUnreadCount, + this.unreadChannels, + this.reaction, + this.online, + this.channel, + this.member, + this.channelId, + this.channelType, + this.parentId, + this.extraData, + }) : isLocal = true; + + /// Known top level fields. + /// Useful for [Serialization] methods. + static final topLevelFields = [ + 'type', + 'cid', + 'connection_id', + 'created_at', + 'me', + 'user', + 'message', + 'total_unread_count', + 'unread_channels', + 'reaction', + 'online', + 'channel', + 'member', + 'channel_id', + 'channel_type', + 'parent_id', + 'is_local', + ]; + + /// Create a new instance from a json + factory Event.fromJson(Map json) { + return _$EventFromJson(Serialization.moveToExtraDataFromRoot( + json, + topLevelFields, + )) + ..isLocal = false; + } + + /// Serialize to json + Map toJson() => Serialization.moveFromExtraDataToRoot( + _$EventToJson(this), + topLevelFields, + ); +} + +/// The channel embedded in the event object +@JsonSerializable() +class EventChannel extends ChannelModel { + /// A paginated list of channel members + final List members; + + /// Known top level fields. + /// Useful for [Serialization] methods. + static final topLevelFields = [ + 'members', + ...ChannelModel.topLevelFields, + ]; + + /// Constructor used for json serialization + EventChannel({ + this.members, + String id, + String type, + String cid, + ChannelConfig config, + User createdBy, + bool frozen, + DateTime lastMessageAt, + DateTime createdAt, + DateTime updatedAt, + DateTime deletedAt, + int memberCount, + Map extraData, + }) : super( + id: id, + type: type, + cid: cid, + config: config, + createdBy: createdBy, + frozen: frozen, + lastMessageAt: lastMessageAt, + createdAt: createdAt, + updatedAt: updatedAt, + deletedAt: deletedAt, + memberCount: memberCount, + extraData: extraData, + ); + + /// Create a new instance from a json + factory EventChannel.fromJson(Map json) { + return _$EventChannelFromJson(Serialization.moveToExtraDataFromRoot( + json, + topLevelFields, + )); + } +} diff --git a/packages/dart_client/lib/src/models/event.g.dart b/packages/dart_client/lib/src/models/event.g.dart new file mode 100644 index 00000000..aaef8181 --- /dev/null +++ b/packages/dart_client/lib/src/models/event.g.dart @@ -0,0 +1,156 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'event.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +Event _$EventFromJson(Map json) { + return Event( + type: json['type'] as String, + cid: json['cid'] as String, + connectionId: json['connection_id'] as String, + createdAt: json['created_at'] == null + ? null + : DateTime.parse(json['created_at'] as String), + me: json['me'] == null + ? null + : OwnUser.fromJson((json['me'] as Map)?.map( + (k, e) => MapEntry(k as String, e), + )), + user: json['user'] == null + ? null + : User.fromJson((json['user'] as Map)?.map( + (k, e) => MapEntry(k as String, e), + )), + message: json['message'] == null + ? null + : Message.fromJson((json['message'] as Map)?.map( + (k, e) => MapEntry(k as String, e), + )), + totalUnreadCount: json['total_unread_count'] as int, + unreadChannels: json['unread_channels'] as int, + reaction: json['reaction'] == null + ? null + : Reaction.fromJson((json['reaction'] as Map)?.map( + (k, e) => MapEntry(k as String, e), + )), + online: json['online'] as bool, + channel: json['channel'] == null + ? null + : EventChannel.fromJson((json['channel'] as Map)?.map( + (k, e) => MapEntry(k as String, e), + )), + member: json['member'] == null + ? null + : Member.fromJson((json['member'] as Map)?.map( + (k, e) => MapEntry(k as String, e), + )), + channelId: json['channel_id'] as String, + channelType: json['channel_type'] as String, + parentId: json['parent_id'] as String, + extraData: (json['extra_data'] as Map)?.map( + (k, e) => MapEntry(k as String, e), + ), + )..isLocal = json['is_local'] as bool; +} + +Map _$EventToJson(Event instance) { + final val = { + 'type': instance.type, + 'cid': instance.cid, + 'channel_id': instance.channelId, + 'channel_type': instance.channelType, + 'connection_id': instance.connectionId, + 'created_at': instance.createdAt?.toIso8601String(), + 'me': instance.me?.toJson(), + 'user': instance.user?.toJson(), + 'message': instance.message?.toJson(), + 'channel': instance.channel?.toJson(), + 'member': instance.member?.toJson(), + 'reaction': instance.reaction?.toJson(), + 'total_unread_count': instance.totalUnreadCount, + 'unread_channels': instance.unreadChannels, + 'online': instance.online, + 'parent_id': instance.parentId, + 'is_local': instance.isLocal, + }; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('extra_data', instance.extraData); + return val; +} + +EventChannel _$EventChannelFromJson(Map json) { + return EventChannel( + members: (json['members'] as List) + ?.map((e) => e == null + ? null + : Member.fromJson((e as Map)?.map( + (k, e) => MapEntry(k as String, e), + ))) + ?.toList(), + id: json['id'] as String, + type: json['type'] as String, + cid: json['cid'] as String, + config: json['config'] == null + ? null + : ChannelConfig.fromJson((json['config'] as Map)?.map( + (k, e) => MapEntry(k as String, e), + )), + createdBy: json['created_by'] == null + ? null + : User.fromJson((json['created_by'] as Map)?.map( + (k, e) => MapEntry(k as String, e), + )), + frozen: json['frozen'] as bool, + lastMessageAt: json['last_message_at'] == null + ? null + : DateTime.parse(json['last_message_at'] as String), + createdAt: json['created_at'] == null + ? null + : DateTime.parse(json['created_at'] as String), + updatedAt: json['updated_at'] == null + ? null + : DateTime.parse(json['updated_at'] as String), + deletedAt: json['deleted_at'] == null + ? null + : DateTime.parse(json['deleted_at'] as String), + memberCount: json['member_count'] as int, + extraData: (json['extra_data'] as Map)?.map( + (k, e) => MapEntry(k as String, e), + ), + ); +} + +Map _$EventChannelToJson(EventChannel instance) { + final val = { + 'id': instance.id, + 'type': instance.type, + }; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('cid', readonly(instance.cid)); + writeNotNull('config', readonly(instance.config)); + writeNotNull('created_by', readonly(instance.createdBy)); + writeNotNull('frozen', instance.frozen); + writeNotNull('last_message_at', readonly(instance.lastMessageAt)); + writeNotNull('created_at', readonly(instance.createdAt)); + writeNotNull('updated_at', readonly(instance.updatedAt)); + writeNotNull('deleted_at', readonly(instance.deletedAt)); + writeNotNull('member_count', readonly(instance.memberCount)); + writeNotNull('extra_data', instance.extraData); + val['members'] = instance.members?.map((e) => e?.toJson())?.toList(); + return val; +} diff --git a/packages/dart_client/lib/src/models/member.dart b/packages/dart_client/lib/src/models/member.dart new file mode 100644 index 00000000..511b7a7b --- /dev/null +++ b/packages/dart_client/lib/src/models/member.dart @@ -0,0 +1,96 @@ +import 'package:json_annotation/json_annotation.dart'; + +import '../models/user.dart'; + +part 'member.g.dart'; + +/// The class that contains the information about the user membership in a channel +@JsonSerializable() +class Member { + /// The interested user + final User user; + + /// The date in which the user accepted the invite to the channel + final DateTime inviteAcceptedAt; + + /// The date in which the user rejected the invite to the channel + final DateTime inviteRejectedAt; + + /// True if the user has been invited to the channel + final bool invited; + + /// The role of the user in the channel + final String role; + + /// The id of the interested user + final String userId; + + /// True if the user is a moderator of the channel + final bool isModerator; + + /// True if the member is banned from the channel + final bool banned; + + /// True if the member is shadow banned from the channel + final bool shadowBanned; + + /// The date of creation + final DateTime createdAt; + + /// The last date of update + final DateTime updatedAt; + + /// Constructor used for json serialization + Member({ + this.user, + this.inviteAcceptedAt, + this.inviteRejectedAt, + this.invited, + this.role, + this.userId, + this.isModerator, + this.createdAt, + this.updatedAt, + this.banned, + this.shadowBanned, + }); + + /// Create a new instance from a json + factory Member.fromJson(Map json) { + final member = _$MemberFromJson(json); + return member.copyWith( + userId: member.user?.id, + ); + } + + /// Creates a copy of [Member] with specified attributes overridden. + Member copyWith({ + User user, + DateTime inviteAcceptedAt, + DateTime inviteRejectedAt, + bool invited, + String role, + String userId, + bool isModerator, + DateTime createdAt, + DateTime updatedAt, + bool banned, + bool shadowBanned, + }) => + Member( + user: user ?? this.user, + inviteAcceptedAt: inviteAcceptedAt ?? this.inviteAcceptedAt, + inviteRejectedAt: inviteRejectedAt ?? this.inviteRejectedAt, + invited: invited ?? this.invited, + banned: banned ?? this.banned, + shadowBanned: shadowBanned ?? this.shadowBanned, + role: role ?? this.role, + userId: userId ?? this.userId, + isModerator: isModerator ?? this.isModerator, + createdAt: createdAt ?? this.createdAt, + updatedAt: updatedAt ?? this.updatedAt, + ); + + /// Serialize to json + Map toJson() => _$MemberToJson(this); +} diff --git a/packages/dart_client/lib/src/models/member.g.dart b/packages/dart_client/lib/src/models/member.g.dart new file mode 100644 index 00000000..3ac8778e --- /dev/null +++ b/packages/dart_client/lib/src/models/member.g.dart @@ -0,0 +1,49 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'member.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +Member _$MemberFromJson(Map json) { + return Member( + user: json['user'] == null + ? null + : User.fromJson((json['user'] as Map)?.map( + (k, e) => MapEntry(k as String, e), + )), + inviteAcceptedAt: json['invite_accepted_at'] == null + ? null + : DateTime.parse(json['invite_accepted_at'] as String), + inviteRejectedAt: json['invite_rejected_at'] == null + ? null + : DateTime.parse(json['invite_rejected_at'] as String), + invited: json['invited'] as bool, + role: json['role'] as String, + userId: json['user_id'] as String, + isModerator: json['is_moderator'] as bool, + createdAt: json['created_at'] == null + ? null + : DateTime.parse(json['created_at'] as String), + updatedAt: json['updated_at'] == null + ? null + : DateTime.parse(json['updated_at'] as String), + banned: json['banned'] as bool, + shadowBanned: json['shadow_banned'] as bool, + ); +} + +Map _$MemberToJson(Member instance) => { + 'user': instance.user?.toJson(), + 'invite_accepted_at': instance.inviteAcceptedAt?.toIso8601String(), + 'invite_rejected_at': instance.inviteRejectedAt?.toIso8601String(), + 'invited': instance.invited, + 'role': instance.role, + 'user_id': instance.userId, + 'is_moderator': instance.isModerator, + 'banned': instance.banned, + 'shadow_banned': instance.shadowBanned, + 'created_at': instance.createdAt?.toIso8601String(), + 'updated_at': instance.updatedAt?.toIso8601String(), + }; diff --git a/packages/dart_client/lib/src/models/message.dart b/packages/dart_client/lib/src/models/message.dart new file mode 100644 index 00000000..46f2551a --- /dev/null +++ b/packages/dart_client/lib/src/models/message.dart @@ -0,0 +1,278 @@ +import 'package:json_annotation/json_annotation.dart'; + +import 'attachment.dart'; +import 'reaction.dart'; +import 'serialization.dart'; +import 'user.dart'; + +part 'message.g.dart'; + +/// Enum defining the status of a sending message +enum MessageSendingStatus { + /// Message is being sent + SENDING, + + /// Message is being updated + UPDATING, + + /// Message is being deleted + DELETING, + + /// Message failed to send + FAILED, + + /// Message failed to updated + FAILED_UPDATE, + + /// Message failed to delete + FAILED_DELETE, + + /// Message correctly sent + SENT, +} + +/// The class that contains the information about a message +@JsonSerializable() +class Message { + /// The message ID. This is either created by Stream or set client side when the message is added. + final String id; + + /// The text of this message + final String text; + + /// The status of a sending message + @JsonKey(ignore: true) + final MessageSendingStatus status; + + /// The message type + @JsonKey(includeIfNull: false, toJson: Serialization.readOnly) + final String type; + + /// The list of attachments, either provided by the user or generated from a command or as a result of URL scraping. + @JsonKey(includeIfNull: false) + final List attachments; + + /// The list of user mentioned in the message + @JsonKey(toJson: Serialization.userIds) + final List mentionedUsers; + + /// A map describing the count of number of every reaction + @JsonKey(includeIfNull: false, toJson: Serialization.readOnly) + final Map reactionCounts; + + /// A map describing the count of score of every reaction + @JsonKey(includeIfNull: false, toJson: Serialization.readOnly) + final Map reactionScores; + + /// The latest reactions to the message created by any user. + @JsonKey(includeIfNull: false, toJson: Serialization.readOnly) + final List latestReactions; + + /// The reactions added to the message by the current user. + @JsonKey(includeIfNull: false, toJson: Serialization.readOnly) + final List ownReactions; + + /// The ID of the parent message, if the message is a reply. + final String parentId; + + /// A quoted reply message + @JsonKey(toJson: Serialization.readOnly) + final Message quotedMessage; + + /// The ID of the quoted message, if the message is a quoted reply. + final String quotedMessageId; + + /// Reserved field indicating the number of replies for this message. + @JsonKey(includeIfNull: false, toJson: Serialization.readOnly) + final int replyCount; + + /// Reserved field indicating the thread participants for this message. + @JsonKey(includeIfNull: false, toJson: Serialization.readOnly) + final List threadParticipants; + + /// Check if this message needs to show in the channel. + final bool showInChannel; + + /// If true the message is silent + final bool silent; + + /// If true the message is shadowed + @JsonKey(includeIfNull: false, toJson: Serialization.readOnly) + final bool shadowed; + + /// A used command name. + @JsonKey(includeIfNull: false, toJson: Serialization.readOnly) + final String command; + + /// Reserved field indicating when the message was created. + @JsonKey(includeIfNull: false, toJson: Serialization.readOnly) + final DateTime createdAt; + + /// Reserved field indicating when the message was updated last time. + @JsonKey(includeIfNull: false, toJson: Serialization.readOnly) + final DateTime updatedAt; + + /// User who sent the message + @JsonKey(includeIfNull: false, toJson: Serialization.readOnly) + final User user; + + /// Message custom extraData + @JsonKey(includeIfNull: false) + final Map extraData; + + /// True if the message is a system info + bool get isSystem => type == 'system'; + + /// True if the message has been deleted + bool get isDeleted => type == 'deleted'; + + /// True if the message is ephemeral + bool get isEphemeral => type == 'ephemeral'; + + /// Reserved field indicating when the message was deleted. + @JsonKey(includeIfNull: false, toJson: Serialization.readOnly) + final DateTime deletedAt; + + /// Known top level fields. + /// Useful for [Serialization] methods. + static const topLevelFields = [ + 'id', + 'text', + 'type', + 'silent', + 'attachments', + 'latest_reactions', + 'shadowed', + 'own_reactions', + 'mentioned_users', + 'reaction_counts', + 'reaction_scores', + 'silent', + 'parent_id', + 'quoted_message', + 'quoted_message_id', + 'reply_count', + 'thread_participants', + 'show_in_channel', + 'command', + 'created_at', + 'updated_at', + 'deleted_at', + 'user', + ]; + + /// Constructor used for json serialization + Message({ + this.id, + this.text, + this.type, + this.attachments, + this.mentionedUsers, + this.silent, + this.shadowed, + this.reactionCounts, + this.reactionScores, + this.latestReactions, + this.ownReactions, + this.parentId, + this.quotedMessage, + this.quotedMessageId, + this.replyCount = 0, + this.threadParticipants, + this.showInChannel, + this.command, + this.createdAt, + this.updatedAt, + this.user, + this.extraData, + this.deletedAt, + this.status = MessageSendingStatus.SENT, + }); + + /// Create a new instance from a json + factory Message.fromJson(Map json) => _$MessageFromJson( + Serialization.moveToExtraDataFromRoot(json, topLevelFields)); + + /// Serialize to json + Map toJson() => Serialization.moveFromExtraDataToRoot( + _$MessageToJson(this), topLevelFields); + + /// Creates a copy of [Message] with specified attributes overridden. + Message copyWith({ + String id, + String text, + String type, + List attachments, + List mentionedUsers, + Map reactionCounts, + Map reactionScores, + List latestReactions, + List ownReactions, + String parentId, + Message quotedMessage, + String quotedMessageId, + int replyCount, + List threadParticipants, + bool showInChannel, + bool shadowed, + bool silent, + String command, + DateTime createdAt, + DateTime updatedAt, + DateTime deletedAt, + User user, + Map extraData, + MessageSendingStatus status, + }) => + Message( + id: id ?? this.id, + text: text ?? this.text, + type: type ?? this.type, + attachments: attachments ?? this.attachments, + mentionedUsers: mentionedUsers ?? this.mentionedUsers, + reactionCounts: reactionCounts ?? this.reactionCounts, + reactionScores: reactionScores ?? this.reactionScores, + latestReactions: latestReactions ?? this.latestReactions, + ownReactions: ownReactions ?? this.ownReactions, + parentId: parentId ?? this.parentId, + quotedMessage: quotedMessage ?? this.quotedMessage, + quotedMessageId: quotedMessageId ?? this.quotedMessageId, + replyCount: replyCount ?? this.replyCount, + threadParticipants: threadParticipants ?? this.threadParticipants, + showInChannel: showInChannel ?? this.showInChannel, + command: command ?? this.command, + createdAt: createdAt ?? this.createdAt, + silent: silent ?? this.silent, + extraData: extraData ?? this.extraData, + user: user ?? this.user, + shadowed: shadowed ?? this.shadowed, + updatedAt: updatedAt ?? this.updatedAt, + deletedAt: deletedAt ?? this.deletedAt, + status: status ?? this.status, + ); +} + +/// A translated message +/// It has an additional property called [i18n] +@JsonSerializable() +class TranslatedMessage extends Message { + /// Constructor used for json serialization + TranslatedMessage(this.i18n); + + /// A Map of + final Map i18n; + + /// Known top level fields. + /// Useful for [Serialization] methods. + static final topLevelFields = [ + 'i18n', + ...Message.topLevelFields, + ]; + + /// Create a new instance from a json + factory TranslatedMessage.fromJson(Map json) { + return _$TranslatedMessageFromJson( + Serialization.moveToExtraDataFromRoot(json, topLevelFields), + ); + } +} diff --git a/packages/dart_client/lib/src/models/message.g.dart b/packages/dart_client/lib/src/models/message.g.dart new file mode 100644 index 00000000..c30d8fe5 --- /dev/null +++ b/packages/dart_client/lib/src/models/message.g.dart @@ -0,0 +1,135 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'message.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +Message _$MessageFromJson(Map json) { + return Message( + id: json['id'] as String, + text: json['text'] as String, + type: json['type'] as String, + attachments: (json['attachments'] as List) + ?.map((e) => e == null + ? null + : Attachment.fromJson((e as Map)?.map( + (k, e) => MapEntry(k as String, e), + ))) + ?.toList(), + mentionedUsers: (json['mentioned_users'] as List) + ?.map((e) => e == null + ? null + : User.fromJson((e as Map)?.map( + (k, e) => MapEntry(k as String, e), + ))) + ?.toList(), + silent: json['silent'] as bool, + shadowed: json['shadowed'] as bool, + reactionCounts: (json['reaction_counts'] as Map)?.map( + (k, e) => MapEntry(k as String, e as int), + ), + reactionScores: (json['reaction_scores'] as Map)?.map( + (k, e) => MapEntry(k as String, e as int), + ), + latestReactions: (json['latest_reactions'] as List) + ?.map((e) => e == null + ? null + : Reaction.fromJson((e as Map)?.map( + (k, e) => MapEntry(k as String, e), + ))) + ?.toList(), + ownReactions: (json['own_reactions'] as List) + ?.map((e) => e == null + ? null + : Reaction.fromJson((e as Map)?.map( + (k, e) => MapEntry(k as String, e), + ))) + ?.toList(), + parentId: json['parent_id'] as String, + quotedMessage: json['quoted_message'] == null + ? null + : Message.fromJson((json['quoted_message'] as Map)?.map( + (k, e) => MapEntry(k as String, e), + )), + quotedMessageId: json['quoted_message_id'] as String, + replyCount: json['reply_count'] as int, + threadParticipants: (json['thread_participants'] as List) + ?.map((e) => e == null + ? null + : User.fromJson((e as Map)?.map( + (k, e) => MapEntry(k as String, e), + ))) + ?.toList(), + showInChannel: json['show_in_channel'] as bool, + command: json['command'] as String, + createdAt: json['created_at'] == null + ? null + : DateTime.parse(json['created_at'] as String), + updatedAt: json['updated_at'] == null + ? null + : DateTime.parse(json['updated_at'] as String), + user: json['user'] == null + ? null + : User.fromJson((json['user'] as Map)?.map( + (k, e) => MapEntry(k as String, e), + )), + extraData: (json['extra_data'] as Map)?.map( + (k, e) => MapEntry(k as String, e), + ), + deletedAt: json['deleted_at'] == null + ? null + : DateTime.parse(json['deleted_at'] as String), + ); +} + +Map _$MessageToJson(Message instance) { + final val = { + 'id': instance.id, + 'text': instance.text, + }; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('type', readonly(instance.type)); + writeNotNull( + 'attachments', instance.attachments?.map((e) => e?.toJson())?.toList()); + val['mentioned_users'] = Serialization.userIds(instance.mentionedUsers); + writeNotNull('reaction_counts', readonly(instance.reactionCounts)); + writeNotNull('reaction_scores', readonly(instance.reactionScores)); + writeNotNull('latest_reactions', readonly(instance.latestReactions)); + writeNotNull('own_reactions', readonly(instance.ownReactions)); + val['parent_id'] = instance.parentId; + val['quoted_message'] = readonly(instance.quotedMessage); + val['quoted_message_id'] = instance.quotedMessageId; + writeNotNull('reply_count', readonly(instance.replyCount)); + writeNotNull('thread_participants', readonly(instance.threadParticipants)); + val['show_in_channel'] = instance.showInChannel; + val['silent'] = instance.silent; + writeNotNull('shadowed', readonly(instance.shadowed)); + writeNotNull('command', readonly(instance.command)); + writeNotNull('created_at', readonly(instance.createdAt)); + writeNotNull('updated_at', readonly(instance.updatedAt)); + writeNotNull('user', readonly(instance.user)); + writeNotNull('extra_data', instance.extraData); + writeNotNull('deleted_at', readonly(instance.deletedAt)); + return val; +} + +TranslatedMessage _$TranslatedMessageFromJson(Map json) { + return TranslatedMessage( + (json['i18n'] as Map)?.map( + (k, e) => MapEntry(k as String, e as String), + ), + ); +} + +Map _$TranslatedMessageToJson(TranslatedMessage instance) => + { + 'i18n': instance.i18n, + }; diff --git a/packages/dart_client/lib/src/models/mute.dart b/packages/dart_client/lib/src/models/mute.dart new file mode 100644 index 00000000..f33a9956 --- /dev/null +++ b/packages/dart_client/lib/src/models/mute.dart @@ -0,0 +1,36 @@ +import 'package:json_annotation/json_annotation.dart'; +import 'package:stream_chat/src/models/channel_model.dart'; + +import 'serialization.dart'; +import 'user.dart'; + +part 'mute.g.dart'; + +/// The class that contains the information about a muted user +@JsonSerializable() +class Mute { + /// The user that performed the muting action + @JsonKey(includeIfNull: false, toJson: Serialization.readOnly) + final User user; + + /// The target user + @JsonKey(includeIfNull: false, toJson: Serialization.readOnly) + final ChannelModel channel; + + /// The date in which the use was muted + @JsonKey(includeIfNull: false, toJson: Serialization.readOnly) + final DateTime createdAt; + + /// The date of the last update + @JsonKey(includeIfNull: false, toJson: Serialization.readOnly) + final DateTime updatedAt; + + /// Constructor used for json serialization + Mute({this.user, this.channel, this.createdAt, this.updatedAt}); + + /// Create a new instance from a json + factory Mute.fromJson(Map json) => _$MuteFromJson(json); + + /// Serialize to json + Map toJson() => _$MuteToJson(this); +} diff --git a/packages/dart_client/lib/src/models/mute.g.dart b/packages/dart_client/lib/src/models/mute.g.dart new file mode 100644 index 00000000..9d0b9318 --- /dev/null +++ b/packages/dart_client/lib/src/models/mute.g.dart @@ -0,0 +1,44 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'mute.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +Mute _$MuteFromJson(Map json) { + return Mute( + user: json['user'] == null + ? null + : User.fromJson((json['user'] as Map)?.map( + (k, e) => MapEntry(k as String, e), + )), + channel: json['channel'] == null + ? null + : ChannelModel.fromJson((json['channel'] as Map)?.map( + (k, e) => MapEntry(k as String, e), + )), + createdAt: json['created_at'] == null + ? null + : DateTime.parse(json['created_at'] as String), + updatedAt: json['updated_at'] == null + ? null + : DateTime.parse(json['updated_at'] as String), + ); +} + +Map _$MuteToJson(Mute instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('user', readonly(instance.user)); + writeNotNull('channel', readonly(instance.channel)); + writeNotNull('created_at', readonly(instance.createdAt)); + writeNotNull('updated_at', readonly(instance.updatedAt)); + return val; +} diff --git a/packages/dart_client/lib/src/models/own_user.dart b/packages/dart_client/lib/src/models/own_user.dart new file mode 100644 index 00000000..3246788c --- /dev/null +++ b/packages/dart_client/lib/src/models/own_user.dart @@ -0,0 +1,83 @@ +import 'package:json_annotation/json_annotation.dart'; + +import 'device.dart'; +import 'mute.dart'; +import 'serialization.dart'; +import 'user.dart'; + +part 'own_user.g.dart'; + +/// The class that defines the own user model +/// This object can be found in [Event] +@JsonSerializable() +class OwnUser extends User { + /// List of user devices + @JsonKey(includeIfNull: false, toJson: Serialization.readOnly) + final List devices; + + /// List of users muted by the user + @JsonKey(includeIfNull: false, toJson: Serialization.readOnly) + final List mutes; + + /// List of users muted by the user + @JsonKey(includeIfNull: false, toJson: Serialization.readOnly) + final List channelMutes; + + /// Total unread messages by the user + @JsonKey(includeIfNull: false, toJson: Serialization.readOnly) + final int totalUnreadCount; + + /// Total unread channels by the user + @JsonKey(includeIfNull: false, toJson: Serialization.readOnly) + final int unreadChannels; + + /// Known top level fields. + /// Useful for [Serialization] methods. + static final topLevelFields = [ + 'devices', + 'mutes', + 'total_unread_count', + 'unread_channels', + 'channel_mutes', + ...User.topLevelFields, + ]; + + /// Constructor used for json serialization + OwnUser({ + this.devices, + this.mutes, + this.totalUnreadCount, + this.unreadChannels, + this.channelMutes, + String id, + String role, + DateTime createdAt, + DateTime updatedAt, + DateTime lastActive, + bool online, + Map extraData, + bool banned, + }) : super( + id: id, + role: role, + createdAt: createdAt, + updatedAt: updatedAt, + lastActive: lastActive, + online: online, + extraData: extraData, + banned: banned, + ); + + /// Create a new instance from a json + factory OwnUser.fromJson(Map json) { + return _$OwnUserFromJson( + Serialization.moveToExtraDataFromRoot(json, topLevelFields)); + } + + /// Serialize to json + @override + Map toJson() { + return Serialization.moveFromExtraDataToRoot( + _$OwnUserToJson(this), topLevelFields); + } +} diff --git a/packages/dart_client/lib/src/models/own_user.g.dart b/packages/dart_client/lib/src/models/own_user.g.dart new file mode 100644 index 00000000..887e6b28 --- /dev/null +++ b/packages/dart_client/lib/src/models/own_user.g.dart @@ -0,0 +1,77 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'own_user.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +OwnUser _$OwnUserFromJson(Map json) { + return OwnUser( + devices: (json['devices'] as List) + ?.map((e) => e == null + ? null + : Device.fromJson((e as Map)?.map( + (k, e) => MapEntry(k as String, e), + ))) + ?.toList(), + mutes: (json['mutes'] as List) + ?.map((e) => e == null + ? null + : Mute.fromJson((e as Map)?.map( + (k, e) => MapEntry(k as String, e), + ))) + ?.toList(), + totalUnreadCount: json['total_unread_count'] as int, + unreadChannels: json['unread_channels'] as int, + channelMutes: (json['channel_mutes'] as List) + ?.map((e) => e == null + ? null + : Mute.fromJson((e as Map)?.map( + (k, e) => MapEntry(k as String, e), + ))) + ?.toList(), + id: json['id'] as String, + role: json['role'] as String, + createdAt: json['created_at'] == null + ? null + : DateTime.parse(json['created_at'] as String), + updatedAt: json['updated_at'] == null + ? null + : DateTime.parse(json['updated_at'] as String), + lastActive: json['last_active'] == null + ? null + : DateTime.parse(json['last_active'] as String), + online: json['online'] as bool, + extraData: (json['extra_data'] as Map)?.map( + (k, e) => MapEntry(k as String, e), + ), + banned: json['banned'] as bool, + ); +} + +Map _$OwnUserToJson(OwnUser instance) { + final val = { + 'id': instance.id, + }; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('role', readonly(instance.role)); + writeNotNull('created_at', readonly(instance.createdAt)); + writeNotNull('updated_at', readonly(instance.updatedAt)); + writeNotNull('last_active', readonly(instance.lastActive)); + writeNotNull('online', readonly(instance.online)); + writeNotNull('banned', readonly(instance.banned)); + writeNotNull('extra_data', instance.extraData); + writeNotNull('devices', readonly(instance.devices)); + writeNotNull('mutes', readonly(instance.mutes)); + writeNotNull('channel_mutes', readonly(instance.channelMutes)); + writeNotNull('total_unread_count', readonly(instance.totalUnreadCount)); + writeNotNull('unread_channels', readonly(instance.unreadChannels)); + return val; +} diff --git a/packages/dart_client/lib/src/models/reaction.dart b/packages/dart_client/lib/src/models/reaction.dart new file mode 100644 index 00000000..fb0c4fad --- /dev/null +++ b/packages/dart_client/lib/src/models/reaction.dart @@ -0,0 +1,68 @@ +import 'package:json_annotation/json_annotation.dart'; + +import 'serialization.dart'; +import 'user.dart'; + +part 'reaction.g.dart'; + +/// The class that defines a reaction +@JsonSerializable() +class Reaction { + /// The messageId to which the reaction belongs + final String messageId; + + /// The type of the reaction + final String type; + + /// The date of the reaction + @JsonKey(includeIfNull: false, toJson: Serialization.readOnly) + final DateTime createdAt; + + /// The user that sent the reaction + @JsonKey(includeIfNull: false, toJson: Serialization.readOnly) + final User user; + + /// The score of the reaction (ie. number of reactions sent) + final int score; + + /// The userId that sent the reaction + @JsonKey(includeIfNull: false, toJson: Serialization.readOnly) + final String userId; + + /// The score of the reaction (ie. number of reactions sent) + @JsonKey(includeIfNull: false) + final Map extraData; + + /// Map of custom user extraData + static const topLevelFields = [ + 'message_id', + 'created_at', + 'type', + 'user', + 'user_id', + 'score', + ]; + + /// Constructor used for json serialization + Reaction({ + this.messageId, + this.createdAt, + this.type, + this.user, + this.userId, + this.score, + this.extraData, + }); + + /// Create a new instance from a json + factory Reaction.fromJson(Map json) { + return _$ReactionFromJson( + Serialization.moveToExtraDataFromRoot(json, topLevelFields)); + } + + /// Serialize to json + Map toJson() { + return Serialization.moveFromExtraDataToRoot( + _$ReactionToJson(this), topLevelFields); + } +} diff --git a/packages/dart_client/lib/src/models/reaction.g.dart b/packages/dart_client/lib/src/models/reaction.g.dart new file mode 100644 index 00000000..a270af01 --- /dev/null +++ b/packages/dart_client/lib/src/models/reaction.g.dart @@ -0,0 +1,47 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'reaction.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +Reaction _$ReactionFromJson(Map json) { + return Reaction( + messageId: json['message_id'] as String, + createdAt: json['created_at'] == null + ? null + : DateTime.parse(json['created_at'] as String), + type: json['type'] as String, + user: json['user'] == null + ? null + : User.fromJson((json['user'] as Map)?.map( + (k, e) => MapEntry(k as String, e), + )), + userId: json['user_id'] as String, + score: json['score'] as int, + extraData: (json['extra_data'] as Map)?.map( + (k, e) => MapEntry(k as String, e), + ), + ); +} + +Map _$ReactionToJson(Reaction instance) { + final val = { + 'message_id': instance.messageId, + 'type': instance.type, + }; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('created_at', readonly(instance.createdAt)); + writeNotNull('user', readonly(instance.user)); + val['score'] = instance.score; + writeNotNull('user_id', readonly(instance.userId)); + writeNotNull('extra_data', instance.extraData); + return val; +} diff --git a/packages/dart_client/lib/src/models/read.dart b/packages/dart_client/lib/src/models/read.dart new file mode 100644 index 00000000..ae85293d --- /dev/null +++ b/packages/dart_client/lib/src/models/read.dart @@ -0,0 +1,31 @@ +import 'package:json_annotation/json_annotation.dart'; + +import 'user.dart'; + +part 'read.g.dart'; + +/// The class that defines a read event +@JsonSerializable() +class Read { + /// Date of the read event + final DateTime lastRead; + + /// User who sent the event + final User user; + + /// Number of unread messages + final int unreadMessages; + + /// Constructor used for json serialization + Read({ + this.lastRead, + this.user, + this.unreadMessages, + }); + + /// Create a new instance from a json + factory Read.fromJson(Map json) => _$ReadFromJson(json); + + /// Serialize to json + Map toJson() => _$ReadToJson(this); +} diff --git a/packages/dart_client/lib/src/models/read.g.dart b/packages/dart_client/lib/src/models/read.g.dart new file mode 100644 index 00000000..d04ae146 --- /dev/null +++ b/packages/dart_client/lib/src/models/read.g.dart @@ -0,0 +1,27 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'read.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +Read _$ReadFromJson(Map json) { + return Read( + lastRead: json['last_read'] == null + ? null + : DateTime.parse(json['last_read'] as String), + user: json['user'] == null + ? null + : User.fromJson((json['user'] as Map)?.map( + (k, e) => MapEntry(k as String, e), + )), + unreadMessages: json['unread_messages'] as int, + ); +} + +Map _$ReadToJson(Read instance) => { + 'last_read': instance.lastRead?.toIso8601String(), + 'user': instance.user?.toJson(), + 'unread_messages': instance.unreadMessages, + }; diff --git a/packages/dart_client/lib/src/models/serialization.dart b/packages/dart_client/lib/src/models/serialization.dart new file mode 100644 index 00000000..239ccb50 --- /dev/null +++ b/packages/dart_client/lib/src/models/serialization.dart @@ -0,0 +1,49 @@ +import 'user.dart'; + +/// Used to avoid to serialize properties to json +Null readonly(_) => null; + +/// Helper class for serialization to and from json +class Serialization { + /// Used to avoid to serialize properties to json + static const Function readOnly = readonly; + + /// List of users to list of userIds + static List userIds(List users) { + return users?.map((u) => u.id)?.toList(); + } + + /// Takes unknown json keys and puts them in the `extra_data` key + static Map moveToExtraDataFromRoot( + Map json, + List topLevelFields, + ) { + if (json == null) return null; + + final jsonClone = Map.from(json); + + final extraDataMap = Map.from(json) + ..removeWhere( + (key, value) => topLevelFields.contains(key), + ); + final rootFields = jsonClone + ..removeWhere((key, value) => extraDataMap.keys.contains(key)); + return rootFields + ..addAll({ + 'extra_data': extraDataMap, + }); + } + + /// Takes values in `extra_data` key and puts them on the root level of the json map + static Map moveFromExtraDataToRoot( + Map json, + List topLevelFields, + ) { + final jsonClone = Map.from(json); + return jsonClone + ..addAll({ + if (json['extra_data'] != null) ...json['extra_data'], + }) + ..remove('extra_data'); + } +} diff --git a/packages/dart_client/lib/src/models/user.dart b/packages/dart_client/lib/src/models/user.dart new file mode 100644 index 00000000..00ed1200 --- /dev/null +++ b/packages/dart_client/lib/src/models/user.dart @@ -0,0 +1,108 @@ +import 'package:json_annotation/json_annotation.dart'; + +import 'serialization.dart'; + +part 'user.g.dart'; + +/// The class that defines the user model +@JsonSerializable() +class User { + /// User id + final String id; + + /// User role + @JsonKey(includeIfNull: false, toJson: Serialization.readOnly) + final String role; + + /// User role + @JsonKey(includeIfNull: false, toJson: Serialization.readOnly) + final List teams; + + /// Date of user creation + @JsonKey(includeIfNull: false, toJson: Serialization.readOnly) + final DateTime createdAt; + + /// Date of last user update + @JsonKey(includeIfNull: false, toJson: Serialization.readOnly) + final DateTime updatedAt; + + /// Date of last user connection + @JsonKey(includeIfNull: false, toJson: Serialization.readOnly) + final DateTime lastActive; + + /// True if user is online + @JsonKey(includeIfNull: false, toJson: Serialization.readOnly) + final bool online; + + /// True if user is banned from the chat + @JsonKey(includeIfNull: false, toJson: Serialization.readOnly) + final bool banned; + + /// Map of custom user extraData + @JsonKey(includeIfNull: false) + final Map extraData; + + /// Known top level fields. + /// Useful for [Serialization] methods. + static const topLevelFields = [ + 'id', + 'role', + 'created_at', + 'updated_at', + 'last_active', + 'online', + 'banned', + 'teams', + ]; + + /// Use this named constructor to create a new user instance + User.init( + this.id, { + this.online, + this.extraData, + }) : createdAt = null, + updatedAt = null, + lastActive = null, + banned = null, + teams = null, + role = null; + + /// Constructor used for json serialization + User({ + this.id, + this.role, + this.createdAt, + this.updatedAt, + this.lastActive, + this.online, + this.extraData, + this.banned, + this.teams, + }); + + /// Shortcut for user name + String get name => + (extraData?.containsKey('name') == true && extraData['name'] != '') + ? extraData['name'] + : id; + + /// Create a new instance from a json + factory User.fromJson(Map json) { + return _$UserFromJson( + Serialization.moveToExtraDataFromRoot(json, topLevelFields)); + } + + /// Serialize to json + Map toJson() { + return Serialization.moveFromExtraDataToRoot( + _$UserToJson(this), topLevelFields); + } + + @override + bool operator ==(Object other) => + identical(this, other) || + other is User && runtimeType == other.runtimeType && id == other.id; + + @override + int get hashCode => id.hashCode; +} diff --git a/packages/dart_client/lib/src/models/user.g.dart b/packages/dart_client/lib/src/models/user.g.dart new file mode 100644 index 00000000..b27935a7 --- /dev/null +++ b/packages/dart_client/lib/src/models/user.g.dart @@ -0,0 +1,51 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'user.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +User _$UserFromJson(Map json) { + return User( + id: json['id'] as String, + role: json['role'] as String, + createdAt: json['created_at'] == null + ? null + : DateTime.parse(json['created_at'] as String), + updatedAt: json['updated_at'] == null + ? null + : DateTime.parse(json['updated_at'] as String), + lastActive: json['last_active'] == null + ? null + : DateTime.parse(json['last_active'] as String), + online: json['online'] as bool, + extraData: (json['extra_data'] as Map)?.map( + (k, e) => MapEntry(k as String, e), + ), + banned: json['banned'] as bool, + teams: (json['teams'] as List)?.map((e) => e as String)?.toList(), + ); +} + +Map _$UserToJson(User instance) { + final val = { + 'id': instance.id, + }; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('role', readonly(instance.role)); + writeNotNull('teams', readonly(instance.teams)); + writeNotNull('created_at', readonly(instance.createdAt)); + writeNotNull('updated_at', readonly(instance.updatedAt)); + writeNotNull('last_active', readonly(instance.lastActive)); + writeNotNull('online', readonly(instance.online)); + writeNotNull('banned', readonly(instance.banned)); + writeNotNull('extra_data', instance.extraData); + return val; +} diff --git a/packages/dart_client/lib/src/notifications.dart b/packages/dart_client/lib/src/notifications.dart new file mode 100644 index 00000000..2fc500cf --- /dev/null +++ b/packages/dart_client/lib/src/notifications.dart @@ -0,0 +1,119 @@ +import 'dart:convert'; + +import 'package:logging/logging.dart'; +import 'package:shared_preferences/shared_preferences.dart'; +import 'package:stream_chat/src/api/responses.dart'; +import 'package:stream_chat/src/db/offline_storage.dart'; +import 'package:stream_chat/src/models/channel_model.dart'; +import 'package:stream_chat/src/models/channel_state.dart'; +import 'package:stream_chat/src/models/message.dart'; + +import 'client.dart'; +import 'models/own_user.dart'; + +/// Utility class to handle and show notifications +class NotificationService { + static Future _handleNotification( + Message message, + ChannelModel channelModel, + Client client, + ) async { + if (message != null && client.persistenceEnabled) { + if (client?.state?.channels == null) { + final sharedPreferences = await _getSharedPreferences(); + final userId = sharedPreferences.getString(KEY_USER_ID); + + final offlineStorage = OfflineStorage(userId, Logger('💽')); + await offlineStorage.updateChannelState( + ChannelState( + channel: channelModel, + messages: [message], + ), + ); + await offlineStorage.disconnect(); + } else { + final channel = client.state.channels[channelModel.cid]; + channel.state.updateChannelState( + ChannelState( + channel: channelModel, + messages: [message], + ), + ); + } + } + } + + static SharedPreferences _sharedPreferences; + static Future _getSharedPreferences() async { + _sharedPreferences ??= await SharedPreferences.getInstance(); + return _sharedPreferences; + } + + /// Gets the message using the client without storing it in the offline storage + /// It returns an object containing the information about the message and the channel + static Future getMessage(String messageId) async { + final sharedPreferences = await _getSharedPreferences(); + final apiKey = sharedPreferences.getString(KEY_API_KEY); + + final client = Client( + apiKey, + persistenceEnabled: false, + ); + final userId = sharedPreferences.getString(KEY_USER_ID); + final token = sharedPreferences.getString(KEY_TOKEN); + + client.state.user = OwnUser(id: userId); + client.token = token; + + final res = await client.getMessage(messageId); + return res; + } + + /// Stores the message in the offline storage + static Future storeMessage(GetMessageResponse messageResponse) async { + final sharedPreferences = await _getSharedPreferences(); + final userId = sharedPreferences.getString(KEY_USER_ID); + + final offlineStorage = OfflineStorage( + userId, + Logger('💽'), + ); + + await offlineStorage.updateChannelState(ChannelState( + messages: [messageResponse.message], + channel: messageResponse.channel, + )); + + await offlineStorage.disconnect(); + } + + /// Gets the message using the client and stores it in the offline storage + /// It returns an object containing the information about the message and the channel + static Future getAndStoreMessage(String messageId) async { + final getMessageResponse = await getMessage(messageId); + await storeMessage(getMessageResponse); + return getMessageResponse; + } + + /// Handles the ios message queue generated by the Notification Service Extension + static Future handleIosMessageQueue(Client client) async { + final sharedPreferences = await SharedPreferences.getInstance(); + await sharedPreferences.reload(); + final messageQueue = sharedPreferences.getStringList('messageQueue'); + if (messageQueue != null) { + messageQueue.forEach((m) { + final jsonMessage = jsonDecode(m); + + final message = Message.fromJson(jsonMessage); + final channelModel = ChannelModel.fromJson(jsonMessage['channel']); + + _handleNotification( + message, + channelModel, + client, + ); + }); + await sharedPreferences.remove('messageQueue'); + } + } +} diff --git a/packages/dart_client/lib/stream_chat.dart b/packages/dart_client/lib/stream_chat.dart new file mode 100644 index 00000000..101e9440 --- /dev/null +++ b/packages/dart_client/lib/stream_chat.dart @@ -0,0 +1,29 @@ +library stream_chat; + +export 'package:dio/src/dio_error.dart'; +export 'package:dio/src/multipart_file.dart'; +export 'package:logging/src/level.dart'; + +export './src/api/channel.dart'; +export './src/api/connection_status.dart'; +export './src/api/requests.dart'; +export './src/api/requests.dart'; +export './src/api/responses.dart'; +export './src/client.dart'; +export './src/event_type.dart'; +export './src/models/action.dart'; +export './src/models/attachment.dart'; +export './src/models/channel_config.dart'; +export './src/models/channel_model.dart'; +export './src/models/channel_state.dart'; +export './src/models/command.dart'; +export './src/models/device.dart'; +export './src/models/event.dart'; +export './src/models/member.dart'; +export './src/models/message.dart'; +export './src/models/mute.dart'; +export './src/models/own_user.dart'; +export './src/models/reaction.dart'; +export './src/models/read.dart'; +export './src/models/user.dart'; +export './src/notifications.dart'; diff --git a/packages/dart_client/lib/version.dart b/packages/dart_client/lib/version.dart new file mode 100644 index 00000000..75bf93d6 --- /dev/null +++ b/packages/dart_client/lib/version.dart @@ -0,0 +1,5 @@ +import 'package:stream_chat/src/client.dart'; + +/// Current package version +/// Used in [Client] to build the `x-stream-client` header +const PACKAGE_VERSION = '0.2.23+1'; diff --git a/packages/dart_client/peanut.yaml b/packages/dart_client/peanut.yaml new file mode 100644 index 00000000..97d20f52 --- /dev/null +++ b/packages/dart_client/peanut.yaml @@ -0,0 +1,3 @@ +# Configuration for https://pub.dev/packages/peanut +directories: + - example/web diff --git a/packages/dart_client/pubspec.yaml b/packages/dart_client/pubspec.yaml new file mode 100644 index 00000000..2c28136d --- /dev/null +++ b/packages/dart_client/pubspec.yaml @@ -0,0 +1,36 @@ +name: stream_chat +homepage: https://getstream.io/ +description: The official Dart client for Stream Chat, a service for building chat applications. +version: 0.2.23+1 +repository: https://github.com/GetStream/stream-chat-dart +issue_tracker: https://github.com/GetStream/stream-chat-dart/issues + +environment: + sdk: ">=2.2.2 <3.0.0" + +dependencies: + flutter: + sdk: flutter + json_annotation: ^3.0.1 + shared_preferences: ^0.5.7+3 + logging: ^0.11.4 + dio: ^3.0.10 + web_socket_channel: ^1.1.0 + uuid: ^2.2.2 + async: ^2.4.1 + stream_channel: ^2.0.0 + moor: ^3.3.1 + path_provider: ^1.6.10 + path: ^1.6.4 + rxdart: ^0.24.1 + collection: ^1.14.12 + sqlite3_flutter_libs: ^0.3.0 + +dev_dependencies: + build_runner: ^1.10.0 + json_serializable: ^3.3.0 + moor_generator: ^3.1.0 + flutter_test: + sdk: flutter + pedantic: ^1.8.0+1 + mockito: ^4.1.1 diff --git a/packages/dart_client/test/src/api/channel_test.dart b/packages/dart_client/test/src/api/channel_test.dart new file mode 100644 index 00000000..d83d6f12 --- /dev/null +++ b/packages/dart_client/test/src/api/channel_test.dart @@ -0,0 +1,2099 @@ +import 'package:dio/dio.dart'; +import 'package:dio/native_imp.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mockito/mockito.dart'; +import 'package:stream_chat/src/api/requests.dart'; +import 'package:stream_chat/src/client.dart'; +import 'package:stream_chat/src/event_type.dart'; +import 'package:stream_chat/src/models/event.dart'; +import 'package:stream_chat/src/models/message.dart'; +import 'package:stream_chat/src/models/reaction.dart'; + +class MockDio extends Mock implements DioForNative {} + +class MockHttpClientAdapter extends Mock implements HttpClientAdapter {} + +void main() { + group('src/api/channel', () { + group('message', () { + test('sendMessage', () async { + final mockDio = MockDio(); + + when(mockDio.options).thenReturn(BaseOptions()); + when(mockDio.interceptors).thenReturn(Interceptors()); + + final client = Client( + 'api-key', + httpClient: mockDio, + tokenProvider: (_) async => '', + ); + final channelClient = client.channel('messaging', id: 'testid'); + final message = Message( + text: 'hey', + id: 'test', + ); + + when(mockDio.post('/channels/messaging/testid/message', data: { + 'message': message.toJson(), + })).thenAnswer((_) async => Response(data: '{}', statusCode: 200)); + + await channelClient.sendMessage(message); + + verify( + mockDio.post('/channels/messaging/testid/message', data: { + 'message': message.toJson(), + })).called(1); + }); + + test('markRead', () async { + final mockDio = MockDio(); + + when(mockDio.options).thenReturn(BaseOptions()); + when(mockDio.interceptors).thenReturn(Interceptors()); + + final client = Client( + 'api-key', + httpClient: mockDio, + tokenProvider: (_) async => '', + ); + + final channelClient = client.channel('messaging', id: 'testid'); + + when(mockDio.post( + any, + data: anyNamed('data'), + )).thenAnswer((_) async => Response( + data: '{}', + statusCode: 200, + )); + await channelClient.watch(); + + when(mockDio.post('/channels/messaging/testid/read', data: {})) + .thenAnswer((_) async => Response(data: '{}', statusCode: 200)); + + await channelClient.markRead(); + + verify(mockDio.post('/channels/messaging/testid/read', + data: {})).called(1); + }); + + test('getReplies', () async { + final mockDio = MockDio(); + + when(mockDio.options).thenReturn(BaseOptions()); + when(mockDio.interceptors).thenReturn(Interceptors()); + + final client = Client( + 'api-key', + httpClient: mockDio, + tokenProvider: (_) async => '', + ); + final channelClient = client.channel('messaging', id: 'testid'); + final pagination = PaginationParams(); + + when(mockDio.get('/messages/messageid/replies', + queryParameters: pagination.toJson())) + .thenAnswer((_) async => Response(data: '{}', statusCode: 200)); + + await channelClient.getReplies('messageid', pagination); + + verify(mockDio.get('/messages/messageid/replies', + queryParameters: pagination.toJson())) + .called(1); + }); + + test('sendAction', () async { + final mockDio = MockDio(); + + when(mockDio.options).thenReturn(BaseOptions()); + when(mockDio.interceptors).thenReturn(Interceptors()); + + final client = Client( + 'api-key', + httpClient: mockDio, + tokenProvider: (_) async => '', + ); + final channelClient = client.channel('messaging', id: 'testid'); + + when(mockDio.post( + any, + data: anyNamed('data'), + )).thenAnswer((_) async => Response( + data: '{}', + statusCode: 200, + )); + await channelClient.watch(); + + final Map data = {'test': true}; + + when(mockDio.post('/messages/messageid/action', data: { + 'id': 'testid', + 'type': 'messaging', + 'form_data': data, + 'message_id': 'messageid', + })).thenAnswer((_) async => Response(data: '{}', statusCode: 200)); + + await channelClient.sendAction(Message(id: 'messageid'), data); + + verify(mockDio.post('/messages/messageid/action', data: { + 'id': 'testid', + 'type': 'messaging', + 'form_data': data, + 'message_id': 'messageid', + })).called(1); + }); + + test('getMessagesById', () async { + final mockDio = MockDio(); + + when(mockDio.options).thenReturn(BaseOptions()); + when(mockDio.interceptors).thenReturn(Interceptors()); + + final client = Client( + 'api-key', + httpClient: mockDio, + tokenProvider: (_) async => '', + ); + final channelClient = client.channel('messaging', id: 'testid'); + final messageIds = ['a', 'b']; + + when(mockDio.get('/channels/messaging/testid/messages', + queryParameters: {'ids': messageIds.join(',')})) + .thenAnswer((_) async => Response(data: '{}', statusCode: 200)); + + await channelClient.getMessagesById(messageIds); + + verify(mockDio.get('/channels/messaging/testid/messages', + queryParameters: {'ids': messageIds.join(',')})).called(1); + }); + + test('sendFile', () async { + final mockDio = MockDio(); + + when(mockDio.options).thenReturn(BaseOptions()); + when(mockDio.interceptors).thenReturn(Interceptors()); + + final client = Client( + 'api-key', + httpClient: mockDio, + tokenProvider: (_) async => '', + ); + final channelClient = client.channel('messaging', id: 'testid'); + final file = MultipartFile.fromString('file'); + + when(mockDio.post('/channels/messaging/testid/file', + data: argThat(isA(), named: 'data'))) + .thenAnswer((_) async => Response(data: '{}', statusCode: 200)); + + await channelClient.sendFile(file); + + verify(mockDio.post('/channels/messaging/testid/file', + data: argThat(isA(), named: 'data'))) + .called(1); + }); + + test('sendImage', () async { + final mockDio = MockDio(); + + when(mockDio.options).thenReturn(BaseOptions()); + when(mockDio.interceptors).thenReturn(Interceptors()); + + final client = Client( + 'api-key', + httpClient: mockDio, + tokenProvider: (_) async => '', + ); + final channelClient = client.channel('messaging', id: 'testid'); + final file = MultipartFile.fromString('file'); + + when(mockDio.post('/channels/messaging/testid/image', + data: argThat(isA(), named: 'data'))) + .thenAnswer((_) async => Response(data: '{}', statusCode: 200)); + + await channelClient.sendImage(file); + + verify(mockDio.post('/channels/messaging/testid/image', + data: argThat(isA(), named: 'data'))) + .called(1); + }); + + test('deleteFile', () async { + final mockDio = MockDio(); + + when(mockDio.options).thenReturn(BaseOptions()); + when(mockDio.interceptors).thenReturn(Interceptors()); + + final client = Client( + 'api-key', + httpClient: mockDio, + tokenProvider: (_) async => '', + ); + final channelClient = client.channel('messaging', id: 'testid'); + final url = 'url'; + + when(mockDio.delete('/channels/messaging/testid/file', + queryParameters: {'url': url})) + .thenAnswer((_) async => Response(data: '{}', statusCode: 200)); + + await channelClient.deleteFile(url); + + verify(mockDio.delete('/channels/messaging/testid/file', + queryParameters: {'url': url})).called(1); + }); + + test('deleteImage', () async { + final mockDio = MockDio(); + + when(mockDio.options).thenReturn(BaseOptions()); + when(mockDio.interceptors).thenReturn(Interceptors()); + + final client = Client( + 'api-key', + httpClient: mockDio, + tokenProvider: (_) async => '', + ); + final channelClient = client.channel('messaging', id: 'testid'); + final url = 'url'; + + when(mockDio.delete('/channels/messaging/testid/image', + queryParameters: {'url': url})) + .thenAnswer((_) async => Response(data: '{}', statusCode: 200)); + + await channelClient.deleteImage(url); + + verify(mockDio.delete('/channels/messaging/testid/image', + queryParameters: {'url': url})).called(1); + }); + }); + + test('sendEvent', () async { + final mockDio = MockDio(); + + when(mockDio.options).thenReturn(BaseOptions()); + when(mockDio.interceptors).thenReturn(Interceptors()); + + final client = Client( + 'api-key', + httpClient: mockDio, + tokenProvider: (_) async => '', + ); + final channelClient = client.channel('messaging', id: 'testid'); + + when(mockDio.post( + any, + data: anyNamed('data'), + )).thenAnswer((_) async => Response( + data: '{}', + statusCode: 200, + )); + await channelClient.watch(); + + final event = Event(type: EventType.any); + + when(mockDio.post('/channels/messaging/testid/event', + data: {'event': event.toJson()})) + .thenAnswer((_) async => Response(data: '{}', statusCode: 200)); + + await channelClient.sendEvent(event); + + verify(mockDio.post('/channels/messaging/testid/event', + data: {'event': event.toJson()})).called(1); + }); + + test('keyStroke', () async { + final mockDio = MockDio(); + + when(mockDio.options).thenReturn(BaseOptions()); + when(mockDio.interceptors).thenReturn(Interceptors()); + + final client = Client( + 'api-key', + httpClient: mockDio, + tokenProvider: (_) async => '', + ); + final channelClient = client.channel('messaging', id: 'testid'); + + when(mockDio.post( + any, + data: anyNamed('data'), + )).thenAnswer((_) async => Response( + data: '{}', + statusCode: 200, + )); + await channelClient.watch(); + + final event = Event(type: EventType.typingStart); + + when(mockDio.post('/channels/messaging/testid/event', + data: {'event': event.toJson()})) + .thenAnswer((_) async => Response(data: '{}', statusCode: 200)); + + await channelClient.keyStroke(); + + verify(mockDio.post('/channels/messaging/testid/event', + data: {'event': event.toJson()})).called(1); + }); + + test('stopTyping', () async { + final mockDio = MockDio(); + + when(mockDio.options).thenReturn(BaseOptions()); + when(mockDio.interceptors).thenReturn(Interceptors()); + + final client = Client( + 'api-key', + httpClient: mockDio, + tokenProvider: (_) async => '', + ); + final channelClient = client.channel('messaging', id: 'testid'); + + when(mockDio.post( + any, + data: anyNamed('data'), + )).thenAnswer((_) async => Response( + data: '{}', + statusCode: 200, + )); + await channelClient.watch(); + + final event = Event(type: EventType.typingStop); + + when(mockDio.post('/channels/messaging/testid/event', + data: {'event': event.toJson()})) + .thenAnswer((_) async => Response(data: '{}', statusCode: 200)); + + await channelClient.stopTyping(); + + verify(mockDio.post('/channels/messaging/testid/event', + data: {'event': event.toJson()})).called(1); + }); + + group('reactions', () { + test('sendReaction', () async { + final mockDio = MockDio(); + + when(mockDio.options).thenReturn(BaseOptions()); + when(mockDio.interceptors).thenReturn(Interceptors()); + + final client = Client( + 'api-key', + httpClient: mockDio, + tokenProvider: (_) async => '', + ); + final channelClient = client.channel('messaging', id: 'testid'); + final reactionType = 'test'; + + when(mockDio.post( + '/messages/messageid/reaction', + data: { + 'reaction': { + 'type': reactionType, + }, + 'enforce_unique': false, + }, + )).thenAnswer((_) async => Response(data: '{}', statusCode: 200)); + + await channelClient.sendReaction( + Message( + id: 'messageid', + ), + reactionType, + ); + + verify(mockDio.post('/messages/messageid/reaction', data: { + 'reaction': { + 'type': reactionType, + }, + 'enforce_unique': false, + })).called(1); + }); + + test('deleteReaction', () async { + final mockDio = MockDio(); + + when(mockDio.options).thenReturn(BaseOptions()); + when(mockDio.interceptors).thenReturn(Interceptors()); + + final client = Client( + 'api-key', + httpClient: mockDio, + tokenProvider: (_) async => '', + ); + final channelClient = client.channel('messaging', id: 'testid'); + + when(mockDio.post( + any, + data: anyNamed('data'), + )).thenAnswer((_) async => Response( + data: '{}', + statusCode: 200, + )); + await channelClient.watch(); + + when(mockDio.delete('/messages/messageid/reaction/test')) + .thenAnswer((_) async => Response(data: '{}', statusCode: 200)); + + await channelClient.deleteReaction( + Message(id: 'messageid'), + Reaction(type: 'test'), + ); + + verify(mockDio.delete('/messages/messageid/reaction/test')) + .called(1); + }); + + test('getReactions', () async { + final mockDio = MockDio(); + + when(mockDio.options).thenReturn(BaseOptions()); + when(mockDio.interceptors).thenReturn(Interceptors()); + + final client = Client( + 'api-key', + httpClient: mockDio, + tokenProvider: (_) async => '', + ); + final channelClient = client.channel('messaging', id: 'testid'); + final pagination = PaginationParams(); + + when(mockDio.get('/messages/messageid/reactions', + queryParameters: pagination.toJson())) + .thenAnswer((_) async => Response(data: '{}', statusCode: 200)); + + await channelClient.getReactions('messageid', pagination); + + verify(mockDio.get('/messages/messageid/reactions', + queryParameters: pagination.toJson())) + .called(1); + }); + }); + + group('channel', () { + test('addMembers', () async { + final mockDio = MockDio(); + + when(mockDio.options).thenReturn(BaseOptions()); + when(mockDio.interceptors).thenReturn(Interceptors()); + + final client = Client( + 'api-key', + httpClient: mockDio, + tokenProvider: (_) async => '', + ); + final channelClient = client.channel('messaging', id: 'testid'); + final members = ['vishal']; + final message = Message(text: 'test'); + + when(mockDio.post('/channels/messaging/testid', + data: {'add_members': members, 'message': message.toJson()})) + .thenAnswer((_) async => Response(data: '{}', statusCode: 200)); + + await channelClient.addMembers(members, message); + + verify(mockDio.post('/channels/messaging/testid', + data: {'add_members': members, 'message': message.toJson()})) + .called(1); + }); + + test('acceptInvite', () async { + final mockDio = MockDio(); + + when(mockDio.options).thenReturn(BaseOptions()); + when(mockDio.interceptors).thenReturn(Interceptors()); + + final client = Client( + 'api-key', + httpClient: mockDio, + tokenProvider: (_) async => '', + ); + final channelClient = client.channel('messaging', id: 'testid'); + final message = Message(text: 'test'); + + when(mockDio.post('/channels/messaging/testid', + data: {'accept_invite': true, 'message': message.toJson()})) + .thenAnswer((_) async => Response(data: '{}', statusCode: 200)); + + await channelClient.acceptInvite(message); + + verify(mockDio.post('/channels/messaging/testid', + data: {'accept_invite': true, 'message': message.toJson()})) + .called(1); + }); + + group('query', () { + test('without id', () async { + final mockDio = MockDio(); + + when(mockDio.options).thenReturn(BaseOptions()); + when(mockDio.interceptors).thenReturn(Interceptors()); + + final client = Client( + 'api-key', + httpClient: mockDio, + tokenProvider: (_) async => '', + ); + final channelClient = client.channel('messaging'); + final Map options = { + 'watch': true, + 'state': false, + 'presence': true, + }; + + when(mockDio.post('/channels/messaging/query', data: options)) + .thenAnswer((_) async { + return Response(data: r''' + { + "channel": { + "id": "!members-0LOcD0mZtTan60zHobLmELjdndXsonnBVNzZnB5mTt0", + "type": "messaging", + "cid": "messaging:!members-0LOcD0mZtTan60zHobLmELjdndXsonnBVNzZnB5mTt0", + "last_message_at": "2020-01-28T22:17:31.204287Z", + "created_at": "2020-01-28T22:17:31.00187Z", + "updated_at": "2020-01-28T22:17:31.00187Z", + "created_by": { + "id": "spring-voice-7", + "role": "user", + "created_at": "2020-01-28T22:17:30.834135Z", + "updated_at": "2020-01-28T22:17:31.186771Z", + "banned": false, + "online": false, + "image": "https://getstream.io/random_svg/?id=spring-voice-7\u0026name=Spring+voice", + "name": "Spring voice" + }, + "frozen": false, + "member_count": 2, + "config": { + "created_at": "2020-01-29T12:59:14.291912835Z", + "updated_at": "2020-01-29T12:59:14.291912991Z", + "name": "messaging", + "typing_events": true, + "read_events": true, + "connect_events": true, + "search": true, + "reactions": true, + "replies": true, + "mutes": true, + "uploads": true, + "url_enrichment": true, + "message_retention": "infinite", + "max_message_length": 5000, + "automod": "disabled", + "automod_behavior": "flag", + "commands": [ + { + "name": "giphy", + "description": "Post a random gif to the channel", + "args": "[text]", + "set": "fun_set" + } + ] + }, + "name": "Mia Denys", + "image": "https://randomuser.me/api/portraits/women/2.jpg" + }, + "messages": [ + { + "id": "4637f7e4-a06b-42db-ba5a-8d8270dd926f", + "text": "https://giphy.com/gifs/the-lion-king-live-action-5zvN79uTGfLMOVfQaA", + "html": "\u003cp\u003e\u003ca href=\"https://giphy.com/gifs/the-lion-king-live-action-5zvN79uTGfLMOVfQaA\" rel=\"nofollow\"\u003ehttps://giphy.com/gifs/the-lion-king-live-action-5zvN79uTGfLMOVfQaA\u003c/a\u003e\u003c/p\u003e\n", + "type": "regular", + "user": { + "id": "c1c9b454-2bcc-402d-8bb0-2f3706ce1680", + "role": "user", + "created_at": "2020-01-28T22:17:30.83015Z", + "updated_at": "2020-01-28T22:17:31.19435Z", + "banned": false, + "online": false, + "image": "https://randomuser.me/api/portraits/women/2.jpg", + "name": "Mia Denys" + }, + "attachments": [ + { + "type": "video", + "author_name": "GIPHY", + "title": "The Lion King Disney GIF - Find \u0026 Share on GIPHY", + "title_link": "https://media.giphy.com/media/5zvN79uTGfLMOVfQaA/giphy.gif", + "text": "Discover \u0026 share this Lion King Live Action GIF with everyone you know. GIPHY is how you search, share, discover, and create GIFs.", + "image_url": "https://media.giphy.com/media/5zvN79uTGfLMOVfQaA/giphy.gif", + "thumb_url": "https://media.giphy.com/media/5zvN79uTGfLMOVfQaA/giphy.gif", + "asset_url": "https://media.giphy.com/media/5zvN79uTGfLMOVfQaA/giphy.mp4", + "og_scrape_url": "https://giphy.com/gifs/the-lion-king-live-action-5zvN79uTGfLMOVfQaA" + } + ], + "latest_reactions": [ + { + "message_id": "4637f7e4-a06b-42db-ba5a-8d8270dd926f", + "user_id": "c1c9b454-2bcc-402d-8bb0-2f3706ce1680", + "user": { + "id": "c1c9b454-2bcc-402d-8bb0-2f3706ce1680", + "role": "user", + "created_at": "2020-01-28T22:17:30.83015Z", + "updated_at": "2020-01-28T22:17:31.19435Z", + "banned": false, + "online": false, + "image": "https://randomuser.me/api/portraits/women/2.jpg", + "name": "Mia Denys" + }, + "type": "love", + "score": 1, + "created_at": "2020-01-28T22:17:31.128376Z", + "updated_at": "2020-01-28T22:17:31.128376Z" + } + ], + "own_reactions": [], + "reaction_counts": { + "love": 1 + }, + "reaction_scores": { + "love": 1 + }, + "reply_count": 0, + "created_at": "2020-01-28T22:17:31.107978Z", + "updated_at": "2020-01-28T22:17:31.130506Z", + "mentioned_users": [] + }, + { + "id": "16e19c46-fb96-4f89-8031-d5bd2ce3bd64", + "text": "Few can name a topfull mother that isn't a breezeless damage.", + "html": "\u003cp\u003eFew can name a topfull mother that isn’t a breezeless damage.\u003c/p\u003e\n", + "type": "regular", + "user": { + "id": "spring-voice-7", + "role": "user", + "created_at": "2020-01-28T22:17:30.834135Z", + "updated_at": "2020-01-28T22:17:31.186771Z", + "banned": false, + "online": false, + "image": "https://getstream.io/random_svg/?id=spring-voice-7\u0026name=Spring+voice", + "name": "Spring voice" + }, + "attachments": [], + "latest_reactions": [], + "own_reactions": [], + "reaction_counts": {}, + "reaction_scores": {}, + "reply_count": 0, + "created_at": "2020-01-28T22:17:31.153518Z", + "updated_at": "2020-01-28T22:17:31.153518Z", + "mentioned_users": [] + }, + { + "id": "38b1b252-c9a6-4aea-a39e-8de3b7f7604b", + "text": "https://giphy.com/gifs/beard-muscle-73Sjhw0N4hyog", + "html": "\u003cp\u003e\u003ca href=\"https://giphy.com/gifs/beard-muscle-73Sjhw0N4hyog\" rel=\"nofollow\"\u003ehttps://giphy.com/gifs/beard-muscle-73Sjhw0N4hyog\u003c/a\u003e\u003c/p\u003e\n", + "type": "regular", + "user": { + "id": "spring-voice-7", + "role": "user", + "created_at": "2020-01-28T22:17:30.834135Z", + "updated_at": "2020-01-28T22:17:31.186771Z", + "banned": false, + "online": false, + "image": "https://getstream.io/random_svg/?id=spring-voice-7\u0026name=Spring+voice", + "name": "Spring voice" + }, + "attachments": [ + { + "type": "video", + "author_name": "GIPHY", + "title": "Moustache Thumbs Up GIF - Find \u0026 Share on GIPHY", + "title_link": "https://media.giphy.com/media/73Sjhw0N4hyog/giphy.gif", + "text": "Discover \u0026 share this Pouce Leve GIF with everyone you know. GIPHY is how you search, share, discover, and create GIFs.", + "image_url": "https://media.giphy.com/media/73Sjhw0N4hyog/giphy.gif", + "thumb_url": "https://media.giphy.com/media/73Sjhw0N4hyog/giphy.gif", + "asset_url": "https://media.giphy.com/media/73Sjhw0N4hyog/giphy.mp4", + "og_scrape_url": "https://giphy.com/gifs/beard-muscle-73Sjhw0N4hyog" + } + ], + "latest_reactions": [], + "own_reactions": [], + "reaction_counts": {}, + "reaction_scores": {}, + "reply_count": 0, + "created_at": "2020-01-28T22:17:31.155428Z", + "updated_at": "2020-01-28T22:17:31.155428Z", + "mentioned_users": [] + }, + { + "id": "5c7d0c68-72d5-4027-b6b7-711b342d0fc4", + "text": "The carbons could be said to resemble smartish hoods.", + "html": "\u003cp\u003eThe carbons could be said to resemble smartish hoods.\u003c/p\u003e\n", + "type": "regular", + "user": { + "id": "c1c9b454-2bcc-402d-8bb0-2f3706ce1680", + "role": "user", + "created_at": "2020-01-28T22:17:30.83015Z", + "updated_at": "2020-01-28T22:17:31.19435Z", + "banned": false, + "online": false, + "image": "https://randomuser.me/api/portraits/women/2.jpg", + "name": "Mia Denys" + }, + "attachments": [], + "latest_reactions": [], + "own_reactions": [], + "reaction_counts": {}, + "reaction_scores": {}, + "reply_count": 1, + "created_at": "2020-01-28T22:17:31.157811Z", + "updated_at": "2020-01-28T22:17:31.157811Z", + "mentioned_users": [] + }, + { + "id": "5b02535a-0c3c-45fa-9cf8-16f840c5123f", + "text": "Their software was, in this moment, a prolix feature.", + "html": "\u003cp\u003eTheir software was, in this moment, a prolix feature.\u003c/p\u003e\n", + "type": "regular", + "user": { + "id": "c1c9b454-2bcc-402d-8bb0-2f3706ce1680", + "role": "user", + "created_at": "2020-01-28T22:17:30.83015Z", + "updated_at": "2020-01-28T22:17:31.19435Z", + "banned": false, + "online": false, + "image": "https://randomuser.me/api/portraits/women/2.jpg", + "name": "Mia Denys" + }, + "attachments": [], + "latest_reactions": [], + "own_reactions": [], + "reaction_counts": {}, + "reaction_scores": {}, + "reply_count": 1, + "created_at": "2020-01-28T22:17:31.158391Z", + "updated_at": "2020-01-28T22:17:31.158391Z", + "mentioned_users": [] + } + ], + "watcher_count": 1, + "read": [ + { + "user": { + "id": "c1c9b454-2bcc-402d-8bb0-2f3706ce1680", + "role": "user", + "created_at": "2020-01-28T22:17:30.83015Z", + "updated_at": "2020-01-28T22:17:31.19435Z", + "banned": false, + "online": false, + "image": "https://randomuser.me/api/portraits/women/2.jpg", + "name": "Mia Denys" + }, + "last_read": "2020-01-28T22:17:31.016937728Z" + }, + { + "user": { + "id": "spring-voice-7", + "role": "user", + "created_at": "2020-01-28T22:17:30.834135Z", + "updated_at": "2020-01-28T22:17:31.186771Z", + "banned": false, + "online": false, + "image": "https://getstream.io/random_svg/?id=spring-voice-7\u0026name=Spring+voice", + "name": "Spring voice" + }, + "last_read": "2020-01-28T22:17:31.018856448Z" + } + ], + "members": [ + { + "user": { + "id": "c1c9b454-2bcc-402d-8bb0-2f3706ce1680", + "role": "user", + "created_at": "2020-01-28T22:17:30.83015Z", + "updated_at": "2020-01-28T22:17:31.19435Z", + "banned": false, + "online": false, + "image": "https://randomuser.me/api/portraits/women/2.jpg", + "name": "Mia Denys" + }, + "role": "member", + "created_at": "2020-01-28T22:17:31.005135Z", + "updated_at": "2020-01-28T22:17:31.005135Z" + }, + { + "user": { + "id": "spring-voice-7", + "role": "user", + "created_at": "2020-01-28T22:17:30.834135Z", + "updated_at": "2020-01-28T22:17:31.186771Z", + "banned": false, + "online": false, + "image": "https://getstream.io/random_svg/?id=spring-voice-7\u0026name=Spring+voice", + "name": "Spring voice" + }, + "role": "owner", + "created_at": "2020-01-28T22:17:31.005135Z", + "updated_at": "2020-01-28T22:17:31.005135Z" + } + ] + } + ''', statusCode: 200); + }); + + final response = await channelClient.query(options: options); + + verify(mockDio.post('/channels/messaging/query', + data: options)) + .called(1); + expect(channelClient.id, response.channel.id); + expect(channelClient.cid, response.channel.cid); + }); + + test('with id', () async { + final mockDio = MockDio(); + + when(mockDio.options).thenReturn(BaseOptions()); + when(mockDio.interceptors).thenReturn(Interceptors()); + + final client = Client( + 'api-key', + httpClient: mockDio, + tokenProvider: (_) async => '', + ); + final channelClient = client.channel('messaging', id: 'testid'); + final Map options = { + 'state': false, + }; + + when(mockDio.post('/channels/messaging/testid/query', + data: options)) + .thenAnswer((_) async => Response(data: r''' + { + "channel": { + "id": "!members-0LOcD0mZtTan60zHobLmELjdndXsonnBVNzZnB5mTt0", + "type": "messaging", + "cid": "messaging:!members-0LOcD0mZtTan60zHobLmELjdndXsonnBVNzZnB5mTt0", + "last_message_at": "2020-01-28T22:17:31.204287Z", + "created_at": "2020-01-28T22:17:31.00187Z", + "updated_at": "2020-01-28T22:17:31.00187Z", + "created_by": { + "id": "spring-voice-7", + "role": "user", + "created_at": "2020-01-28T22:17:30.834135Z", + "updated_at": "2020-01-28T22:17:31.186771Z", + "banned": false, + "online": false, + "image": "https://getstream.io/random_svg/?id=spring-voice-7\u0026name=Spring+voice", + "name": "Spring voice" + }, + "frozen": false, + "member_count": 2, + "config": { + "created_at": "2020-01-29T12:59:14.291912835Z", + "updated_at": "2020-01-29T12:59:14.291912991Z", + "name": "messaging", + "typing_events": true, + "read_events": true, + "connect_events": true, + "search": true, + "reactions": true, + "replies": true, + "mutes": true, + "uploads": true, + "url_enrichment": true, + "message_retention": "infinite", + "max_message_length": 5000, + "automod": "disabled", + "automod_behavior": "flag", + "commands": [ + { + "name": "giphy", + "description": "Post a random gif to the channel", + "args": "[text]", + "set": "fun_set" + } + ] + }, + "name": "Mia Denys", + "image": "https://randomuser.me/api/portraits/women/2.jpg" + }, + "messages": [ + { + "id": "4637f7e4-a06b-42db-ba5a-8d8270dd926f", + "text": "https://giphy.com/gifs/the-lion-king-live-action-5zvN79uTGfLMOVfQaA", + "html": "\u003cp\u003e\u003ca href=\"https://giphy.com/gifs/the-lion-king-live-action-5zvN79uTGfLMOVfQaA\" rel=\"nofollow\"\u003ehttps://giphy.com/gifs/the-lion-king-live-action-5zvN79uTGfLMOVfQaA\u003c/a\u003e\u003c/p\u003e\n", + "type": "regular", + "user": { + "id": "c1c9b454-2bcc-402d-8bb0-2f3706ce1680", + "role": "user", + "created_at": "2020-01-28T22:17:30.83015Z", + "updated_at": "2020-01-28T22:17:31.19435Z", + "banned": false, + "online": false, + "image": "https://randomuser.me/api/portraits/women/2.jpg", + "name": "Mia Denys" + }, + "attachments": [ + { + "type": "video", + "author_name": "GIPHY", + "title": "The Lion King Disney GIF - Find \u0026 Share on GIPHY", + "title_link": "https://media.giphy.com/media/5zvN79uTGfLMOVfQaA/giphy.gif", + "text": "Discover \u0026 share this Lion King Live Action GIF with everyone you know. GIPHY is how you search, share, discover, and create GIFs.", + "image_url": "https://media.giphy.com/media/5zvN79uTGfLMOVfQaA/giphy.gif", + "thumb_url": "https://media.giphy.com/media/5zvN79uTGfLMOVfQaA/giphy.gif", + "asset_url": "https://media.giphy.com/media/5zvN79uTGfLMOVfQaA/giphy.mp4", + "og_scrape_url": "https://giphy.com/gifs/the-lion-king-live-action-5zvN79uTGfLMOVfQaA" + } + ], + "latest_reactions": [ + { + "message_id": "4637f7e4-a06b-42db-ba5a-8d8270dd926f", + "user_id": "c1c9b454-2bcc-402d-8bb0-2f3706ce1680", + "user": { + "id": "c1c9b454-2bcc-402d-8bb0-2f3706ce1680", + "role": "user", + "created_at": "2020-01-28T22:17:30.83015Z", + "updated_at": "2020-01-28T22:17:31.19435Z", + "banned": false, + "online": false, + "image": "https://randomuser.me/api/portraits/women/2.jpg", + "name": "Mia Denys" + }, + "type": "love", + "score": 1, + "created_at": "2020-01-28T22:17:31.128376Z", + "updated_at": "2020-01-28T22:17:31.128376Z" + } + ], + "own_reactions": [], + "reaction_counts": { + "love": 1 + }, + "reaction_scores": { + "love": 1 + }, + "reply_count": 0, + "created_at": "2020-01-28T22:17:31.107978Z", + "updated_at": "2020-01-28T22:17:31.130506Z", + "mentioned_users": [] + }, + { + "id": "16e19c46-fb96-4f89-8031-d5bd2ce3bd64", + "text": "Few can name a topfull mother that isn't a breezeless damage.", + "html": "\u003cp\u003eFew can name a topfull mother that isn’t a breezeless damage.\u003c/p\u003e\n", + "type": "regular", + "user": { + "id": "spring-voice-7", + "role": "user", + "created_at": "2020-01-28T22:17:30.834135Z", + "updated_at": "2020-01-28T22:17:31.186771Z", + "banned": false, + "online": false, + "image": "https://getstream.io/random_svg/?id=spring-voice-7\u0026name=Spring+voice", + "name": "Spring voice" + }, + "attachments": [], + "latest_reactions": [], + "own_reactions": [], + "reaction_counts": {}, + "reaction_scores": {}, + "reply_count": 0, + "created_at": "2020-01-28T22:17:31.153518Z", + "updated_at": "2020-01-28T22:17:31.153518Z", + "mentioned_users": [] + }, + { + "id": "38b1b252-c9a6-4aea-a39e-8de3b7f7604b", + "text": "https://giphy.com/gifs/beard-muscle-73Sjhw0N4hyog", + "html": "\u003cp\u003e\u003ca href=\"https://giphy.com/gifs/beard-muscle-73Sjhw0N4hyog\" rel=\"nofollow\"\u003ehttps://giphy.com/gifs/beard-muscle-73Sjhw0N4hyog\u003c/a\u003e\u003c/p\u003e\n", + "type": "regular", + "user": { + "id": "spring-voice-7", + "role": "user", + "created_at": "2020-01-28T22:17:30.834135Z", + "updated_at": "2020-01-28T22:17:31.186771Z", + "banned": false, + "online": false, + "image": "https://getstream.io/random_svg/?id=spring-voice-7\u0026name=Spring+voice", + "name": "Spring voice" + }, + "attachments": [ + { + "type": "video", + "author_name": "GIPHY", + "title": "Moustache Thumbs Up GIF - Find \u0026 Share on GIPHY", + "title_link": "https://media.giphy.com/media/73Sjhw0N4hyog/giphy.gif", + "text": "Discover \u0026 share this Pouce Leve GIF with everyone you know. GIPHY is how you search, share, discover, and create GIFs.", + "image_url": "https://media.giphy.com/media/73Sjhw0N4hyog/giphy.gif", + "thumb_url": "https://media.giphy.com/media/73Sjhw0N4hyog/giphy.gif", + "asset_url": "https://media.giphy.com/media/73Sjhw0N4hyog/giphy.mp4", + "og_scrape_url": "https://giphy.com/gifs/beard-muscle-73Sjhw0N4hyog" + } + ], + "latest_reactions": [], + "own_reactions": [], + "reaction_counts": {}, + "reaction_scores": {}, + "reply_count": 0, + "created_at": "2020-01-28T22:17:31.155428Z", + "updated_at": "2020-01-28T22:17:31.155428Z", + "mentioned_users": [] + }, + { + "id": "5c7d0c68-72d5-4027-b6b7-711b342d0fc4", + "text": "The carbons could be said to resemble smartish hoods.", + "html": "\u003cp\u003eThe carbons could be said to resemble smartish hoods.\u003c/p\u003e\n", + "type": "regular", + "user": { + "id": "c1c9b454-2bcc-402d-8bb0-2f3706ce1680", + "role": "user", + "created_at": "2020-01-28T22:17:30.83015Z", + "updated_at": "2020-01-28T22:17:31.19435Z", + "banned": false, + "online": false, + "image": "https://randomuser.me/api/portraits/women/2.jpg", + "name": "Mia Denys" + }, + "attachments": [], + "latest_reactions": [], + "own_reactions": [], + "reaction_counts": {}, + "reaction_scores": {}, + "reply_count": 1, + "created_at": "2020-01-28T22:17:31.157811Z", + "updated_at": "2020-01-28T22:17:31.157811Z", + "mentioned_users": [] + }, + { + "id": "5b02535a-0c3c-45fa-9cf8-16f840c5123f", + "text": "Their software was, in this moment, a prolix feature.", + "html": "\u003cp\u003eTheir software was, in this moment, a prolix feature.\u003c/p\u003e\n", + "type": "regular", + "user": { + "id": "c1c9b454-2bcc-402d-8bb0-2f3706ce1680", + "role": "user", + "created_at": "2020-01-28T22:17:30.83015Z", + "updated_at": "2020-01-28T22:17:31.19435Z", + "banned": false, + "online": false, + "image": "https://randomuser.me/api/portraits/women/2.jpg", + "name": "Mia Denys" + }, + "attachments": [], + "latest_reactions": [], + "own_reactions": [], + "reaction_counts": {}, + "reaction_scores": {}, + "reply_count": 1, + "created_at": "2020-01-28T22:17:31.158391Z", + "updated_at": "2020-01-28T22:17:31.158391Z", + "mentioned_users": [] + } + ], + "watcher_count": 1, + "read": [ + { + "user": { + "id": "c1c9b454-2bcc-402d-8bb0-2f3706ce1680", + "role": "user", + "created_at": "2020-01-28T22:17:30.83015Z", + "updated_at": "2020-01-28T22:17:31.19435Z", + "banned": false, + "online": false, + "image": "https://randomuser.me/api/portraits/women/2.jpg", + "name": "Mia Denys" + }, + "last_read": "2020-01-28T22:17:31.016937728Z" + }, + { + "user": { + "id": "spring-voice-7", + "role": "user", + "created_at": "2020-01-28T22:17:30.834135Z", + "updated_at": "2020-01-28T22:17:31.186771Z", + "banned": false, + "online": false, + "image": "https://getstream.io/random_svg/?id=spring-voice-7\u0026name=Spring+voice", + "name": "Spring voice" + }, + "last_read": "2020-01-28T22:17:31.018856448Z" + } + ], + "members": [ + { + "user": { + "id": "c1c9b454-2bcc-402d-8bb0-2f3706ce1680", + "role": "user", + "created_at": "2020-01-28T22:17:30.83015Z", + "updated_at": "2020-01-28T22:17:31.19435Z", + "banned": false, + "online": false, + "image": "https://randomuser.me/api/portraits/women/2.jpg", + "name": "Mia Denys" + }, + "role": "member", + "created_at": "2020-01-28T22:17:31.005135Z", + "updated_at": "2020-01-28T22:17:31.005135Z" + }, + { + "user": { + "id": "spring-voice-7", + "role": "user", + "created_at": "2020-01-28T22:17:30.834135Z", + "updated_at": "2020-01-28T22:17:31.186771Z", + "banned": false, + "online": false, + "image": "https://getstream.io/random_svg/?id=spring-voice-7\u0026name=Spring+voice", + "name": "Spring voice" + }, + "role": "owner", + "created_at": "2020-01-28T22:17:31.005135Z", + "updated_at": "2020-01-28T22:17:31.005135Z" + } + ] + } + ''', statusCode: 200)); + + await channelClient.query(options: options); + + verify(mockDio.post('/channels/messaging/testid/query', + data: options)) + .called(1); + }); + }); + + test('create', () async { + final mockDio = MockDio(); + + when(mockDio.options).thenReturn(BaseOptions()); + when(mockDio.interceptors).thenReturn(Interceptors()); + + final client = Client( + 'api-key', + httpClient: mockDio, + tokenProvider: (_) async => '', + ); + final channelClient = client.channel('messaging'); + final Map options = { + 'watch': false, + 'state': false, + 'presence': false, + }; + + when(mockDio.post('/channels/messaging/query', data: options)) + .thenAnswer((_) async => Response(data: r''' + { + "channel": { + "id": "!members-0LOcD0mZtTan60zHobLmELjdndXsonnBVNzZnB5mTt0", + "type": "messaging", + "cid": "messaging:!members-0LOcD0mZtTan60zHobLmELjdndXsonnBVNzZnB5mTt0", + "last_message_at": "2020-01-28T22:17:31.204287Z", + "created_at": "2020-01-28T22:17:31.00187Z", + "updated_at": "2020-01-28T22:17:31.00187Z", + "created_by": { + "id": "spring-voice-7", + "role": "user", + "created_at": "2020-01-28T22:17:30.834135Z", + "updated_at": "2020-01-28T22:17:31.186771Z", + "banned": false, + "online": false, + "image": "https://getstream.io/random_svg/?id=spring-voice-7\u0026name=Spring+voice", + "name": "Spring voice" + }, + "frozen": false, + "member_count": 2, + "config": { + "created_at": "2020-01-29T12:59:14.291912835Z", + "updated_at": "2020-01-29T12:59:14.291912991Z", + "name": "messaging", + "typing_events": true, + "read_events": true, + "connect_events": true, + "search": true, + "reactions": true, + "replies": true, + "mutes": true, + "uploads": true, + "url_enrichment": true, + "message_retention": "infinite", + "max_message_length": 5000, + "automod": "disabled", + "automod_behavior": "flag", + "commands": [ + { + "name": "giphy", + "description": "Post a random gif to the channel", + "args": "[text]", + "set": "fun_set" + } + ] + }, + "name": "Mia Denys", + "image": "https://randomuser.me/api/portraits/women/2.jpg" + }, + "messages": [ + { + "id": "4637f7e4-a06b-42db-ba5a-8d8270dd926f", + "text": "https://giphy.com/gifs/the-lion-king-live-action-5zvN79uTGfLMOVfQaA", + "html": "\u003cp\u003e\u003ca href=\"https://giphy.com/gifs/the-lion-king-live-action-5zvN79uTGfLMOVfQaA\" rel=\"nofollow\"\u003ehttps://giphy.com/gifs/the-lion-king-live-action-5zvN79uTGfLMOVfQaA\u003c/a\u003e\u003c/p\u003e\n", + "type": "regular", + "user": { + "id": "c1c9b454-2bcc-402d-8bb0-2f3706ce1680", + "role": "user", + "created_at": "2020-01-28T22:17:30.83015Z", + "updated_at": "2020-01-28T22:17:31.19435Z", + "banned": false, + "online": false, + "image": "https://randomuser.me/api/portraits/women/2.jpg", + "name": "Mia Denys" + }, + "attachments": [ + { + "type": "video", + "author_name": "GIPHY", + "title": "The Lion King Disney GIF - Find \u0026 Share on GIPHY", + "title_link": "https://media.giphy.com/media/5zvN79uTGfLMOVfQaA/giphy.gif", + "text": "Discover \u0026 share this Lion King Live Action GIF with everyone you know. GIPHY is how you search, share, discover, and create GIFs.", + "image_url": "https://media.giphy.com/media/5zvN79uTGfLMOVfQaA/giphy.gif", + "thumb_url": "https://media.giphy.com/media/5zvN79uTGfLMOVfQaA/giphy.gif", + "asset_url": "https://media.giphy.com/media/5zvN79uTGfLMOVfQaA/giphy.mp4", + "og_scrape_url": "https://giphy.com/gifs/the-lion-king-live-action-5zvN79uTGfLMOVfQaA" + } + ], + "latest_reactions": [ + { + "message_id": "4637f7e4-a06b-42db-ba5a-8d8270dd926f", + "user_id": "c1c9b454-2bcc-402d-8bb0-2f3706ce1680", + "user": { + "id": "c1c9b454-2bcc-402d-8bb0-2f3706ce1680", + "role": "user", + "created_at": "2020-01-28T22:17:30.83015Z", + "updated_at": "2020-01-28T22:17:31.19435Z", + "banned": false, + "online": false, + "image": "https://randomuser.me/api/portraits/women/2.jpg", + "name": "Mia Denys" + }, + "type": "love", + "score": 1, + "created_at": "2020-01-28T22:17:31.128376Z", + "updated_at": "2020-01-28T22:17:31.128376Z" + } + ], + "own_reactions": [], + "reaction_counts": { + "love": 1 + }, + "reaction_scores": { + "love": 1 + }, + "reply_count": 0, + "created_at": "2020-01-28T22:17:31.107978Z", + "updated_at": "2020-01-28T22:17:31.130506Z", + "mentioned_users": [] + }, + { + "id": "16e19c46-fb96-4f89-8031-d5bd2ce3bd64", + "text": "Few can name a topfull mother that isn't a breezeless damage.", + "html": "\u003cp\u003eFew can name a topfull mother that isn’t a breezeless damage.\u003c/p\u003e\n", + "type": "regular", + "user": { + "id": "spring-voice-7", + "role": "user", + "created_at": "2020-01-28T22:17:30.834135Z", + "updated_at": "2020-01-28T22:17:31.186771Z", + "banned": false, + "online": false, + "image": "https://getstream.io/random_svg/?id=spring-voice-7\u0026name=Spring+voice", + "name": "Spring voice" + }, + "attachments": [], + "latest_reactions": [], + "own_reactions": [], + "reaction_counts": {}, + "reaction_scores": {}, + "reply_count": 0, + "created_at": "2020-01-28T22:17:31.153518Z", + "updated_at": "2020-01-28T22:17:31.153518Z", + "mentioned_users": [] + }, + { + "id": "38b1b252-c9a6-4aea-a39e-8de3b7f7604b", + "text": "https://giphy.com/gifs/beard-muscle-73Sjhw0N4hyog", + "html": "\u003cp\u003e\u003ca href=\"https://giphy.com/gifs/beard-muscle-73Sjhw0N4hyog\" rel=\"nofollow\"\u003ehttps://giphy.com/gifs/beard-muscle-73Sjhw0N4hyog\u003c/a\u003e\u003c/p\u003e\n", + "type": "regular", + "user": { + "id": "spring-voice-7", + "role": "user", + "created_at": "2020-01-28T22:17:30.834135Z", + "updated_at": "2020-01-28T22:17:31.186771Z", + "banned": false, + "online": false, + "image": "https://getstream.io/random_svg/?id=spring-voice-7\u0026name=Spring+voice", + "name": "Spring voice" + }, + "attachments": [ + { + "type": "video", + "author_name": "GIPHY", + "title": "Moustache Thumbs Up GIF - Find \u0026 Share on GIPHY", + "title_link": "https://media.giphy.com/media/73Sjhw0N4hyog/giphy.gif", + "text": "Discover \u0026 share this Pouce Leve GIF with everyone you know. GIPHY is how you search, share, discover, and create GIFs.", + "image_url": "https://media.giphy.com/media/73Sjhw0N4hyog/giphy.gif", + "thumb_url": "https://media.giphy.com/media/73Sjhw0N4hyog/giphy.gif", + "asset_url": "https://media.giphy.com/media/73Sjhw0N4hyog/giphy.mp4", + "og_scrape_url": "https://giphy.com/gifs/beard-muscle-73Sjhw0N4hyog" + } + ], + "latest_reactions": [], + "own_reactions": [], + "reaction_counts": {}, + "reaction_scores": {}, + "reply_count": 0, + "created_at": "2020-01-28T22:17:31.155428Z", + "updated_at": "2020-01-28T22:17:31.155428Z", + "mentioned_users": [] + }, + { + "id": "5c7d0c68-72d5-4027-b6b7-711b342d0fc4", + "text": "The carbons could be said to resemble smartish hoods.", + "html": "\u003cp\u003eThe carbons could be said to resemble smartish hoods.\u003c/p\u003e\n", + "type": "regular", + "user": { + "id": "c1c9b454-2bcc-402d-8bb0-2f3706ce1680", + "role": "user", + "created_at": "2020-01-28T22:17:30.83015Z", + "updated_at": "2020-01-28T22:17:31.19435Z", + "banned": false, + "online": false, + "image": "https://randomuser.me/api/portraits/women/2.jpg", + "name": "Mia Denys" + }, + "attachments": [], + "latest_reactions": [], + "own_reactions": [], + "reaction_counts": {}, + "reaction_scores": {}, + "reply_count": 1, + "created_at": "2020-01-28T22:17:31.157811Z", + "updated_at": "2020-01-28T22:17:31.157811Z", + "mentioned_users": [] + }, + { + "id": "5b02535a-0c3c-45fa-9cf8-16f840c5123f", + "text": "Their software was, in this moment, a prolix feature.", + "html": "\u003cp\u003eTheir software was, in this moment, a prolix feature.\u003c/p\u003e\n", + "type": "regular", + "user": { + "id": "c1c9b454-2bcc-402d-8bb0-2f3706ce1680", + "role": "user", + "created_at": "2020-01-28T22:17:30.83015Z", + "updated_at": "2020-01-28T22:17:31.19435Z", + "banned": false, + "online": false, + "image": "https://randomuser.me/api/portraits/women/2.jpg", + "name": "Mia Denys" + }, + "attachments": [], + "latest_reactions": [], + "own_reactions": [], + "reaction_counts": {}, + "reaction_scores": {}, + "reply_count": 1, + "created_at": "2020-01-28T22:17:31.158391Z", + "updated_at": "2020-01-28T22:17:31.158391Z", + "mentioned_users": [] + } + ], + "watcher_count": 1, + "read": [ + { + "user": { + "id": "c1c9b454-2bcc-402d-8bb0-2f3706ce1680", + "role": "user", + "created_at": "2020-01-28T22:17:30.83015Z", + "updated_at": "2020-01-28T22:17:31.19435Z", + "banned": false, + "online": false, + "image": "https://randomuser.me/api/portraits/women/2.jpg", + "name": "Mia Denys" + }, + "last_read": "2020-01-28T22:17:31.016937728Z" + }, + { + "user": { + "id": "spring-voice-7", + "role": "user", + "created_at": "2020-01-28T22:17:30.834135Z", + "updated_at": "2020-01-28T22:17:31.186771Z", + "banned": false, + "online": false, + "image": "https://getstream.io/random_svg/?id=spring-voice-7\u0026name=Spring+voice", + "name": "Spring voice" + }, + "last_read": "2020-01-28T22:17:31.018856448Z" + } + ], + "members": [ + { + "user": { + "id": "c1c9b454-2bcc-402d-8bb0-2f3706ce1680", + "role": "user", + "created_at": "2020-01-28T22:17:30.83015Z", + "updated_at": "2020-01-28T22:17:31.19435Z", + "banned": false, + "online": false, + "image": "https://randomuser.me/api/portraits/women/2.jpg", + "name": "Mia Denys" + }, + "role": "member", + "created_at": "2020-01-28T22:17:31.005135Z", + "updated_at": "2020-01-28T22:17:31.005135Z" + }, + { + "user": { + "id": "spring-voice-7", + "role": "user", + "created_at": "2020-01-28T22:17:30.834135Z", + "updated_at": "2020-01-28T22:17:31.186771Z", + "banned": false, + "online": false, + "image": "https://getstream.io/random_svg/?id=spring-voice-7\u0026name=Spring+voice", + "name": "Spring voice" + }, + "role": "owner", + "created_at": "2020-01-28T22:17:31.005135Z", + "updated_at": "2020-01-28T22:17:31.005135Z" + } + ] + } + ''', statusCode: 200)); + + final response = await channelClient.create(); + + verify(mockDio.post('/channels/messaging/query', data: options)) + .called(1); + expect(channelClient.id, response.channel.id); + expect(channelClient.cid, response.channel.cid); + }); + + test('watch', () async { + final mockDio = MockDio(); + + when(mockDio.options).thenReturn(BaseOptions()); + when(mockDio.interceptors).thenReturn(Interceptors()); + + final client = Client( + 'api-key', + httpClient: mockDio, + tokenProvider: (_) async => '', + ); + final channelClient = client.channel('messaging'); + final options = { + 'watch': true, + 'state': true, + 'presence': true, + }; + + when(mockDio.post('/channels/messaging/query', data: options)) + .thenAnswer((_) async => Response(data: r''' + { + "channel": { + "id": "!members-0LOcD0mZtTan60zHobLmELjdndXsonnBVNzZnB5mTt0", + "type": "messaging", + "cid": "messaging:!members-0LOcD0mZtTan60zHobLmELjdndXsonnBVNzZnB5mTt0", + "last_message_at": "2020-01-28T22:17:31.204287Z", + "created_at": "2020-01-28T22:17:31.00187Z", + "updated_at": "2020-01-28T22:17:31.00187Z", + "created_by": { + "id": "spring-voice-7", + "role": "user", + "created_at": "2020-01-28T22:17:30.834135Z", + "updated_at": "2020-01-28T22:17:31.186771Z", + "banned": false, + "online": false, + "image": "https://getstream.io/random_svg/?id=spring-voice-7\u0026name=Spring+voice", + "name": "Spring voice" + }, + "frozen": false, + "member_count": 2, + "config": { + "created_at": "2020-01-29T12:59:14.291912835Z", + "updated_at": "2020-01-29T12:59:14.291912991Z", + "name": "messaging", + "typing_events": true, + "read_events": true, + "connect_events": true, + "search": true, + "reactions": true, + "replies": true, + "mutes": true, + "uploads": true, + "url_enrichment": true, + "message_retention": "infinite", + "max_message_length": 5000, + "automod": "disabled", + "automod_behavior": "flag", + "commands": [ + { + "name": "giphy", + "description": "Post a random gif to the channel", + "args": "[text]", + "set": "fun_set" + } + ] + }, + "name": "Mia Denys", + "image": "https://randomuser.me/api/portraits/women/2.jpg" + }, + "messages": [ + { + "id": "4637f7e4-a06b-42db-ba5a-8d8270dd926f", + "text": "https://giphy.com/gifs/the-lion-king-live-action-5zvN79uTGfLMOVfQaA", + "html": "\u003cp\u003e\u003ca href=\"https://giphy.com/gifs/the-lion-king-live-action-5zvN79uTGfLMOVfQaA\" rel=\"nofollow\"\u003ehttps://giphy.com/gifs/the-lion-king-live-action-5zvN79uTGfLMOVfQaA\u003c/a\u003e\u003c/p\u003e\n", + "type": "regular", + "user": { + "id": "c1c9b454-2bcc-402d-8bb0-2f3706ce1680", + "role": "user", + "created_at": "2020-01-28T22:17:30.83015Z", + "updated_at": "2020-01-28T22:17:31.19435Z", + "banned": false, + "online": false, + "image": "https://randomuser.me/api/portraits/women/2.jpg", + "name": "Mia Denys" + }, + "attachments": [ + { + "type": "video", + "author_name": "GIPHY", + "title": "The Lion King Disney GIF - Find \u0026 Share on GIPHY", + "title_link": "https://media.giphy.com/media/5zvN79uTGfLMOVfQaA/giphy.gif", + "text": "Discover \u0026 share this Lion King Live Action GIF with everyone you know. GIPHY is how you search, share, discover, and create GIFs.", + "image_url": "https://media.giphy.com/media/5zvN79uTGfLMOVfQaA/giphy.gif", + "thumb_url": "https://media.giphy.com/media/5zvN79uTGfLMOVfQaA/giphy.gif", + "asset_url": "https://media.giphy.com/media/5zvN79uTGfLMOVfQaA/giphy.mp4", + "og_scrape_url": "https://giphy.com/gifs/the-lion-king-live-action-5zvN79uTGfLMOVfQaA" + } + ], + "latest_reactions": [ + { + "message_id": "4637f7e4-a06b-42db-ba5a-8d8270dd926f", + "user_id": "c1c9b454-2bcc-402d-8bb0-2f3706ce1680", + "user": { + "id": "c1c9b454-2bcc-402d-8bb0-2f3706ce1680", + "role": "user", + "created_at": "2020-01-28T22:17:30.83015Z", + "updated_at": "2020-01-28T22:17:31.19435Z", + "banned": false, + "online": false, + "image": "https://randomuser.me/api/portraits/women/2.jpg", + "name": "Mia Denys" + }, + "type": "love", + "score": 1, + "created_at": "2020-01-28T22:17:31.128376Z", + "updated_at": "2020-01-28T22:17:31.128376Z" + } + ], + "own_reactions": [], + "reaction_counts": { + "love": 1 + }, + "reaction_scores": { + "love": 1 + }, + "reply_count": 0, + "created_at": "2020-01-28T22:17:31.107978Z", + "updated_at": "2020-01-28T22:17:31.130506Z", + "mentioned_users": [] + }, + { + "id": "16e19c46-fb96-4f89-8031-d5bd2ce3bd64", + "text": "Few can name a topfull mother that isn't a breezeless damage.", + "html": "\u003cp\u003eFew can name a topfull mother that isn’t a breezeless damage.\u003c/p\u003e\n", + "type": "regular", + "user": { + "id": "spring-voice-7", + "role": "user", + "created_at": "2020-01-28T22:17:30.834135Z", + "updated_at": "2020-01-28T22:17:31.186771Z", + "banned": false, + "online": false, + "image": "https://getstream.io/random_svg/?id=spring-voice-7\u0026name=Spring+voice", + "name": "Spring voice" + }, + "attachments": [], + "latest_reactions": [], + "own_reactions": [], + "reaction_counts": {}, + "reaction_scores": {}, + "reply_count": 0, + "created_at": "2020-01-28T22:17:31.153518Z", + "updated_at": "2020-01-28T22:17:31.153518Z", + "mentioned_users": [] + }, + { + "id": "38b1b252-c9a6-4aea-a39e-8de3b7f7604b", + "text": "https://giphy.com/gifs/beard-muscle-73Sjhw0N4hyog", + "html": "\u003cp\u003e\u003ca href=\"https://giphy.com/gifs/beard-muscle-73Sjhw0N4hyog\" rel=\"nofollow\"\u003ehttps://giphy.com/gifs/beard-muscle-73Sjhw0N4hyog\u003c/a\u003e\u003c/p\u003e\n", + "type": "regular", + "user": { + "id": "spring-voice-7", + "role": "user", + "created_at": "2020-01-28T22:17:30.834135Z", + "updated_at": "2020-01-28T22:17:31.186771Z", + "banned": false, + "online": false, + "image": "https://getstream.io/random_svg/?id=spring-voice-7\u0026name=Spring+voice", + "name": "Spring voice" + }, + "attachments": [ + { + "type": "video", + "author_name": "GIPHY", + "title": "Moustache Thumbs Up GIF - Find \u0026 Share on GIPHY", + "title_link": "https://media.giphy.com/media/73Sjhw0N4hyog/giphy.gif", + "text": "Discover \u0026 share this Pouce Leve GIF with everyone you know. GIPHY is how you search, share, discover, and create GIFs.", + "image_url": "https://media.giphy.com/media/73Sjhw0N4hyog/giphy.gif", + "thumb_url": "https://media.giphy.com/media/73Sjhw0N4hyog/giphy.gif", + "asset_url": "https://media.giphy.com/media/73Sjhw0N4hyog/giphy.mp4", + "og_scrape_url": "https://giphy.com/gifs/beard-muscle-73Sjhw0N4hyog" + } + ], + "latest_reactions": [], + "own_reactions": [], + "reaction_counts": {}, + "reaction_scores": {}, + "reply_count": 0, + "created_at": "2020-01-28T22:17:31.155428Z", + "updated_at": "2020-01-28T22:17:31.155428Z", + "mentioned_users": [] + }, + { + "id": "5c7d0c68-72d5-4027-b6b7-711b342d0fc4", + "text": "The carbons could be said to resemble smartish hoods.", + "html": "\u003cp\u003eThe carbons could be said to resemble smartish hoods.\u003c/p\u003e\n", + "type": "regular", + "user": { + "id": "c1c9b454-2bcc-402d-8bb0-2f3706ce1680", + "role": "user", + "created_at": "2020-01-28T22:17:30.83015Z", + "updated_at": "2020-01-28T22:17:31.19435Z", + "banned": false, + "online": false, + "image": "https://randomuser.me/api/portraits/women/2.jpg", + "name": "Mia Denys" + }, + "attachments": [], + "latest_reactions": [], + "own_reactions": [], + "reaction_counts": {}, + "reaction_scores": {}, + "reply_count": 1, + "created_at": "2020-01-28T22:17:31.157811Z", + "updated_at": "2020-01-28T22:17:31.157811Z", + "mentioned_users": [] + }, + { + "id": "5b02535a-0c3c-45fa-9cf8-16f840c5123f", + "text": "Their software was, in this moment, a prolix feature.", + "html": "\u003cp\u003eTheir software was, in this moment, a prolix feature.\u003c/p\u003e\n", + "type": "regular", + "user": { + "id": "c1c9b454-2bcc-402d-8bb0-2f3706ce1680", + "role": "user", + "created_at": "2020-01-28T22:17:30.83015Z", + "updated_at": "2020-01-28T22:17:31.19435Z", + "banned": false, + "online": false, + "image": "https://randomuser.me/api/portraits/women/2.jpg", + "name": "Mia Denys" + }, + "attachments": [], + "latest_reactions": [], + "own_reactions": [], + "reaction_counts": {}, + "reaction_scores": {}, + "reply_count": 1, + "created_at": "2020-01-28T22:17:31.158391Z", + "updated_at": "2020-01-28T22:17:31.158391Z", + "mentioned_users": [] + } + ], + "watcher_count": 1, + "read": [ + { + "user": { + "id": "c1c9b454-2bcc-402d-8bb0-2f3706ce1680", + "role": "user", + "created_at": "2020-01-28T22:17:30.83015Z", + "updated_at": "2020-01-28T22:17:31.19435Z", + "banned": false, + "online": false, + "image": "https://randomuser.me/api/portraits/women/2.jpg", + "name": "Mia Denys" + }, + "last_read": "2020-01-28T22:17:31.016937728Z" + }, + { + "user": { + "id": "spring-voice-7", + "role": "user", + "created_at": "2020-01-28T22:17:30.834135Z", + "updated_at": "2020-01-28T22:17:31.186771Z", + "banned": false, + "online": false, + "image": "https://getstream.io/random_svg/?id=spring-voice-7\u0026name=Spring+voice", + "name": "Spring voice" + }, + "last_read": "2020-01-28T22:17:31.018856448Z" + } + ], + "members": [ + { + "user": { + "id": "c1c9b454-2bcc-402d-8bb0-2f3706ce1680", + "role": "user", + "created_at": "2020-01-28T22:17:30.83015Z", + "updated_at": "2020-01-28T22:17:31.19435Z", + "banned": false, + "online": false, + "image": "https://randomuser.me/api/portraits/women/2.jpg", + "name": "Mia Denys" + }, + "role": "member", + "created_at": "2020-01-28T22:17:31.005135Z", + "updated_at": "2020-01-28T22:17:31.005135Z" + }, + { + "user": { + "id": "spring-voice-7", + "role": "user", + "created_at": "2020-01-28T22:17:30.834135Z", + "updated_at": "2020-01-28T22:17:31.186771Z", + "banned": false, + "online": false, + "image": "https://getstream.io/random_svg/?id=spring-voice-7\u0026name=Spring+voice", + "name": "Spring voice" + }, + "role": "owner", + "created_at": "2020-01-28T22:17:31.005135Z", + "updated_at": "2020-01-28T22:17:31.005135Z" + } + ] + } + ''', statusCode: 200)); + + final response = await channelClient.watch({'presence': true}); + + verify(mockDio.post('/channels/messaging/query', data: options)) + .called(1); + expect(channelClient.id, response.channel.id); + expect(channelClient.cid, response.channel.cid); + }); + + test('stopWatching', () async { + final mockDio = MockDio(); + + when(mockDio.options).thenReturn(BaseOptions()); + when(mockDio.interceptors).thenReturn(Interceptors()); + + final client = Client( + 'api-key', + httpClient: mockDio, + tokenProvider: (_) async => '', + ); + final channelClient = client.channel('messaging', id: 'testid'); + + when(mockDio.post( + '/channels/messaging/testid/stop-watching', + data: {}, + )).thenAnswer((_) async => Response(data: '{}', statusCode: 200)); + + await channelClient.stopWatching(); + + verify(mockDio.post( + '/channels/messaging/testid/stop-watching', + data: {}, + )).called(1); + }); + + test('update', () async { + final mockDio = MockDio(); + + when(mockDio.options).thenReturn(BaseOptions()); + when(mockDio.interceptors).thenReturn(Interceptors()); + + final client = Client( + 'api-key', + httpClient: mockDio, + tokenProvider: (_) async => '', + ); + final channelClient = client.channel('messaging', id: 'testid'); + final message = Message(text: 'test'); + + when(mockDio.post('/channels/messaging/testid', data: { + 'message': message.toJson(), + 'data': {'test': true}, + })).thenAnswer((_) async => Response(data: '{}', statusCode: 200)); + + await channelClient.update({'test': true}, message); + + verify(mockDio.post('/channels/messaging/testid', data: { + 'message': message.toJson(), + 'data': {'test': true}, + })).called(1); + }); + + test('delete', () async { + final mockDio = MockDio(); + + when(mockDio.options).thenReturn(BaseOptions()); + when(mockDio.interceptors).thenReturn(Interceptors()); + + final client = Client( + 'api-key', + httpClient: mockDio, + tokenProvider: (_) async => '', + ); + final channelClient = client.channel('messaging', id: 'testid'); + + when(mockDio.delete('/channels/messaging/testid')) + .thenAnswer((_) async => Response(data: '{}', statusCode: 200)); + + await channelClient.delete(); + + verify(mockDio.delete('/channels/messaging/testid')).called(1); + }); + + test('truncate', () async { + final mockDio = MockDio(); + + when(mockDio.options).thenReturn(BaseOptions()); + when(mockDio.interceptors).thenReturn(Interceptors()); + + final client = Client( + 'api-key', + httpClient: mockDio, + tokenProvider: (_) async => '', + ); + final channelClient = client.channel('messaging', id: 'testid'); + + when(mockDio.post('/channels/messaging/testid/truncate')) + .thenAnswer((_) async => Response(data: '{}', statusCode: 200)); + + await channelClient.truncate(); + + verify(mockDio.post('/channels/messaging/testid/truncate')) + .called(1); + }); + + test('rejectInvite', () async { + final mockDio = MockDio(); + + when(mockDio.options).thenReturn(BaseOptions()); + when(mockDio.interceptors).thenReturn(Interceptors()); + + final client = Client( + 'api-key', + httpClient: mockDio, + tokenProvider: (_) async => '', + ); + final channelClient = client.channel('messaging', id: 'testid'); + final message = Message(text: 'test'); + + when(mockDio.post('/channels/messaging/testid', + data: {'reject_invite': true, 'message': message.toJson()})) + .thenAnswer((_) async => Response(data: '{}', statusCode: 200)); + + await channelClient.rejectInvite(message); + + verify(mockDio.post('/channels/messaging/testid', + data: {'reject_invite': true, 'message': message.toJson()})) + .called(1); + }); + + test('inviteMembers', () async { + final mockDio = MockDio(); + + when(mockDio.options).thenReturn(BaseOptions()); + when(mockDio.interceptors).thenReturn(Interceptors()); + + final client = Client( + 'api-key', + httpClient: mockDio, + tokenProvider: (_) async => '', + ); + final channelClient = client.channel('messaging', id: 'testid'); + final members = ['vishal']; + final message = Message(text: 'test'); + + when(mockDio.post('/channels/messaging/testid', + data: {'invites': members, 'message': message.toJson()})) + .thenAnswer((_) async => Response(data: '{}', statusCode: 200)); + + await channelClient.inviteMembers(members, message); + + verify(mockDio.post('/channels/messaging/testid', + data: {'invites': members, 'message': message.toJson()})).called(1); + }); + + test('removeMembers', () async { + final mockDio = MockDio(); + + when(mockDio.options).thenReturn(BaseOptions()); + when(mockDio.interceptors).thenReturn(Interceptors()); + + final client = Client( + 'api-key', + httpClient: mockDio, + tokenProvider: (_) async => '', + ); + final channelClient = client.channel('messaging', id: 'testid'); + final members = ['vishal']; + final message = Message(text: 'test'); + + when(mockDio.post('/channels/messaging/testid', + data: {'remove_members': members, 'message': message.toJson()})) + .thenAnswer((_) async => Response(data: '{}', statusCode: 200)); + + await channelClient.removeMembers(members, message); + + verify(mockDio.post('/channels/messaging/testid', + data: {'remove_members': members, 'message': message.toJson()})) + .called(1); + }); + + test('hide', () async { + final mockDio = MockDio(); + + when(mockDio.options).thenReturn(BaseOptions()); + when(mockDio.interceptors).thenReturn(Interceptors()); + + final client = Client( + 'api-key', + httpClient: mockDio, + tokenProvider: (_) async => '', + ); + final channelClient = client.channel('messaging', id: 'testid'); + + when(mockDio.post( + any, + data: anyNamed('data'), + )).thenAnswer((_) async => Response( + data: '{}', + statusCode: 200, + )); + await channelClient.watch(); + + when(mockDio.post('/channels/messaging/testid/hide', + data: {'clear_history': true})) + .thenAnswer((_) async => Response(data: '{}', statusCode: 200)); + + await channelClient.hide(clearHistory: true); + + verify(mockDio.post('/channels/messaging/testid/hide', + data: {'clear_history': true})).called(1); + }); + + test('show', () async { + final mockDio = MockDio(); + + when(mockDio.options).thenReturn(BaseOptions()); + when(mockDio.interceptors).thenReturn(Interceptors()); + + final client = Client( + 'api-key', + httpClient: mockDio, + tokenProvider: (_) async => '', + ); + final channelClient = client.channel('messaging', id: 'testid'); + + when(mockDio.post( + any, + data: anyNamed('data'), + )).thenAnswer((_) async => Response( + data: '{}', + statusCode: 200, + )); + await channelClient.watch(); + + when(mockDio.post('/channels/messaging/testid/show')) + .thenAnswer((_) async => Response(data: '{}', statusCode: 200)); + + await channelClient.show(); + + verify(mockDio.post('/channels/messaging/testid/show')) + .called(1); + }); + + test('banUser', () async { + final mockDio = MockDio(); + + when(mockDio.options).thenReturn(BaseOptions()); + when(mockDio.interceptors).thenReturn(Interceptors()); + + final client = Client( + 'api-key', + httpClient: mockDio, + tokenProvider: (_) async => '', + ); + final channelClient = client.channel('messaging', id: 'testid'); + + when(mockDio.post( + any, + data: anyNamed('data'), + )).thenAnswer((_) async => Response( + data: '{}', + statusCode: 200, + )); + await channelClient.watch(); + + when(mockDio.post('/moderation/ban', data: { + 'test': true, + 'target_user_id': 'test-id', + 'type': 'messaging', + 'id': 'testid', + })).thenAnswer((_) async => Response(data: '{}', statusCode: 200)); + + final Map options = {'test': true}; + await channelClient.banUser('test-id', options); + + verify(mockDio.post('/moderation/ban', data: { + 'test': true, + 'target_user_id': 'test-id', + 'type': 'messaging', + 'id': 'testid', + })).called(1); + }); + + test('unbanUser', () async { + final mockDio = MockDio(); + + when(mockDio.options).thenReturn(BaseOptions()); + when(mockDio.interceptors).thenReturn(Interceptors()); + + final client = Client( + 'api-key', + httpClient: mockDio, + tokenProvider: (_) async => '', + ); + final channelClient = client.channel('messaging', id: 'testid'); + + when(mockDio.post( + any, + data: anyNamed('data'), + )).thenAnswer((_) async => Response( + data: '{}', + statusCode: 200, + )); + await channelClient.watch(); + + when(mockDio.delete('/moderation/ban', queryParameters: { + 'target_user_id': 'test-id', + 'type': 'messaging', + 'id': 'testid', + })).thenAnswer((_) async => Response(data: '{}', statusCode: 200)); + + await channelClient.unbanUser('test-id'); + + verify(mockDio.delete('/moderation/ban', queryParameters: { + 'target_user_id': 'test-id', + 'type': 'messaging', + 'id': 'testid', + })).called(1); + }); + }); + }); +} diff --git a/packages/dart_client/test/src/api/requests_test.dart b/packages/dart_client/test/src/api/requests_test.dart new file mode 100644 index 00000000..3ad762a7 --- /dev/null +++ b/packages/dart_client/test/src/api/requests_test.dart @@ -0,0 +1,18 @@ +import 'package:flutter_test/flutter_test.dart'; +import 'package:stream_chat/stream_chat.dart'; + +void main() { + group('src/api/requests', () { + test('SortOption', () { + final option = SortOption('name'); + final j = option.toJson(); + expect(j, {'field': 'name', 'direction': -1}); + }); + + test('PaginationParams', () { + final option = PaginationParams(); + final j = option.toJson(); + expect(j, {'limit': 10}); + }); + }); +} diff --git a/packages/dart_client/test/src/api/responses_test.dart b/packages/dart_client/test/src/api/responses_test.dart new file mode 100644 index 00000000..df576ba4 --- /dev/null +++ b/packages/dart_client/test/src/api/responses_test.dart @@ -0,0 +1,4336 @@ +import 'dart:convert'; + +import 'package:flutter_test/flutter_test.dart'; +import 'package:stream_chat/src/api/responses.dart'; +import 'package:stream_chat/src/models/device.dart'; +import 'package:stream_chat/src/models/member.dart'; +import 'package:stream_chat/src/models/message.dart'; +import 'package:stream_chat/src/models/reaction.dart'; +import 'package:stream_chat/src/models/read.dart'; +import 'package:stream_chat/stream_chat.dart'; + +void main() { + group('src/api/responses', () { + test('QueryChannelsResponse', () { + const jsonExample = r'''{ + "channels": [ + { + "channel": { + "id": "!members-0LOcD0mZtTan60zHobLmELjdndXsonnBVNzZnB5mTt0", + "type": "messaging", + "cid": "messaging:!members-0LOcD0mZtTan60zHobLmELjdndXsonnBVNzZnB5mTt0", + "last_message_at": "2020-01-28T22:17:31.204287Z", + "created_at": "2020-01-28T22:17:31.00187Z", + "updated_at": "2020-01-28T22:17:31.00187Z", + "created_by": { + "id": "spring-voice-7", + "role": "user", + "created_at": "2020-01-28T22:17:30.834135Z", + "updated_at": "2020-01-28T22:17:31.186771Z", + "banned": false, + "online": false, + "image": "https://getstream.io/random_svg/?id=spring-voice-7\u0026name=Spring+voice", + "name": "Spring voice" + }, + "frozen": false, + "member_count": 2, + "config": { + "created_at": "2020-01-29T12:59:14.291912835Z", + "updated_at": "2020-01-29T12:59:14.291912991Z", + "name": "messaging", + "typing_events": true, + "read_events": true, + "connect_events": true, + "search": true, + "reactions": true, + "replies": true, + "mutes": true, + "uploads": true, + "url_enrichment": true, + "message_retention": "infinite", + "max_message_length": 5000, + "automod": "disabled", + "automod_behavior": "flag", + "commands": [ + { + "name": "giphy", + "description": "Post a random gif to the channel", + "args": "[text]", + "set": "fun_set" + } + ] + }, + "name": "Mia Denys", + "image": "https://randomuser.me/api/portraits/women/2.jpg" + }, + "messages": [ + { + "id": "4637f7e4-a06b-42db-ba5a-8d8270dd926f", + "text": "https://giphy.com/gifs/the-lion-king-live-action-5zvN79uTGfLMOVfQaA", + "html": "\u003cp\u003e\u003ca href=\"https://giphy.com/gifs/the-lion-king-live-action-5zvN79uTGfLMOVfQaA\" rel=\"nofollow\"\u003ehttps://giphy.com/gifs/the-lion-king-live-action-5zvN79uTGfLMOVfQaA\u003c/a\u003e\u003c/p\u003e\n", + "type": "regular", + "user": { + "id": "c1c9b454-2bcc-402d-8bb0-2f3706ce1680", + "role": "user", + "created_at": "2020-01-28T22:17:30.83015Z", + "updated_at": "2020-01-28T22:17:31.19435Z", + "banned": false, + "online": false, + "image": "https://randomuser.me/api/portraits/women/2.jpg", + "name": "Mia Denys" + }, + "attachments": [ + { + "type": "video", + "author_name": "GIPHY", + "title": "The Lion King Disney GIF - Find \u0026 Share on GIPHY", + "title_link": "https://media.giphy.com/media/5zvN79uTGfLMOVfQaA/giphy.gif", + "text": "Discover \u0026 share this Lion King Live Action GIF with everyone you know. GIPHY is how you search, share, discover, and create GIFs.", + "image_url": "https://media.giphy.com/media/5zvN79uTGfLMOVfQaA/giphy.gif", + "thumb_url": "https://media.giphy.com/media/5zvN79uTGfLMOVfQaA/giphy.gif", + "asset_url": "https://media.giphy.com/media/5zvN79uTGfLMOVfQaA/giphy.mp4", + "og_scrape_url": "https://giphy.com/gifs/the-lion-king-live-action-5zvN79uTGfLMOVfQaA" + } + ], + "latest_reactions": [ + { + "message_id": "4637f7e4-a06b-42db-ba5a-8d8270dd926f", + "user_id": "c1c9b454-2bcc-402d-8bb0-2f3706ce1680", + "user": { + "id": "c1c9b454-2bcc-402d-8bb0-2f3706ce1680", + "role": "user", + "created_at": "2020-01-28T22:17:30.83015Z", + "updated_at": "2020-01-28T22:17:31.19435Z", + "banned": false, + "online": false, + "image": "https://randomuser.me/api/portraits/women/2.jpg", + "name": "Mia Denys" + }, + "type": "love", + "score": 1, + "created_at": "2020-01-28T22:17:31.128376Z", + "updated_at": "2020-01-28T22:17:31.128376Z" + } + ], + "own_reactions": [], + "reaction_counts": { + "love": 1 + }, + "reaction_scores": { + "love": 1 + }, + "reply_count": 0, + "created_at": "2020-01-28T22:17:31.107978Z", + "updated_at": "2020-01-28T22:17:31.130506Z", + "mentioned_users": [] + }, + { + "id": "16e19c46-fb96-4f89-8031-d5bd2ce3bd64", + "text": "Few can name a topfull mother that isn't a breezeless damage.", + "html": "\u003cp\u003eFew can name a topfull mother that isn’t a breezeless damage.\u003c/p\u003e\n", + "type": "regular", + "user": { + "id": "spring-voice-7", + "role": "user", + "created_at": "2020-01-28T22:17:30.834135Z", + "updated_at": "2020-01-28T22:17:31.186771Z", + "banned": false, + "online": false, + "image": "https://getstream.io/random_svg/?id=spring-voice-7\u0026name=Spring+voice", + "name": "Spring voice" + }, + "attachments": [], + "latest_reactions": [], + "own_reactions": [], + "reaction_counts": {}, + "reaction_scores": {}, + "reply_count": 0, + "created_at": "2020-01-28T22:17:31.153518Z", + "updated_at": "2020-01-28T22:17:31.153518Z", + "mentioned_users": [] + }, + { + "id": "38b1b252-c9a6-4aea-a39e-8de3b7f7604b", + "text": "https://giphy.com/gifs/beard-muscle-73Sjhw0N4hyog", + "html": "\u003cp\u003e\u003ca href=\"https://giphy.com/gifs/beard-muscle-73Sjhw0N4hyog\" rel=\"nofollow\"\u003ehttps://giphy.com/gifs/beard-muscle-73Sjhw0N4hyog\u003c/a\u003e\u003c/p\u003e\n", + "type": "regular", + "user": { + "id": "spring-voice-7", + "role": "user", + "created_at": "2020-01-28T22:17:30.834135Z", + "updated_at": "2020-01-28T22:17:31.186771Z", + "banned": false, + "online": false, + "image": "https://getstream.io/random_svg/?id=spring-voice-7\u0026name=Spring+voice", + "name": "Spring voice" + }, + "attachments": [ + { + "type": "video", + "author_name": "GIPHY", + "title": "Moustache Thumbs Up GIF - Find \u0026 Share on GIPHY", + "title_link": "https://media.giphy.com/media/73Sjhw0N4hyog/giphy.gif", + "text": "Discover \u0026 share this Pouce Leve GIF with everyone you know. GIPHY is how you search, share, discover, and create GIFs.", + "image_url": "https://media.giphy.com/media/73Sjhw0N4hyog/giphy.gif", + "thumb_url": "https://media.giphy.com/media/73Sjhw0N4hyog/giphy.gif", + "asset_url": "https://media.giphy.com/media/73Sjhw0N4hyog/giphy.mp4", + "og_scrape_url": "https://giphy.com/gifs/beard-muscle-73Sjhw0N4hyog" + } + ], + "latest_reactions": [], + "own_reactions": [], + "reaction_counts": {}, + "reaction_scores": {}, + "reply_count": 0, + "created_at": "2020-01-28T22:17:31.155428Z", + "updated_at": "2020-01-28T22:17:31.155428Z", + "mentioned_users": [] + }, + { + "id": "5c7d0c68-72d5-4027-b6b7-711b342d0fc4", + "text": "The carbons could be said to resemble smartish hoods.", + "html": "\u003cp\u003eThe carbons could be said to resemble smartish hoods.\u003c/p\u003e\n", + "type": "regular", + "user": { + "id": "c1c9b454-2bcc-402d-8bb0-2f3706ce1680", + "role": "user", + "created_at": "2020-01-28T22:17:30.83015Z", + "updated_at": "2020-01-28T22:17:31.19435Z", + "banned": false, + "online": false, + "image": "https://randomuser.me/api/portraits/women/2.jpg", + "name": "Mia Denys" + }, + "attachments": [], + "latest_reactions": [], + "own_reactions": [], + "reaction_counts": {}, + "reaction_scores": {}, + "reply_count": 1, + "created_at": "2020-01-28T22:17:31.157811Z", + "updated_at": "2020-01-28T22:17:31.157811Z", + "mentioned_users": [] + }, + { + "id": "5b02535a-0c3c-45fa-9cf8-16f840c5123f", + "text": "Their software was, in this moment, a prolix feature.", + "html": "\u003cp\u003eTheir software was, in this moment, a prolix feature.\u003c/p\u003e\n", + "type": "regular", + "user": { + "id": "c1c9b454-2bcc-402d-8bb0-2f3706ce1680", + "role": "user", + "created_at": "2020-01-28T22:17:30.83015Z", + "updated_at": "2020-01-28T22:17:31.19435Z", + "banned": false, + "online": false, + "image": "https://randomuser.me/api/portraits/women/2.jpg", + "name": "Mia Denys" + }, + "attachments": [], + "latest_reactions": [], + "own_reactions": [], + "reaction_counts": {}, + "reaction_scores": {}, + "reply_count": 1, + "created_at": "2020-01-28T22:17:31.158391Z", + "updated_at": "2020-01-28T22:17:31.158391Z", + "mentioned_users": [] + } + ], + "watcher_count": 1, + "read": [ + { + "user": { + "id": "c1c9b454-2bcc-402d-8bb0-2f3706ce1680", + "role": "user", + "created_at": "2020-01-28T22:17:30.83015Z", + "updated_at": "2020-01-28T22:17:31.19435Z", + "banned": false, + "online": false, + "image": "https://randomuser.me/api/portraits/women/2.jpg", + "name": "Mia Denys" + }, + "last_read": "2020-01-28T22:17:31.016937728Z" + }, + { + "user": { + "id": "spring-voice-7", + "role": "user", + "created_at": "2020-01-28T22:17:30.834135Z", + "updated_at": "2020-01-28T22:17:31.186771Z", + "banned": false, + "online": false, + "image": "https://getstream.io/random_svg/?id=spring-voice-7\u0026name=Spring+voice", + "name": "Spring voice" + }, + "last_read": "2020-01-28T22:17:31.018856448Z" + } + ], + "members": [ + { + "user": { + "id": "c1c9b454-2bcc-402d-8bb0-2f3706ce1680", + "role": "user", + "created_at": "2020-01-28T22:17:30.83015Z", + "updated_at": "2020-01-28T22:17:31.19435Z", + "banned": false, + "online": false, + "image": "https://randomuser.me/api/portraits/women/2.jpg", + "name": "Mia Denys" + }, + "role": "member", + "created_at": "2020-01-28T22:17:31.005135Z", + "updated_at": "2020-01-28T22:17:31.005135Z" + }, + { + "user": { + "id": "spring-voice-7", + "role": "user", + "created_at": "2020-01-28T22:17:30.834135Z", + "updated_at": "2020-01-28T22:17:31.186771Z", + "banned": false, + "online": false, + "image": "https://getstream.io/random_svg/?id=spring-voice-7\u0026name=Spring+voice", + "name": "Spring voice" + }, + "role": "owner", + "created_at": "2020-01-28T22:17:31.005135Z", + "updated_at": "2020-01-28T22:17:31.005135Z" + } + ] + }, + { + "channel": { + "id": "spring-voice-7", + "type": "messaging", + "cid": "messaging:spring-voice-7", + "last_message_at": "2020-01-28T22:17:31.194334Z", + "created_at": "2020-01-28T22:17:30.858437Z", + "updated_at": "2020-01-28T22:17:30.858438Z", + "created_by": { + "id": "spring-voice-7", + "role": "user", + "created_at": "2020-01-28T22:17:30.834135Z", + "updated_at": "2020-01-28T22:17:31.186771Z", + "banned": false, + "online": false, + "image": "https://getstream.io/random_svg/?id=spring-voice-7\u0026name=Spring+voice", + "name": "Spring voice" + }, + "frozen": false, + "config": { + "created_at": "2020-01-29T12:59:14.291912835Z", + "updated_at": "2020-01-29T12:59:14.291912991Z", + "name": "messaging", + "typing_events": true, + "read_events": true, + "connect_events": true, + "search": true, + "reactions": true, + "replies": true, + "mutes": true, + "uploads": true, + "url_enrichment": true, + "message_retention": "infinite", + "max_message_length": 5000, + "automod": "disabled", + "automod_behavior": "flag", + "commands": [ + { + "name": "giphy", + "description": "Post a random gif to the channel", + "args": "[text]", + "set": "fun_set" + } + ] + } + }, + "messages": [ + { + "id": "9db3ef01-e779-4279-8c54-ffd021eccec4", + "text": "A lustred seal is an alto of the mind.", + "html": "\u003cp\u003eA lustred seal is an alto of the mind.\u003c/p\u003e\n", + "type": "regular", + "user": { + "id": "spring-voice-7", + "role": "user", + "created_at": "2020-01-28T22:17:30.834135Z", + "updated_at": "2020-01-28T22:17:31.186771Z", + "banned": false, + "online": false, + "image": "https://getstream.io/random_svg/?id=spring-voice-7\u0026name=Spring+voice", + "name": "Spring voice" + }, + "attachments": [], + "latest_reactions": [], + "own_reactions": [], + "reaction_counts": {}, + "reaction_scores": {}, + "reply_count": 0, + "created_at": "2020-01-28T22:17:31.167579Z", + "updated_at": "2020-01-28T22:17:31.167579Z", + "mentioned_users": [] + }, + { + "id": "3232e92f-a96f-4b5e-bacb-3565e7155dc4", + "text": "https://giphy.com/gifs/netflix-marvel-the-punisher-l3mZsRS7ZfftbdLdS", + "html": "\u003cp\u003e\u003ca href=\"https://giphy.com/gifs/netflix-marvel-the-punisher-l3mZsRS7ZfftbdLdS\" rel=\"nofollow\"\u003ehttps://giphy.com/gifs/netflix-marvel-the-punisher-l3mZsRS7ZfftbdLdS\u003c/a\u003e\u003c/p\u003e\n", + "type": "regular", + "user": { + "id": "spring-voice-7", + "role": "user", + "created_at": "2020-01-28T22:17:30.834135Z", + "updated_at": "2020-01-28T22:17:31.186771Z", + "banned": false, + "online": false, + "image": "https://getstream.io/random_svg/?id=spring-voice-7\u0026name=Spring+voice", + "name": "Spring voice" + }, + "attachments": [ + { + "type": "video", + "author_name": "GIPHY", + "title": "The Punisher Marvel GIF by NETFLIX - Find \u0026 Share on GIPHY", + "title_link": "https://media.giphy.com/media/l3mZsRS7ZfftbdLdS/giphy.gif", + "text": "See What's Next in entertainment and Netflix original series, movies, TV, docs, and comedies. You can stream Netflix anytime, anywhere, on any device.", + "image_url": "https://media.giphy.com/media/l3mZsRS7ZfftbdLdS/giphy.gif", + "thumb_url": "https://media.giphy.com/media/l3mZsRS7ZfftbdLdS/giphy.gif", + "asset_url": "https://media.giphy.com/media/l3mZsRS7ZfftbdLdS/giphy.mp4", + "og_scrape_url": "https://giphy.com/gifs/netflix-marvel-the-punisher-l3mZsRS7ZfftbdLdS" + } + ], + "latest_reactions": [], + "own_reactions": [], + "reaction_counts": {}, + "reaction_scores": {}, + "reply_count": 1, + "created_at": "2020-01-28T22:17:31.168454Z", + "updated_at": "2020-01-28T22:17:31.168454Z", + "mentioned_users": [] + }, + { + "id": "ae6e196c-0a66-4941-9832-d66a40c95699", + "text": "A height of the parallelogram is assumed to be a sunfast cone.", + "html": "\u003cp\u003eA height of the parallelogram is assumed to be a sunfast cone.\u003c/p\u003e\n", + "type": "regular", + "user": { + "id": "spring-voice-7", + "role": "user", + "created_at": "2020-01-28T22:17:30.834135Z", + "updated_at": "2020-01-28T22:17:31.186771Z", + "banned": false, + "online": false, + "image": "https://getstream.io/random_svg/?id=spring-voice-7\u0026name=Spring+voice", + "name": "Spring voice" + }, + "attachments": [], + "latest_reactions": [], + "own_reactions": [], + "reaction_counts": {}, + "reaction_scores": {}, + "reply_count": 0, + "created_at": "2020-01-28T22:17:31.17494Z", + "updated_at": "2020-01-28T22:17:31.17494Z", + "mentioned_users": [] + }, + { + "id": "38fee958-1efe-456b-b2d2-7bd1ba975eab", + "text": "In modern times the braided bridge reveals itself as a daisied burn to those who look.", + "html": "\u003cp\u003eIn modern times the braided bridge reveals itself as a daisied burn to those who look.\u003c/p\u003e\n", + "type": "regular", + "user": { + "id": "spring-voice-7", + "role": "user", + "created_at": "2020-01-28T22:17:30.834135Z", + "updated_at": "2020-01-28T22:17:31.186771Z", + "banned": false, + "online": false, + "image": "https://getstream.io/random_svg/?id=spring-voice-7\u0026name=Spring+voice", + "name": "Spring voice" + }, + "attachments": [], + "latest_reactions": [ + { + "message_id": "38fee958-1efe-456b-b2d2-7bd1ba975eab", + "user_id": "spring-voice-7", + "user": { + "id": "spring-voice-7", + "role": "user", + "created_at": "2020-01-28T22:17:30.834135Z", + "updated_at": "2020-01-28T22:17:31.186771Z", + "banned": false, + "online": false, + "image": "https://getstream.io/random_svg/?id=spring-voice-7\u0026name=Spring+voice", + "name": "Spring voice" + }, + "type": "like", + "score": 1, + "created_at": "2020-01-28T22:17:31.213167Z", + "updated_at": "2020-01-28T22:17:31.213167Z" + } + ], + "own_reactions": [], + "reaction_counts": { + "like": 1 + }, + "reaction_scores": { + "like": 1 + }, + "reply_count": 0, + "created_at": "2020-01-28T22:17:31.184974Z", + "updated_at": "2020-01-28T22:17:31.215223Z", + "mentioned_users": [] + }, + { + "id": "8dbc9bec-35c4-4c42-942a-5c97bd4400c0", + "text": "Nowhere is it disputed that some posit the unfiled japan to be less than fretted.", + "html": "\u003cp\u003eNowhere is it disputed that some posit the unfiled japan to be less than fretted.\u003c/p\u003e\n", + "type": "regular", + "user": { + "id": "spring-voice-7", + "role": "user", + "created_at": "2020-01-28T22:17:30.834135Z", + "updated_at": "2020-01-28T22:17:31.186771Z", + "banned": false, + "online": false, + "image": "https://getstream.io/random_svg/?id=spring-voice-7\u0026name=Spring+voice", + "name": "Spring voice" + }, + "attachments": [], + "latest_reactions": [ + { + "message_id": "8dbc9bec-35c4-4c42-942a-5c97bd4400c0", + "user_id": "spring-voice-7", + "user": { + "id": "spring-voice-7", + "role": "user", + "created_at": "2020-01-28T22:17:30.834135Z", + "updated_at": "2020-01-28T22:17:31.186771Z", + "banned": false, + "online": false, + "image": "https://getstream.io/random_svg/?id=spring-voice-7\u0026name=Spring+voice", + "name": "Spring voice" + }, + "type": "love", + "score": 1, + "created_at": "2020-01-28T22:17:31.20517Z", + "updated_at": "2020-01-28T22:17:31.20517Z" + } + ], + "own_reactions": [], + "reaction_counts": { + "love": 1 + }, + "reaction_scores": { + "love": 1 + }, + "reply_count": 0, + "created_at": "2020-01-28T22:17:31.18983Z", + "updated_at": "2020-01-28T22:17:31.207426Z", + "mentioned_users": [] + } + ], + "watcher_count": 1, + "members": [] + }, + { + "channel": { + "id": "!members-1xFd7ZzcZ3c3ypDAOvvHynN4Yqy1TV5vw08XTxa4usg", + "type": "messaging", + "cid": "messaging:!members-1xFd7ZzcZ3c3ypDAOvvHynN4Yqy1TV5vw08XTxa4usg", + "last_message_at": "2020-01-28T22:17:31.179366Z", + "created_at": "2020-01-28T22:17:30.951407Z", + "updated_at": "2020-01-28T22:17:30.951407Z", + "created_by": { + "id": "spring-voice-7", + "role": "user", + "created_at": "2020-01-28T22:17:30.834135Z", + "updated_at": "2020-01-28T22:17:31.186771Z", + "banned": false, + "online": false, + "image": "https://getstream.io/random_svg/?id=spring-voice-7\u0026name=Spring+voice", + "name": "Spring voice" + }, + "frozen": false, + "member_count": 2, + "config": { + "created_at": "2020-01-29T12:59:14.291912835Z", + "updated_at": "2020-01-29T12:59:14.291912991Z", + "name": "messaging", + "typing_events": true, + "read_events": true, + "connect_events": true, + "search": true, + "reactions": true, + "replies": true, + "mutes": true, + "uploads": true, + "url_enrichment": true, + "message_retention": "infinite", + "max_message_length": 5000, + "automod": "disabled", + "automod_behavior": "flag", + "commands": [ + { + "name": "giphy", + "description": "Post a random gif to the channel", + "args": "[text]", + "set": "fun_set" + } + ] + }, + "name": "Robin Papa", + "image": "https://pbs.twimg.com/profile_images/669512187778498560/L7wQctBt.jpg" + }, + "messages": [ + { + "id": "c6076f11-7768-4a04-bdf2-c43dddd6d666", + "text": "What we don't know for sure is whether or not a step-daughter of the bear is assumed to be a farci hourglass.", + "html": "\u003cp\u003eWhat we don’t know for sure is whether or not a step-daughter of the bear is assumed to be a farci hourglass.\u003c/p\u003e\n", + "type": "regular", + "user": { + "id": "bbb19d9a-ee50-45bc-84e5-0584e79d0c9e", + "role": "user", + "created_at": "2020-01-28T22:17:30.826259Z", + "updated_at": "2020-01-28T22:17:31.101222Z", + "banned": false, + "online": false, + "image": "https://pbs.twimg.com/profile_images/669512187778498560/L7wQctBt.jpg", + "name": "Robin Papa" + }, + "attachments": [], + "latest_reactions": [], + "own_reactions": [], + "reaction_counts": {}, + "reaction_scores": {}, + "reply_count": 1, + "created_at": "2020-01-28T22:17:31.092262Z", + "updated_at": "2020-01-28T22:17:31.092262Z", + "mentioned_users": [] + }, + { + "id": "0fe600b6-9cb7-4d1b-a9ba-eef7dd133b26", + "text": "A plagal ease without britishes is truly a james of premorse entrances.", + "html": "\u003cp\u003eA plagal ease without britishes is truly a james of premorse entrances.\u003c/p\u003e\n", + "type": "regular", + "user": { + "id": "bbb19d9a-ee50-45bc-84e5-0584e79d0c9e", + "role": "user", + "created_at": "2020-01-28T22:17:30.826259Z", + "updated_at": "2020-01-28T22:17:31.101222Z", + "banned": false, + "online": false, + "image": "https://pbs.twimg.com/profile_images/669512187778498560/L7wQctBt.jpg", + "name": "Robin Papa" + }, + "attachments": [], + "latest_reactions": [ + { + "message_id": "0fe600b6-9cb7-4d1b-a9ba-eef7dd133b26", + "user_id": "spring-voice-7", + "user": { + "id": "spring-voice-7", + "role": "user", + "created_at": "2020-01-28T22:17:30.834135Z", + "updated_at": "2020-01-28T22:17:31.186771Z", + "banned": false, + "online": false, + "image": "https://getstream.io/random_svg/?id=spring-voice-7\u0026name=Spring+voice", + "name": "Spring voice" + }, + "type": "wow", + "score": 1, + "created_at": "2020-01-28T22:17:31.118131Z", + "updated_at": "2020-01-28T22:17:31.118131Z" + } + ], + "own_reactions": [], + "reaction_counts": { + "wow": 1 + }, + "reaction_scores": { + "wow": 1 + }, + "reply_count": 0, + "created_at": "2020-01-28T22:17:31.1022Z", + "updated_at": "2020-01-28T22:17:31.123766Z", + "mentioned_users": [] + }, + { + "id": "4905cb95-c4db-42df-ac6c-5d6531f5f67b", + "text": "A lustred seal is an alto of the mind.", + "html": "\u003cp\u003eA lustred seal is an alto of the mind.\u003c/p\u003e\n", + "type": "regular", + "user": { + "id": "bbb19d9a-ee50-45bc-84e5-0584e79d0c9e", + "role": "user", + "created_at": "2020-01-28T22:17:30.826259Z", + "updated_at": "2020-01-28T22:17:31.101222Z", + "banned": false, + "online": false, + "image": "https://pbs.twimg.com/profile_images/669512187778498560/L7wQctBt.jpg", + "name": "Robin Papa" + }, + "attachments": [], + "latest_reactions": [ + { + "message_id": "4905cb95-c4db-42df-ac6c-5d6531f5f67b", + "user_id": "spring-voice-7", + "user": { + "id": "spring-voice-7", + "role": "user", + "created_at": "2020-01-28T22:17:30.834135Z", + "updated_at": "2020-01-28T22:17:31.186771Z", + "banned": false, + "online": false, + "image": "https://getstream.io/random_svg/?id=spring-voice-7\u0026name=Spring+voice", + "name": "Spring voice" + }, + "type": "love", + "score": 1, + "created_at": "2020-01-28T22:17:31.135966Z", + "updated_at": "2020-01-28T22:17:31.135966Z" + } + ], + "own_reactions": [], + "reaction_counts": { + "love": 1 + }, + "reaction_scores": { + "love": 1 + }, + "reply_count": 1, + "created_at": "2020-01-28T22:17:31.103279Z", + "updated_at": "2020-01-28T22:17:31.142756Z", + "mentioned_users": [] + }, + { + "id": "549888c4-0d13-48ca-aaa5-7da8effb9c6f", + "text": "Before aftershaves, snowflakes were only deer.", + "html": "\u003cp\u003eBefore aftershaves, snowflakes were only deer.\u003c/p\u003e\n", + "type": "regular", + "user": { + "id": "bbb19d9a-ee50-45bc-84e5-0584e79d0c9e", + "role": "user", + "created_at": "2020-01-28T22:17:30.826259Z", + "updated_at": "2020-01-28T22:17:31.101222Z", + "banned": false, + "online": false, + "image": "https://pbs.twimg.com/profile_images/669512187778498560/L7wQctBt.jpg", + "name": "Robin Papa" + }, + "attachments": [], + "latest_reactions": [], + "own_reactions": [], + "reaction_counts": {}, + "reaction_scores": {}, + "reply_count": 0, + "created_at": "2020-01-28T22:17:31.10644Z", + "updated_at": "2020-01-28T22:17:31.10644Z", + "mentioned_users": [] + }, + { + "id": "c74784e7-07ef-4b41-a8e3-b2b0e0b6b7ce", + "text": "https://unsplash.com/photos/JdGtvgzQmgQ", + "html": "\u003cp\u003e\u003ca href=\"https://unsplash.com/photos/JdGtvgzQmgQ\" rel=\"nofollow\"\u003ehttps://unsplash.com/photos/JdGtvgzQmgQ\u003c/a\u003e\u003c/p\u003e\n", + "type": "regular", + "user": { + "id": "spring-voice-7", + "role": "user", + "created_at": "2020-01-28T22:17:30.834135Z", + "updated_at": "2020-01-28T22:17:31.186771Z", + "banned": false, + "online": false, + "image": "https://getstream.io/random_svg/?id=spring-voice-7\u0026name=Spring+voice", + "name": "Spring voice" + }, + "attachments": [ + { + "type": "image", + "title": "Photo by Markus Spiske on Unsplash", + "title_link": "https://unsplash.com/photos/JdGtvgzQmgQ", + "text": "THIS IS NOT A BOT – Save Your Internet – Demo against Uploadfilter – Article 13 #CensorshipMachine – March 16. 2019, Nürnberg, Germany. Download this photo by Markus Spiske on Unsplash", + "image_url": "https://images.unsplash.com/photo-1554272014-73b77edeb47f?ixlib=rb-1.2.1\u0026q=80\u0026fm=jpg\u0026crop=entropy\u0026cs=tinysrgb\u0026w=1080\u0026fit=max\u0026ixid=eyJhcHBfaWQiOjEyMDd9", + "thumb_url": "https://images.unsplash.com/photo-1554272014-73b77edeb47f?ixlib=rb-1.2.1\u0026q=80\u0026fm=jpg\u0026crop=entropy\u0026cs=tinysrgb\u0026w=1080\u0026fit=max\u0026ixid=eyJhcHBfaWQiOjEyMDd9", + "og_scrape_url": "https://unsplash.com/photos/JdGtvgzQmgQ" + } + ], + "latest_reactions": [ + { + "message_id": "c74784e7-07ef-4b41-a8e3-b2b0e0b6b7ce", + "user_id": "spring-voice-7", + "user": { + "id": "spring-voice-7", + "role": "user", + "created_at": "2020-01-28T22:17:30.834135Z", + "updated_at": "2020-01-28T22:17:31.186771Z", + "banned": false, + "online": false, + "name": "Spring voice", + "image": "https://getstream.io/random_svg/?id=spring-voice-7\u0026name=Spring+voice" + }, + "type": "sad", + "score": 1, + "created_at": "2020-01-28T22:17:31.131489Z", + "updated_at": "2020-01-28T22:17:31.131489Z" + } + ], + "own_reactions": [], + "reaction_counts": { + "sad": 1 + }, + "reaction_scores": { + "sad": 1 + }, + "reply_count": 1, + "created_at": "2020-01-28T22:17:31.11065Z", + "updated_at": "2020-01-28T22:17:31.133783Z", + "mentioned_users": [] + } + ], + "watcher_count": 1, + "read": [ + { + "user": { + "id": "bbb19d9a-ee50-45bc-84e5-0584e79d0c9e", + "role": "user", + "created_at": "2020-01-28T22:17:30.826259Z", + "updated_at": "2020-01-28T22:17:31.101222Z", + "banned": false, + "online": false, + "image": "https://pbs.twimg.com/profile_images/669512187778498560/L7wQctBt.jpg", + "name": "Robin Papa" + }, + "last_read": "2020-01-28T22:17:30.966485504Z" + }, + { + "user": { + "id": "spring-voice-7", + "role": "user", + "created_at": "2020-01-28T22:17:30.834135Z", + "updated_at": "2020-01-28T22:17:31.186771Z", + "banned": false, + "online": false, + "image": "https://getstream.io/random_svg/?id=spring-voice-7\u0026name=Spring+voice", + "name": "Spring voice" + }, + "last_read": "2020-01-28T22:17:30.968339456Z" + } + ], + "members": [ + { + "user": { + "id": "bbb19d9a-ee50-45bc-84e5-0584e79d0c9e", + "role": "user", + "created_at": "2020-01-28T22:17:30.826259Z", + "updated_at": "2020-01-28T22:17:31.101222Z", + "banned": false, + "online": false, + "name": "Robin Papa", + "image": "https://pbs.twimg.com/profile_images/669512187778498560/L7wQctBt.jpg" + }, + "role": "member", + "created_at": "2020-01-28T22:17:30.95443Z", + "updated_at": "2020-01-28T22:17:30.95443Z" + }, + { + "user": { + "id": "spring-voice-7", + "role": "user", + "created_at": "2020-01-28T22:17:30.834135Z", + "updated_at": "2020-01-28T22:17:31.186771Z", + "banned": false, + "online": false, + "image": "https://getstream.io/random_svg/?id=spring-voice-7\u0026name=Spring+voice", + "name": "Spring voice" + }, + "role": "owner", + "created_at": "2020-01-28T22:17:30.95443Z", + "updated_at": "2020-01-28T22:17:30.95443Z" + } + ] + }, + { + "channel": { + "id": "!members-6ngG6o5HlqKK7B_YIWnamzM4O9IqkfuaFOLO0QVPP-0", + "type": "messaging", + "cid": "messaging:!members-6ngG6o5HlqKK7B_YIWnamzM4O9IqkfuaFOLO0QVPP-0", + "last_message_at": "2020-01-28T22:17:31.171308Z", + "created_at": "2020-01-28T22:17:30.891989Z", + "updated_at": "2020-01-28T22:17:30.891989Z", + "created_by": { + "id": "spring-voice-7", + "role": "user", + "created_at": "2020-01-28T22:17:30.834135Z", + "updated_at": "2020-01-28T22:17:31.186771Z", + "banned": false, + "online": false, + "image": "https://getstream.io/random_svg/?id=spring-voice-7\u0026name=Spring+voice", + "name": "Spring voice" + }, + "frozen": false, + "member_count": 5, + "config": { + "created_at": "2020-01-29T12:59:14.291912835Z", + "updated_at": "2020-01-29T12:59:14.291912991Z", + "name": "messaging", + "typing_events": true, + "read_events": true, + "connect_events": true, + "search": true, + "reactions": true, + "replies": true, + "mutes": true, + "uploads": true, + "url_enrichment": true, + "message_retention": "infinite", + "max_message_length": 5000, + "automod": "disabled", + "automod_behavior": "flag", + "commands": [ + { + "name": "giphy", + "description": "Post a random gif to the channel", + "args": "[text]", + "set": "fun_set" + } + ] + }, + "image": "https://getstream.imgix.net/images/rn-chat-tutorial/caterpillar_01.png", + "name": "Family" + }, + "messages": [ + { + "id": "0bee6d7f-f479-47bb-998c-f449f6f30d74", + "text": "A described discovery's great-grandfather comes with it the thought that the topmost meter is a tsunami.", + "html": "\u003cp\u003eA described discovery’s great-grandfather comes with it the thought that the topmost meter is a tsunami.\u003c/p\u003e\n", + "type": "regular", + "user": { + "id": "b816b921-ed3a-4d32-8e9e-f6eca413a7b0", + "role": "user", + "created_at": "2020-01-28T22:17:30.8148Z", + "updated_at": "2020-01-28T22:17:31.08123Z", + "banned": false, + "online": false, + "name": "Micheal Murphy", + "image": "https://randomuser.me/api/portraits/men/95.jpg" + }, + "attachments": [], + "latest_reactions": [], + "own_reactions": [], + "reaction_counts": {}, + "reaction_scores": {}, + "reply_count": 0, + "created_at": "2020-01-28T22:17:31.068584Z", + "updated_at": "2020-01-28T22:17:31.068584Z", + "mentioned_users": [] + }, + { + "id": "76cd8c82-b557-4e48-9d12-87995d3a0e04", + "text": "The biggest driver reveals itself as a sclerosed mom to those who look.", + "html": "\u003cp\u003eThe biggest driver reveals itself as a sclerosed mom to those who look.\u003c/p\u003e\n", + "type": "regular", + "user": { + "id": "2de0297c-f3f2-489d-b930-ef77342edccf", + "role": "user", + "created_at": "2020-01-28T22:17:30.810011Z", + "updated_at": "2020-01-28T22:17:31.077195Z", + "banned": false, + "online": false, + "image": "https://randomuser.me/api/portraits/women/45.jpg", + "name": "Daisy Morgan" + }, + "attachments": [], + "latest_reactions": [ + { + "message_id": "76cd8c82-b557-4e48-9d12-87995d3a0e04", + "user_id": "2de0297c-f3f2-489d-b930-ef77342edccf", + "user": { + "id": "2de0297c-f3f2-489d-b930-ef77342edccf", + "role": "user", + "created_at": "2020-01-28T22:17:30.810011Z", + "updated_at": "2020-01-28T22:17:31.077195Z", + "banned": false, + "online": false, + "image": "https://randomuser.me/api/portraits/women/45.jpg", + "name": "Daisy Morgan" + }, + "type": "wow", + "score": 1, + "created_at": "2020-01-28T22:17:31.108742Z", + "updated_at": "2020-01-28T22:17:31.108742Z" + } + ], + "own_reactions": [], + "reaction_counts": { + "wow": 1 + }, + "reaction_scores": { + "wow": 1 + }, + "reply_count": 0, + "created_at": "2020-01-28T22:17:31.077583Z", + "updated_at": "2020-01-28T22:17:31.111709Z", + "mentioned_users": [] + }, + { + "id": "358b8ab3-dd34-4baf-939e-f03617742486", + "text": "A spongy jail without bengals is truly a hawk of rattish canvases.", + "html": "\u003cp\u003eA spongy jail without bengals is truly a hawk of rattish canvases.\u003c/p\u003e\n", + "type": "regular", + "user": { + "id": "b816b921-ed3a-4d32-8e9e-f6eca413a7b0", + "role": "user", + "created_at": "2020-01-28T22:17:30.8148Z", + "updated_at": "2020-01-28T22:17:31.08123Z", + "banned": false, + "online": false, + "image": "https://randomuser.me/api/portraits/men/95.jpg", + "name": "Micheal Murphy" + }, + "attachments": [], + "latest_reactions": [], + "own_reactions": [], + "reaction_counts": {}, + "reaction_scores": {}, + "reply_count": 1, + "created_at": "2020-01-28T22:17:31.08593Z", + "updated_at": "2020-01-28T22:17:31.08593Z", + "mentioned_users": [] + }, + { + "id": "5a559749-2f45-476e-9610-8eae92f3a5c6", + "text": "https://unsplash.com/photos/4v7ubW7jz1Q", + "html": "\u003cp\u003e\u003ca href=\"https://unsplash.com/photos/4v7ubW7jz1Q\" rel=\"nofollow\"\u003ehttps://unsplash.com/photos/4v7ubW7jz1Q\u003c/a\u003e\u003c/p\u003e\n", + "type": "regular", + "user": { + "id": "2de0297c-f3f2-489d-b930-ef77342edccf", + "role": "user", + "created_at": "2020-01-28T22:17:30.810011Z", + "updated_at": "2020-01-28T22:17:31.077195Z", + "banned": false, + "online": false, + "image": "https://randomuser.me/api/portraits/women/45.jpg", + "name": "Daisy Morgan" + }, + "attachments": [ + { + "type": "image", + "title": "Photo by Joel Filipe on Unsplash", + "title_link": "https://unsplash.com/photos/4v7ubW7jz1Q", + "text": "Download this photo by Joel Filipe on Unsplash", + "image_url": "https://images.unsplash.com/photo-1557389352-e721da78ad9f?ixlib=rb-1.2.1\u0026q=80\u0026fm=jpg\u0026crop=entropy\u0026cs=tinysrgb\u0026w=1080\u0026fit=max\u0026ixid=eyJhcHBfaWQiOjEyMDd9", + "thumb_url": "https://images.unsplash.com/photo-1557389352-e721da78ad9f?ixlib=rb-1.2.1\u0026q=80\u0026fm=jpg\u0026crop=entropy\u0026cs=tinysrgb\u0026w=1080\u0026fit=max\u0026ixid=eyJhcHBfaWQiOjEyMDd9", + "og_scrape_url": "https://unsplash.com/photos/4v7ubW7jz1Q" + } + ], + "latest_reactions": [], + "own_reactions": [], + "reaction_counts": {}, + "reaction_scores": {}, + "reply_count": 1, + "created_at": "2020-01-28T22:17:31.090006Z", + "updated_at": "2020-01-28T22:17:31.090006Z", + "mentioned_users": [] + }, + { + "id": "da57c33b-ae12-438c-a672-4e5bad0d1467", + "text": "https://unsplash.com/photos/XttWKETqCCQ", + "html": "\u003cp\u003e\u003ca href=\"https://unsplash.com/photos/XttWKETqCCQ\" rel=\"nofollow\"\u003ehttps://unsplash.com/photos/XttWKETqCCQ\u003c/a\u003e\u003c/p\u003e\n", + "type": "regular", + "user": { + "id": "6e60091e-2173-4aa8-a6d2-1a79e4cad790", + "role": "user", + "created_at": "2020-01-28T22:17:30.818618Z", + "updated_at": "2020-01-28T22:17:31.056057Z", + "banned": false, + "online": false, + "image": "https://images.unsplash.com/photo-1502378735452-bc7d86632805?ixlib=rb-0.3.5\u0026q=80\u0026fm=jpg\u0026crop=entropy\u0026cs=tinysrgb\u0026w=200\u0026fit=max\u0026s=aa3a807e1bbdfd4364d1f449eaa96d82", + "name": "Carys Metz" + }, + "attachments": [ + { + "type": "image", + "title": "Photo by Olena Sergienko on Unsplash", + "title_link": "https://unsplash.com/photos/XttWKETqCCQ", + "text": "Download this photo by Olena Sergienko on Unsplash", + "image_url": "https://images.unsplash.com/photo-1557053910-d9eadeed1c58?ixlib=rb-1.2.1\u0026q=80\u0026fm=jpg\u0026crop=entropy\u0026cs=tinysrgb\u0026w=1080\u0026fit=max\u0026ixid=eyJhcHBfaWQiOjEyMDd9", + "thumb_url": "https://images.unsplash.com/photo-1557053910-d9eadeed1c58?ixlib=rb-1.2.1\u0026q=80\u0026fm=jpg\u0026crop=entropy\u0026cs=tinysrgb\u0026w=1080\u0026fit=max\u0026ixid=eyJhcHBfaWQiOjEyMDd9", + "og_scrape_url": "https://unsplash.com/photos/XttWKETqCCQ" + } + ], + "latest_reactions": [], + "own_reactions": [], + "reaction_counts": {}, + "reaction_scores": {}, + "reply_count": 0, + "created_at": "2020-01-28T22:17:31.171308Z", + "updated_at": "2020-01-28T22:17:31.171308Z", + "mentioned_users": [] + } + ], + "watcher_count": 1, + "read": [ + { + "user": { + "id": "spring-voice-7", + "role": "user", + "created_at": "2020-01-28T22:17:30.834135Z", + "updated_at": "2020-01-28T22:17:31.186771Z", + "banned": false, + "online": false, + "name": "Spring voice", + "image": "https://getstream.io/random_svg/?id=spring-voice-7\u0026name=Spring+voice" + }, + "last_read": "2020-01-28T22:17:30.916570624Z" + }, + { + "user": { + "id": "2de0297c-f3f2-489d-b930-ef77342edccf", + "role": "user", + "created_at": "2020-01-28T22:17:30.810011Z", + "updated_at": "2020-01-28T22:17:31.077195Z", + "banned": false, + "online": false, + "name": "Daisy Morgan", + "image": "https://randomuser.me/api/portraits/women/45.jpg" + }, + "last_read": "2020-01-28T22:17:30.90931712Z" + }, + { + "user": { + "id": "b816b921-ed3a-4d32-8e9e-f6eca413a7b0", + "role": "user", + "created_at": "2020-01-28T22:17:30.8148Z", + "updated_at": "2020-01-28T22:17:31.08123Z", + "banned": false, + "online": false, + "image": "https://randomuser.me/api/portraits/men/95.jpg", + "name": "Micheal Murphy" + }, + "last_read": "2020-01-28T22:17:30.911188736Z" + }, + { + "user": { + "id": "6e60091e-2173-4aa8-a6d2-1a79e4cad790", + "role": "user", + "created_at": "2020-01-28T22:17:30.818618Z", + "updated_at": "2020-01-28T22:17:31.056057Z", + "banned": false, + "online": false, + "image": "https://images.unsplash.com/photo-1502378735452-bc7d86632805?ixlib=rb-0.3.5\u0026q=80\u0026fm=jpg\u0026crop=entropy\u0026cs=tinysrgb\u0026w=200\u0026fit=max\u0026s=aa3a807e1bbdfd4364d1f449eaa96d82", + "name": "Carys Metz" + }, + "last_read": "2020-01-28T22:17:30.912969472Z" + }, + { + "user": { + "id": "dbcd6837-5d93-4b6e-ab27-ee13a490b873", + "role": "user", + "created_at": "2020-01-28T22:17:30.822448Z", + "updated_at": "2020-01-28T22:17:30.823463Z", + "banned": false, + "online": false, + "image": "https://images-na.ssl-images-amazon.com/images/M/MV5BMjAwNjM3NjY5MF5BMl5BanBnXkFtZTcwMjM4NTYwOQ@@._V1_UY256_CR0,0,172,256_AL_.jpg", + "name": "Dakota Fanning" + }, + "last_read": "2020-01-28T22:17:30.914806272Z" + } + ], + "members": [ + { + "user": { + "id": "2de0297c-f3f2-489d-b930-ef77342edccf", + "role": "user", + "created_at": "2020-01-28T22:17:30.810011Z", + "updated_at": "2020-01-28T22:17:31.077195Z", + "banned": false, + "online": false, + "image": "https://randomuser.me/api/portraits/women/45.jpg", + "name": "Daisy Morgan" + }, + "role": "member", + "created_at": "2020-01-28T22:17:30.895522Z", + "updated_at": "2020-01-28T22:17:30.895522Z" + }, + { + "user": { + "id": "6e60091e-2173-4aa8-a6d2-1a79e4cad790", + "role": "user", + "created_at": "2020-01-28T22:17:30.818618Z", + "updated_at": "2020-01-28T22:17:31.056057Z", + "banned": false, + "online": false, + "image": "https://images.unsplash.com/photo-1502378735452-bc7d86632805?ixlib=rb-0.3.5\u0026q=80\u0026fm=jpg\u0026crop=entropy\u0026cs=tinysrgb\u0026w=200\u0026fit=max\u0026s=aa3a807e1bbdfd4364d1f449eaa96d82", + "name": "Carys Metz" + }, + "role": "member", + "created_at": "2020-01-28T22:17:30.895522Z", + "updated_at": "2020-01-28T22:17:30.895522Z" + }, + { + "user": { + "id": "b816b921-ed3a-4d32-8e9e-f6eca413a7b0", + "role": "user", + "created_at": "2020-01-28T22:17:30.8148Z", + "updated_at": "2020-01-28T22:17:31.08123Z", + "banned": false, + "online": false, + "name": "Micheal Murphy", + "image": "https://randomuser.me/api/portraits/men/95.jpg" + }, + "role": "member", + "created_at": "2020-01-28T22:17:30.895522Z", + "updated_at": "2020-01-28T22:17:30.895522Z" + }, + { + "user": { + "id": "dbcd6837-5d93-4b6e-ab27-ee13a490b873", + "role": "user", + "created_at": "2020-01-28T22:17:30.822448Z", + "updated_at": "2020-01-28T22:17:30.823463Z", + "banned": false, + "online": false, + "name": "Dakota Fanning", + "image": "https://images-na.ssl-images-amazon.com/images/M/MV5BMjAwNjM3NjY5MF5BMl5BanBnXkFtZTcwMjM4NTYwOQ@@._V1_UY256_CR0,0,172,256_AL_.jpg" + }, + "role": "member", + "created_at": "2020-01-28T22:17:30.895523Z", + "updated_at": "2020-01-28T22:17:30.895523Z" + }, + { + "user": { + "id": "spring-voice-7", + "role": "user", + "created_at": "2020-01-28T22:17:30.834135Z", + "updated_at": "2020-01-28T22:17:31.186771Z", + "banned": false, + "online": false, + "image": "https://getstream.io/random_svg/?id=spring-voice-7\u0026name=Spring+voice", + "name": "Spring voice" + }, + "role": "owner", + "created_at": "2020-01-28T22:17:30.895523Z", + "updated_at": "2020-01-28T22:17:30.895523Z" + } + ] + }, + { + "channel": { + "id": "still-union-5", + "type": "messaging", + "cid": "messaging:still-union-5", + "last_message_at": "2020-01-24T14:46:19.683016Z", + "created_at": "2020-01-24T14:46:18.808933Z", + "updated_at": "2020-01-24T14:46:18.808933Z", + "created_by": { + "id": "still-union-5", + "role": "user", + "created_at": "2020-01-24T14:46:18.776236Z", + "updated_at": "2020-01-24T14:46:32.065913Z", + "last_active": "2020-01-24T14:46:32.05853Z", + "banned": false, + "online": false, + "image": "https://getstream.io/random_svg/?id=still-union-5\u0026amp;name=Still+union", + "name": "Still union" + }, + "frozen": false, + "config": { + "created_at": "2020-01-29T12:59:14.291912835Z", + "updated_at": "2020-01-29T12:59:14.291912991Z", + "name": "messaging", + "typing_events": true, + "read_events": true, + "connect_events": true, + "search": true, + "reactions": true, + "replies": true, + "mutes": true, + "uploads": true, + "url_enrichment": true, + "message_retention": "infinite", + "max_message_length": 5000, + "automod": "disabled", + "automod_behavior": "flag", + "commands": [ + { + "name": "giphy", + "description": "Post a random gif to the channel", + "args": "[text]", + "set": "fun_set" + } + ] + } + }, + "messages": [ + { + "id": "f77e582d-c4b3-461c-89de-9612a3bee8b1", + "text": "Some posit the phylloid cycle to be less than slimmer.", + "html": "\u003cp\u003eSome posit the phylloid cycle to be less than slimmer.\u003c/p\u003e\n", + "type": "regular", + "user": { + "id": "still-union-5", + "role": "user", + "created_at": "2020-01-24T14:46:18.776236Z", + "updated_at": "2020-01-24T14:46:32.065913Z", + "last_active": "2020-01-24T14:46:32.05853Z", + "banned": false, + "online": false, + "image": "https://getstream.io/random_svg/?id=still-union-5\u0026amp;name=Still+union", + "name": "Still union" + }, + "attachments": [], + "latest_reactions": [ + { + "message_id": "f77e582d-c4b3-461c-89de-9612a3bee8b1", + "user_id": "still-union-5", + "user": { + "id": "still-union-5", + "role": "user", + "created_at": "2020-01-24T14:46:18.776236Z", + "updated_at": "2020-01-24T14:46:32.065913Z", + "last_active": "2020-01-24T14:46:32.05853Z", + "banned": false, + "online": false, + "image": "https://getstream.io/random_svg/?id=still-union-5\u0026amp;name=Still+union", + "name": "Still union" + }, + "type": "angry", + "score": 1, + "created_at": "2020-01-24T14:46:19.14806Z", + "updated_at": "2020-01-24T14:46:19.14806Z" + } + ], + "own_reactions": [], + "reaction_counts": { + "angry": 1 + }, + "reaction_scores": { + "angry": 1 + }, + "reply_count": 0, + "created_at": "2020-01-24T14:46:19.127738Z", + "updated_at": "2020-01-24T14:46:19.149795Z", + "mentioned_users": [] + }, + { + "id": "82e2fbe7-4367-49e3-b80f-fc66e31e5afb", + "text": "A smarty panda is a cactus of the mind.", + "html": "\u003cp\u003eA smarty panda is a cactus of the mind.\u003c/p\u003e\n", + "type": "regular", + "user": { + "id": "still-union-5", + "role": "user", + "created_at": "2020-01-24T14:46:18.776236Z", + "updated_at": "2020-01-24T14:46:32.065913Z", + "last_active": "2020-01-24T14:46:32.05853Z", + "banned": false, + "online": false, + "image": "https://getstream.io/random_svg/?id=still-union-5\u0026amp;name=Still+union", + "name": "Still union" + }, + "attachments": [], + "latest_reactions": [], + "own_reactions": [], + "reaction_counts": {}, + "reaction_scores": {}, + "reply_count": 0, + "created_at": "2020-01-24T14:46:19.165153Z", + "updated_at": "2020-01-24T14:46:19.165154Z", + "mentioned_users": [] + }, + { + "id": "5a5ec35e-c925-4244-9d4c-098b32dd7fce", + "text": "https://unsplash.com/photos/4v7ubW7jz1Q", + "html": "\u003cp\u003e\u003ca href=\"https://unsplash.com/photos/4v7ubW7jz1Q\" rel=\"nofollow\"\u003ehttps://unsplash.com/photos/4v7ubW7jz1Q\u003c/a\u003e\u003c/p\u003e\n", + "type": "regular", + "user": { + "id": "still-union-5", + "role": "user", + "created_at": "2020-01-24T14:46:18.776236Z", + "updated_at": "2020-01-24T14:46:32.065913Z", + "last_active": "2020-01-24T14:46:32.05853Z", + "banned": false, + "online": false, + "image": "https://getstream.io/random_svg/?id=still-union-5\u0026amp;name=Still+union", + "name": "Still union" + }, + "attachments": [ + { + "type": "image", + "title": "Photo by Joel Filipe on Unsplash", + "title_link": "https://unsplash.com/photos/4v7ubW7jz1Q", + "text": "Download this photo by Joel Filipe on Unsplash", + "image_url": "https://images.unsplash.com/photo-1557389352-e721da78ad9f?ixlib=rb-1.2.1\u0026q=80\u0026fm=jpg\u0026crop=entropy\u0026cs=tinysrgb\u0026w=1080\u0026fit=max\u0026ixid=eyJhcHBfaWQiOjEyMDd9", + "thumb_url": "https://images.unsplash.com/photo-1557389352-e721da78ad9f?ixlib=rb-1.2.1\u0026q=80\u0026fm=jpg\u0026crop=entropy\u0026cs=tinysrgb\u0026w=1080\u0026fit=max\u0026ixid=eyJhcHBfaWQiOjEyMDd9", + "og_scrape_url": "https://unsplash.com/photos/4v7ubW7jz1Q" + } + ], + "latest_reactions": [], + "own_reactions": [], + "reaction_counts": {}, + "reaction_scores": {}, + "reply_count": 1, + "created_at": "2020-01-24T14:46:19.168615Z", + "updated_at": "2020-01-24T14:46:19.168615Z", + "mentioned_users": [] + }, + { + "id": "bf27a1a7-911f-4432-8fe4-1d77a7736ef1", + "text": "A volumed ease's eyelash comes with it the thought that the unwiped energy is a flute.", + "html": "\u003cp\u003eA volumed ease’s eyelash comes with it the thought that the unwiped energy is a flute.\u003c/p\u003e\n", + "type": "regular", + "user": { + "id": "still-union-5", + "role": "user", + "created_at": "2020-01-24T14:46:18.776236Z", + "updated_at": "2020-01-24T14:46:32.065913Z", + "last_active": "2020-01-24T14:46:32.05853Z", + "banned": false, + "online": false, + "name": "Still union", + "image": "https://getstream.io/random_svg/?id=still-union-5\u0026amp;name=Still+union" + }, + "attachments": [], + "latest_reactions": [], + "own_reactions": [], + "reaction_counts": {}, + "reaction_scores": {}, + "reply_count": 1, + "created_at": "2020-01-24T14:46:19.171548Z", + "updated_at": "2020-01-24T14:46:19.171548Z", + "mentioned_users": [] + }, + { + "id": "9cecc024-a5fc-469f-a3a7-69f8bbeda40b", + "text": "https://www.youtube.com/watch?v=sCtixpIWBto", + "html": "\u003cp\u003e\u003ca href=\"https://www.youtube.com/watch?v=sCtixpIWBto\" rel=\"nofollow\"\u003ehttps://www.youtube.com/watch?v=sCtixpIWBto\u003c/a\u003e\u003c/p\u003e\n", + "type": "regular", + "user": { + "id": "still-union-5", + "role": "user", + "created_at": "2020-01-24T14:46:18.776236Z", + "updated_at": "2020-01-24T14:46:32.065913Z", + "last_active": "2020-01-24T14:46:32.05853Z", + "banned": false, + "online": false, + "name": "Still union", + "image": "https://getstream.io/random_svg/?id=still-union-5\u0026amp;name=Still+union" + }, + "attachments": [ + { + "type": "video", + "author_name": "YouTube", + "title": "Rachmaninoff - Prelude in C Sharp Minor (Op. 3 No. 2)", + "title_link": "https://www.youtube.com/watch?v=sCtixpIWBto", + "text": "Rachmaninoff - Prelude in C Sharp Minor (Op. 3 No. 2) Click the 🔔bell to always be notified on new uploads! ♫ Listen on Spotify: http://spoti.fi/2LdpqK7 ♫ MI...", + "image_url": "https://i.ytimg.com/vi/sCtixpIWBto/maxresdefault.jpg", + "thumb_url": "https://i.ytimg.com/vi/sCtixpIWBto/maxresdefault.jpg", + "asset_url": "https://www.youtube.com/embed/sCtixpIWBto", + "og_scrape_url": "https://www.youtube.com/watch?v=sCtixpIWBto" + } + ], + "latest_reactions": [ + { + "message_id": "9cecc024-a5fc-469f-a3a7-69f8bbeda40b", + "user_id": "still-union-5", + "user": { + "id": "still-union-5", + "role": "user", + "created_at": "2020-01-24T14:46:18.776236Z", + "updated_at": "2020-01-24T14:46:32.065913Z", + "last_active": "2020-01-24T14:46:32.05853Z", + "banned": false, + "online": false, + "image": "https://getstream.io/random_svg/?id=still-union-5\u0026amp;name=Still+union", + "name": "Still union" + }, + "type": "like", + "score": 1, + "created_at": "2020-01-24T14:46:19.703554Z", + "updated_at": "2020-01-24T14:46:19.703554Z" + } + ], + "own_reactions": [], + "reaction_counts": { + "like": 1 + }, + "reaction_scores": { + "like": 1 + }, + "reply_count": 0, + "created_at": "2020-01-24T14:46:19.683016Z", + "updated_at": "2020-01-24T14:46:19.705034Z", + "mentioned_users": [] + } + ], + "watcher_count": 1, + "members": [] + }, + { + "channel": { + "id": "!members-9CAnYw3rnRNrqnSyxvA1rQyL6HLVTt1KUgAz1CeoEvo", + "type": "messaging", + "cid": "messaging:!members-9CAnYw3rnRNrqnSyxvA1rQyL6HLVTt1KUgAz1CeoEvo", + "last_message_at": "2020-01-24T14:46:19.168507Z", + "created_at": "2020-01-24T14:46:18.846673Z", + "updated_at": "2020-01-24T14:46:18.846673Z", + "created_by": { + "id": "still-union-5", + "role": "user", + "created_at": "2020-01-24T14:46:18.776236Z", + "updated_at": "2020-01-24T14:46:32.065913Z", + "last_active": "2020-01-24T14:46:32.05853Z", + "banned": false, + "online": false, + "image": "https://getstream.io/random_svg/?id=still-union-5\u0026amp;name=Still+union", + "name": "Still union" + }, + "frozen": false, + "member_count": 5, + "config": { + "created_at": "2020-01-29T12:59:14.291912835Z", + "updated_at": "2020-01-29T12:59:14.291912991Z", + "name": "messaging", + "typing_events": true, + "read_events": true, + "connect_events": true, + "search": true, + "reactions": true, + "replies": true, + "mutes": true, + "uploads": true, + "url_enrichment": true, + "message_retention": "infinite", + "max_message_length": 5000, + "automod": "disabled", + "automod_behavior": "flag", + "commands": [ + { + "name": "giphy", + "description": "Post a random gif to the channel", + "args": "[text]", + "set": "fun_set" + } + ] + }, + "image": "https://getstream.imgix.net/images/rn-chat-tutorial/caterpillar_01.png", + "name": "Family" + }, + "messages": [ + { + "id": "a5ee396a-34bf-42d9-8388-819e84d770e2", + "text": "https://giphy.com/gifs/the-lion-king-live-action-5zvN79uTGfLMOVfQaA", + "html": "\u003cp\u003e\u003ca href=\"https://giphy.com/gifs/the-lion-king-live-action-5zvN79uTGfLMOVfQaA\" rel=\"nofollow\"\u003ehttps://giphy.com/gifs/the-lion-king-live-action-5zvN79uTGfLMOVfQaA\u003c/a\u003e\u003c/p\u003e\n", + "type": "regular", + "user": { + "id": "7cdf7f97-c336-4263-9430-42a1f4d165c8", + "role": "user", + "created_at": "2020-01-24T14:46:18.764869Z", + "updated_at": "2020-01-24T14:46:19.007916Z", + "banned": false, + "online": false, + "image": "https://pbs.twimg.com/profile_images/669512187778498560/L7wQctBt.jpg", + "name": "Robin Papa" + }, + "attachments": [ + { + "type": "video", + "author_name": "GIPHY", + "title": "The Lion King Disney GIF - Find \u0026 Share on GIPHY", + "title_link": "https://media.giphy.com/media/5zvN79uTGfLMOVfQaA/giphy.gif", + "text": "Discover \u0026 share this Lion King Live Action GIF with everyone you know. GIPHY is how you search, share, discover, and create GIFs.", + "image_url": "https://media.giphy.com/media/5zvN79uTGfLMOVfQaA/giphy.gif", + "thumb_url": "https://media.giphy.com/media/5zvN79uTGfLMOVfQaA/giphy.gif", + "asset_url": "https://media.giphy.com/media/5zvN79uTGfLMOVfQaA/giphy.mp4", + "og_scrape_url": "https://giphy.com/gifs/the-lion-king-live-action-5zvN79uTGfLMOVfQaA" + } + ], + "latest_reactions": [], + "own_reactions": [], + "reaction_counts": {}, + "reaction_scores": {}, + "reply_count": 0, + "created_at": "2020-01-24T14:46:19.014504Z", + "updated_at": "2020-01-24T14:46:19.014505Z", + "mentioned_users": [] + }, + { + "id": "31bdba04-b86f-48d6-91d9-972bb50e3ffe", + "text": "A chiefly care is a pressure of the mind.", + "html": "\u003cp\u003eA chiefly care is a pressure of the mind.\u003c/p\u003e\n", + "type": "regular", + "user": { + "id": "5a46018e-252b-4598-a7e8-40949c3be4d6", + "role": "user", + "created_at": "2020-01-24T14:46:18.783718Z", + "updated_at": "2020-01-24T14:46:19.096044Z", + "banned": false, + "online": false, + "image": "https://randomuser.me/api/portraits/women/44.jpg", + "name": "June Cha" + }, + "attachments": [], + "latest_reactions": [], + "own_reactions": [], + "reaction_counts": {}, + "reaction_scores": {}, + "reply_count": 1, + "created_at": "2020-01-24T14:46:19.050641Z", + "updated_at": "2020-01-24T14:46:19.050641Z", + "mentioned_users": [] + }, + { + "id": "bc08ad2e-4da0-4d9f-b349-4e9b85d45899", + "text": "What we don't know for sure is whether or not a step-daughter of the bear is assumed to be a farci hourglass.", + "html": "\u003cp\u003eWhat we don’t know for sure is whether or not a step-daughter of the bear is assumed to be a farci hourglass.\u003c/p\u003e\n", + "type": "regular", + "user": { + "id": "694bc286-80d5-4be5-81f8-068028d561e4", + "role": "user", + "created_at": "2020-01-24T14:46:18.760346Z", + "updated_at": "2020-01-24T14:46:19.132067Z", + "banned": false, + "online": false, + "name": "Adelle Charles", + "image": "https://pbs.twimg.com/profile_images/1108790938640531456/Bl2JvdG_.png" + }, + "attachments": [], + "latest_reactions": [ + { + "message_id": "bc08ad2e-4da0-4d9f-b349-4e9b85d45899", + "user_id": "694bc286-80d5-4be5-81f8-068028d561e4", + "user": { + "id": "694bc286-80d5-4be5-81f8-068028d561e4", + "role": "user", + "created_at": "2020-01-24T14:46:18.760346Z", + "updated_at": "2020-01-24T14:46:19.132067Z", + "banned": false, + "online": false, + "image": "https://pbs.twimg.com/profile_images/1108790938640531456/Bl2JvdG_.png", + "name": "Adelle Charles" + }, + "type": "angry", + "score": 1, + "created_at": "2020-01-24T14:46:19.08354Z", + "updated_at": "2020-01-24T14:46:19.08354Z" + } + ], + "own_reactions": [], + "reaction_counts": { + "angry": 1 + }, + "reaction_scores": { + "angry": 1 + }, + "reply_count": 1, + "created_at": "2020-01-24T14:46:19.055407Z", + "updated_at": "2020-01-24T14:46:19.08681Z", + "mentioned_users": [] + }, + { + "id": "9b0063ad-cd62-4dc7-ba21-3feee5853122", + "text": "A height of the parallelogram is assumed to be a sunfast cone.", + "html": "\u003cp\u003eA height of the parallelogram is assumed to be a sunfast cone.\u003c/p\u003e\n", + "type": "regular", + "user": { + "id": "still-union-5", + "role": "user", + "created_at": "2020-01-24T14:46:18.776236Z", + "updated_at": "2020-01-24T14:46:32.065913Z", + "last_active": "2020-01-24T14:46:32.05853Z", + "banned": false, + "online": false, + "image": "https://getstream.io/random_svg/?id=still-union-5\u0026amp;name=Still+union", + "name": "Still union" + }, + "attachments": [], + "latest_reactions": [ + { + "message_id": "9b0063ad-cd62-4dc7-ba21-3feee5853122", + "user_id": "still-union-5", + "user": { + "id": "still-union-5", + "role": "user", + "created_at": "2020-01-24T14:46:18.776236Z", + "updated_at": "2020-01-24T14:46:32.065913Z", + "last_active": "2020-01-24T14:46:32.05853Z", + "banned": false, + "online": false, + "image": "https://getstream.io/random_svg/?id=still-union-5\u0026amp;name=Still+union", + "name": "Still union" + }, + "type": "love", + "score": 1, + "created_at": "2020-01-24T14:46:19.094595Z", + "updated_at": "2020-01-24T14:46:19.094595Z" + } + ], + "own_reactions": [], + "reaction_counts": { + "love": 1 + }, + "reaction_scores": { + "love": 1 + }, + "reply_count": 0, + "created_at": "2020-01-24T14:46:19.068177Z", + "updated_at": "2020-01-24T14:46:19.096185Z", + "mentioned_users": [] + }, + { + "id": "4f11cd19-66cc-4fc4-b153-9eced2518e21", + "text": "Few can name a topfull mother that isn't a breezeless damage.", + "html": "\u003cp\u003eFew can name a topfull mother that isn’t a breezeless damage.\u003c/p\u003e\n", + "type": "regular", + "user": { + "id": "694bc286-80d5-4be5-81f8-068028d561e4", + "role": "user", + "created_at": "2020-01-24T14:46:18.760346Z", + "updated_at": "2020-01-24T14:46:19.132067Z", + "banned": false, + "online": false, + "image": "https://pbs.twimg.com/profile_images/1108790938640531456/Bl2JvdG_.png", + "name": "Adelle Charles" + }, + "attachments": [], + "latest_reactions": [ + { + "message_id": "4f11cd19-66cc-4fc4-b153-9eced2518e21", + "user_id": "still-union-5", + "user": { + "id": "still-union-5", + "role": "user", + "created_at": "2020-01-24T14:46:18.776236Z", + "updated_at": "2020-01-24T14:46:32.065913Z", + "last_active": "2020-01-24T14:46:32.05853Z", + "banned": false, + "online": false, + "image": "https://getstream.io/random_svg/?id=still-union-5\u0026amp;name=Still+union", + "name": "Still union" + }, + "type": "haha", + "score": 1, + "created_at": "2020-01-24T14:46:19.110667Z", + "updated_at": "2020-01-24T14:46:19.110667Z" + } + ], + "own_reactions": [], + "reaction_counts": { + "haha": 1 + }, + "reaction_scores": { + "haha": 1 + }, + "reply_count": 1, + "created_at": "2020-01-24T14:46:19.077713Z", + "updated_at": "2020-01-24T14:46:19.113185Z", + "mentioned_users": [] + } + ], + "watcher_count": 1, + "read": [ + { + "user": { + "id": "0f345a0c-3f35-4e2f-805e-77f53f8332cd", + "role": "user", + "created_at": "2020-01-24T14:46:18.779973Z", + "updated_at": "2020-01-24T14:46:19.157321Z", + "banned": false, + "online": false, + "image": "https://images-na.ssl-images-amazon.com/images/M/MV5BMDc2M2NkMTctNmQ0MS00MjQxLWFkMGItNGY1Y2Y3NzYzZjg1XkEyXkFqcGdeQXVyNjAzMTgxNjY@._V1_UY256_CR74,0,172,256_AL_.jpg", + "name": "Zoe McLellan" + }, + "last_read": "2020-01-24T14:46:18.863312384Z" + }, + { + "user": { + "id": "5a46018e-252b-4598-a7e8-40949c3be4d6", + "role": "user", + "created_at": "2020-01-24T14:46:18.783718Z", + "updated_at": "2020-01-24T14:46:19.096044Z", + "banned": false, + "online": false, + "image": "https://randomuser.me/api/portraits/women/44.jpg", + "name": "June Cha" + }, + "last_read": "2020-01-24T14:46:18.8644352Z" + }, + { + "user": { + "id": "7cdf7f97-c336-4263-9430-42a1f4d165c8", + "role": "user", + "created_at": "2020-01-24T14:46:18.764869Z", + "updated_at": "2020-01-24T14:46:19.007916Z", + "banned": false, + "online": false, + "image": "https://pbs.twimg.com/profile_images/669512187778498560/L7wQctBt.jpg", + "name": "Robin Papa" + }, + "last_read": "2020-01-24T14:46:18.866511104Z" + }, + { + "user": { + "id": "still-union-5", + "role": "user", + "created_at": "2020-01-24T14:46:18.776236Z", + "updated_at": "2020-01-24T14:46:32.065913Z", + "last_active": "2020-01-24T14:46:32.05853Z", + "banned": false, + "online": false, + "image": "https://getstream.io/random_svg/?id=still-union-5\u0026amp;name=Still+union", + "name": "Still union" + }, + "last_read": "2020-01-24T14:46:18.867566336Z" + }, + { + "user": { + "id": "694bc286-80d5-4be5-81f8-068028d561e4", + "role": "user", + "created_at": "2020-01-24T14:46:18.760346Z", + "updated_at": "2020-01-24T14:46:19.132067Z", + "banned": false, + "online": false, + "image": "https://pbs.twimg.com/profile_images/1108790938640531456/Bl2JvdG_.png", + "name": "Adelle Charles" + }, + "last_read": "2020-01-24T14:46:18.865476096Z" + } + ], + "members": [ + { + "user": { + "id": "0f345a0c-3f35-4e2f-805e-77f53f8332cd", + "role": "user", + "created_at": "2020-01-24T14:46:18.779973Z", + "updated_at": "2020-01-24T14:46:19.157321Z", + "banned": false, + "online": false, + "image": "https://images-na.ssl-images-amazon.com/images/M/MV5BMDc2M2NkMTctNmQ0MS00MjQxLWFkMGItNGY1Y2Y3NzYzZjg1XkEyXkFqcGdeQXVyNjAzMTgxNjY@._V1_UY256_CR74,0,172,256_AL_.jpg", + "name": "Zoe McLellan" + }, + "role": "member", + "created_at": "2020-01-24T14:46:18.850178Z", + "updated_at": "2020-01-24T14:46:18.850178Z" + }, + { + "user": { + "id": "5a46018e-252b-4598-a7e8-40949c3be4d6", + "role": "user", + "created_at": "2020-01-24T14:46:18.783718Z", + "updated_at": "2020-01-24T14:46:19.096044Z", + "banned": false, + "online": false, + "name": "June Cha", + "image": "https://randomuser.me/api/portraits/women/44.jpg" + }, + "role": "member", + "created_at": "2020-01-24T14:46:18.850179Z", + "updated_at": "2020-01-24T14:46:18.850179Z" + }, + { + "user": { + "id": "694bc286-80d5-4be5-81f8-068028d561e4", + "role": "user", + "created_at": "2020-01-24T14:46:18.760346Z", + "updated_at": "2020-01-24T14:46:19.132067Z", + "banned": false, + "online": false, + "image": "https://pbs.twimg.com/profile_images/1108790938640531456/Bl2JvdG_.png", + "name": "Adelle Charles" + }, + "role": "member", + "created_at": "2020-01-24T14:46:18.850179Z", + "updated_at": "2020-01-24T14:46:18.850179Z" + }, + { + "user": { + "id": "7cdf7f97-c336-4263-9430-42a1f4d165c8", + "role": "user", + "created_at": "2020-01-24T14:46:18.764869Z", + "updated_at": "2020-01-24T14:46:19.007916Z", + "banned": false, + "online": false, + "image": "https://pbs.twimg.com/profile_images/669512187778498560/L7wQctBt.jpg", + "name": "Robin Papa" + }, + "role": "member", + "created_at": "2020-01-24T14:46:18.850179Z", + "updated_at": "2020-01-24T14:46:18.850179Z" + }, + { + "user": { + "id": "still-union-5", + "role": "user", + "created_at": "2020-01-24T14:46:18.776236Z", + "updated_at": "2020-01-24T14:46:32.065913Z", + "last_active": "2020-01-24T14:46:32.05853Z", + "banned": false, + "online": false, + "image": "https://getstream.io/random_svg/?id=still-union-5\u0026amp;name=Still+union", + "name": "Still union" + }, + "role": "owner", + "created_at": "2020-01-24T14:46:18.85018Z", + "updated_at": "2020-01-24T14:46:18.85018Z" + } + ] + }, + { + "channel": { + "id": "!members-Hc19Pf6huW0QTLRkQscRvline00uxqpj2OAYIcxTPFw", + "type": "messaging", + "cid": "messaging:!members-Hc19Pf6huW0QTLRkQscRvline00uxqpj2OAYIcxTPFw", + "last_message_at": "2020-01-24T14:46:19.16305Z", + "created_at": "2020-01-24T14:46:18.953227Z", + "updated_at": "2020-01-24T14:46:18.953227Z", + "created_by": { + "id": "still-union-5", + "role": "user", + "created_at": "2020-01-24T14:46:18.776236Z", + "updated_at": "2020-01-24T14:46:32.065913Z", + "last_active": "2020-01-24T14:46:32.05853Z", + "banned": false, + "online": false, + "image": "https://getstream.io/random_svg/?id=still-union-5\u0026amp;name=Still+union", + "name": "Still union" + }, + "frozen": false, + "member_count": 2, + "config": { + "created_at": "2020-01-29T12:59:14.291912835Z", + "updated_at": "2020-01-29T12:59:14.291912991Z", + "name": "messaging", + "typing_events": true, + "read_events": true, + "connect_events": true, + "search": true, + "reactions": true, + "replies": true, + "mutes": true, + "uploads": true, + "url_enrichment": true, + "message_retention": "infinite", + "max_message_length": 5000, + "automod": "disabled", + "automod_behavior": "flag", + "commands": [ + { + "name": "giphy", + "description": "Post a random gif to the channel", + "args": "[text]", + "set": "fun_set" + } + ] + }, + "image": "https://randomuser.me/api/portraits/women/8.jpg", + "name": "Jennifer Fritz" + }, + "messages": [ + { + "id": "17b0dc4a-78b3-4e08-860e-11ad2d8ac89d", + "text": "Extending this logic, the witted tree reveals itself as a glummest danger to those who look.", + "html": "\u003cp\u003eExtending this logic, the witted tree reveals itself as a glummest danger to those who look.\u003c/p\u003e\n", + "type": "regular", + "user": { + "id": "still-union-5", + "role": "user", + "created_at": "2020-01-24T14:46:18.776236Z", + "updated_at": "2020-01-24T14:46:32.065913Z", + "last_active": "2020-01-24T14:46:32.05853Z", + "banned": false, + "online": false, + "image": "https://getstream.io/random_svg/?id=still-union-5\u0026amp;name=Still+union", + "name": "Still union" + }, + "attachments": [], + "latest_reactions": [ + { + "message_id": "17b0dc4a-78b3-4e08-860e-11ad2d8ac89d", + "user_id": "05ab6a02-9160-47b7-87d9-c6888fa85f83", + "user": { + "id": "05ab6a02-9160-47b7-87d9-c6888fa85f83", + "role": "user", + "created_at": "2020-01-24T14:46:18.772459Z", + "updated_at": "2020-01-24T14:46:19.151717Z", + "banned": false, + "online": false, + "image": "https://randomuser.me/api/portraits/women/8.jpg", + "name": "Jennifer Fritz" + }, + "type": "like", + "score": 1, + "created_at": "2020-01-24T14:46:19.08279Z", + "updated_at": "2020-01-24T14:46:19.08279Z" + } + ], + "own_reactions": [], + "reaction_counts": { + "like": 1 + }, + "reaction_scores": { + "like": 1 + }, + "reply_count": 0, + "created_at": "2020-01-24T14:46:19.051688Z", + "updated_at": "2020-01-24T14:46:19.085197Z", + "mentioned_users": [] + }, + { + "id": "ca22e5e3-5f2c-456e-8699-522cba94d177", + "text": "A cricoid melody without replaces is truly a cocktail of unripe badgers.", + "html": "\u003cp\u003eA cricoid melody without replaces is truly a cocktail of unripe badgers.\u003c/p\u003e\n", + "type": "regular", + "user": { + "id": "05ab6a02-9160-47b7-87d9-c6888fa85f83", + "role": "user", + "created_at": "2020-01-24T14:46:18.772459Z", + "updated_at": "2020-01-24T14:46:19.151717Z", + "banned": false, + "online": false, + "image": "https://randomuser.me/api/portraits/women/8.jpg", + "name": "Jennifer Fritz" + }, + "attachments": [], + "latest_reactions": [ + { + "message_id": "ca22e5e3-5f2c-456e-8699-522cba94d177", + "user_id": "05ab6a02-9160-47b7-87d9-c6888fa85f83", + "user": { + "id": "05ab6a02-9160-47b7-87d9-c6888fa85f83", + "role": "user", + "created_at": "2020-01-24T14:46:18.772459Z", + "updated_at": "2020-01-24T14:46:19.151717Z", + "banned": false, + "online": false, + "name": "Jennifer Fritz", + "image": "https://randomuser.me/api/portraits/women/8.jpg" + }, + "type": "like", + "score": 1, + "created_at": "2020-01-24T14:46:19.133825Z", + "updated_at": "2020-01-24T14:46:19.133825Z" + } + ], + "own_reactions": [], + "reaction_counts": { + "like": 1 + }, + "reaction_scores": { + "like": 1 + }, + "reply_count": 0, + "created_at": "2020-01-24T14:46:19.10105Z", + "updated_at": "2020-01-24T14:46:19.135877Z", + "mentioned_users": [] + }, + { + "id": "494916be-b66b-48b0-a1c5-bb2cab32eb7a", + "text": "The first towy harmony is, in its own way, a voyage.", + "html": "\u003cp\u003eThe first towy harmony is, in its own way, a voyage.\u003c/p\u003e\n", + "type": "regular", + "user": { + "id": "still-union-5", + "role": "user", + "created_at": "2020-01-24T14:46:18.776236Z", + "updated_at": "2020-01-24T14:46:32.065913Z", + "last_active": "2020-01-24T14:46:32.05853Z", + "banned": false, + "online": false, + "image": "https://getstream.io/random_svg/?id=still-union-5\u0026amp;name=Still+union", + "name": "Still union" + }, + "attachments": [], + "latest_reactions": [], + "own_reactions": [], + "reaction_counts": {}, + "reaction_scores": {}, + "reply_count": 1, + "created_at": "2020-01-24T14:46:19.115607Z", + "updated_at": "2020-01-24T14:46:19.115608Z", + "mentioned_users": [] + }, + { + "id": "633c149b-2b1d-461a-8dfe-0f941acc34d4", + "text": "A bicycle can hardly be considered a yearning jar without also being an alley.", + "html": "\u003cp\u003eA bicycle can hardly be considered a yearning jar without also being an alley.\u003c/p\u003e\n", + "type": "regular", + "user": { + "id": "05ab6a02-9160-47b7-87d9-c6888fa85f83", + "role": "user", + "created_at": "2020-01-24T14:46:18.772459Z", + "updated_at": "2020-01-24T14:46:19.151717Z", + "banned": false, + "online": false, + "image": "https://randomuser.me/api/portraits/women/8.jpg", + "name": "Jennifer Fritz" + }, + "attachments": [], + "latest_reactions": [], + "own_reactions": [], + "reaction_counts": {}, + "reaction_scores": {}, + "reply_count": 0, + "created_at": "2020-01-24T14:46:19.135028Z", + "updated_at": "2020-01-24T14:46:19.135028Z", + "mentioned_users": [] + }, + { + "id": "2378fa62-8a5f-4dd3-8ea0-e0276e682c8a", + "text": "https://unsplash.com/photos/4v7ubW7jz1Q", + "html": "\u003cp\u003e\u003ca href=\"https://unsplash.com/photos/4v7ubW7jz1Q\" rel=\"nofollow\"\u003ehttps://unsplash.com/photos/4v7ubW7jz1Q\u003c/a\u003e\u003c/p\u003e\n", + "type": "regular", + "user": { + "id": "05ab6a02-9160-47b7-87d9-c6888fa85f83", + "role": "user", + "created_at": "2020-01-24T14:46:18.772459Z", + "updated_at": "2020-01-24T14:46:19.151717Z", + "banned": false, + "online": false, + "image": "https://randomuser.me/api/portraits/women/8.jpg", + "name": "Jennifer Fritz" + }, + "attachments": [ + { + "type": "image", + "title": "Photo by Joel Filipe on Unsplash", + "title_link": "https://unsplash.com/photos/4v7ubW7jz1Q", + "text": "Download this photo by Joel Filipe on Unsplash", + "image_url": "https://images.unsplash.com/photo-1557389352-e721da78ad9f?ixlib=rb-1.2.1\u0026q=80\u0026fm=jpg\u0026crop=entropy\u0026cs=tinysrgb\u0026w=1080\u0026fit=max\u0026ixid=eyJhcHBfaWQiOjEyMDd9", + "thumb_url": "https://images.unsplash.com/photo-1557389352-e721da78ad9f?ixlib=rb-1.2.1\u0026q=80\u0026fm=jpg\u0026crop=entropy\u0026cs=tinysrgb\u0026w=1080\u0026fit=max\u0026ixid=eyJhcHBfaWQiOjEyMDd9", + "og_scrape_url": "https://unsplash.com/photos/4v7ubW7jz1Q" + } + ], + "latest_reactions": [], + "own_reactions": [], + "reaction_counts": {}, + "reaction_scores": {}, + "reply_count": 0, + "created_at": "2020-01-24T14:46:19.140074Z", + "updated_at": "2020-01-24T14:46:19.140075Z", + "mentioned_users": [] + } + ], + "watcher_count": 1, + "read": [ + { + "user": { + "id": "still-union-5", + "role": "user", + "created_at": "2020-01-24T14:46:18.776236Z", + "updated_at": "2020-01-24T14:46:32.065913Z", + "last_active": "2020-01-24T14:46:32.05853Z", + "banned": false, + "online": false, + "image": "https://getstream.io/random_svg/?id=still-union-5\u0026amp;name=Still+union", + "name": "Still union" + }, + "last_read": "2020-01-24T14:46:18.969139712Z" + }, + { + "user": { + "id": "05ab6a02-9160-47b7-87d9-c6888fa85f83", + "role": "user", + "created_at": "2020-01-24T14:46:18.772459Z", + "updated_at": "2020-01-24T14:46:19.151717Z", + "banned": false, + "online": false, + "image": "https://randomuser.me/api/portraits/women/8.jpg", + "name": "Jennifer Fritz" + }, + "last_read": "2020-01-24T14:46:18.96800512Z" + } + ], + "members": [ + { + "user": { + "id": "05ab6a02-9160-47b7-87d9-c6888fa85f83", + "role": "user", + "created_at": "2020-01-24T14:46:18.772459Z", + "updated_at": "2020-01-24T14:46:19.151717Z", + "banned": false, + "online": false, + "image": "https://randomuser.me/api/portraits/women/8.jpg", + "name": "Jennifer Fritz" + }, + "role": "member", + "created_at": "2020-01-24T14:46:18.956793Z", + "updated_at": "2020-01-24T14:46:18.956793Z" + }, + { + "user": { + "id": "still-union-5", + "role": "user", + "created_at": "2020-01-24T14:46:18.776236Z", + "updated_at": "2020-01-24T14:46:32.065913Z", + "last_active": "2020-01-24T14:46:32.05853Z", + "banned": false, + "online": false, + "image": "https://getstream.io/random_svg/?id=still-union-5\u0026amp;name=Still+union", + "name": "Still union" + }, + "role": "owner", + "created_at": "2020-01-24T14:46:18.956793Z", + "updated_at": "2020-01-24T14:46:18.956793Z" + } + ] + }, + { + "channel": { + "id": "!members-og1pgcoaqCSdh6KyIXz4qKB_d22pnWth6Yfbovd8yP0", + "type": "messaging", + "cid": "messaging:!members-og1pgcoaqCSdh6KyIXz4qKB_d22pnWth6Yfbovd8yP0", + "last_message_at": "2020-01-24T14:46:19.124398Z", + "created_at": "2020-01-24T14:46:18.902415Z", + "updated_at": "2020-01-24T14:46:18.902415Z", + "created_by": { + "id": "still-union-5", + "role": "user", + "created_at": "2020-01-24T14:46:18.776236Z", + "updated_at": "2020-01-24T14:46:32.065913Z", + "last_active": "2020-01-24T14:46:32.05853Z", + "banned": false, + "online": false, + "image": "https://getstream.io/random_svg/?id=still-union-5\u0026amp;name=Still+union", + "name": "Still union" + }, + "frozen": false, + "member_count": 2, + "config": { + "created_at": "2020-01-29T12:59:14.291912835Z", + "updated_at": "2020-01-29T12:59:14.291912991Z", + "name": "messaging", + "typing_events": true, + "read_events": true, + "connect_events": true, + "search": true, + "reactions": true, + "replies": true, + "mutes": true, + "uploads": true, + "url_enrichment": true, + "message_retention": "infinite", + "max_message_length": 5000, + "automod": "disabled", + "automod_behavior": "flag", + "commands": [ + { + "name": "giphy", + "description": "Post a random gif to the channel", + "args": "[text]", + "set": "fun_set" + } + ] + }, + "name": "Ana De Armas", + "image": "https://images-na.ssl-images-amazon.com/images/M/MV5BMjA3NjYzMzE1MV5BMl5BanBnXkFtZTgwNTA4NDY4OTE@._V1_UX172_CR0,0,172,256_AL_.jpg" + }, + "messages": [ + { + "id": "1aec347f-c1c4-4d83-ab42-76a12d3d3da2", + "text": "Before aftershaves, snowflakes were only deer.", + "html": "\u003cp\u003eBefore aftershaves, snowflakes were only deer.\u003c/p\u003e\n", + "type": "regular", + "user": { + "id": "still-union-5", + "role": "user", + "created_at": "2020-01-24T14:46:18.776236Z", + "updated_at": "2020-01-24T14:46:32.065913Z", + "last_active": "2020-01-24T14:46:32.05853Z", + "banned": false, + "online": false, + "image": "https://getstream.io/random_svg/?id=still-union-5\u0026amp;name=Still+union", + "name": "Still union" + }, + "attachments": [], + "latest_reactions": [], + "own_reactions": [], + "reaction_counts": {}, + "reaction_scores": {}, + "reply_count": 0, + "created_at": "2020-01-24T14:46:19.057578Z", + "updated_at": "2020-01-24T14:46:19.057578Z", + "mentioned_users": [] + }, + { + "id": "1ec1473d-405d-4a3c-b771-ab09fcbe071f", + "text": "https://giphy.com/gifs/movie-trailer-gemini-man-QsU9X0AxxfSAwsaz7n", + "html": "\u003cp\u003e\u003ca href=\"https://giphy.com/gifs/movie-trailer-gemini-man-QsU9X0AxxfSAwsaz7n\" rel=\"nofollow\"\u003ehttps://giphy.com/gifs/movie-trailer-gemini-man-QsU9X0AxxfSAwsaz7n\u003c/a\u003e\u003c/p\u003e\n", + "type": "regular", + "user": { + "id": "still-union-5", + "role": "user", + "created_at": "2020-01-24T14:46:18.776236Z", + "updated_at": "2020-01-24T14:46:32.065913Z", + "last_active": "2020-01-24T14:46:32.05853Z", + "banned": false, + "online": false, + "image": "https://getstream.io/random_svg/?id=still-union-5\u0026amp;name=Still+union", + "name": "Still union" + }, + "attachments": [ + { + "type": "video", + "author_name": "GIPHY", + "title": "Gemini Man Trailer GIF - Find \u0026 Share on GIPHY", + "title_link": "https://media.giphy.com/media/QsU9X0AxxfSAwsaz7n/giphy.gif", + "text": "Discover \u0026 share this Gemini Man GIF with everyone you know. GIPHY is how you search, share, discover, and create GIFs.", + "image_url": "https://media.giphy.com/media/QsU9X0AxxfSAwsaz7n/giphy.gif", + "thumb_url": "https://media.giphy.com/media/QsU9X0AxxfSAwsaz7n/giphy.gif", + "asset_url": "https://media.giphy.com/media/QsU9X0AxxfSAwsaz7n/giphy.mp4", + "og_scrape_url": "https://giphy.com/gifs/movie-trailer-gemini-man-QsU9X0AxxfSAwsaz7n" + } + ], + "latest_reactions": [], + "own_reactions": [], + "reaction_counts": {}, + "reaction_scores": {}, + "reply_count": 0, + "created_at": "2020-01-24T14:46:19.076425Z", + "updated_at": "2020-01-24T14:46:19.076425Z", + "mentioned_users": [] + }, + { + "id": "3c6b5f22-da06-470e-bb7f-499fa7466de0", + "text": "Their chord was, in this moment, a slipshod parenthesis.", + "html": "\u003cp\u003eTheir chord was, in this moment, a slipshod parenthesis.\u003c/p\u003e\n", + "type": "regular", + "user": { + "id": "db375ac9-6a3f-4d9c-a5ea-4cd6c169fd09", + "role": "user", + "created_at": "2020-01-24T14:46:18.768629Z", + "updated_at": "2020-01-24T14:46:19.076467Z", + "banned": false, + "online": false, + "image": "https://images-na.ssl-images-amazon.com/images/M/MV5BMjA3NjYzMzE1MV5BMl5BanBnXkFtZTgwNTA4NDY4OTE@._V1_UX172_CR0,0,172,256_AL_.jpg", + "name": "Ana De Armas" + }, + "attachments": [], + "latest_reactions": [ + { + "message_id": "3c6b5f22-da06-470e-bb7f-499fa7466de0", + "user_id": "db375ac9-6a3f-4d9c-a5ea-4cd6c169fd09", + "user": { + "id": "db375ac9-6a3f-4d9c-a5ea-4cd6c169fd09", + "role": "user", + "created_at": "2020-01-24T14:46:18.768629Z", + "updated_at": "2020-01-24T14:46:19.076467Z", + "banned": false, + "online": false, + "image": "https://images-na.ssl-images-amazon.com/images/M/MV5BMjA3NjYzMzE1MV5BMl5BanBnXkFtZTgwNTA4NDY4OTE@._V1_UX172_CR0,0,172,256_AL_.jpg", + "name": "Ana De Armas" + }, + "type": "like", + "score": 1, + "created_at": "2020-01-24T14:46:19.118307Z", + "updated_at": "2020-01-24T14:46:19.118307Z" + } + ], + "own_reactions": [], + "reaction_counts": { + "like": 1 + }, + "reaction_scores": { + "like": 1 + }, + "reply_count": 0, + "created_at": "2020-01-24T14:46:19.078556Z", + "updated_at": "2020-01-24T14:46:19.120491Z", + "mentioned_users": [] + }, + { + "id": "86eb957d-54fd-4ed9-8e80-1bb3212e57ea", + "text": "However, the porcine puffin reveals itself as an uncaught mirror to those who look.", + "html": "\u003cp\u003eHowever, the porcine puffin reveals itself as an uncaught mirror to those who look.\u003c/p\u003e\n", + "type": "regular", + "user": { + "id": "still-union-5", + "role": "user", + "created_at": "2020-01-24T14:46:18.776236Z", + "updated_at": "2020-01-24T14:46:32.065913Z", + "last_active": "2020-01-24T14:46:32.05853Z", + "banned": false, + "online": false, + "image": "https://getstream.io/random_svg/?id=still-union-5\u0026amp;name=Still+union", + "name": "Still union" + }, + "attachments": [], + "latest_reactions": [], + "own_reactions": [], + "reaction_counts": {}, + "reaction_scores": {}, + "reply_count": 1, + "created_at": "2020-01-24T14:46:19.078749Z", + "updated_at": "2020-01-24T14:46:19.07875Z", + "mentioned_users": [] + }, + { + "id": "179eb482-b005-4b34-965c-22b1dbb60a8e", + "text": "A parklike screw without ants is truly a fly of hooly rings.", + "html": "\u003cp\u003eA parklike screw without ants is truly a fly of hooly rings.\u003c/p\u003e\n", + "type": "regular", + "user": { + "id": "db375ac9-6a3f-4d9c-a5ea-4cd6c169fd09", + "role": "user", + "created_at": "2020-01-24T14:46:18.768629Z", + "updated_at": "2020-01-24T14:46:19.076467Z", + "banned": false, + "online": false, + "name": "Ana De Armas", + "image": "https://images-na.ssl-images-amazon.com/images/M/MV5BMjA3NjYzMzE1MV5BMl5BanBnXkFtZTgwNTA4NDY4OTE@._V1_UX172_CR0,0,172,256_AL_.jpg" + }, + "attachments": [], + "latest_reactions": [], + "own_reactions": [], + "reaction_counts": {}, + "reaction_scores": {}, + "reply_count": 0, + "created_at": "2020-01-24T14:46:19.080192Z", + "updated_at": "2020-01-24T14:46:19.080192Z", + "mentioned_users": [] + } + ], + "watcher_count": 1, + "read": [ + { + "user": { + "id": "still-union-5", + "role": "user", + "created_at": "2020-01-24T14:46:18.776236Z", + "updated_at": "2020-01-24T14:46:32.065913Z", + "last_active": "2020-01-24T14:46:32.05853Z", + "banned": false, + "online": false, + "image": "https://getstream.io/random_svg/?id=still-union-5\u0026amp;name=Still+union", + "name": "Still union" + }, + "last_read": "2020-01-24T14:46:18.92038528Z" + }, + { + "user": { + "id": "db375ac9-6a3f-4d9c-a5ea-4cd6c169fd09", + "role": "user", + "created_at": "2020-01-24T14:46:18.768629Z", + "updated_at": "2020-01-24T14:46:19.076467Z", + "banned": false, + "online": false, + "image": "https://images-na.ssl-images-amazon.com/images/M/MV5BMjA3NjYzMzE1MV5BMl5BanBnXkFtZTgwNTA4NDY4OTE@._V1_UX172_CR0,0,172,256_AL_.jpg", + "name": "Ana De Armas" + }, + "last_read": "2020-01-24T14:46:18.919357952Z" + } + ], + "members": [ + { + "user": { + "id": "db375ac9-6a3f-4d9c-a5ea-4cd6c169fd09", + "role": "user", + "created_at": "2020-01-24T14:46:18.768629Z", + "updated_at": "2020-01-24T14:46:19.076467Z", + "banned": false, + "online": false, + "image": "https://images-na.ssl-images-amazon.com/images/M/MV5BMjA3NjYzMzE1MV5BMl5BanBnXkFtZTgwNTA4NDY4OTE@._V1_UX172_CR0,0,172,256_AL_.jpg", + "name": "Ana De Armas" + }, + "role": "member", + "created_at": "2020-01-24T14:46:18.905968Z", + "updated_at": "2020-01-24T14:46:18.905968Z" + }, + { + "user": { + "id": "still-union-5", + "role": "user", + "created_at": "2020-01-24T14:46:18.776236Z", + "updated_at": "2020-01-24T14:46:32.065913Z", + "last_active": "2020-01-24T14:46:32.05853Z", + "banned": false, + "online": false, + "image": "https://getstream.io/random_svg/?id=still-union-5\u0026amp;name=Still+union", + "name": "Still union" + }, + "role": "owner", + "created_at": "2020-01-24T14:46:18.905968Z", + "updated_at": "2020-01-24T14:46:18.905968Z" + } + ] + }, + { + "channel": { + "id": "holy-sun-6", + "type": "messaging", + "cid": "messaging:holy-sun-6", + "last_message_at": "2020-01-23T00:52:40.316069Z", + "created_at": "2020-01-23T00:52:39.457615Z", + "updated_at": "2020-01-23T00:52:39.457615Z", + "created_by": { + "id": "holy-sun-6", + "role": "user", + "created_at": "2020-01-23T00:52:39.412193Z", + "updated_at": "2020-01-23T00:52:40.211607Z", + "banned": false, + "online": false, + "name": "Holy sun", + "image": "https://getstream.io/random_svg/?id=holy-sun-6\u0026name=Holy+sun" + }, + "frozen": false, + "config": { + "created_at": "2020-01-29T12:59:14.291912835Z", + "updated_at": "2020-01-29T12:59:14.291912991Z", + "name": "messaging", + "typing_events": true, + "read_events": true, + "connect_events": true, + "search": true, + "reactions": true, + "replies": true, + "mutes": true, + "uploads": true, + "url_enrichment": true, + "message_retention": "infinite", + "max_message_length": 5000, + "automod": "disabled", + "automod_behavior": "flag", + "commands": [ + { + "name": "giphy", + "description": "Post a random gif to the channel", + "args": "[text]", + "set": "fun_set" + } + ] + } + }, + "messages": [ + { + "id": "d0843e2b-2dd8-404e-a4a4-3730287d144b", + "text": "A robert of the august is assumed to be an accurst fortnight.", + "html": "\u003cp\u003eA robert of the august is assumed to be an accurst fortnight.\u003c/p\u003e\n", + "type": "regular", + "user": { + "id": "holy-sun-6", + "role": "user", + "created_at": "2020-01-23T00:52:39.412193Z", + "updated_at": "2020-01-23T00:52:40.211607Z", + "banned": false, + "online": false, + "image": "https://getstream.io/random_svg/?id=holy-sun-6\u0026name=Holy+sun", + "name": "Holy sun" + }, + "attachments": [], + "latest_reactions": [], + "own_reactions": [], + "reaction_counts": {}, + "reaction_scores": {}, + "reply_count": 0, + "created_at": "2020-01-23T00:52:39.828172Z", + "updated_at": "2020-01-23T00:52:39.828172Z", + "mentioned_users": [] + }, + { + "id": "af6c4391-be20-4b25-b824-b4751507cd33", + "text": "Authors often misinterpret the railway as a louvred range, when in actuality it feels more like a pitted fridge.", + "html": "\u003cp\u003eAuthors often misinterpret the railway as a louvred range, when in actuality it feels more like a pitted fridge.\u003c/p\u003e\n", + "type": "regular", + "user": { + "id": "holy-sun-6", + "role": "user", + "created_at": "2020-01-23T00:52:39.412193Z", + "updated_at": "2020-01-23T00:52:40.211607Z", + "banned": false, + "online": false, + "image": "https://getstream.io/random_svg/?id=holy-sun-6\u0026name=Holy+sun", + "name": "Holy sun" + }, + "attachments": [], + "latest_reactions": [], + "own_reactions": [], + "reaction_counts": {}, + "reaction_scores": {}, + "reply_count": 0, + "created_at": "2020-01-23T00:52:39.850576Z", + "updated_at": "2020-01-23T00:52:39.850577Z", + "mentioned_users": [] + }, + { + "id": "960d62ad-00c6-4237-9b3c-cd440408ea18", + "text": "A dugout can hardly be considered a soundless acknowledgment without also being a raft.", + "html": "\u003cp\u003eA dugout can hardly be considered a soundless acknowledgment without also being a raft.\u003c/p\u003e\n", + "type": "regular", + "user": { + "id": "holy-sun-6", + "role": "user", + "created_at": "2020-01-23T00:52:39.412193Z", + "updated_at": "2020-01-23T00:52:40.211607Z", + "banned": false, + "online": false, + "image": "https://getstream.io/random_svg/?id=holy-sun-6\u0026name=Holy+sun", + "name": "Holy sun" + }, + "attachments": [], + "latest_reactions": [], + "own_reactions": [], + "reaction_counts": {}, + "reaction_scores": {}, + "reply_count": 0, + "created_at": "2020-01-23T00:52:39.873187Z", + "updated_at": "2020-01-23T00:52:39.873187Z", + "mentioned_users": [] + }, + { + "id": "409074d7-c830-4c16-9205-393de08898d3", + "text": "https://giphy.com/gifs/the-lion-king-live-action-5zvN79uTGfLMOVfQaA", + "html": "\u003cp\u003e\u003ca href=\"https://giphy.com/gifs/the-lion-king-live-action-5zvN79uTGfLMOVfQaA\" rel=\"nofollow\"\u003ehttps://giphy.com/gifs/the-lion-king-live-action-5zvN79uTGfLMOVfQaA\u003c/a\u003e\u003c/p\u003e\n", + "type": "regular", + "user": { + "id": "holy-sun-6", + "role": "user", + "created_at": "2020-01-23T00:52:39.412193Z", + "updated_at": "2020-01-23T00:52:40.211607Z", + "banned": false, + "online": false, + "image": "https://getstream.io/random_svg/?id=holy-sun-6\u0026name=Holy+sun", + "name": "Holy sun" + }, + "attachments": [ + { + "type": "video", + "author_name": "GIPHY", + "title": "The Lion King Disney GIF - Find \u0026 Share on GIPHY", + "title_link": "https://media.giphy.com/media/5zvN79uTGfLMOVfQaA/giphy.gif", + "text": "Discover \u0026 share this Lion King Live Action GIF with everyone you know. GIPHY is how you search, share, discover, and create GIFs.", + "image_url": "https://media.giphy.com/media/5zvN79uTGfLMOVfQaA/giphy.gif", + "thumb_url": "https://media.giphy.com/media/5zvN79uTGfLMOVfQaA/giphy.gif", + "asset_url": "https://media.giphy.com/media/5zvN79uTGfLMOVfQaA/giphy.mp4", + "og_scrape_url": "https://giphy.com/gifs/the-lion-king-live-action-5zvN79uTGfLMOVfQaA" + } + ], + "latest_reactions": [], + "own_reactions": [], + "reaction_counts": {}, + "reaction_scores": {}, + "reply_count": 1, + "created_at": "2020-01-23T00:52:40.191037Z", + "updated_at": "2020-01-23T00:52:40.191037Z", + "mentioned_users": [] + }, + { + "id": "2f1b8944-014a-4753-886f-1042163ada46", + "text": "https://www.youtube.com/watch?v=sCtixpIWBto", + "html": "\u003cp\u003e\u003ca href=\"https://www.youtube.com/watch?v=sCtixpIWBto\" rel=\"nofollow\"\u003ehttps://www.youtube.com/watch?v=sCtixpIWBto\u003c/a\u003e\u003c/p\u003e\n", + "type": "regular", + "user": { + "id": "holy-sun-6", + "role": "user", + "created_at": "2020-01-23T00:52:39.412193Z", + "updated_at": "2020-01-23T00:52:40.211607Z", + "banned": false, + "online": false, + "image": "https://getstream.io/random_svg/?id=holy-sun-6\u0026name=Holy+sun", + "name": "Holy sun" + }, + "attachments": [ + { + "type": "video", + "author_name": "YouTube", + "title": "Rachmaninoff - Prelude in C Sharp Minor (Op. 3 No. 2)", + "title_link": "https://www.youtube.com/watch?v=sCtixpIWBto", + "text": "Rachmaninoff - Prelude in C Sharp Minor (Op. 3 No. 2) Click the 🔔bell to always be notified on new uploads! ♫ Listen on Spotify: http://spoti.fi/2LdpqK7 ♫ MI...", + "image_url": "https://i.ytimg.com/vi/sCtixpIWBto/maxresdefault.jpg", + "thumb_url": "https://i.ytimg.com/vi/sCtixpIWBto/maxresdefault.jpg", + "asset_url": "https://www.youtube.com/embed/sCtixpIWBto", + "og_scrape_url": "https://www.youtube.com/watch?v=sCtixpIWBto" + } + ], + "latest_reactions": [ + { + "message_id": "2f1b8944-014a-4753-886f-1042163ada46", + "user_id": "holy-sun-6", + "user": { + "id": "holy-sun-6", + "role": "user", + "created_at": "2020-01-23T00:52:39.412193Z", + "updated_at": "2020-01-23T00:52:40.211607Z", + "banned": false, + "online": false, + "image": "https://getstream.io/random_svg/?id=holy-sun-6\u0026name=Holy+sun", + "name": "Holy sun" + }, + "type": "haha", + "score": 1, + "created_at": "2020-01-23T00:52:40.336054Z", + "updated_at": "2020-01-23T00:52:40.336054Z" + } + ], + "own_reactions": [], + "reaction_counts": { + "haha": 1 + }, + "reaction_scores": { + "haha": 1 + }, + "reply_count": 0, + "created_at": "2020-01-23T00:52:40.316069Z", + "updated_at": "2020-01-23T00:52:40.337791Z", + "mentioned_users": [] + } + ], + "watcher_count": 1, + "members": [] + }, + { + "channel": { + "id": "!members-aOjLAUKF7f4tB6iysBURUm7soQp6BBPpr0chg1KjGAA", + "type": "messaging", + "cid": "messaging:!members-aOjLAUKF7f4tB6iysBURUm7soQp6BBPpr0chg1KjGAA", + "last_message_at": "2020-01-23T00:52:40.193868Z", + "created_at": "2020-01-23T00:52:39.556322Z", + "updated_at": "2020-01-23T00:52:39.556322Z", + "created_by": { + "id": "holy-sun-6", + "role": "user", + "created_at": "2020-01-23T00:52:39.412193Z", + "updated_at": "2020-01-23T00:52:40.211607Z", + "banned": false, + "online": false, + "image": "https://getstream.io/random_svg/?id=holy-sun-6\u0026name=Holy+sun", + "name": "Holy sun" + }, + "frozen": false, + "member_count": 2, + "config": { + "created_at": "2020-01-29T12:59:14.291912835Z", + "updated_at": "2020-01-29T12:59:14.291912991Z", + "name": "messaging", + "typing_events": true, + "read_events": true, + "connect_events": true, + "search": true, + "reactions": true, + "replies": true, + "mutes": true, + "uploads": true, + "url_enrichment": true, + "message_retention": "infinite", + "max_message_length": 5000, + "automod": "disabled", + "automod_behavior": "flag", + "commands": [ + { + "name": "giphy", + "description": "Post a random gif to the channel", + "args": "[text]", + "set": "fun_set" + } + ] + }, + "image": "https://randomuser.me/api/portraits/women/65.jpg", + "name": "Renee Sims" + }, + "messages": [ + { + "id": "0fd2c220-4871-49d6-873d-84e7e12782e9", + "text": "A smarty panda is a cactus of the mind.", + "html": "\u003cp\u003eA smarty panda is a cactus of the mind.\u003c/p\u003e\n", + "type": "regular", + "user": { + "id": "636fdc1b-8b86-47b0-8ea1-8bb7f7c38910", + "role": "user", + "created_at": "2020-01-23T00:52:39.43164Z", + "updated_at": "2020-01-23T00:52:39.798407Z", + "banned": false, + "online": false, + "image": "https://randomuser.me/api/portraits/women/65.jpg", + "name": "Renee Sims" + }, + "attachments": [], + "latest_reactions": [], + "own_reactions": [], + "reaction_counts": {}, + "reaction_scores": {}, + "reply_count": 0, + "created_at": "2020-01-23T00:52:39.763764Z", + "updated_at": "2020-01-23T00:52:39.763764Z", + "mentioned_users": [] + }, + { + "id": "85a2e430-f9af-4e60-a43e-c87e48102aa7", + "text": "We can assume that any instance of a half-brother can be construed as an allowed half-brother.", + "html": "\u003cp\u003eWe can assume that any instance of a half-brother can be construed as an allowed half-brother.\u003c/p\u003e\n", + "type": "regular", + "user": { + "id": "holy-sun-6", + "role": "user", + "created_at": "2020-01-23T00:52:39.412193Z", + "updated_at": "2020-01-23T00:52:40.211607Z", + "banned": false, + "online": false, + "image": "https://getstream.io/random_svg/?id=holy-sun-6\u0026name=Holy+sun", + "name": "Holy sun" + }, + "attachments": [], + "latest_reactions": [], + "own_reactions": [], + "reaction_counts": {}, + "reaction_scores": {}, + "reply_count": 1, + "created_at": "2020-01-23T00:52:39.764235Z", + "updated_at": "2020-01-23T00:52:39.764236Z", + "mentioned_users": [] + }, + { + "id": "8bc5aeb6-6b39-488f-95ac-8c4bbb704b0e", + "text": "https://www.sciencenews.org/article/peacock-spiders-superblack-spots-reflect-just-05-percent-light?tgt=nr", + "html": "\u003cp\u003e\u003ca href=\"https://www.sciencenews.org/article/peacock-spiders-superblack-spots-reflect-just-05-percent-light?tgt=nr\" rel=\"nofollow\"\u003ehttps://www.sciencenews.org/article/peacock-spiders-superblack-spots-reflect-just-05-percent-light?tgt=nr\u003c/a\u003e\u003c/p\u003e\n", + "type": "regular", + "user": { + "id": "holy-sun-6", + "role": "user", + "created_at": "2020-01-23T00:52:39.412193Z", + "updated_at": "2020-01-23T00:52:40.211607Z", + "banned": false, + "online": false, + "image": "https://getstream.io/random_svg/?id=holy-sun-6\u0026name=Holy+sun", + "name": "Holy sun" + }, + "attachments": [ + { + "type": "image", + "author_name": "Science News", + "title": "Peacock spiders’ superblack spots reflect just 0.5 percent of light", + "title_link": "https://www.sciencenews.org/article/peacock-spiders-superblack-spots-reflect-just-05-percent-light", + "text": "By manipulating light with tiny structures, patches on peacock spiders appear superblack, helping accentuate the arachnids’ bright colors.", + "image_url": "https://www.sciencenews.org/wp-content/uploads/2019/05/051419_cw_spider_feat.jpg", + "thumb_url": "https://www.sciencenews.org/wp-content/uploads/2019/05/051419_cw_spider_feat.jpg", + "og_scrape_url": "https://www.sciencenews.org/article/peacock-spiders-superblack-spots-reflect-just-05-percent-light?tgt=nr" + } + ], + "latest_reactions": [ + { + "message_id": "8bc5aeb6-6b39-488f-95ac-8c4bbb704b0e", + "user_id": "636fdc1b-8b86-47b0-8ea1-8bb7f7c38910", + "user": { + "id": "636fdc1b-8b86-47b0-8ea1-8bb7f7c38910", + "role": "user", + "created_at": "2020-01-23T00:52:39.43164Z", + "updated_at": "2020-01-23T00:52:39.798407Z", + "banned": false, + "online": false, + "image": "https://randomuser.me/api/portraits/women/65.jpg", + "name": "Renee Sims" + }, + "type": "love", + "score": 1, + "created_at": "2020-01-23T00:52:40.173357Z", + "updated_at": "2020-01-23T00:52:40.173357Z" + } + ], + "own_reactions": [], + "reaction_counts": { + "love": 1 + }, + "reaction_scores": { + "love": 1 + }, + "reply_count": 0, + "created_at": "2020-01-23T00:52:40.151326Z", + "updated_at": "2020-01-23T00:52:40.175705Z", + "mentioned_users": [] + }, + { + "id": "4dc8a789-3930-44b7-9707-7302209189fb", + "text": "https://www.sciencenews.org/article/peacock-spiders-superblack-spots-reflect-just-05-percent-light?tgt=nr", + "html": "\u003cp\u003e\u003ca href=\"https://www.sciencenews.org/article/peacock-spiders-superblack-spots-reflect-just-05-percent-light?tgt=nr\" rel=\"nofollow\"\u003ehttps://www.sciencenews.org/article/peacock-spiders-superblack-spots-reflect-just-05-percent-light?tgt=nr\u003c/a\u003e\u003c/p\u003e\n", + "type": "regular", + "user": { + "id": "636fdc1b-8b86-47b0-8ea1-8bb7f7c38910", + "role": "user", + "created_at": "2020-01-23T00:52:39.43164Z", + "updated_at": "2020-01-23T00:52:39.798407Z", + "banned": false, + "online": false, + "image": "https://randomuser.me/api/portraits/women/65.jpg", + "name": "Renee Sims" + }, + "attachments": [ + { + "type": "image", + "author_name": "Science News", + "title": "Peacock spiders’ superblack spots reflect just 0.5 percent of light", + "title_link": "https://www.sciencenews.org/article/peacock-spiders-superblack-spots-reflect-just-05-percent-light", + "text": "By manipulating light with tiny structures, patches on peacock spiders appear superblack, helping accentuate the arachnids’ bright colors.", + "image_url": "https://www.sciencenews.org/wp-content/uploads/2019/05/051419_cw_spider_feat.jpg", + "thumb_url": "https://www.sciencenews.org/wp-content/uploads/2019/05/051419_cw_spider_feat.jpg", + "og_scrape_url": "https://www.sciencenews.org/article/peacock-spiders-superblack-spots-reflect-just-05-percent-light?tgt=nr" + } + ], + "latest_reactions": [], + "own_reactions": [], + "reaction_counts": {}, + "reaction_scores": {}, + "reply_count": 0, + "created_at": "2020-01-23T00:52:40.151921Z", + "updated_at": "2020-01-23T00:52:40.151921Z", + "mentioned_users": [] + }, + { + "id": "793722c6-5bbc-408c-8ba9-e1728e09d7c3", + "text": "https://www.youtube.com/watch?v=cJCtiJydw9U", + "html": "\u003cp\u003e\u003ca href=\"https://www.youtube.com/watch?v=cJCtiJydw9U\" rel=\"nofollow\"\u003ehttps://www.youtube.com/watch?v=cJCtiJydw9U\u003c/a\u003e\u003c/p\u003e\n", + "type": "regular", + "user": { + "id": "holy-sun-6", + "role": "user", + "created_at": "2020-01-23T00:52:39.412193Z", + "updated_at": "2020-01-23T00:52:40.211607Z", + "banned": false, + "online": false, + "image": "https://getstream.io/random_svg/?id=holy-sun-6\u0026name=Holy+sun", + "name": "Holy sun" + }, + "attachments": [ + { + "type": "video", + "author_name": "YouTube", + "title": "まるです11。-I am Maru 11.-", + "title_link": "https://www.youtube.com/watch?v=cJCtiJydw9U", + "text": "Happy 11th birthday!! BGM channel by h/mix -秋山裕和 公式チャンネル- https://www.youtube.com/channel/UCNPMwbX6-SclEmvFX5_ihCw Blog: http://sisinmaru.com/ Instagram: htt...", + "image_url": "https://i.ytimg.com/vi/cJCtiJydw9U/maxresdefault.jpg", + "thumb_url": "https://i.ytimg.com/vi/cJCtiJydw9U/maxresdefault.jpg", + "asset_url": "https://www.youtube.com/embed/cJCtiJydw9U", + "og_scrape_url": "https://www.youtube.com/watch?v=cJCtiJydw9U" + } + ], + "latest_reactions": [], + "own_reactions": [], + "reaction_counts": {}, + "reaction_scores": {}, + "reply_count": 0, + "created_at": "2020-01-23T00:52:40.193868Z", + "updated_at": "2020-01-23T00:52:40.193868Z", + "mentioned_users": [] + } + ], + "watcher_count": 1, + "read": [ + { + "user": { + "id": "636fdc1b-8b86-47b0-8ea1-8bb7f7c38910", + "role": "user", + "created_at": "2020-01-23T00:52:39.43164Z", + "updated_at": "2020-01-23T00:52:39.798407Z", + "banned": false, + "online": false, + "name": "Renee Sims", + "image": "https://randomuser.me/api/portraits/women/65.jpg" + }, + "last_read": "2020-01-23T00:52:39.570845184Z" + }, + { + "user": { + "id": "holy-sun-6", + "role": "user", + "created_at": "2020-01-23T00:52:39.412193Z", + "updated_at": "2020-01-23T00:52:40.211607Z", + "banned": false, + "online": false, + "image": "https://getstream.io/random_svg/?id=holy-sun-6\u0026name=Holy+sun", + "name": "Holy sun" + }, + "last_read": "2020-01-23T00:52:39.572206592Z" + } + ], + "members": [ + { + "user": { + "id": "636fdc1b-8b86-47b0-8ea1-8bb7f7c38910", + "role": "user", + "created_at": "2020-01-23T00:52:39.43164Z", + "updated_at": "2020-01-23T00:52:39.798407Z", + "banned": false, + "online": false, + "name": "Renee Sims", + "image": "https://randomuser.me/api/portraits/women/65.jpg" + }, + "role": "member", + "created_at": "2020-01-23T00:52:39.559506Z", + "updated_at": "2020-01-23T00:52:39.559506Z" + }, + { + "user": { + "id": "holy-sun-6", + "role": "user", + "created_at": "2020-01-23T00:52:39.412193Z", + "updated_at": "2020-01-23T00:52:40.211607Z", + "banned": false, + "online": false, + "image": "https://getstream.io/random_svg/?id=holy-sun-6\u0026name=Holy+sun", + "name": "Holy sun" + }, + "role": "owner", + "created_at": "2020-01-23T00:52:39.559506Z", + "updated_at": "2020-01-23T00:52:39.559506Z" + } + ] + } + ], + "duration": "30.85ms" +}'''; + final response = QueryChannelsResponse.fromJson(json.decode(jsonExample)); + expect(response.channels, isA>()); + }); + + test('ChannelStateResponse', () { + const jsonExample = r''' + { + "channel": { + "id": "!members-0LOcD0mZtTan60zHobLmELjdndXsonnBVNzZnB5mTt0", + "type": "messaging", + "cid": "messaging:!members-0LOcD0mZtTan60zHobLmELjdndXsonnBVNzZnB5mTt0", + "last_message_at": "2020-01-28T22:17:31.204287Z", + "created_at": "2020-01-28T22:17:31.00187Z", + "updated_at": "2020-01-28T22:17:31.00187Z", + "created_by": { + "id": "spring-voice-7", + "role": "user", + "created_at": "2020-01-28T22:17:30.834135Z", + "updated_at": "2020-01-28T22:17:31.186771Z", + "banned": false, + "online": false, + "image": "https://getstream.io/random_svg/?id=spring-voice-7\u0026name=Spring+voice", + "name": "Spring voice" + }, + "frozen": false, + "member_count": 2, + "config": { + "created_at": "2020-01-29T12:59:14.291912835Z", + "updated_at": "2020-01-29T12:59:14.291912991Z", + "name": "messaging", + "typing_events": true, + "read_events": true, + "connect_events": true, + "search": true, + "reactions": true, + "replies": true, + "mutes": true, + "uploads": true, + "url_enrichment": true, + "message_retention": "infinite", + "max_message_length": 5000, + "automod": "disabled", + "automod_behavior": "flag", + "commands": [ + { + "name": "giphy", + "description": "Post a random gif to the channel", + "args": "[text]", + "set": "fun_set" + } + ] + }, + "name": "Mia Denys", + "image": "https://randomuser.me/api/portraits/women/2.jpg" + }, + "messages": [ + { + "id": "4637f7e4-a06b-42db-ba5a-8d8270dd926f", + "text": "https://giphy.com/gifs/the-lion-king-live-action-5zvN79uTGfLMOVfQaA", + "html": "\u003cp\u003e\u003ca href=\"https://giphy.com/gifs/the-lion-king-live-action-5zvN79uTGfLMOVfQaA\" rel=\"nofollow\"\u003ehttps://giphy.com/gifs/the-lion-king-live-action-5zvN79uTGfLMOVfQaA\u003c/a\u003e\u003c/p\u003e\n", + "type": "regular", + "user": { + "id": "c1c9b454-2bcc-402d-8bb0-2f3706ce1680", + "role": "user", + "created_at": "2020-01-28T22:17:30.83015Z", + "updated_at": "2020-01-28T22:17:31.19435Z", + "banned": false, + "online": false, + "image": "https://randomuser.me/api/portraits/women/2.jpg", + "name": "Mia Denys" + }, + "attachments": [ + { + "type": "video", + "author_name": "GIPHY", + "title": "The Lion King Disney GIF - Find \u0026 Share on GIPHY", + "title_link": "https://media.giphy.com/media/5zvN79uTGfLMOVfQaA/giphy.gif", + "text": "Discover \u0026 share this Lion King Live Action GIF with everyone you know. GIPHY is how you search, share, discover, and create GIFs.", + "image_url": "https://media.giphy.com/media/5zvN79uTGfLMOVfQaA/giphy.gif", + "thumb_url": "https://media.giphy.com/media/5zvN79uTGfLMOVfQaA/giphy.gif", + "asset_url": "https://media.giphy.com/media/5zvN79uTGfLMOVfQaA/giphy.mp4", + "og_scrape_url": "https://giphy.com/gifs/the-lion-king-live-action-5zvN79uTGfLMOVfQaA" + } + ], + "latest_reactions": [ + { + "message_id": "4637f7e4-a06b-42db-ba5a-8d8270dd926f", + "user_id": "c1c9b454-2bcc-402d-8bb0-2f3706ce1680", + "user": { + "id": "c1c9b454-2bcc-402d-8bb0-2f3706ce1680", + "role": "user", + "created_at": "2020-01-28T22:17:30.83015Z", + "updated_at": "2020-01-28T22:17:31.19435Z", + "banned": false, + "online": false, + "image": "https://randomuser.me/api/portraits/women/2.jpg", + "name": "Mia Denys" + }, + "type": "love", + "score": 1, + "created_at": "2020-01-28T22:17:31.128376Z", + "updated_at": "2020-01-28T22:17:31.128376Z" + } + ], + "own_reactions": [], + "reaction_counts": { + "love": 1 + }, + "reaction_scores": { + "love": 1 + }, + "reply_count": 0, + "created_at": "2020-01-28T22:17:31.107978Z", + "updated_at": "2020-01-28T22:17:31.130506Z", + "mentioned_users": [] + }, + { + "id": "16e19c46-fb96-4f89-8031-d5bd2ce3bd64", + "text": "Few can name a topfull mother that isn't a breezeless damage.", + "html": "\u003cp\u003eFew can name a topfull mother that isn’t a breezeless damage.\u003c/p\u003e\n", + "type": "regular", + "user": { + "id": "spring-voice-7", + "role": "user", + "created_at": "2020-01-28T22:17:30.834135Z", + "updated_at": "2020-01-28T22:17:31.186771Z", + "banned": false, + "online": false, + "image": "https://getstream.io/random_svg/?id=spring-voice-7\u0026name=Spring+voice", + "name": "Spring voice" + }, + "attachments": [], + "latest_reactions": [], + "own_reactions": [], + "reaction_counts": {}, + "reaction_scores": {}, + "reply_count": 0, + "created_at": "2020-01-28T22:17:31.153518Z", + "updated_at": "2020-01-28T22:17:31.153518Z", + "mentioned_users": [] + }, + { + "id": "38b1b252-c9a6-4aea-a39e-8de3b7f7604b", + "text": "https://giphy.com/gifs/beard-muscle-73Sjhw0N4hyog", + "html": "\u003cp\u003e\u003ca href=\"https://giphy.com/gifs/beard-muscle-73Sjhw0N4hyog\" rel=\"nofollow\"\u003ehttps://giphy.com/gifs/beard-muscle-73Sjhw0N4hyog\u003c/a\u003e\u003c/p\u003e\n", + "type": "regular", + "user": { + "id": "spring-voice-7", + "role": "user", + "created_at": "2020-01-28T22:17:30.834135Z", + "updated_at": "2020-01-28T22:17:31.186771Z", + "banned": false, + "online": false, + "image": "https://getstream.io/random_svg/?id=spring-voice-7\u0026name=Spring+voice", + "name": "Spring voice" + }, + "attachments": [ + { + "type": "video", + "author_name": "GIPHY", + "title": "Moustache Thumbs Up GIF - Find \u0026 Share on GIPHY", + "title_link": "https://media.giphy.com/media/73Sjhw0N4hyog/giphy.gif", + "text": "Discover \u0026 share this Pouce Leve GIF with everyone you know. GIPHY is how you search, share, discover, and create GIFs.", + "image_url": "https://media.giphy.com/media/73Sjhw0N4hyog/giphy.gif", + "thumb_url": "https://media.giphy.com/media/73Sjhw0N4hyog/giphy.gif", + "asset_url": "https://media.giphy.com/media/73Sjhw0N4hyog/giphy.mp4", + "og_scrape_url": "https://giphy.com/gifs/beard-muscle-73Sjhw0N4hyog" + } + ], + "latest_reactions": [], + "own_reactions": [], + "reaction_counts": {}, + "reaction_scores": {}, + "reply_count": 0, + "created_at": "2020-01-28T22:17:31.155428Z", + "updated_at": "2020-01-28T22:17:31.155428Z", + "mentioned_users": [] + }, + { + "id": "5c7d0c68-72d5-4027-b6b7-711b342d0fc4", + "text": "The carbons could be said to resemble smartish hoods.", + "html": "\u003cp\u003eThe carbons could be said to resemble smartish hoods.\u003c/p\u003e\n", + "type": "regular", + "user": { + "id": "c1c9b454-2bcc-402d-8bb0-2f3706ce1680", + "role": "user", + "created_at": "2020-01-28T22:17:30.83015Z", + "updated_at": "2020-01-28T22:17:31.19435Z", + "banned": false, + "online": false, + "image": "https://randomuser.me/api/portraits/women/2.jpg", + "name": "Mia Denys" + }, + "attachments": [], + "latest_reactions": [], + "own_reactions": [], + "reaction_counts": {}, + "reaction_scores": {}, + "reply_count": 1, + "created_at": "2020-01-28T22:17:31.157811Z", + "updated_at": "2020-01-28T22:17:31.157811Z", + "mentioned_users": [] + }, + { + "id": "5b02535a-0c3c-45fa-9cf8-16f840c5123f", + "text": "Their software was, in this moment, a prolix feature.", + "html": "\u003cp\u003eTheir software was, in this moment, a prolix feature.\u003c/p\u003e\n", + "type": "regular", + "user": { + "id": "c1c9b454-2bcc-402d-8bb0-2f3706ce1680", + "role": "user", + "created_at": "2020-01-28T22:17:30.83015Z", + "updated_at": "2020-01-28T22:17:31.19435Z", + "banned": false, + "online": false, + "image": "https://randomuser.me/api/portraits/women/2.jpg", + "name": "Mia Denys" + }, + "attachments": [], + "latest_reactions": [], + "own_reactions": [], + "reaction_counts": {}, + "reaction_scores": {}, + "reply_count": 1, + "created_at": "2020-01-28T22:17:31.158391Z", + "updated_at": "2020-01-28T22:17:31.158391Z", + "mentioned_users": [] + } + ], + "watcher_count": 1, + "read": [ + { + "user": { + "id": "c1c9b454-2bcc-402d-8bb0-2f3706ce1680", + "role": "user", + "created_at": "2020-01-28T22:17:30.83015Z", + "updated_at": "2020-01-28T22:17:31.19435Z", + "banned": false, + "online": false, + "image": "https://randomuser.me/api/portraits/women/2.jpg", + "name": "Mia Denys" + }, + "last_read": "2020-01-28T22:17:31.016937728Z" + }, + { + "user": { + "id": "spring-voice-7", + "role": "user", + "created_at": "2020-01-28T22:17:30.834135Z", + "updated_at": "2020-01-28T22:17:31.186771Z", + "banned": false, + "online": false, + "image": "https://getstream.io/random_svg/?id=spring-voice-7\u0026name=Spring+voice", + "name": "Spring voice" + }, + "last_read": "2020-01-28T22:17:31.018856448Z" + } + ], + "members": [ + { + "user": { + "id": "c1c9b454-2bcc-402d-8bb0-2f3706ce1680", + "role": "user", + "created_at": "2020-01-28T22:17:30.83015Z", + "updated_at": "2020-01-28T22:17:31.19435Z", + "banned": false, + "online": false, + "image": "https://randomuser.me/api/portraits/women/2.jpg", + "name": "Mia Denys" + }, + "role": "member", + "created_at": "2020-01-28T22:17:31.005135Z", + "updated_at": "2020-01-28T22:17:31.005135Z" + }, + { + "user": { + "id": "spring-voice-7", + "role": "user", + "created_at": "2020-01-28T22:17:30.834135Z", + "updated_at": "2020-01-28T22:17:31.186771Z", + "banned": false, + "online": false, + "image": "https://getstream.io/random_svg/?id=spring-voice-7\u0026name=Spring+voice", + "name": "Spring voice" + }, + "role": "owner", + "created_at": "2020-01-28T22:17:31.005135Z", + "updated_at": "2020-01-28T22:17:31.005135Z" + } + ] + } + '''; + final response = ChannelStateResponse.fromJson(json.decode(jsonExample)); + expect(response.channel, isA()); + expect(response.watcherCount, isA()); + expect(response.members, isA>()); + expect(response.messages, isA>()); + expect(response.read, isA>()); + }); + + test('QueryUsersResponse', () { + const jsonExample = r''' + {"users":[{"id":"wild-breeze-7","role":"user","created_at":"2020-01-12T12:03:19.102029Z","updated_at":"2020-02-03T08:58:33.971562Z","last_active":"2020-02-03T08:58:33.965072Z","banned":false,"online":true,"name":"Wild breeze","image":"https://getstream.io/random_svg/?id=wild-breeze-7\u0026amp;name=Wild+breeze"}],"duration":"2.44ms"} + '''; + final response = QueryUsersResponse.fromJson(json.decode(jsonExample)); + expect(response.users, isA>()); + }); + + test('QueryReactionsResponse', () { + const jsonExample = r''' + {"reactions": [{"message_id": "4637f7e4-a06b-42db-ba5a-8d8270dd926f","user_id": "c1c9b454-2bcc-402d-8bb0-2f3706ce1680","user": {"id": "c1c9b454-2bcc-402d-8bb0-2f3706ce1680","role": "user","created_at": "2020-01-28T22:17:30.83015Z","updated_at": "2020-01-28T22:17:31.19435Z","banned": false,"online": false,"image": "https://randomuser.me/api/portraits/women/2.jpg","name": "Mia Denys"},"type": "love","score": 1,"created_at": "2020-01-28T22:17:31.128376Z","updated_at": "2020-01-28T22:17:31.128376Z"}]} + '''; + final response = + QueryReactionsResponse.fromJson(json.decode(jsonExample)); + expect(response.reactions, isA>()); + }); + + test('QueryRepliesResponse', () { + const jsonExample = r''' + { "messages": [ + { + "id": "9db3ef01-e779-4279-8c54-ffd021eccec4", + "text": "A lustred seal is an alto of the mind.", + "html": "\u003cp\u003eA lustred seal is an alto of the mind.\u003c/p\u003e\n", + "type": "regular", + "user": { + "id": "spring-voice-7", + "role": "user", + "created_at": "2020-01-28T22:17:30.834135Z", + "updated_at": "2020-01-28T22:17:31.186771Z", + "banned": false, + "online": false, + "image": "https://getstream.io/random_svg/?id=spring-voice-7\u0026name=Spring+voice", + "name": "Spring voice" + }, + "attachments": [], + "latest_reactions": [], + "own_reactions": [], + "reaction_counts": {}, + "reaction_scores": {}, + "reply_count": 0, + "created_at": "2020-01-28T22:17:31.167579Z", + "updated_at": "2020-01-28T22:17:31.167579Z", + "mentioned_users": [] + }, + { + "id": "3232e92f-a96f-4b5e-bacb-3565e7155dc4", + "text": "https://giphy.com/gifs/netflix-marvel-the-punisher-l3mZsRS7ZfftbdLdS", + "html": "\u003cp\u003e\u003ca href=\"https://giphy.com/gifs/netflix-marvel-the-punisher-l3mZsRS7ZfftbdLdS\" rel=\"nofollow\"\u003ehttps://giphy.com/gifs/netflix-marvel-the-punisher-l3mZsRS7ZfftbdLdS\u003c/a\u003e\u003c/p\u003e\n", + "type": "regular", + "user": { + "id": "spring-voice-7", + "role": "user", + "created_at": "2020-01-28T22:17:30.834135Z", + "updated_at": "2020-01-28T22:17:31.186771Z", + "banned": false, + "online": false, + "image": "https://getstream.io/random_svg/?id=spring-voice-7\u0026name=Spring+voice", + "name": "Spring voice" + }, + "attachments": [ + { + "type": "video", + "author_name": "GIPHY", + "title": "The Punisher Marvel GIF by NETFLIX - Find \u0026 Share on GIPHY", + "title_link": "https://media.giphy.com/media/l3mZsRS7ZfftbdLdS/giphy.gif", + "text": "See What's Next in entertainment and Netflix original series, movies, TV, docs, and comedies. You can stream Netflix anytime, anywhere, on any device.", + "image_url": "https://media.giphy.com/media/l3mZsRS7ZfftbdLdS/giphy.gif", + "thumb_url": "https://media.giphy.com/media/l3mZsRS7ZfftbdLdS/giphy.gif", + "asset_url": "https://media.giphy.com/media/l3mZsRS7ZfftbdLdS/giphy.mp4", + "og_scrape_url": "https://giphy.com/gifs/netflix-marvel-the-punisher-l3mZsRS7ZfftbdLdS" + } + ], + "latest_reactions": [], + "own_reactions": [], + "reaction_counts": {}, + "reaction_scores": {}, + "reply_count": 1, + "created_at": "2020-01-28T22:17:31.168454Z", + "updated_at": "2020-01-28T22:17:31.168454Z", + "mentioned_users": [] + } + ]} + '''; + final response = QueryRepliesResponse.fromJson(json.decode(jsonExample)); + expect(response.messages, isA>()); + }); + + test('SearchMessagesResponse', () { + const jsonExample = r''' + { "results": [ + { + "message": { + "id": "9db3ef01-e779-4279-8c54-ffd021eccec4", + "text": "A lustred seal is an alto of the mind.", + "html": "\u003cp\u003eA lustred seal is an alto of the mind.\u003c/p\u003e\n", + "type": "regular", + "user": { + "id": "spring-voice-7", + "role": "user", + "created_at": "2020-01-28T22:17:30.834135Z", + "updated_at": "2020-01-28T22:17:31.186771Z", + "banned": false, + "online": false, + "image": "https://getstream.io/random_svg/?id=spring-voice-7\u0026name=Spring+voice", + "name": "Spring voice" + }, + "attachments": [], + "latest_reactions": [], + "own_reactions": [], + "reaction_counts": {}, + "reaction_scores": {}, + "reply_count": 0, + "created_at": "2020-01-28T22:17:31.167579Z", + "updated_at": "2020-01-28T22:17:31.167579Z", + "mentioned_users": [] + } + }] + } + '''; + final response = + SearchMessagesResponse.fromJson(json.decode(jsonExample)); + expect(response.results, isA>()); + }); + + test('ListDevicesResponse', () { + const jsonExample = + r'''{"devices":[{"push_provider":"firebase","id":"test"}],"duration":"0.35ms"}'''; + final response = ListDevicesResponse.fromJson(json.decode(jsonExample)); + expect(response.devices, isA>()); + }); + + test('SendFileResponse', () { + const jsonExample = r'''{"file": "file-url","duration":"0.35ms"}'''; + final response = SendFileResponse.fromJson(json.decode(jsonExample)); + expect(response.file, isA()); + }); + + test('SendImageResponse', () { + const jsonExample = r'''{"file": "file-url","duration":"0.35ms"}'''; + final response = SendImageResponse.fromJson(json.decode(jsonExample)); + expect(response.file, isA()); + }); + + test('SendImageResponse', () { + const jsonExample = r'''{"file": "file-url","duration":"0.35ms"}'''; + final response = SendImageResponse.fromJson(json.decode(jsonExample)); + expect(response.file, isA()); + }); + + test('EmptyResponse', () { + const jsonExample = r'''{"file": "file-url","duration":"0.35ms"}'''; + final response = EmptyResponse.fromJson(json.decode(jsonExample)); + expect(response.duration, isA()); + }); + + test('SendReactionResponse', () { + const jsonExample = r'''{"message": { + "id": "c6076f11-7768-4a04-bdf2-c43dddd6d666", + "text": "What we don't know for sure is whether or not a step-daughter of the bear is assumed to be a farci hourglass.", + "html": "\u003cp\u003eWhat we don’t know for sure is whether or not a step-daughter of the bear is assumed to be a farci hourglass.\u003c/p\u003e\n", + "type": "regular", + "user": { + "id": "bbb19d9a-ee50-45bc-84e5-0584e79d0c9e", + "role": "user", + "created_at": "2020-01-28T22:17:30.826259Z", + "updated_at": "2020-01-28T22:17:31.101222Z", + "banned": false, + "online": false, + "image": "https://pbs.twimg.com/profile_images/669512187778498560/L7wQctBt.jpg", + "name": "Robin Papa" + }, + "attachments": [], + "latest_reactions": [], + "own_reactions": [], + "reaction_counts": {}, + "reaction_scores": {}, + "reply_count": 1, + "created_at": "2020-01-28T22:17:31.092262Z", + "updated_at": "2020-01-28T22:17:31.092262Z", + "mentioned_users": [] + }, + "reaction":{ + "message_id": "c74784e7-07ef-4b41-a8e3-b2b0e0b6b7ce", + "user_id": "spring-voice-7", + "user": { + "id": "spring-voice-7", + "role": "user", + "created_at": "2020-01-28T22:17:30.834135Z", + "updated_at": "2020-01-28T22:17:31.186771Z", + "banned": false, + "online": false, + "name": "Spring voice", + "image": "https://getstream.io/random_svg/?id=spring-voice-7\u0026name=Spring+voice" + }, + "type": "sad", + "score": 1, + "created_at": "2020-01-28T22:17:31.131489Z", + "updated_at": "2020-01-28T22:17:31.131489Z" + },"duration":"0.35ms"}'''; + final response = SendReactionResponse.fromJson(json.decode(jsonExample)); + expect(response.message, isA()); + expect(response.reaction, isA()); + }); + + test('UpdateUsersResponse', () { + const jsonExample = + r'''{"users": {"bbb19d9a-ee50-45bc-84e5-0584e79d0c9e":{ + "id": "bbb19d9a-ee50-45bc-84e5-0584e79d0c9e", + "role": "user", + "created_at": "2020-01-28T22:17:30.826259Z", + "updated_at": "2020-01-28T22:17:31.101222Z", + "banned": false, + "online": false, + "image": "https://pbs.twimg.com/profile_images/669512187778498560/L7wQctBt.jpg", + "name": "Robin Papa" + }},"duration":"0.35ms"}'''; + final response = UpdateUsersResponse.fromJson(json.decode(jsonExample)); + expect(response.users, isA>()); + }); + + test('SetGuestUserResponse', () { + const jsonExample = + r'{"user":{"id":"guest-ac612aee-25fe-49fb-b1af-969e41f452a0-wild-breeze-7","role":"guest","created_at":"2020-02-03T10:19:01.538434Z","updated_at":"2020-02-03T10:19:01.539543Z","banned":false,"online":false},"access_token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoiZ3Vlc3QtYWM2MTJhZWUtMjVmZS00OWZiLWIxYWYtOTY5ZTQxZjQ1MmEwLXdpbGQtYnJlZXplLTcifQ.mmoFGu7oJjpFsp7nFN78UbIpO7gowbuIbyoppsuvbXA","duration":"4.66ms"}'; + final response = SetGuestUserResponse.fromJson(json.decode(jsonExample)); + expect(response.user, isA()); + expect(response.accessToken, isA()); + }); + + test('GetMessagesByIdResponse', () { + const jsonExample = r'''{"messages":[{ + "id": "c6076f11-7768-4a04-bdf2-c43dddd6d666", + "text": "What we don't know for sure is whether or not a step-daughter of the bear is assumed to be a farci hourglass.", + "html": "\u003cp\u003eWhat we don’t know for sure is whether or not a step-daughter of the bear is assumed to be a farci hourglass.\u003c/p\u003e\n", + "type": "regular", + "user": { + "id": "bbb19d9a-ee50-45bc-84e5-0584e79d0c9e", + "role": "user", + "created_at": "2020-01-28T22:17:30.826259Z", + "updated_at": "2020-01-28T22:17:31.101222Z", + "banned": false, + "online": false, + "image": "https://pbs.twimg.com/profile_images/669512187778498560/L7wQctBt.jpg", + "name": "Robin Papa" + }, + "attachments": [], + "latest_reactions": [], + "own_reactions": [], + "reaction_counts": {}, + "reaction_scores": {}, + "reply_count": 1, + "created_at": "2020-01-28T22:17:31.092262Z", + "updated_at": "2020-01-28T22:17:31.092262Z", + "mentioned_users": [] + }],"duration":"4.66ms"}'''; + final response = + GetMessagesByIdResponse.fromJson(json.decode(jsonExample)); + expect(response.messages, isA>()); + }); + + test('SendActionResponse', () { + const jsonExample = r'''{"message":{ + "id": "c6076f11-7768-4a04-bdf2-c43dddd6d666", + "text": "What we don't know for sure is whether or not a step-daughter of the bear is assumed to be a farci hourglass.", + "html": "\u003cp\u003eWhat we don’t know for sure is whether or not a step-daughter of the bear is assumed to be a farci hourglass.\u003c/p\u003e\n", + "type": "regular", + "user": { + "id": "bbb19d9a-ee50-45bc-84e5-0584e79d0c9e", + "role": "user", + "created_at": "2020-01-28T22:17:30.826259Z", + "updated_at": "2020-01-28T22:17:31.101222Z", + "banned": false, + "online": false, + "image": "https://pbs.twimg.com/profile_images/669512187778498560/L7wQctBt.jpg", + "name": "Robin Papa" + }, + "attachments": [], + "latest_reactions": [], + "own_reactions": [], + "reaction_counts": {}, + "reaction_scores": {}, + "reply_count": 1, + "created_at": "2020-01-28T22:17:31.092262Z", + "updated_at": "2020-01-28T22:17:31.092262Z", + "mentioned_users": [] + },"duration":"4.66ms"}'''; + final response = SendActionResponse.fromJson(json.decode(jsonExample)); + expect(response.message, isA()); + }); + + test('UpdateMessageResponse', () { + const jsonExample = r'''{"message":{ + "id": "c6076f11-7768-4a04-bdf2-c43dddd6d666", + "text": "What we don't know for sure is whether or not a step-daughter of the bear is assumed to be a farci hourglass.", + "html": "\u003cp\u003eWhat we don’t know for sure is whether or not a step-daughter of the bear is assumed to be a farci hourglass.\u003c/p\u003e\n", + "type": "regular", + "user": { + "id": "bbb19d9a-ee50-45bc-84e5-0584e79d0c9e", + "role": "user", + "created_at": "2020-01-28T22:17:30.826259Z", + "updated_at": "2020-01-28T22:17:31.101222Z", + "banned": false, + "online": false, + "image": "https://pbs.twimg.com/profile_images/669512187778498560/L7wQctBt.jpg", + "name": "Robin Papa" + }, + "attachments": [], + "latest_reactions": [], + "own_reactions": [], + "reaction_counts": {}, + "reaction_scores": {}, + "reply_count": 1, + "created_at": "2020-01-28T22:17:31.092262Z", + "updated_at": "2020-01-28T22:17:31.092262Z", + "mentioned_users": [] + },"duration":"4.66ms"}'''; + final response = UpdateMessageResponse.fromJson(json.decode(jsonExample)); + expect(response.message, isA()); + }); + + test('SendMessageResponse', () { + const jsonExample = r'''{"message":{ + "id": "c6076f11-7768-4a04-bdf2-c43dddd6d666", + "text": "What we don't know for sure is whether or not a step-daughter of the bear is assumed to be a farci hourglass.", + "html": "\u003cp\u003eWhat we don’t know for sure is whether or not a step-daughter of the bear is assumed to be a farci hourglass.\u003c/p\u003e\n", + "type": "regular", + "user": { + "id": "bbb19d9a-ee50-45bc-84e5-0584e79d0c9e", + "role": "user", + "created_at": "2020-01-28T22:17:30.826259Z", + "updated_at": "2020-01-28T22:17:31.101222Z", + "banned": false, + "online": false, + "image": "https://pbs.twimg.com/profile_images/669512187778498560/L7wQctBt.jpg", + "name": "Robin Papa" + }, + "attachments": [], + "latest_reactions": [], + "own_reactions": [], + "reaction_counts": {}, + "reaction_scores": {}, + "reply_count": 1, + "created_at": "2020-01-28T22:17:31.092262Z", + "updated_at": "2020-01-28T22:17:31.092262Z", + "mentioned_users": [] + },"duration":"4.66ms"}'''; + final response = SendMessageResponse.fromJson(json.decode(jsonExample)); + expect(response.message, isA()); + }); + + test('GetMessageResponse', () { + const jsonExample = r'''{"message":{ + "id": "c6076f11-7768-4a04-bdf2-c43dddd6d666", + "text": "What we don't know for sure is whether or not a step-daughter of the bear is assumed to be a farci hourglass.", + "html": "\u003cp\u003eWhat we don’t know for sure is whether or not a step-daughter of the bear is assumed to be a farci hourglass.\u003c/p\u003e\n", + "type": "regular", + "user": { + "id": "bbb19d9a-ee50-45bc-84e5-0584e79d0c9e", + "role": "user", + "created_at": "2020-01-28T22:17:30.826259Z", + "updated_at": "2020-01-28T22:17:31.101222Z", + "banned": false, + "online": false, + "image": "https://pbs.twimg.com/profile_images/669512187778498560/L7wQctBt.jpg", + "name": "Robin Papa" + }, + "attachments": [], + "latest_reactions": [], + "own_reactions": [], + "reaction_counts": {}, + "reaction_scores": {}, + "reply_count": 1, + "created_at": "2020-01-28T22:17:31.092262Z", + "updated_at": "2020-01-28T22:17:31.092262Z", + "mentioned_users": [] + },"duration":"4.66ms"}'''; + final response = GetMessageResponse.fromJson(json.decode(jsonExample)); + expect(response.message, isA()); + }); + + test('UpdateChannelResponse', () { + const jsonExample = r'''{"message":{ + "id": "c6076f11-7768-4a04-bdf2-c43dddd6d666", + "text": "What we don't know for sure is whether or not a step-daughter of the bear is assumed to be a farci hourglass.", + "html": "\u003cp\u003eWhat we don’t know for sure is whether or not a step-daughter of the bear is assumed to be a farci hourglass.\u003c/p\u003e\n", + "type": "regular", + "user": { + "id": "bbb19d9a-ee50-45bc-84e5-0584e79d0c9e", + "role": "user", + "created_at": "2020-01-28T22:17:30.826259Z", + "updated_at": "2020-01-28T22:17:31.101222Z", + "banned": false, + "online": false, + "image": "https://pbs.twimg.com/profile_images/669512187778498560/L7wQctBt.jpg", + "name": "Robin Papa" + }, + "attachments": [], + "latest_reactions": [], + "own_reactions": [], + "reaction_counts": {}, + "reaction_scores": {}, + "reply_count": 1, + "created_at": "2020-01-28T22:17:31.092262Z", + "updated_at": "2020-01-28T22:17:31.092262Z", + "mentioned_users": [] + }, + "members": [ + { + "user": { + "id": "c1c9b454-2bcc-402d-8bb0-2f3706ce1680", + "role": "user", + "created_at": "2020-01-28T22:17:30.83015Z", + "updated_at": "2020-01-28T22:17:31.19435Z", + "banned": false, + "online": false, + "image": "https://randomuser.me/api/portraits/women/2.jpg", + "name": "Mia Denys" + }, + "role": "member", + "created_at": "2020-01-28T22:17:31.005135Z", + "updated_at": "2020-01-28T22:17:31.005135Z" + }, + { + "user": { + "id": "spring-voice-7", + "role": "user", + "created_at": "2020-01-28T22:17:30.834135Z", + "updated_at": "2020-01-28T22:17:31.186771Z", + "banned": false, + "online": false, + "image": "https://getstream.io/random_svg/?id=spring-voice-7\u0026name=Spring+voice", + "name": "Spring voice" + }, + "role": "owner", + "created_at": "2020-01-28T22:17:31.005135Z", + "updated_at": "2020-01-28T22:17:31.005135Z" + } + ], + "channel": { + "id": "!members-0LOcD0mZtTan60zHobLmELjdndXsonnBVNzZnB5mTt0", + "type": "messaging", + "cid": "messaging:!members-0LOcD0mZtTan60zHobLmELjdndXsonnBVNzZnB5mTt0", + "last_message_at": "2020-01-28T22:17:31.204287Z", + "created_at": "2020-01-28T22:17:31.00187Z", + "updated_at": "2020-01-28T22:17:31.00187Z", + "created_by": { + "id": "spring-voice-7", + "role": "user", + "created_at": "2020-01-28T22:17:30.834135Z", + "updated_at": "2020-01-28T22:17:31.186771Z", + "banned": false, + "online": false, + "image": "https://getstream.io/random_svg/?id=spring-voice-7\u0026name=Spring+voice", + "name": "Spring voice" + }, + "frozen": false, + "member_count": 2, + "config": { + "created_at": "2020-01-29T12:59:14.291912835Z", + "updated_at": "2020-01-29T12:59:14.291912991Z", + "name": "messaging", + "typing_events": true, + "read_events": true, + "connect_events": true, + "search": true, + "reactions": true, + "replies": true, + "mutes": true, + "uploads": true, + "url_enrichment": true, + "message_retention": "infinite", + "max_message_length": 5000, + "automod": "disabled", + "automod_behavior": "flag", + "commands": [ + { + "name": "giphy", + "description": "Post a random gif to the channel", + "args": "[text]", + "set": "fun_set" + } + ] + }, + "name": "Mia Denys", + "image": "https://randomuser.me/api/portraits/women/2.jpg" + }, + "duration":"4.66ms"}'''; + final response = UpdateChannelResponse.fromJson(json.decode(jsonExample)); + expect(response.channel, isA()); + expect(response.members, isA>()); + expect(response.message, isA()); + }); + + test('InviteMembersResponse', () { + const jsonExample = r'''{"message":{ + "id": "c6076f11-7768-4a04-bdf2-c43dddd6d666", + "text": "What we don't know for sure is whether or not a step-daughter of the bear is assumed to be a farci hourglass.", + "html": "\u003cp\u003eWhat we don’t know for sure is whether or not a step-daughter of the bear is assumed to be a farci hourglass.\u003c/p\u003e\n", + "type": "regular", + "user": { + "id": "bbb19d9a-ee50-45bc-84e5-0584e79d0c9e", + "role": "user", + "created_at": "2020-01-28T22:17:30.826259Z", + "updated_at": "2020-01-28T22:17:31.101222Z", + "banned": false, + "online": false, + "image": "https://pbs.twimg.com/profile_images/669512187778498560/L7wQctBt.jpg", + "name": "Robin Papa" + }, + "attachments": [], + "latest_reactions": [], + "own_reactions": [], + "reaction_counts": {}, + "reaction_scores": {}, + "reply_count": 1, + "created_at": "2020-01-28T22:17:31.092262Z", + "updated_at": "2020-01-28T22:17:31.092262Z", + "mentioned_users": [] + }, + "members": [ + { + "user": { + "id": "c1c9b454-2bcc-402d-8bb0-2f3706ce1680", + "role": "user", + "created_at": "2020-01-28T22:17:30.83015Z", + "updated_at": "2020-01-28T22:17:31.19435Z", + "banned": false, + "online": false, + "image": "https://randomuser.me/api/portraits/women/2.jpg", + "name": "Mia Denys" + }, + "role": "member", + "created_at": "2020-01-28T22:17:31.005135Z", + "updated_at": "2020-01-28T22:17:31.005135Z" + }, + { + "user": { + "id": "spring-voice-7", + "role": "user", + "created_at": "2020-01-28T22:17:30.834135Z", + "updated_at": "2020-01-28T22:17:31.186771Z", + "banned": false, + "online": false, + "image": "https://getstream.io/random_svg/?id=spring-voice-7\u0026name=Spring+voice", + "name": "Spring voice" + }, + "role": "owner", + "created_at": "2020-01-28T22:17:31.005135Z", + "updated_at": "2020-01-28T22:17:31.005135Z" + } + ], + "channel": { + "id": "!members-0LOcD0mZtTan60zHobLmELjdndXsonnBVNzZnB5mTt0", + "type": "messaging", + "cid": "messaging:!members-0LOcD0mZtTan60zHobLmELjdndXsonnBVNzZnB5mTt0", + "last_message_at": "2020-01-28T22:17:31.204287Z", + "created_at": "2020-01-28T22:17:31.00187Z", + "updated_at": "2020-01-28T22:17:31.00187Z", + "created_by": { + "id": "spring-voice-7", + "role": "user", + "created_at": "2020-01-28T22:17:30.834135Z", + "updated_at": "2020-01-28T22:17:31.186771Z", + "banned": false, + "online": false, + "image": "https://getstream.io/random_svg/?id=spring-voice-7\u0026name=Spring+voice", + "name": "Spring voice" + }, + "frozen": false, + "member_count": 2, + "config": { + "created_at": "2020-01-29T12:59:14.291912835Z", + "updated_at": "2020-01-29T12:59:14.291912991Z", + "name": "messaging", + "typing_events": true, + "read_events": true, + "connect_events": true, + "search": true, + "reactions": true, + "replies": true, + "mutes": true, + "uploads": true, + "url_enrichment": true, + "message_retention": "infinite", + "max_message_length": 5000, + "automod": "disabled", + "automod_behavior": "flag", + "commands": [ + { + "name": "giphy", + "description": "Post a random gif to the channel", + "args": "[text]", + "set": "fun_set" + } + ] + }, + "name": "Mia Denys", + "image": "https://randomuser.me/api/portraits/women/2.jpg" + }, + "duration":"4.66ms"}'''; + final response = InviteMembersResponse.fromJson(json.decode(jsonExample)); + expect(response.channel, isA()); + expect(response.members, isA>()); + expect(response.message, isA()); + }); + + test('RemoveMembersResponse', () { + const jsonExample = r'''{"message":{ + "id": "c6076f11-7768-4a04-bdf2-c43dddd6d666", + "text": "What we don't know for sure is whether or not a step-daughter of the bear is assumed to be a farci hourglass.", + "html": "\u003cp\u003eWhat we don’t know for sure is whether or not a step-daughter of the bear is assumed to be a farci hourglass.\u003c/p\u003e\n", + "type": "regular", + "user": { + "id": "bbb19d9a-ee50-45bc-84e5-0584e79d0c9e", + "role": "user", + "created_at": "2020-01-28T22:17:30.826259Z", + "updated_at": "2020-01-28T22:17:31.101222Z", + "banned": false, + "online": false, + "image": "https://pbs.twimg.com/profile_images/669512187778498560/L7wQctBt.jpg", + "name": "Robin Papa" + }, + "attachments": [], + "latest_reactions": [], + "own_reactions": [], + "reaction_counts": {}, + "reaction_scores": {}, + "reply_count": 1, + "created_at": "2020-01-28T22:17:31.092262Z", + "updated_at": "2020-01-28T22:17:31.092262Z", + "mentioned_users": [] + }, + "members": [ + { + "user": { + "id": "c1c9b454-2bcc-402d-8bb0-2f3706ce1680", + "role": "user", + "created_at": "2020-01-28T22:17:30.83015Z", + "updated_at": "2020-01-28T22:17:31.19435Z", + "banned": false, + "online": false, + "image": "https://randomuser.me/api/portraits/women/2.jpg", + "name": "Mia Denys" + }, + "role": "member", + "created_at": "2020-01-28T22:17:31.005135Z", + "updated_at": "2020-01-28T22:17:31.005135Z" + }, + { + "user": { + "id": "spring-voice-7", + "role": "user", + "created_at": "2020-01-28T22:17:30.834135Z", + "updated_at": "2020-01-28T22:17:31.186771Z", + "banned": false, + "online": false, + "image": "https://getstream.io/random_svg/?id=spring-voice-7\u0026name=Spring+voice", + "name": "Spring voice" + }, + "role": "owner", + "created_at": "2020-01-28T22:17:31.005135Z", + "updated_at": "2020-01-28T22:17:31.005135Z" + } + ], + "channel": { + "id": "!members-0LOcD0mZtTan60zHobLmELjdndXsonnBVNzZnB5mTt0", + "type": "messaging", + "cid": "messaging:!members-0LOcD0mZtTan60zHobLmELjdndXsonnBVNzZnB5mTt0", + "last_message_at": "2020-01-28T22:17:31.204287Z", + "created_at": "2020-01-28T22:17:31.00187Z", + "updated_at": "2020-01-28T22:17:31.00187Z", + "created_by": { + "id": "spring-voice-7", + "role": "user", + "created_at": "2020-01-28T22:17:30.834135Z", + "updated_at": "2020-01-28T22:17:31.186771Z", + "banned": false, + "online": false, + "image": "https://getstream.io/random_svg/?id=spring-voice-7\u0026name=Spring+voice", + "name": "Spring voice" + }, + "frozen": false, + "member_count": 2, + "config": { + "created_at": "2020-01-29T12:59:14.291912835Z", + "updated_at": "2020-01-29T12:59:14.291912991Z", + "name": "messaging", + "typing_events": true, + "read_events": true, + "connect_events": true, + "search": true, + "reactions": true, + "replies": true, + "mutes": true, + "uploads": true, + "url_enrichment": true, + "message_retention": "infinite", + "max_message_length": 5000, + "automod": "disabled", + "automod_behavior": "flag", + "commands": [ + { + "name": "giphy", + "description": "Post a random gif to the channel", + "args": "[text]", + "set": "fun_set" + } + ] + }, + "name": "Mia Denys", + "image": "https://randomuser.me/api/portraits/women/2.jpg" + }, + "duration":"4.66ms"}'''; + final response = RemoveMembersResponse.fromJson(json.decode(jsonExample)); + expect(response.channel, isA()); + expect(response.members, isA>()); + expect(response.message, isA()); + }); + + test('AddMembersResponse', () { + const jsonExample = r'''{"message":{ + "id": "c6076f11-7768-4a04-bdf2-c43dddd6d666", + "text": "What we don't know for sure is whether or not a step-daughter of the bear is assumed to be a farci hourglass.", + "html": "\u003cp\u003eWhat we don’t know for sure is whether or not a step-daughter of the bear is assumed to be a farci hourglass.\u003c/p\u003e\n", + "type": "regular", + "user": { + "id": "bbb19d9a-ee50-45bc-84e5-0584e79d0c9e", + "role": "user", + "created_at": "2020-01-28T22:17:30.826259Z", + "updated_at": "2020-01-28T22:17:31.101222Z", + "banned": false, + "online": false, + "image": "https://pbs.twimg.com/profile_images/669512187778498560/L7wQctBt.jpg", + "name": "Robin Papa" + }, + "attachments": [], + "latest_reactions": [], + "own_reactions": [], + "reaction_counts": {}, + "reaction_scores": {}, + "reply_count": 1, + "created_at": "2020-01-28T22:17:31.092262Z", + "updated_at": "2020-01-28T22:17:31.092262Z", + "mentioned_users": [] + }, + "members": [ + { + "user": { + "id": "c1c9b454-2bcc-402d-8bb0-2f3706ce1680", + "role": "user", + "created_at": "2020-01-28T22:17:30.83015Z", + "updated_at": "2020-01-28T22:17:31.19435Z", + "banned": false, + "online": false, + "image": "https://randomuser.me/api/portraits/women/2.jpg", + "name": "Mia Denys" + }, + "role": "member", + "created_at": "2020-01-28T22:17:31.005135Z", + "updated_at": "2020-01-28T22:17:31.005135Z" + }, + { + "user": { + "id": "spring-voice-7", + "role": "user", + "created_at": "2020-01-28T22:17:30.834135Z", + "updated_at": "2020-01-28T22:17:31.186771Z", + "banned": false, + "online": false, + "image": "https://getstream.io/random_svg/?id=spring-voice-7\u0026name=Spring+voice", + "name": "Spring voice" + }, + "role": "owner", + "created_at": "2020-01-28T22:17:31.005135Z", + "updated_at": "2020-01-28T22:17:31.005135Z" + } + ], + "channel": { + "id": "!members-0LOcD0mZtTan60zHobLmELjdndXsonnBVNzZnB5mTt0", + "type": "messaging", + "cid": "messaging:!members-0LOcD0mZtTan60zHobLmELjdndXsonnBVNzZnB5mTt0", + "last_message_at": "2020-01-28T22:17:31.204287Z", + "created_at": "2020-01-28T22:17:31.00187Z", + "updated_at": "2020-01-28T22:17:31.00187Z", + "created_by": { + "id": "spring-voice-7", + "role": "user", + "created_at": "2020-01-28T22:17:30.834135Z", + "updated_at": "2020-01-28T22:17:31.186771Z", + "banned": false, + "online": false, + "image": "https://getstream.io/random_svg/?id=spring-voice-7\u0026name=Spring+voice", + "name": "Spring voice" + }, + "frozen": false, + "member_count": 2, + "config": { + "created_at": "2020-01-29T12:59:14.291912835Z", + "updated_at": "2020-01-29T12:59:14.291912991Z", + "name": "messaging", + "typing_events": true, + "read_events": true, + "connect_events": true, + "search": true, + "reactions": true, + "replies": true, + "mutes": true, + "uploads": true, + "url_enrichment": true, + "message_retention": "infinite", + "max_message_length": 5000, + "automod": "disabled", + "automod_behavior": "flag", + "commands": [ + { + "name": "giphy", + "description": "Post a random gif to the channel", + "args": "[text]", + "set": "fun_set" + } + ] + }, + "name": "Mia Denys", + "image": "https://randomuser.me/api/portraits/women/2.jpg" + }, + "duration":"4.66ms"}'''; + final response = AddMembersResponse.fromJson(json.decode(jsonExample)); + expect(response.channel, isA()); + expect(response.members, isA>()); + expect(response.message, isA()); + }); + + test('AcceptInviteResponse', () { + const jsonExample = r'''{"message":{ + "id": "c6076f11-7768-4a04-bdf2-c43dddd6d666", + "text": "What we don't know for sure is whether or not a step-daughter of the bear is assumed to be a farci hourglass.", + "html": "\u003cp\u003eWhat we don’t know for sure is whether or not a step-daughter of the bear is assumed to be a farci hourglass.\u003c/p\u003e\n", + "type": "regular", + "user": { + "id": "bbb19d9a-ee50-45bc-84e5-0584e79d0c9e", + "role": "user", + "created_at": "2020-01-28T22:17:30.826259Z", + "updated_at": "2020-01-28T22:17:31.101222Z", + "banned": false, + "online": false, + "image": "https://pbs.twimg.com/profile_images/669512187778498560/L7wQctBt.jpg", + "name": "Robin Papa" + }, + "attachments": [], + "latest_reactions": [], + "own_reactions": [], + "reaction_counts": {}, + "reaction_scores": {}, + "reply_count": 1, + "created_at": "2020-01-28T22:17:31.092262Z", + "updated_at": "2020-01-28T22:17:31.092262Z", + "mentioned_users": [] + }, + "members": [ + { + "user": { + "id": "c1c9b454-2bcc-402d-8bb0-2f3706ce1680", + "role": "user", + "created_at": "2020-01-28T22:17:30.83015Z", + "updated_at": "2020-01-28T22:17:31.19435Z", + "banned": false, + "online": false, + "image": "https://randomuser.me/api/portraits/women/2.jpg", + "name": "Mia Denys" + }, + "role": "member", + "created_at": "2020-01-28T22:17:31.005135Z", + "updated_at": "2020-01-28T22:17:31.005135Z" + }, + { + "user": { + "id": "spring-voice-7", + "role": "user", + "created_at": "2020-01-28T22:17:30.834135Z", + "updated_at": "2020-01-28T22:17:31.186771Z", + "banned": false, + "online": false, + "image": "https://getstream.io/random_svg/?id=spring-voice-7\u0026name=Spring+voice", + "name": "Spring voice" + }, + "role": "owner", + "created_at": "2020-01-28T22:17:31.005135Z", + "updated_at": "2020-01-28T22:17:31.005135Z" + } + ], + "channel": { + "id": "!members-0LOcD0mZtTan60zHobLmELjdndXsonnBVNzZnB5mTt0", + "type": "messaging", + "cid": "messaging:!members-0LOcD0mZtTan60zHobLmELjdndXsonnBVNzZnB5mTt0", + "last_message_at": "2020-01-28T22:17:31.204287Z", + "created_at": "2020-01-28T22:17:31.00187Z", + "updated_at": "2020-01-28T22:17:31.00187Z", + "created_by": { + "id": "spring-voice-7", + "role": "user", + "created_at": "2020-01-28T22:17:30.834135Z", + "updated_at": "2020-01-28T22:17:31.186771Z", + "banned": false, + "online": false, + "image": "https://getstream.io/random_svg/?id=spring-voice-7\u0026name=Spring+voice", + "name": "Spring voice" + }, + "frozen": false, + "member_count": 2, + "config": { + "created_at": "2020-01-29T12:59:14.291912835Z", + "updated_at": "2020-01-29T12:59:14.291912991Z", + "name": "messaging", + "typing_events": true, + "read_events": true, + "connect_events": true, + "search": true, + "reactions": true, + "replies": true, + "mutes": true, + "uploads": true, + "url_enrichment": true, + "message_retention": "infinite", + "max_message_length": 5000, + "automod": "disabled", + "automod_behavior": "flag", + "commands": [ + { + "name": "giphy", + "description": "Post a random gif to the channel", + "args": "[text]", + "set": "fun_set" + } + ] + }, + "name": "Mia Denys", + "image": "https://randomuser.me/api/portraits/women/2.jpg" + }, + "duration":"4.66ms"}'''; + final response = AcceptInviteResponse.fromJson(json.decode(jsonExample)); + expect(response.channel, isA()); + expect(response.members, isA>()); + expect(response.message, isA()); + }); + + test('RejectInviteResponse', () { + const jsonExample = r'''{"message":{ + "id": "c6076f11-7768-4a04-bdf2-c43dddd6d666", + "text": "What we don't know for sure is whether or not a step-daughter of the bear is assumed to be a farci hourglass.", + "html": "\u003cp\u003eWhat we don’t know for sure is whether or not a step-daughter of the bear is assumed to be a farci hourglass.\u003c/p\u003e\n", + "type": "regular", + "user": { + "id": "bbb19d9a-ee50-45bc-84e5-0584e79d0c9e", + "role": "user", + "created_at": "2020-01-28T22:17:30.826259Z", + "updated_at": "2020-01-28T22:17:31.101222Z", + "banned": false, + "online": false, + "image": "https://pbs.twimg.com/profile_images/669512187778498560/L7wQctBt.jpg", + "name": "Robin Papa" + }, + "attachments": [], + "latest_reactions": [], + "own_reactions": [], + "reaction_counts": {}, + "reaction_scores": {}, + "reply_count": 1, + "created_at": "2020-01-28T22:17:31.092262Z", + "updated_at": "2020-01-28T22:17:31.092262Z", + "mentioned_users": [] + }, + "members": [ + { + "user": { + "id": "c1c9b454-2bcc-402d-8bb0-2f3706ce1680", + "role": "user", + "created_at": "2020-01-28T22:17:30.83015Z", + "updated_at": "2020-01-28T22:17:31.19435Z", + "banned": false, + "online": false, + "image": "https://randomuser.me/api/portraits/women/2.jpg", + "name": "Mia Denys" + }, + "role": "member", + "created_at": "2020-01-28T22:17:31.005135Z", + "updated_at": "2020-01-28T22:17:31.005135Z" + }, + { + "user": { + "id": "spring-voice-7", + "role": "user", + "created_at": "2020-01-28T22:17:30.834135Z", + "updated_at": "2020-01-28T22:17:31.186771Z", + "banned": false, + "online": false, + "image": "https://getstream.io/random_svg/?id=spring-voice-7\u0026name=Spring+voice", + "name": "Spring voice" + }, + "role": "owner", + "created_at": "2020-01-28T22:17:31.005135Z", + "updated_at": "2020-01-28T22:17:31.005135Z" + } + ], + "channel": { + "id": "!members-0LOcD0mZtTan60zHobLmELjdndXsonnBVNzZnB5mTt0", + "type": "messaging", + "cid": "messaging:!members-0LOcD0mZtTan60zHobLmELjdndXsonnBVNzZnB5mTt0", + "last_message_at": "2020-01-28T22:17:31.204287Z", + "created_at": "2020-01-28T22:17:31.00187Z", + "updated_at": "2020-01-28T22:17:31.00187Z", + "created_by": { + "id": "spring-voice-7", + "role": "user", + "created_at": "2020-01-28T22:17:30.834135Z", + "updated_at": "2020-01-28T22:17:31.186771Z", + "banned": false, + "online": false, + "image": "https://getstream.io/random_svg/?id=spring-voice-7\u0026name=Spring+voice", + "name": "Spring voice" + }, + "frozen": false, + "member_count": 2, + "config": { + "created_at": "2020-01-29T12:59:14.291912835Z", + "updated_at": "2020-01-29T12:59:14.291912991Z", + "name": "messaging", + "typing_events": true, + "read_events": true, + "connect_events": true, + "search": true, + "reactions": true, + "replies": true, + "mutes": true, + "uploads": true, + "url_enrichment": true, + "message_retention": "infinite", + "max_message_length": 5000, + "automod": "disabled", + "automod_behavior": "flag", + "commands": [ + { + "name": "giphy", + "description": "Post a random gif to the channel", + "args": "[text]", + "set": "fun_set" + } + ] + }, + "name": "Mia Denys", + "image": "https://randomuser.me/api/portraits/women/2.jpg" + }, + "duration":"4.66ms"}'''; + final response = RejectInviteResponse.fromJson(json.decode(jsonExample)); + expect(response.channel, isA()); + expect(response.members, isA>()); + expect(response.message, isA()); + }); + }); +} diff --git a/packages/dart_client/test/src/api/web_socket_stub_test.dart b/packages/dart_client/test/src/api/web_socket_stub_test.dart new file mode 100644 index 00000000..5de61b4a --- /dev/null +++ b/packages/dart_client/test/src/api/web_socket_stub_test.dart @@ -0,0 +1,9 @@ +import 'package:flutter_test/flutter_test.dart'; +import 'package:stream_chat/src/api/web_socket_channel_stub.dart'; + +void main() { + test('src/api/web_socket_stub_test', () { + expect( + () => connectWebSocket('fakeurl'), throwsA(isA())); + }); +} diff --git a/packages/dart_client/test/src/api/websocket_test.dart b/packages/dart_client/test/src/api/websocket_test.dart new file mode 100644 index 00000000..e5a88bd8 --- /dev/null +++ b/packages/dart_client/test/src/api/websocket_test.dart @@ -0,0 +1,353 @@ +import 'dart:async'; + +import 'package:flutter_test/flutter_test.dart'; +import 'package:logging/logging.dart'; +import 'package:mockito/mockito.dart'; +import 'package:stream_chat/src/api/connection_status.dart'; +import 'package:stream_chat/src/api/websocket.dart'; +import 'package:stream_chat/src/models/event.dart'; +import 'package:stream_chat/src/models/user.dart'; +import 'package:stream_chat/stream_chat.dart'; +import 'package:web_socket_channel/web_socket_channel.dart'; + +class Functions { + WebSocketChannel connectFunc( + String url, { + Iterable protocols, + Map headers, + Duration pingInterval, + }) => + null; + + void handleFunc(Event event) => null; +} + +class MockFunctions extends Mock implements Functions {} + +class MockWSChannel extends Mock implements WebSocketChannel {} + +class MockWSSink extends Mock implements WebSocketSink {} + +void main() { + group('src/api/websocket', () { + test('should connect with correct parameters', () async { + final ConnectWebSocket connectFunc = MockFunctions().connectFunc; + + final ws = WebSocket( + baseUrl: 'baseurl', + user: User(id: 'testid'), + logger: Logger('ws'), + connectParams: {'test': 'true'}, + connectPayload: {'payload': 'test'}, + handler: (e) { + print(e); + }, + connectFunc: connectFunc, + ); + + final mockWSChannel = MockWSChannel(); + + final StreamController streamController = + StreamController.broadcast(); + + final computedUrl = + 'wss://baseurl/connect?test=true&json=%7B%22payload%22%3A%22test%22%2C%22user_details%22%3A%7B%22id%22%3A%22testid%22%7D%7D'; + + when(connectFunc(computedUrl)).thenAnswer((_) => mockWSChannel); + when(mockWSChannel.sink).thenAnswer((_) => MockWSSink()); + when(mockWSChannel.stream).thenAnswer((_) { + return streamController.stream; + }); + + final timer = Timer.periodic( + Duration(milliseconds: 100), + (_) => streamController.sink.add('{}'), + ); + + await ws.connect(); + + verify(connectFunc(computedUrl)).called(1); + expect(ws.connectionStatus.value, ConnectionStatus.connected); + + await streamController.close(); + timer.cancel(); + }); + }); + + test('should connect with correct parameters and handle events', () async { + final handleFunc = MockFunctions().handleFunc; + final ConnectWebSocket connectFunc = MockFunctions().connectFunc; + + final ws = WebSocket( + baseUrl: 'baseurl', + user: User(id: 'testid'), + logger: Logger('ws'), + connectParams: {'test': 'true'}, + connectPayload: {'payload': 'test'}, + handler: handleFunc, + connectFunc: connectFunc, + ); + + final mockWSChannel = MockWSChannel(); + + final StreamController streamController = + StreamController.broadcast(); + + final computedUrl = + 'wss://baseurl/connect?test=true&json=%7B%22payload%22%3A%22test%22%2C%22user_details%22%3A%7B%22id%22%3A%22testid%22%7D%7D'; + + when(connectFunc(computedUrl)).thenAnswer((_) => mockWSChannel); + when(mockWSChannel.sink).thenAnswer((_) => MockWSSink()); + when(mockWSChannel.stream).thenAnswer((_) { + return streamController.stream; + }); + + final connect = ws.connect().then((_) { + streamController.sink.add('{}'); + return Future.delayed(Duration(milliseconds: 200)); + }).then((value) { + verify(connectFunc(computedUrl)).called(1); + verify(handleFunc(any)).called(greaterThan(0)); + + return streamController.close(); + }); + + streamController.sink.add('{}'); + + return connect; + }); + + test('should close correctly the controller', () async { + final handleFunc = MockFunctions().handleFunc; + + final ConnectWebSocket connectFunc = MockFunctions().connectFunc; + + final ws = WebSocket( + baseUrl: 'baseurl', + user: User(id: 'testid'), + logger: Logger('ws'), + connectParams: {'test': 'true'}, + connectPayload: {'payload': 'test'}, + handler: handleFunc, + connectFunc: connectFunc, + ); + + final mockWSChannel = MockWSChannel(); + + final StreamController streamController = + StreamController.broadcast(); + + final computedUrl = + 'wss://baseurl/connect?test=true&json=%7B%22payload%22%3A%22test%22%2C%22user_details%22%3A%7B%22id%22%3A%22testid%22%7D%7D'; + + when(connectFunc(computedUrl)).thenAnswer((_) => mockWSChannel); + when(mockWSChannel.sink).thenAnswer((_) => MockWSSink()); + when(mockWSChannel.stream).thenAnswer((_) { + return streamController.stream; + }); + + final connect = ws.connect().then((_) { + streamController.sink.add('{}'); + return Future.delayed(Duration(milliseconds: 200)); + }).then((value) { + verify(connectFunc(computedUrl)).called(1); + verify(handleFunc(any)).called(greaterThan(0)); + + return streamController.close(); + }); + + streamController.sink.add('{}'); + + return connect; + }); + + test('should run correctly health check', () async { + final handleFunc = MockFunctions().handleFunc; + + final ConnectWebSocket connectFunc = MockFunctions().connectFunc; + + final ws = WebSocket( + baseUrl: 'baseurl', + user: User(id: 'testid'), + logger: Logger('ws'), + connectParams: {'test': 'true'}, + connectPayload: {'payload': 'test'}, + handler: handleFunc, + connectFunc: connectFunc, + ); + + final mockWSChannel = MockWSChannel(); + final mockWSSink = MockWSSink(); + + final StreamController streamController = + StreamController.broadcast(); + + final computedUrl = + 'wss://baseurl/connect?test=true&json=%7B%22payload%22%3A%22test%22%2C%22user_details%22%3A%7B%22id%22%3A%22testid%22%7D%7D'; + + when(connectFunc(computedUrl)).thenAnswer((_) => mockWSChannel); + when(mockWSChannel.stream).thenAnswer((_) { + return streamController.stream; + }); + when(mockWSChannel.sink).thenReturn(mockWSSink); + + final timer = Timer.periodic( + Duration(milliseconds: 1000), + (_) => streamController.sink.add('{}'), + ); + + final connect = ws.connect().then((_) { + streamController.sink.add('{}'); + return Future.delayed(Duration(milliseconds: 200)); + }).then((value) async { + verify(mockWSSink.add("{'type': 'health.check'}")).called(greaterThan(0)); + + timer.cancel(); + await streamController.close(); + return mockWSSink.close(); + }); + + streamController.sink.add('{}'); + + return connect; + }); + + test('should run correctly reconnection check', () async { + final handleFunc = MockFunctions().handleFunc; + + final ConnectWebSocket connectFunc = MockFunctions().connectFunc; + + Logger.root.level = Level.ALL; + final ws = WebSocket( + baseUrl: 'baseurl', + user: User(id: 'testid'), + logger: Logger('ws'), + connectParams: {'test': 'true'}, + connectPayload: {'payload': 'test'}, + handler: handleFunc, + connectFunc: connectFunc, + reconnectionMonitorTimeout: 1, + reconnectionMonitorInterval: 1, + ); + + final mockWSChannel = MockWSChannel(); + final mockWSSink = MockWSSink(); + + StreamController streamController = + StreamController.broadcast(); + + final computedUrl = + 'wss://baseurl/connect?test=true&json=%7B%22payload%22%3A%22test%22%2C%22user_details%22%3A%7B%22id%22%3A%22testid%22%7D%7D'; + + when(connectFunc(computedUrl)).thenAnswer((_) => mockWSChannel); + when(mockWSChannel.stream).thenAnswer((_) { + return streamController.stream; + }); + when(mockWSChannel.sink).thenReturn(mockWSSink); + + final connect = ws.connect().then((_) { + streamController.sink.add('{}'); + streamController.close(); + streamController = StreamController.broadcast(); + streamController.sink.add('{}'); + return Future.delayed(Duration(milliseconds: 200)); + }).then((value) async { + verify(mockWSSink.add("{'type': 'health.check'}")).called(greaterThan(0)); + + verify(connectFunc(computedUrl)).called(2); + + await streamController.close(); + return mockWSSink.close(); + }); + + streamController.sink.add('{}'); + + return connect; + }); + + test('should close correctly the controller', () async { + final handleFunc = MockFunctions().handleFunc; + + final ConnectWebSocket connectFunc = MockFunctions().connectFunc; + + final ws = WebSocket( + baseUrl: 'baseurl', + user: User(id: 'testid'), + logger: Logger('ws'), + connectParams: {'test': 'true'}, + connectPayload: {'payload': 'test'}, + handler: handleFunc, + connectFunc: connectFunc, + ); + + final mockWSChannel = MockWSChannel(); + final mockWSSink = MockWSSink(); + + final StreamController streamController = + StreamController.broadcast(); + + final computedUrl = + 'wss://baseurl/connect?test=true&json=%7B%22payload%22%3A%22test%22%2C%22user_details%22%3A%7B%22id%22%3A%22testid%22%7D%7D'; + + when(connectFunc(computedUrl)).thenAnswer((_) => mockWSChannel); + when(mockWSChannel.stream).thenAnswer((_) { + return streamController.stream; + }); + when(mockWSChannel.sink).thenReturn(mockWSSink); + + final connect = ws.connect().then((_) { + streamController.sink.add('{}'); + return Future.delayed(Duration(milliseconds: 200)); + }).then((value) async { + await ws.disconnect(); + verify(mockWSSink.close()).called(greaterThan(0)); + + await streamController.close(); + await mockWSSink.close(); + }); + + streamController.sink.add('{}'); + + return connect; + }); + + test('should throw an error', () async { + final ConnectWebSocket connectFunc = MockFunctions().connectFunc; + + final ws = WebSocket( + baseUrl: 'baseurl', + user: User(id: 'testid'), + logger: Logger('ws'), + connectParams: {'test': 'true'}, + connectPayload: {'payload': 'test'}, + handler: (e) { + print(e); + }, + connectFunc: connectFunc, + ); + + final mockWSChannel = MockWSChannel(); + + final streamController = StreamController.broadcast(); + + final computedUrl = + 'wss://baseurl/connect?test=true&json=%7B%22payload%22%3A%22test%22%2C%22user_details%22%3A%7B%22id%22%3A%22testid%22%7D%7D'; + + when(connectFunc(computedUrl)).thenAnswer((_) => mockWSChannel); + when(mockWSChannel.sink).thenAnswer((_) => MockWSSink()); + when(mockWSChannel.stream).thenAnswer((_) { + return streamController.stream; + }); + + Future.delayed( + Duration(milliseconds: 1000), + () => streamController.sink.addError('test error'), + ); + + try { + expect(await ws.connect(), throwsA(isA())); + } catch (e) { + verify(connectFunc(computedUrl)).called(greaterThanOrEqualTo(1)); + } + }); +} diff --git a/packages/dart_client/test/src/client_test.dart b/packages/dart_client/test/src/client_test.dart new file mode 100644 index 00000000..738255cc --- /dev/null +++ b/packages/dart_client/test/src/client_test.dart @@ -0,0 +1,979 @@ +import 'dart:async'; +import 'dart:convert'; + +import 'package:dio/dio.dart'; +import 'package:dio/native_imp.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:logging/logging.dart'; +import 'package:mockito/mockito.dart'; +import 'package:stream_chat/src/api/requests.dart'; +import 'package:stream_chat/src/client.dart'; +import 'package:stream_chat/src/exceptions.dart'; +import 'package:stream_chat/src/models/message.dart'; +import 'package:stream_chat/src/models/user.dart'; + +class MockDio extends Mock implements DioForNative {} + +class MockHttpClientAdapter extends Mock implements HttpClientAdapter {} + +class Functions { + Future tokenProvider(String userId) => null; +} + +class MockFunctions extends Mock implements Functions {} + +void main() { + group('src/client', () { + group('constructor', () { + final List log = []; + + overridePrint(testFn()) => () { + log.clear(); + final spec = ZoneSpecification(print: (_, __, ___, String msg) { + // Add to log instead of printing to stdout + log.add(msg); + }); + return Zone.current.fork(specification: spec).run(testFn); + }; + + tearDown(() { + log.clear(); + }); + + test('should create the object correctly', () { + final client = Client( + 'api-key', + persistenceEnabled: false, + ); + + expect(client.baseURL, 'chat-us-east-1.stream-io-api.com'); + expect(client.apiKey, 'api-key'); + expect(client.logLevel, Level.WARNING); + expect(client.httpClient.options.connectTimeout, 6000); + expect(client.httpClient.options.receiveTimeout, 6000); + }); + + test('should create the object correctly', overridePrint(() { + final LogHandlerFunction logHandler = (LogRecord record) { + print(record.message); + }; + + final client = Client( + 'api-key', + persistenceEnabled: false, + connectTimeout: Duration(seconds: 10), + receiveTimeout: Duration(seconds: 12), + logLevel: Level.INFO, + baseURL: 'test.com', + logHandlerFunction: logHandler, + ); + + expect(client.baseURL, 'test.com'); + expect(client.apiKey, 'api-key'); + expect(Logger.root.level, Level.INFO); + expect(client.httpClient.options.connectTimeout, 10000); + expect(client.httpClient.options.receiveTimeout, 12000); + + client.logger.warning('test'); + client.logger.config('test config'); + + expect([log[log.length - 2], log[log.length - 1]], + ['instantiating new client', 'test']); + })); + + test('Channel', () { + final client = Client( + 'test', + persistenceEnabled: false, + ); + final Map data = {'test': 1}; + final channelClient = client.channel('type', id: 'id', extraData: data); + expect(channelClient.type, 'type'); + expect(channelClient.id, 'id'); + }); + }); + + group('queryChannels', () { + test('should pass right default parameters', () async { + final mockDio = MockDio(); + + when(mockDio.options).thenReturn(BaseOptions()); + when(mockDio.interceptors).thenReturn(Interceptors()); + + final client = Client( + 'api-key', + httpClient: mockDio, + persistenceEnabled: false, + ); + + final queryParams = { + 'payload': json.encode({ + "filter_conditions": null, + "sort": null, + "state": true, + "watch": true, + "presence": false, + "limit": 10, + }), + }; + + when(mockDio.get('/channels', queryParameters: queryParams)) + .thenAnswer((_) async => Response(data: '{}', statusCode: 200)); + + await client.queryChannels(waitForConnect: false); + + verify(mockDio.get('/channels', queryParameters: queryParams)) + .called(1); + }); + + test('should pass right parameters', () async { + final mockDio = MockDio(); + + when(mockDio.options).thenReturn(BaseOptions()); + when(mockDio.interceptors).thenReturn(Interceptors()); + + final client = Client( + 'api-key', + httpClient: mockDio, + persistenceEnabled: false, + ); + + final queryFilter = { + "id": { + "\$in": ["test"], + }, + }; + final sortOptions = []; + final options = {"state": false, "watch": false, "presence": true}; + final paginationParams = PaginationParams( + limit: 10, + offset: 2, + ); + + final queryParams = { + 'payload': json.encode({ + "filter_conditions": queryFilter, + "sort": sortOptions, + } + ..addAll(options) + ..addAll(paginationParams.toJson())), + }; + + when(mockDio.get('/channels', queryParameters: queryParams)) + .thenAnswer((_) async { + return Response(data: '{}', statusCode: 200); + }); + + await client.queryChannels( + filter: queryFilter, + sort: sortOptions, + options: options, + paginationParams: paginationParams, + waitForConnect: false, + ); + + verify(mockDio.get('/channels', queryParameters: queryParams)) + .called(1); + }); + }); + + group('search', () { + test('should pass right default parameters', () async { + final mockDio = MockDio(); + + when(mockDio.options).thenReturn(BaseOptions()); + when(mockDio.interceptors).thenReturn(Interceptors()); + + final client = Client( + 'api-key', + persistenceEnabled: false, + httpClient: mockDio, + ); + + final queryParams = { + 'payload': json.encode({ + "filter_conditions": null, + 'query': null, + 'sort': null, + }), + }; + + when(mockDio.get('/search', queryParameters: queryParams)) + .thenAnswer((_) async => Response(data: '{}', statusCode: 200)); + + await client.search(null, null, null, null); + + verify(mockDio.get('/search', queryParameters: queryParams)) + .called(1); + }); + + test('should pass right parameters', () async { + final mockDio = MockDio(); + + when(mockDio.options).thenReturn(BaseOptions()); + when(mockDio.interceptors).thenReturn(Interceptors()); + + final client = Client( + 'api-key', + persistenceEnabled: false, + httpClient: mockDio, + ); + + final filters = { + "id": { + "\$in": ["test"], + }, + }; + final sortOptions = [SortOption('name')]; + final query = 'query'; + + final queryParams = { + 'payload': json.encode({ + "filter_conditions": filters, + 'query': query, + 'sort': sortOptions, + "limit": 10, + }), + }; + + when(mockDio.get('/search', queryParameters: queryParams)) + .thenAnswer((_) async => Response(data: '{}', statusCode: 200)); + + await client.search( + filters, + sortOptions, + query, + PaginationParams(), + ); + + verify(mockDio.get('/search', queryParameters: queryParams)) + .called(1); + }); + }); + + group('devices', () { + test('addDevice', () async { + final mockDio = MockDio(); + + when(mockDio.options).thenReturn(BaseOptions()); + when(mockDio.interceptors).thenReturn(Interceptors()); + + final client = Client( + 'api-key', + persistenceEnabled: false, + httpClient: mockDio, + ); + + when(mockDio.post('/devices', data: { + 'id': 'test-id', + 'push_provider': 'test', + })).thenAnswer((_) async => Response(data: '{}', statusCode: 200)); + + await client.addDevice('test-id', 'test'); + + verify(mockDio.post('/devices', + data: {'id': 'test-id', 'push_provider': 'test'})).called(1); + }); + + test('getDevices', () async { + final mockDio = MockDio(); + + when(mockDio.options).thenReturn(BaseOptions()); + when(mockDio.interceptors).thenReturn(Interceptors()); + + final client = Client( + 'api-key', + persistenceEnabled: false, + httpClient: mockDio, + ); + + when(mockDio.get('/devices')) + .thenAnswer((_) async => Response(data: '{}', statusCode: 200)); + + await client.getDevices(); + + verify(mockDio.get('/devices')).called(1); + }); + + test('removeDevice', () async { + final mockDio = MockDio(); + + when(mockDio.options).thenReturn(BaseOptions()); + when(mockDio.interceptors).thenReturn(Interceptors()); + + final client = Client( + 'api-key', + persistenceEnabled: false, + httpClient: mockDio, + ); + + when(mockDio + .delete('/devices', queryParameters: {'id': 'test-id'})) + .thenAnswer((_) async => Response(data: '{}', statusCode: 200)); + + await client.removeDevice('test-id'); + + verify(mockDio.delete('/devices', + queryParameters: {'id': 'test-id'})).called(1); + }); + }); + + test('devToken', () { + final client = Client( + 'api-key', + persistenceEnabled: false, + ); + final token = client.devToken('test'); + + expect( + token, + 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoidGVzdCJ9.devtoken', + ); + }); + + group('queryUsers', () { + test('should pass right default parameters', () async { + final mockDio = MockDio(); + + when(mockDio.options).thenReturn(BaseOptions()); + when(mockDio.interceptors).thenReturn(Interceptors()); + + final client = Client( + 'api-key', + persistenceEnabled: false, + httpClient: mockDio, + ); + + final queryParams = { + 'payload': json.encode({ + "filter_conditions": {}, + "sort": null, + "presence": false, + }), + }; + + when(mockDio.get('/users', queryParameters: queryParams)) + .thenAnswer((_) async => Response(data: '{}', statusCode: 200)); + + await client.queryUsers(); + + verify(mockDio.get('/users', queryParameters: queryParams)) + .called(1); + }); + + test('should pass right parameters', () async { + final mockDio = MockDio(); + + when(mockDio.options).thenReturn(BaseOptions()); + when(mockDio.interceptors).thenReturn(Interceptors()); + + final client = Client( + 'api-key', + persistenceEnabled: false, + httpClient: mockDio, + ); + + final Map queryFilter = { + "id": { + "\$in": ["test"], + }, + }; + final List sortOptions = []; + final options = {"presence": true}; + + final Map queryParams = { + 'payload': json.encode({ + "filter_conditions": queryFilter, + "sort": sortOptions, + }..addAll(options)), + }; + + when(mockDio.get('/users', queryParameters: queryParams)) + .thenAnswer((_) async { + return Response(data: '{}', statusCode: 200); + }); + + await client.queryUsers( + filter: queryFilter, + sort: sortOptions, + options: options, + ); + + verify(mockDio.get('/users', queryParameters: queryParams)) + .called(1); + }); + }); + + group('user', () { + test('setUser should throw exception', () async { + final mockDio = MockDio(); + + when(mockDio.options).thenReturn(BaseOptions()); + when(mockDio.interceptors).thenReturn(Interceptors()); + + final client = Client( + 'api-key', + persistenceEnabled: false, + httpClient: mockDio, + ); + + when(mockDio.post('/moderation/flag', + data: {'target_user_id': 'test-id'})) + .thenAnswer((_) async => Response(data: '{}', statusCode: 200)); + + await client.flagUser('test-id'); + + verify(mockDio.post('/moderation/flag', + data: {'target_user_id': 'test-id'})).called(1); + }); + + test('flagUser', () async { + final mockDio = MockDio(); + + when(mockDio.options).thenReturn(BaseOptions()); + when(mockDio.interceptors).thenReturn(Interceptors()); + + final client = Client( + 'api-key', + persistenceEnabled: false, + httpClient: mockDio, + ); + + expect(() => client.setUserWithProvider(User(id: 'test-id')), + throwsA(isA())); + }); + + test('unflagUser', () async { + final mockDio = MockDio(); + + when(mockDio.options).thenReturn(BaseOptions()); + when(mockDio.interceptors).thenReturn(Interceptors()); + + final client = Client( + 'api-key', + persistenceEnabled: false, + httpClient: mockDio, + ); + + when(mockDio.post('/moderation/unflag', + data: {'target_user_id': 'test-id'})) + .thenAnswer((_) async => Response(data: '{}', statusCode: 200)); + + await client.unflagUser('test-id'); + + verify(mockDio.post('/moderation/unflag', + data: {'target_user_id': 'test-id'})).called(1); + }); + + test('updateUser', () async { + final mockDio = MockDio(); + + when(mockDio.options).thenReturn(BaseOptions()); + when(mockDio.interceptors).thenReturn(Interceptors()); + + final client = Client( + 'api-key', + persistenceEnabled: false, + httpClient: mockDio, + ); + + final user = User(id: 'test-id'); + + final data = { + 'users': {user.id: user.toJson()}, + }; + + when(mockDio.post('/users', data: data)) + .thenAnswer((_) async => Response(data: '{}', statusCode: 200)); + + await client.updateUser(user); + + verify(mockDio.post('/users', data: data)).called(1); + }); + + test('updateUsers', () async { + final mockDio = MockDio(); + + when(mockDio.options).thenReturn(BaseOptions()); + when(mockDio.interceptors).thenReturn(Interceptors()); + + final client = Client( + 'api-key', + persistenceEnabled: false, + httpClient: mockDio, + ); + + final user = User(id: 'test-id'); + final user2 = User(id: 'test-id2'); + + final data = { + 'users': { + user.id: user.toJson(), + user2.id: user2.toJson(), + }, + }; + + when(mockDio.post('/users', data: data)) + .thenAnswer((_) async => Response(data: '{}', statusCode: 200)); + + await client.updateUsers([user, user2]); + + verify(mockDio.post('/users', data: data)).called(1); + }); + + test('banUser', () async { + final mockDio = MockDio(); + + when(mockDio.options).thenReturn(BaseOptions()); + when(mockDio.interceptors).thenReturn(Interceptors()); + + final client = Client( + 'api-key', + persistenceEnabled: false, + httpClient: mockDio, + ); + + when(mockDio.post('/moderation/ban', + data: {'test': true, 'target_user_id': 'test-id'})) + .thenAnswer((_) async => Response(data: '{}', statusCode: 200)); + + await client.banUser('test-id', {'test': true}); + + verify(mockDio.post('/moderation/ban', + data: {'test': true, 'target_user_id': 'test-id'})).called(1); + }); + + test('unbanUser', () async { + final mockDio = MockDio(); + + when(mockDio.options).thenReturn(BaseOptions()); + when(mockDio.interceptors).thenReturn(Interceptors()); + + final client = Client( + 'api-key', + persistenceEnabled: false, + httpClient: mockDio, + ); + + when(mockDio.delete('/moderation/ban', + queryParameters: {'test': true, 'target_user_id': 'test-id'})) + .thenAnswer((_) async => Response(data: '{}', statusCode: 200)); + + await client.unbanUser('test-id', {'test': true}); + + verify(mockDio.delete('/moderation/ban', + queryParameters: {'test': true, 'target_user_id': 'test-id'})) + .called(1); + }); + + test('muteUser', () async { + final mockDio = MockDio(); + + when(mockDio.options).thenReturn(BaseOptions()); + when(mockDio.interceptors).thenReturn(Interceptors()); + + final client = Client( + 'api-key', + persistenceEnabled: false, + httpClient: mockDio, + ); + + when(mockDio.post('/moderation/mute', + data: {'target_id': 'test-id'})) + .thenAnswer((_) async => Response(data: '{}', statusCode: 200)); + + await client.muteUser('test-id'); + + verify(mockDio.post('/moderation/mute', + data: {'target_id': 'test-id'})).called(1); + }); + + test('unmuteUser', () async { + final mockDio = MockDio(); + + when(mockDio.options).thenReturn(BaseOptions()); + when(mockDio.interceptors).thenReturn(Interceptors()); + + final client = Client( + 'api-key', + persistenceEnabled: false, + httpClient: mockDio, + ); + + when(mockDio.post('/moderation/unmute', + data: {'target_id': 'test-id'})) + .thenAnswer((_) async => Response(data: '{}', statusCode: 200)); + + await client.unmuteUser('test-id'); + + verify(mockDio.post('/moderation/unmute', + data: {'target_id': 'test-id'})).called(1); + }); + }); + + group('message', () { + test('flagMessage', () async { + final mockDio = MockDio(); + + when(mockDio.options).thenReturn(BaseOptions()); + when(mockDio.interceptors).thenReturn(Interceptors()); + + final client = Client( + 'api-key', + persistenceEnabled: false, + httpClient: mockDio, + ); + + when(mockDio.post('/moderation/flag', + data: {'target_message_id': 'test-id'})) + .thenAnswer((_) async => Response(data: '{}', statusCode: 200)); + + await client.flagMessage('test-id'); + + verify(mockDio.post('/moderation/flag', + data: {'target_message_id': 'test-id'})).called(1); + }); + + test('unflagMessage', () async { + final mockDio = MockDio(); + + when(mockDio.options).thenReturn(BaseOptions()); + when(mockDio.interceptors).thenReturn(Interceptors()); + + final client = Client( + 'api-key', + persistenceEnabled: false, + httpClient: mockDio, + ); + + when(mockDio.post('/moderation/unflag', + data: {'target_message_id': 'test-id'})) + .thenAnswer((_) async => Response(data: '{}', statusCode: 200)); + + await client.unflagMessage('test-id'); + + verify(mockDio.post('/moderation/unflag', + data: {'target_message_id': 'test-id'})).called(1); + }); + + test('updateMessage', () async { + final mockDio = MockDio(); + + when(mockDio.options).thenReturn(BaseOptions()); + when(mockDio.interceptors).thenReturn(Interceptors()); + + final client = Client( + 'api-key', + persistenceEnabled: false, + httpClient: mockDio, + ); + + final message = Message( + id: 'test', + updatedAt: DateTime.now(), + ); + + when(mockDio.post( + '/messages/${message.id}', + data: {'message': message}, + )).thenAnswer((_) async => Response(data: '{}', statusCode: 200)); + + await client.updateMessage(message); + + verify(mockDio.post('/messages/${message.id}', + data: {'message': anything})).called(1); + }); + + test('deleteMessage', () async { + final mockDio = MockDio(); + + when(mockDio.options).thenReturn(BaseOptions()); + when(mockDio.interceptors).thenReturn(Interceptors()); + + final client = Client( + 'api-key', + persistenceEnabled: false, + httpClient: mockDio, + ); + + final messageId = 'test'; + + when(mockDio.delete('/messages/$messageId')) + .thenAnswer((_) async => Response(data: '{}', statusCode: 200)); + + await client.deleteMessage(Message(id: messageId)); + + verify(mockDio.delete('/messages/$messageId')).called(1); + }); + + test('getMessage', () async { + final mockDio = MockDio(); + + when(mockDio.options).thenReturn(BaseOptions()); + when(mockDio.interceptors).thenReturn(Interceptors()); + + final client = Client( + 'api-key', + persistenceEnabled: false, + httpClient: mockDio, + ); + + final messageId = 'test'; + + when(mockDio.get('/messages/$messageId')) + .thenAnswer((_) async => Response(data: '{}', statusCode: 200)); + + await client.getMessage(messageId); + + verify(mockDio.get('/messages/$messageId')).called(1); + }); + + test('markAllRead', () async { + final mockDio = MockDio(); + + when(mockDio.options).thenReturn(BaseOptions()); + when(mockDio.interceptors).thenReturn(Interceptors()); + + final client = Client( + 'api-key', + persistenceEnabled: false, + httpClient: mockDio, + ); + + when(mockDio.post('/channels/read')) + .thenAnswer((_) async => Response(data: '{}', statusCode: 200)); + + await client.markAllRead(); + + verify(mockDio.post('/channels/read')).called(1); + }); + }); + + group('api methods', () { + group('get', () { + test('should put the correct parameters', () async { + final mockDio = MockDio(); + + when(mockDio.options).thenReturn(BaseOptions()); + when(mockDio.interceptors).thenReturn(Interceptors()); + + final client = Client( + 'api-key', + persistenceEnabled: false, + httpClient: mockDio, + ); + + final Map queryParams = { + 'test': 1, + }; + + when(mockDio.get('/test', queryParameters: queryParams)) + .thenAnswer((_) async { + return Response(data: '{}', statusCode: 200); + }); + + await client.get('/test', queryParameters: queryParams); + + verify(mockDio.get('/test', queryParameters: queryParams)) + .called(1); + }); + + test('should catch the error', () async { + final dioHttp = Dio(); + final mockHttpClientAdapter = MockHttpClientAdapter(); + dioHttp.httpClientAdapter = mockHttpClientAdapter; + + final client = Client( + 'api-key', + persistenceEnabled: false, + httpClient: dioHttp, + ); + + when(mockHttpClientAdapter.fetch(any, any, any)).thenAnswer( + (_) async => ResponseBody.fromString('test error', 400)); + + expect(client.get('/test'), throwsA(ApiError('test error', 400))); + }); + }); + + group('post', () { + test('should put the correct parameters', () async { + final mockDio = MockDio(); + + when(mockDio.options).thenReturn(BaseOptions()); + when(mockDio.interceptors).thenReturn(Interceptors()); + + final client = Client( + 'api-key', + persistenceEnabled: false, + httpClient: mockDio, + ); + + final Map data = { + 'test': 1, + }; + + when(mockDio.post('/test', data: data)).thenAnswer((_) async { + return Response(data: '{}', statusCode: 200); + }); + + await client.post('/test', data: data); + + verify(mockDio.post('/test', data: data)).called(1); + }); + + test('should catch the error', () async { + final dioHttp = Dio(); + final mockHttpClientAdapter = MockHttpClientAdapter(); + dioHttp.httpClientAdapter = mockHttpClientAdapter; + + final client = Client( + 'api-key', + persistenceEnabled: false, + httpClient: dioHttp, + ); + + when(mockHttpClientAdapter.fetch(any, any, any)).thenAnswer( + (_) async => ResponseBody.fromString('test error', 400)); + + expect(client.post('/test'), throwsA(ApiError('test error', 400))); + }); + }); + + group('put', () { + test('should put the correct parameters', () async { + final mockDio = MockDio(); + + when(mockDio.options).thenReturn(BaseOptions()); + when(mockDio.interceptors).thenReturn(Interceptors()); + + final client = Client( + 'api-key', + persistenceEnabled: false, + httpClient: mockDio, + ); + + final Map data = { + 'test': 1, + }; + + when(mockDio.put('/test', data: data)).thenAnswer((_) async { + return Response(data: '{}', statusCode: 200); + }); + + await client.put('/test', data: data); + + verify(mockDio.put('/test', data: data)).called(1); + }); + + test('should catch the error', () async { + final dioHttp = Dio(); + final mockHttpClientAdapter = MockHttpClientAdapter(); + dioHttp.httpClientAdapter = mockHttpClientAdapter; + + final client = Client( + 'api-key', + persistenceEnabled: false, + httpClient: dioHttp, + ); + + when(mockHttpClientAdapter.fetch(any, any, any)).thenAnswer( + (_) async => ResponseBody.fromString('test error', 400)); + + expect(client.put('/test'), throwsA(ApiError('test error', 400))); + }); + }); + + group('patch', () { + test('should put the correct parameters', () async { + final mockDio = MockDio(); + + when(mockDio.options).thenReturn(BaseOptions()); + when(mockDio.interceptors).thenReturn(Interceptors()); + + final client = Client( + 'api-key', + persistenceEnabled: false, + httpClient: mockDio, + ); + + final Map data = { + 'test': 1, + }; + + when(mockDio.patch('/test', data: data)) + .thenAnswer((_) async { + return Response(data: '{}', statusCode: 200); + }); + + await client.patch('/test', data: data); + + verify(mockDio.patch('/test', data: data)).called(1); + }); + + test('should catch the error', () async { + final dioHttp = Dio(); + final mockHttpClientAdapter = MockHttpClientAdapter(); + dioHttp.httpClientAdapter = mockHttpClientAdapter; + + final client = Client( + 'api-key', + persistenceEnabled: false, + httpClient: dioHttp, + ); + + when(mockHttpClientAdapter.fetch(any, any, any)).thenAnswer( + (_) async => ResponseBody.fromString('test error', 400)); + + expect(client.patch('/test'), throwsA(ApiError('test error', 400))); + }); + }); + + group('delete', () { + test('should put the correct parameters', () async { + final mockDio = MockDio(); + + when(mockDio.options).thenReturn(BaseOptions()); + when(mockDio.interceptors).thenReturn(Interceptors()); + + final client = Client( + 'api-key', + persistenceEnabled: false, + httpClient: mockDio, + ); + + final Map queryParams = { + 'test': 1, + }; + + when(mockDio.delete('/test', queryParameters: queryParams)) + .thenAnswer((_) async { + return Response(data: '{}', statusCode: 200); + }); + + await client.delete('/test', queryParameters: queryParams); + + verify(mockDio.delete('/test', queryParameters: queryParams)) + .called(1); + }); + + test('should catch the error', () async { + final dioHttp = Dio(); + final mockHttpClientAdapter = MockHttpClientAdapter(); + dioHttp.httpClientAdapter = mockHttpClientAdapter; + + final client = Client( + 'api-key', + persistenceEnabled: false, + httpClient: dioHttp, + ); + + when(mockHttpClientAdapter.fetch(any, any, any)).thenAnswer( + (_) async => ResponseBody.fromString('test error', 400)); + + expect(client.delete('/test'), throwsA(ApiError('test error', 400))); + }); + }); + }); + }); +} diff --git a/packages/dart_client/test/src/models/action_test.dart b/packages/dart_client/test/src/models/action_test.dart new file mode 100644 index 00000000..2f75dddb --- /dev/null +++ b/packages/dart_client/test/src/models/action_test.dart @@ -0,0 +1,46 @@ +import 'dart:convert'; + +import 'package:flutter_test/flutter_test.dart'; +import 'package:stream_chat/src/models/action.dart'; + +void main() { + group('src/models/action', () { + const jsonExample = r'''{ + "name": "name", + "style": "style", + "text": "text", + "type": "type", + "value": "value" + }'''; + + test('should parse json correctly', () { + final action = Action.fromJson(json.decode(jsonExample)); + expect(action.name, 'name'); + expect(action.style, 'style'); + expect(action.text, 'text'); + expect(action.type, 'type'); + expect(action.value, 'value'); + }); + + test('should serialize to json correctly', () { + final action = Action( + name: 'name', + style: 'style', + text: 'text', + type: 'type', + value: 'value', + ); + + expect( + action.toJson(), + { + 'name': 'name', + 'style': 'style', + 'text': 'text', + 'type': 'type', + 'value': 'value', + }, + ); + }); + }); +} diff --git a/packages/dart_client/test/src/models/attachment_test.dart b/packages/dart_client/test/src/models/attachment_test.dart new file mode 100644 index 00000000..eaa8e9cc --- /dev/null +++ b/packages/dart_client/test/src/models/attachment_test.dart @@ -0,0 +1,69 @@ +import 'package:stream_chat/src/models/attachment.dart'; +import 'package:stream_chat/src/models/action.dart'; +import 'dart:convert'; + +import 'package:flutter_test/flutter_test.dart'; + +void main() { + group('src/models/attachment', () { + const jsonExample = r'''{ + "type": "giphy", + "title": "awesome", + "title_link": "https://giphy.com/gifs/nrkp3-dance-happy-3o7TKnCdBx5cMg0qti", + "thumb_url": "https://media0.giphy.com/media/3o7TKnCdBx5cMg0qti/giphy.gif", + "actions": [ + { + "name": "image_action", + "text": "Send", + "style": "primary", + "type": "button", + "value": "send" + }, + { + "name": "image_action", + "text": "Shuffle", + "style": "default", + "type": "button", + "value": "shuffle" + }, + { + "name": "image_action", + "text": "Cancel", + "style": "default", + "type": "button", + "value": "cancel" + } + ] +}'''; + + test('should parse json correctly', () { + final attachment = Attachment.fromJson(json.decode(jsonExample)); + expect(attachment.type, "giphy"); + expect(attachment.title, "awesome"); + expect(attachment.titleLink, + "https://giphy.com/gifs/nrkp3-dance-happy-3o7TKnCdBx5cMg0qti"); + expect(attachment.thumbUrl, + "https://media0.giphy.com/media/3o7TKnCdBx5cMg0qti/giphy.gif"); + expect(attachment.actions, hasLength(3)); + expect(attachment.actions[0], isA()); + }); + + test('should serialize to json correctly', () { + final channel = Attachment( + type: "image", + title: "soo", + titleLink: + "https://giphy.com/gifs/nrkp3-dance-happy-3o7TKnCdBx5cMg0qti"); + + expect( + channel.toJson(), + { + 'type': 'image', + 'title': 'soo', + 'title_link': + 'https://giphy.com/gifs/nrkp3-dance-happy-3o7TKnCdBx5cMg0qti' + }, + ); + }); + }); +} diff --git a/packages/dart_client/test/src/models/channel_state_test.dart b/packages/dart_client/test/src/models/channel_state_test.dart new file mode 100644 index 00000000..21ffb20c --- /dev/null +++ b/packages/dart_client/test/src/models/channel_state_test.dart @@ -0,0 +1,1112 @@ +import 'dart:convert'; + +import 'package:flutter_test/flutter_test.dart'; +import 'package:stream_chat/src/models/channel_config.dart'; +import 'package:stream_chat/src/models/channel_state.dart'; +import 'package:stream_chat/src/models/command.dart'; +import 'package:stream_chat/src/models/message.dart'; +import 'package:stream_chat/src/models/user.dart'; +import 'package:stream_chat/stream_chat.dart'; + +void main() { + group('src/models/channel_state', () { + const jsonExample = r'''{ + "channel": { + "id": "dev", + "type": "team", + "cid": "team:dev", + "last_message_at": "2020-01-30T13:43:41.062362Z", + "created_at": "2019-04-03T18:43:33.213373Z", + "updated_at": "2019-04-03T18:43:33.213374Z", + "team": "test", + "created_by": { + "id": "guido", + "role": "user", + "created_at": "2019-04-03T18:43:33.201036Z", + "updated_at": "2019-04-03T18:43:33.204713Z", + "banned": false, + "online": false, + "name": "Guido" + }, + "frozen": true, + "config": { + "created_at": "2019-11-07T22:29:26.776526Z", + "updated_at": "2019-11-07T22:29:48.286746Z", + "name": "team", + "typing_events": true, + "read_events": true, + "connect_events": true, + "search": true, + "reactions": true, + "replies": true, + "mutes": true, + "uploads": true, + "url_enrichment": true, + "message_retention": "infinite", + "max_message_length": 5000, + "automod": "disabled", + "automod_behavior": "flag", + "commands": [ + { + "name": "giphy", + "description": "Post a random gif to the channel", + "args": "[text]", + "set": "fun_set" + } + ] + }, + "name": "#dev", + "image": "https://cdn.chrisshort.net/testing-certificate-chains-in-go/GOPHER_MIC_DROP.png", + "example": 1 + }, + "messages": [ + { + "id": "dry-meadow-0-2b73cc8b-cd86-4a01-8d40-bd82ad07a030", + "text": "fasdfa", + "type": "regular", + "status": "SENT", + "silent": false, + "user": { + "id": "dry-meadow-0", + "role": "user", + "created_at": "2019-03-27T17:40:17.155892Z", + "updated_at": "2020-01-29T03:22:47.641589Z", + "last_active": "2020-01-29T03:22:47.63613Z", + "banned": false, + "online": false, + "image": "https://getstream.io/random_svg/?name=Dry+meadow", + "name": "Dry meadow" + }, + "attachments": [], + "latest_reactions": [], + "own_reactions": [], + "reaction_counts": {}, + "reaction_scores": {}, + "reply_count": 0, + "created_at": "2020-01-29T03:23:02.843948Z", + "updated_at": "2020-01-29T03:23:02.843949Z", + "mentioned_users": [], + "status": "SENT", + "silent": false + }, + { + "id": "dry-meadow-0-e8e74482-b4cd-48db-9d1e-30e6c191786f", + "text": "test message", + "type": "regular", + "user": { + "id": "dry-meadow-0", + "role": "user", + "created_at": "2019-03-27T17:40:17.155892Z", + "updated_at": "2020-01-29T03:22:47.641589Z", + "last_active": "2020-01-29T03:22:47.63613Z", + "banned": false, + "online": false, + "image": "https://getstream.io/random_svg/?name=Dry+meadow", + "name": "Dry meadow" + }, + "attachments": [], + "latest_reactions": [], + "own_reactions": [], + "reaction_counts": {}, + "reaction_scores": {}, + "reply_count": 0, + "created_at": "2020-01-29T03:23:07.981091Z", + "updated_at": "2020-01-29T03:23:07.981091Z", + "mentioned_users": [], + "status": "SENT", + "silent": false + }, + { + "id": "dry-meadow-0-53e6299f-9b97-4a9c-a27e-7e2dde49b7e0", + "text": "test message", + "type": "regular", + "user": { + "id": "dry-meadow-0", + "role": "user", + "created_at": "2019-03-27T17:40:17.155892Z", + "updated_at": "2020-01-29T03:22:47.641589Z", + "last_active": "2020-01-29T03:22:47.63613Z", + "banned": false, + "online": false, + "image": "https://getstream.io/random_svg/?name=Dry+meadow", + "name": "Dry meadow" + }, + "attachments": [], + "latest_reactions": [], + "own_reactions": [], + "reaction_counts": {}, + "reaction_scores": {}, + "reply_count": 0, + "created_at": "2020-01-29T03:23:11.568022Z", + "updated_at": "2020-01-29T03:23:11.568022Z", + "mentioned_users": [], + "status": "SENT", + "silent": false + }, + { + "id": "dry-meadow-0-80925be0-786e-40a5-b225-486518dafd35", + "text": "asdfadf", + "type": "regular", + "user": { + "id": "dry-meadow-0", + "role": "user", + "created_at": "2019-03-27T17:40:17.155892Z", + "updated_at": "2020-01-29T03:22:47.641589Z", + "last_active": "2020-01-29T03:22:47.63613Z", + "banned": false, + "online": false, + "image": "https://getstream.io/random_svg/?name=Dry+meadow", + "name": "Dry meadow" + }, + "attachments": [], + "latest_reactions": [], + "own_reactions": [], + "reaction_counts": {}, + "reaction_scores": {}, + "reply_count": 0, + "created_at": "2020-01-29T03:32:57.403566Z", + "updated_at": "2020-01-29T03:32:57.403566Z", + "mentioned_users": [], + "status": "SENT", + "silent": false + }, + { + "id": "dry-meadow-0-64d7970f-ede8-4b31-9738-1bc1756d2bfe", + "text": "test", + "type": "regular", + "user": { + "id": "dry-meadow-0", + "role": "user", + "created_at": "2019-03-27T17:40:17.155892Z", + "updated_at": "2020-01-29T03:22:47.641589Z", + "last_active": "2020-01-29T03:22:47.63613Z", + "banned": false, + "online": false, + "image": "https://getstream.io/random_svg/?name=Dry+meadow", + "name": "Dry meadow" + }, + "attachments": [], + "latest_reactions": [], + "own_reactions": [], + "reaction_counts": {}, + "reaction_scores": {}, + "reply_count": 0, + "created_at": "2020-01-29T03:33:35.294802Z", + "updated_at": "2020-01-29T03:33:35.294802Z", + "mentioned_users": [], + "status": "SENT", + "silent": false + }, + { + "id": "withered-cell-0-84cbd760-cf55-4f7e-9207-c5f66cccc6dc", + "text": "hi", + "type": "regular", + "user": { + "id": "withered-cell-0", + "role": "user", + "created_at": "2020-01-29T03:34:01.698106Z", + "updated_at": "2020-01-29T03:34:01.708808Z", + "last_active": "2020-01-29T03:34:01.70353Z", + "banned": false, + "online": false, + "name": "Withered cell", + "image": "https://getstream.io/random_svg/?name=Withered+cell" + }, + "attachments": [], + "latest_reactions": [], + "own_reactions": [], + "reaction_counts": {}, + "reaction_scores": {}, + "reply_count": 0, + "created_at": "2020-01-29T03:34:27.393296Z", + "updated_at": "2020-01-29T03:34:27.393296Z", + "mentioned_users": [], + "status": "SENT", + "silent": false + }, + { + "id": "dry-meadow-0-e9203588-43c3-40b1-91f7-f217fc42aa53", + "text": "fantastic", + "type": "regular", + "user": { + "id": "dry-meadow-0", + "role": "user", + "created_at": "2019-03-27T17:40:17.155892Z", + "updated_at": "2020-01-29T03:22:47.641589Z", + "last_active": "2020-01-29T03:22:47.63613Z", + "banned": false, + "online": false, + "image": "https://getstream.io/random_svg/?name=Dry+meadow", + "name": "Dry meadow" + }, + "attachments": [], + "latest_reactions": [], + "own_reactions": [], + "reaction_counts": {}, + "reaction_scores": {}, + "reply_count": 0, + "created_at": "2020-01-29T03:34:37.638376Z", + "updated_at": "2020-01-29T03:34:37.638376Z", + "mentioned_users": [], + "status": "SENT", + "silent": false + }, + { + "id": "withered-cell-0-7e3552d7-7a0d-45f2-a856-e91b23a7e240", + "text": "nice to meet you", + "type": "regular", + "user": { + "id": "withered-cell-0", + "role": "user", + "created_at": "2020-01-29T03:34:01.698106Z", + "updated_at": "2020-01-29T03:34:01.708808Z", + "last_active": "2020-01-29T03:34:01.70353Z", + "banned": false, + "online": false, + "image": "https://getstream.io/random_svg/?name=Withered+cell", + "name": "Withered cell" + }, + "attachments": [], + "latest_reactions": [], + "own_reactions": [], + "reaction_counts": {}, + "reaction_scores": {}, + "reply_count": 0, + "created_at": "2020-01-29T03:35:04.301566Z", + "updated_at": "2020-01-29T03:35:04.301566Z", + "mentioned_users": [], + "status": "SENT", + "silent": false + }, + { + "id": "dry-meadow-0-1ffeafd4-e4fc-4c84-9394-9d7cb10fff42", + "text": "hey", + "type": "regular", + "user": { + "id": "dry-meadow-0", + "role": "user", + "created_at": "2019-03-27T17:40:17.155892Z", + "updated_at": "2020-01-29T03:22:47.641589Z", + "last_active": "2020-01-29T03:22:47.63613Z", + "banned": false, + "online": false, + "image": "https://getstream.io/random_svg/?name=Dry+meadow", + "name": "Dry meadow" + }, + "attachments": [], + "latest_reactions": [], + "own_reactions": [], + "reaction_counts": {}, + "reaction_scores": {}, + "reply_count": 0, + "created_at": "2020-01-29T03:35:24.939084Z", + "updated_at": "2020-01-29T03:35:24.939085Z", + "mentioned_users": [], + "status": "SENT", + "silent": false + }, + { + "id": "dry-meadow-0-3f147324-12c8-4b41-9fb5-2db88d065efa", + "text": "hello, everyone", + "type": "regular", + "user": { + "id": "dry-meadow-0", + "role": "user", + "created_at": "2019-03-27T17:40:17.155892Z", + "updated_at": "2020-01-29T03:22:47.641589Z", + "last_active": "2020-01-29T03:22:47.63613Z", + "banned": false, + "online": false, + "name": "Dry meadow", + "image": "https://getstream.io/random_svg/?name=Dry+meadow" + }, + "attachments": [], + "latest_reactions": [], + "own_reactions": [], + "reaction_counts": {}, + "reaction_scores": {}, + "reply_count": 0, + "created_at": "2020-01-29T03:35:33.101566Z", + "updated_at": "2020-01-29T03:35:33.101566Z", + "mentioned_users": [], + "status": "SENT", + "silent": false + }, + { + "id": "dry-meadow-0-51a348ae-0c0a-44de-a556-eac7891c0cf0", + "text": "who is there?", + "type": "regular", + "user": { + "id": "dry-meadow-0", + "role": "user", + "created_at": "2019-03-27T17:40:17.155892Z", + "updated_at": "2020-01-29T03:22:47.641589Z", + "last_active": "2020-01-29T03:22:47.63613Z", + "banned": false, + "online": false, + "name": "Dry meadow", + "image": "https://getstream.io/random_svg/?name=Dry+meadow" + }, + "attachments": [], + "latest_reactions": [], + "own_reactions": [], + "reaction_counts": {}, + "reaction_scores": {}, + "reply_count": 0, + "created_at": "2020-01-29T03:35:45.458685Z", + "updated_at": "2020-01-29T03:35:45.458685Z", + "mentioned_users": [], + "status": "SENT", + "silent": false + }, + { + "id": "icy-recipe-7-a29e237b-8d81-4a97-9bc8-d42bca3f1356", + "text": "하이", + "type": "regular", + "user": { + "id": "icy-recipe-7", + "role": "user", + "created_at": "2020-01-21T11:36:22.284503Z", + "updated_at": "2020-01-29T07:01:59.69882Z", + "last_active": "2020-01-29T07:01:59.693378Z", + "banned": false, + "online": false, + "image": "https://getstream.io/random_svg/?name=Icy+recipe", + "name": "Icy recipe" + }, + "attachments": [], + "latest_reactions": [], + "own_reactions": [], + "reaction_counts": {}, + "reaction_scores": {}, + "reply_count": 0, + "created_at": "2020-01-29T07:02:11.535395Z", + "updated_at": "2020-01-29T07:02:11.535395Z", + "mentioned_users": [], + "status": "SENT", + "silent": false + }, + { + "id": "icy-recipe-7-935c396e-ddf8-4a9a-951c-0a12fa5bf055", + "text": "what are you doing?", + "type": "regular", + "user": { + "id": "icy-recipe-7", + "role": "user", + "created_at": "2020-01-21T11:36:22.284503Z", + "updated_at": "2020-01-29T07:01:59.69882Z", + "last_active": "2020-01-29T07:01:59.693378Z", + "banned": false, + "online": false, + "image": "https://getstream.io/random_svg/?name=Icy+recipe", + "name": "Icy recipe" + }, + "attachments": [], + "latest_reactions": [], + "own_reactions": [], + "reaction_counts": {}, + "reaction_scores": {}, + "reply_count": 0, + "created_at": "2020-01-29T07:02:22.485136Z", + "updated_at": "2020-01-29T07:02:22.485136Z", + "mentioned_users": [], + "status": "SENT", + "silent": false + }, + { + "id": "throbbing-boat-5-1e4d5730-5ff0-4d25-9948-9f34ffda43e4", + "text": "👍", + "type": "regular", + "user": { + "id": "throbbing-boat-5", + "role": "user", + "created_at": "2019-07-30T06:29:53.060413Z", + "updated_at": "2020-01-29T14:11:27.80176Z", + "last_active": "2020-01-29T14:11:27.7963Z", + "banned": false, + "online": false, + "image": "https://getstream.io/random_svg/?name=Throbbing+boat", + "name": "Throbbing boat" + }, + "attachments": [], + "latest_reactions": [], + "own_reactions": [], + "reaction_counts": {}, + "reaction_scores": {}, + "reply_count": 0, + "created_at": "2020-01-29T14:12:04.688552Z", + "updated_at": "2020-01-29T14:12:04.688552Z", + "mentioned_users": [], + "status": "SENT", + "silent": false + }, + { + "id": "snowy-credit-3-3e0c1a0d-d22f-42ee-b2a1-f9f49477bf21", + "text": "sdasas", + "type": "regular", + "user": { + "id": "snowy-credit-3", + "role": "user", + "created_at": "2020-01-29T15:29:03.693312Z", + "updated_at": "2020-01-29T15:29:03.702648Z", + "last_active": "2020-01-29T15:29:03.696144Z", + "banned": false, + "online": false, + "image": "https://getstream.io/random_svg/?name=Snowy+credit", + "name": "Snowy credit" + }, + "attachments": [], + "latest_reactions": [], + "own_reactions": [], + "reaction_counts": {}, + "reaction_scores": {}, + "reply_count": 0, + "created_at": "2020-01-29T15:29:36.011315Z", + "updated_at": "2020-01-29T15:29:36.011316Z", + "mentioned_users": [], + "status": "SENT", + "silent": false + }, + { + "id": "snowy-credit-3-3319537e-2d0e-4876-8170-a54f046e4b7d", + "text": "cjshsa", + "type": "regular", + "user": { + "id": "snowy-credit-3", + "role": "user", + "created_at": "2020-01-29T15:29:03.693312Z", + "updated_at": "2020-01-29T15:29:03.702648Z", + "last_active": "2020-01-29T15:29:03.696144Z", + "banned": false, + "online": false, + "image": "https://getstream.io/random_svg/?name=Snowy+credit", + "name": "Snowy credit" + }, + "attachments": [], + "latest_reactions": [], + "own_reactions": [], + "reaction_counts": {}, + "reaction_scores": {}, + "reply_count": 0, + "created_at": "2020-01-29T15:29:41.677819Z", + "updated_at": "2020-01-29T15:29:41.677819Z", + "mentioned_users": [], + "status": "SENT", + "silent": false + }, + { + "id": "snowy-credit-3-cfaf0b46-1daa-49c5-947c-b16d6697487d", + "text": "nhisagdhsadz", + "type": "regular", + "user": { + "id": "snowy-credit-3", + "role": "user", + "created_at": "2020-01-29T15:29:03.693312Z", + "updated_at": "2020-01-29T15:29:03.702648Z", + "last_active": "2020-01-29T15:29:03.696144Z", + "banned": false, + "online": false, + "image": "https://getstream.io/random_svg/?name=Snowy+credit", + "name": "Snowy credit" + }, + "attachments": [], + "latest_reactions": [], + "own_reactions": [], + "reaction_counts": {}, + "reaction_scores": {}, + "reply_count": 0, + "created_at": "2020-01-29T15:29:43.354177Z", + "updated_at": "2020-01-29T15:29:43.354177Z", + "mentioned_users": [], + "status": "SENT", + "silent": false + }, + { + "id": "snowy-credit-3-cebe25a7-a3a3-49fc-9919-91c6725e81f3", + "text": "hvadhsahzd", + "type": "regular", + "user": { + "id": "snowy-credit-3", + "role": "user", + "created_at": "2020-01-29T15:29:03.693312Z", + "updated_at": "2020-01-29T15:29:03.702648Z", + "last_active": "2020-01-29T15:29:03.696144Z", + "banned": false, + "online": false, + "image": "https://getstream.io/random_svg/?name=Snowy+credit", + "name": "Snowy credit" + }, + "attachments": [], + "latest_reactions": [], + "own_reactions": [], + "reaction_counts": {}, + "reaction_scores": {}, + "reply_count": 0, + "created_at": "2020-01-29T15:29:44.754713Z", + "updated_at": "2020-01-29T15:29:44.754713Z", + "mentioned_users": [], + "status": "SENT", + "silent": false + }, + { + "id": "divine-glade-9-0cea9262-5766-48e9-8b22-311870aed3bf", + "text": "hello", + "type": "regular", + "user": { + "id": "divine-glade-9", + "role": "user", + "created_at": "2020-01-29T17:02:18.312524Z", + "updated_at": "2020-01-29T17:02:18.320187Z", + "last_active": "2020-01-29T17:02:18.315074Z", + "banned": false, + "online": false, + "image": "https://getstream.io/random_svg/?name=Divine+glade", + "name": "Divine glade" + }, + "attachments": [], + "latest_reactions": [], + "own_reactions": [], + "reaction_counts": {}, + "reaction_scores": {}, + "reply_count": 0, + "created_at": "2020-01-29T17:02:36.933852Z", + "updated_at": "2020-01-29T17:02:36.933852Z", + "mentioned_users": [], + "status": "SENT", + "silent": false + }, + { + "id": "red-firefly-9-c4e9007b-bb7d-4238-ae08-5f8e3cd03d73", + "text": "hello", + "type": "regular", + "user": { + "id": "red-firefly-9", + "role": "user", + "created_at": "2019-08-02T18:56:39.366516Z", + "updated_at": "2020-01-29T22:13:50.491769Z", + "last_active": "2020-01-29T22:13:50.450215Z", + "banned": false, + "online": false, + "image": "https://getstream.io/random_svg/?name=Red+firefly", + "name": "Red firefly" + }, + "attachments": [], + "latest_reactions": [], + "own_reactions": [], + "reaction_counts": {}, + "reaction_scores": {}, + "reply_count": 0, + "created_at": "2020-01-29T22:14:08.54062Z", + "updated_at": "2020-01-29T22:14:08.54062Z", + "mentioned_users": [], + "status": "SENT", + "silent": false + }, + { + "id": "bitter-glade-2-02aee4eb-4093-4736-808b-2de75820e854", + "text": "hello", + "type": "regular", + "user": { + "id": "bitter-glade-2", + "role": "user", + "created_at": "2020-01-30T13:08:56.190678Z", + "updated_at": "2020-01-30T13:08:56.200333Z", + "last_active": "2020-01-30T13:08:56.193882Z", + "banned": false, + "online": false, + "image": "https://getstream.io/random_svg/?name=Bitter+glade", + "name": "Bitter glade" + }, + "attachments": [], + "latest_reactions": [], + "own_reactions": [], + "reaction_counts": {}, + "reaction_scores": {}, + "reply_count": 0, + "created_at": "2020-01-30T13:11:37.191293Z", + "updated_at": "2020-01-30T13:11:37.191293Z", + "mentioned_users": [], + "status": "SENT", + "silent": false + }, + { + "id": "morning-sea-1-0c700bcb-46dd-4224-b590-e77bdbccc480", + "text": "http://jaeger.ui.gtstrm.com/", + "type": "regular", + "user": { + "id": "morning-sea-1", + "role": "user", + "created_at": "2019-07-22T09:19:07.505207Z", + "updated_at": "2020-01-30T13:33:05.831856Z", + "last_active": "2020-01-30T13:33:05.825369Z", + "banned": false, + "online": false, + "image": "https://getstream.io/random_svg/?name=Morning+sea", + "name": "Morning sea" + }, + "attachments": [], + "latest_reactions": [], + "own_reactions": [], + "reaction_counts": {}, + "reaction_scores": {}, + "reply_count": 0, + "created_at": "2020-01-30T13:33:16.853116Z", + "updated_at": "2020-01-30T13:33:16.853116Z", + "mentioned_users": [], + "status": "SENT", + "silent": false + }, + { + "id": "ancient-salad-0-53e8b4e6-5b7b-43ad-aeee-8bfb6a9ed0be", + "text": "hi", + "type": "regular", + "user": { + "id": "ancient-salad-0", + "role": "user", + "created_at": "2020-01-30T13:34:29.286813Z", + "updated_at": "2020-01-30T13:34:29.296196Z", + "last_active": "2020-01-30T13:34:29.289964Z", + "banned": false, + "online": true, + "image": "https://getstream.io/random_svg/?name=Ancient+salad", + "name": "Ancient salad" + }, + "attachments": [], + "latest_reactions": [], + "own_reactions": [], + "reaction_counts": {}, + "reaction_scores": {}, + "reply_count": 0, + "created_at": "2020-01-30T13:36:52.749731Z", + "updated_at": "2020-01-30T13:36:52.749732Z", + "mentioned_users": [], + "status": "SENT", + "silent": false + }, + { + "id": "ancient-salad-0-8c225075-bd4c-42e2-8024-530aae13cd40", + "text": "hi", + "type": "regular", + "user": { + "id": "ancient-salad-0", + "role": "user", + "created_at": "2020-01-30T13:34:29.286813Z", + "updated_at": "2020-01-30T13:34:29.296196Z", + "last_active": "2020-01-30T13:34:29.289964Z", + "banned": false, + "online": true, + "image": "https://getstream.io/random_svg/?name=Ancient+salad", + "name": "Ancient salad" + }, + "attachments": [], + "latest_reactions": [], + "own_reactions": [], + "reaction_counts": {}, + "reaction_scores": {}, + "reply_count": 0, + "created_at": "2020-01-30T13:37:41.631056Z", + "updated_at": "2020-01-30T13:37:41.631056Z", + "mentioned_users": [], + "status": "SENT", + "silent": false + }, + { + "id": "proud-sea-7-17802096-cbf8-4e3c-addd-4ee31f4c8b5c", + "text": "😃", + "type": "regular", + "user": { + "id": "proud-sea-7", + "role": "user", + "created_at": "2020-01-30T13:43:03.903006Z", + "updated_at": "2020-01-30T13:43:03.912307Z", + "last_active": "2020-01-30T13:43:03.906236Z", + "banned": false, + "online": false, + "image": "https://getstream.io/random_svg/?name=Proud+sea", + "name": "Proud sea" + }, + "attachments": [], + "latest_reactions": [], + "own_reactions": [], + "reaction_counts": {}, + "reaction_scores": {}, + "reply_count": 0, + "created_at": "2020-01-30T13:43:41.062362Z", + "updated_at": "2020-01-30T13:43:41.062362Z", + "mentioned_users": [], + "status": "SENT", + "silent": false + } + ], + "watcher_count": 5, + "members": [] + }'''; + + test('should parse json correctly', () { + final channelState = ChannelState.fromJson(json.decode(jsonExample)); + expect(channelState.channel.cid, 'team:dev'); + expect(channelState.channel.id, 'dev'); + expect(channelState.channel.team, 'test'); + expect(channelState.channel.type, 'team'); + expect(channelState.channel.config, isA()); + expect(channelState.channel.config, isNotNull); + expect(channelState.channel.config.commands, hasLength(1)); + expect(channelState.channel.config.commands[0], isA()); + expect(channelState.channel.lastMessageAt, + DateTime.parse("2020-01-30T13:43:41.062362Z")); + expect(channelState.channel.createdAt, + DateTime.parse("2019-04-03T18:43:33.213373Z")); + expect(channelState.channel.updatedAt, + DateTime.parse("2019-04-03T18:43:33.213374Z")); + expect(channelState.channel.createdBy, isA()); + expect(channelState.channel.frozen, true); + expect(channelState.channel.extraData['example'], 1); + expect(channelState.channel.extraData['name'], "#dev"); + expect(channelState.channel.extraData['image'], + "https://cdn.chrisshort.net/testing-certificate-chains-in-go/GOPHER_MIC_DROP.png"); + expect(channelState.messages, hasLength(25)); + expect(channelState.messages[0], isA()); + expect(channelState.messages[0], isNotNull); + expect(channelState.messages[0].createdAt, + DateTime.parse("2020-01-29T03:23:02.843948Z")); + expect(channelState.messages[0].user, isA()); + expect(channelState.watcherCount, 5); + }); + + test('should serialize to json correctly', () { + const toJsonExample = r''' + { + "channel": { + "id": "dev", + "type": "team", + "frozen": true, + "name": "#dev", + "image": "https://cdn.chrisshort.net/testing-certificate-chains-in-go/GOPHER_MIC_DROP.png", + "example": 1 + }, + "watchers": null, + "read": null, + "messages": [ + { + "id": "dry-meadow-0-2b73cc8b-cd86-4a01-8d40-bd82ad07a030", + "text": "fasdfa", + "attachments": [], + "parent_id": null, + "quoted_message": null, + "quoted_message_id": null, + "show_in_channel": null, + "mentioned_users": [], + "status": "SENT", + "silent": false + }, + { + "id": "dry-meadow-0-e8e74482-b4cd-48db-9d1e-30e6c191786f", + "text": "test message", + "attachments": [], + "parent_id": null, + "quoted_message": null, + "quoted_message_id": null, + "show_in_channel": null, + "mentioned_users": [], + "status": "SENT", + "silent": false + }, + { + "id": "dry-meadow-0-53e6299f-9b97-4a9c-a27e-7e2dde49b7e0", + "text": "test message", + "attachments": [], + "parent_id": null, + "quoted_message": null, + "quoted_message_id": null, + "show_in_channel": null, + "mentioned_users": [], + "status": "SENT", + "silent": false + }, + { + "id": "dry-meadow-0-80925be0-786e-40a5-b225-486518dafd35", + "text": "asdfadf", + "attachments": [], + "parent_id": null, + "quoted_message": null, + "quoted_message_id": null, + "show_in_channel": null, + "mentioned_users": [], + "status": "SENT", + "silent": false + }, + { + "id": "dry-meadow-0-64d7970f-ede8-4b31-9738-1bc1756d2bfe", + "text": "test", + "attachments": [], + "parent_id": null, + "quoted_message": null, + "quoted_message_id": null, + "show_in_channel": null, + "mentioned_users": [], + "status": "SENT", + "silent": false + }, + { + "id": "withered-cell-0-84cbd760-cf55-4f7e-9207-c5f66cccc6dc", + "text": "hi", + "attachments": [], + "parent_id": null, + "quoted_message": null, + "quoted_message_id": null, + "show_in_channel": null, + "mentioned_users": [], + "status": "SENT", + "silent": false + }, + { + "id": "dry-meadow-0-e9203588-43c3-40b1-91f7-f217fc42aa53", + "text": "fantastic", + "attachments": [], + "parent_id": null, + "quoted_message": null, + "quoted_message_id": null, + "show_in_channel": null, + "mentioned_users": [], + "status": "SENT", + "silent": false + }, + { + "id": "withered-cell-0-7e3552d7-7a0d-45f2-a856-e91b23a7e240", + "text": "nice to meet you", + "attachments": [], + "parent_id": null, + "quoted_message": null, + "quoted_message_id": null, + "show_in_channel": null, + "mentioned_users": [], + "status": "SENT", + "silent": false + }, + { + "id": "dry-meadow-0-1ffeafd4-e4fc-4c84-9394-9d7cb10fff42", + "text": "hey", + "attachments": [], + "parent_id": null, + "quoted_message": null, + "quoted_message_id": null, + "show_in_channel": null, + "mentioned_users": [], + "status": "SENT", + "silent": false + }, + { + "id": "dry-meadow-0-3f147324-12c8-4b41-9fb5-2db88d065efa", + "text": "hello, everyone", + "attachments": [], + "parent_id": null, + "quoted_message": null, + "quoted_message_id": null, + "show_in_channel": null, + "mentioned_users": [], + "status": "SENT", + "silent": false + }, + { + "id": "dry-meadow-0-51a348ae-0c0a-44de-a556-eac7891c0cf0", + "text": "who is there?", + "attachments": [], + "parent_id": null, + "quoted_message": null, + "quoted_message_id": null, + "show_in_channel": null, + "mentioned_users": [], + "status": "SENT", + "silent": false + }, + { + "id": "icy-recipe-7-a29e237b-8d81-4a97-9bc8-d42bca3f1356", + "text": "하이", + "attachments": [], + "parent_id": null, + "quoted_message": null, + "quoted_message_id": null, + "show_in_channel": null, + "mentioned_users": [], + "status": "SENT", + "silent": false + }, + { + "id": "icy-recipe-7-935c396e-ddf8-4a9a-951c-0a12fa5bf055", + "text": "what are you doing?", + "attachments": [], + "parent_id": null, + "quoted_message": null, + "quoted_message_id": null, + "show_in_channel": null, + "mentioned_users": [], + "status": "SENT", + "silent": false + }, + { + "id": "throbbing-boat-5-1e4d5730-5ff0-4d25-9948-9f34ffda43e4", + "text": "👍", + "attachments": [], + "parent_id": null, + "quoted_message": null, + "quoted_message_id": null, + "show_in_channel": null, + "mentioned_users": [], + "status": "SENT", + "silent": false + }, + { + "id": "snowy-credit-3-3e0c1a0d-d22f-42ee-b2a1-f9f49477bf21", + "text": "sdasas", + "attachments": [], + "parent_id": null, + "quoted_message": null, + "quoted_message_id": null, + "show_in_channel": null, + "mentioned_users": [], + "status": "SENT", + "silent": false + }, + { + "id": "snowy-credit-3-3319537e-2d0e-4876-8170-a54f046e4b7d", + "text": "cjshsa", + "attachments": [], + "parent_id": null, + "quoted_message": null, + "quoted_message_id": null, + "show_in_channel": null, + "mentioned_users": [], + "status": "SENT", + "silent": false + }, + { + "id": "snowy-credit-3-cfaf0b46-1daa-49c5-947c-b16d6697487d", + "text": "nhisagdhsadz", + "attachments": [], + "parent_id": null, + "quoted_message": null, + "quoted_message_id": null, + "show_in_channel": null, + "mentioned_users": [], + "status": "SENT", + "silent": false + }, + { + "id": "snowy-credit-3-cebe25a7-a3a3-49fc-9919-91c6725e81f3", + "text": "hvadhsahzd", + "attachments": [], + "parent_id": null, + "quoted_message": null, + "quoted_message_id": null, + "show_in_channel": null, + "mentioned_users": [], + "status": "SENT", + "silent": false + }, + { + "id": "divine-glade-9-0cea9262-5766-48e9-8b22-311870aed3bf", + "text": "hello", + "attachments": [], + "parent_id": null, + "quoted_message": null, + "quoted_message_id": null, + "show_in_channel": null, + "mentioned_users": [], + "status": "SENT", + "silent": false + }, + { + "id": "red-firefly-9-c4e9007b-bb7d-4238-ae08-5f8e3cd03d73", + "text": "hello", + "attachments": [], + "parent_id": null, + "quoted_message": null, + "quoted_message_id": null, + "show_in_channel": null, + "mentioned_users": [], + "status": "SENT", + "silent": false + }, + { + "id": "bitter-glade-2-02aee4eb-4093-4736-808b-2de75820e854", + "text": "hello", + "attachments": [], + "parent_id": null, + "quoted_message": null, + "quoted_message_id": null, + "show_in_channel": null, + "mentioned_users": [], + "status": "SENT", + "silent": false + }, + { + "id": "morning-sea-1-0c700bcb-46dd-4224-b590-e77bdbccc480", + "text": "http://jaeger.ui.gtstrm.com/", + "attachments": [], + "parent_id": null, + "quoted_message": null, + "quoted_message_id": null, + "show_in_channel": null, + "mentioned_users": [], + "status": "SENT", + "silent": false + }, + { + "id": "ancient-salad-0-53e8b4e6-5b7b-43ad-aeee-8bfb6a9ed0be", + "text": "hi", + "attachments": [], + "parent_id": null, + "quoted_message": null, + "quoted_message_id": null, + "show_in_channel": null, + "mentioned_users": [], + "status": "SENT", + "silent": false + }, + { + "id": "ancient-salad-0-8c225075-bd4c-42e2-8024-530aae13cd40", + "text": "hi", + "attachments": [], + "parent_id": null, + "quoted_message": null, + "quoted_message_id": null, + "show_in_channel": null, + "mentioned_users": [], + "status": "SENT", + "silent": false + }, + { + "id": "proud-sea-7-17802096-cbf8-4e3c-addd-4ee31f4c8b5c", + "text": "😃", + "attachments": [], + "parent_id": null, + "quoted_message": null, + "quoted_message_id": null, + "show_in_channel": null, + "mentioned_users": [], + "status": "SENT", + "silent": false + } + ], + "members": [], + "watcher_count": 5 + } + '''; + final j = jsonDecode(jsonExample); + final channelState = ChannelState( + channel: ChannelModel.fromJson(j['channel']), + members: [], + messages: + (j['messages'] as List).map((m) => Message.fromJson(m)).toList(), + read: null, + watcherCount: 5, + watchers: null, + ); + + expect( + channelState.toJson(), + jsonDecode(toJsonExample), + ); + }); + }); +} diff --git a/packages/dart_client/test/src/models/channel_test.dart b/packages/dart_client/test/src/models/channel_test.dart new file mode 100644 index 00000000..7197d083 --- /dev/null +++ b/packages/dart_client/test/src/models/channel_test.dart @@ -0,0 +1,56 @@ +import 'dart:convert'; + +import 'package:flutter_test/flutter_test.dart'; +import 'package:stream_chat/src/models/channel_model.dart'; + +void main() { + group('src/models/channel', () { + const jsonExample = ''' + { + "id": "test", + "type": "livestream", + "cid": "test:livestream", + "cats": true, + "fruit": ["bananas", "apples"] + } + '''; + + test('should parse json correctly', () { + final channel = ChannelModel.fromJson(json.decode(jsonExample)); + expect(channel.id, equals("test")); + expect(channel.type, equals("livestream")); + expect(channel.cid, equals("test:livestream")); + expect(channel.extraData["cats"], equals(true)); + expect(channel.extraData["fruit"], equals(["bananas", "apples"])); + }); + + test('should serialize to json correctly', () { + final channel = ChannelModel( + type: "type", + id: "id", + cid: "a:a", + extraData: {"name": "cool"}, + ); + + expect( + channel.toJson(), + {'id': 'id', 'type': 'type', 'name': 'cool'}, + ); + }); + + test('should serialize to json correctly when frozen is provided', () { + final channel = ChannelModel( + type: "type", + id: "id", + cid: "a:a", + extraData: {"name": "cool"}, + frozen: false, + ); + + expect( + channel.toJson(), + {'id': 'id', 'type': 'type', 'name': 'cool', 'frozen': false}, + ); + }); + }); +} diff --git a/packages/dart_client/test/src/models/command_test.dart b/packages/dart_client/test/src/models/command_test.dart new file mode 100644 index 00000000..51774b84 --- /dev/null +++ b/packages/dart_client/test/src/models/command_test.dart @@ -0,0 +1,40 @@ +import 'package:stream_chat/src/models/command.dart'; +import 'dart:convert'; + +import 'package:flutter_test/flutter_test.dart'; + +void main() { + group('src/models/command', () { + const jsonExample = ''' + { + "name": "giphy", + "description": "Post a random gif to the channel", + "args": "[text]" + } + '''; + + test('should parse json correctly', () { + final command = Command.fromJson(json.decode(jsonExample)); + expect(command.name, 'giphy'); + expect(command.description, 'Post a random gif to the channel'); + expect(command.args, '[text]'); + }); + + test('should serialize to json correctly', () { + final command = Command( + name: 'giphy', + description: 'Post a random gif to the channel', + args: '[text]', + ); + + expect( + command.toJson(), + { + "name": "giphy", + "description": "Post a random gif to the channel", + "args": "[text]", + }, + ); + }); + }); +} diff --git a/packages/dart_client/test/src/models/device_test.dart b/packages/dart_client/test/src/models/device_test.dart new file mode 100644 index 00000000..3f68929f --- /dev/null +++ b/packages/dart_client/test/src/models/device_test.dart @@ -0,0 +1,31 @@ +import 'dart:convert'; + +import 'package:flutter_test/flutter_test.dart'; +import 'package:stream_chat/src/models/device.dart'; + +void main() { + group('src/models/device', () { + const jsonExample = r'''{ + "id": "device-id", + "push_provider": "push-provider" + }'''; + + test('should parse json correctly', () { + final device = Device.fromJson(json.decode(jsonExample)); + expect(device.id, 'device-id'); + expect(device.pushProvider, 'push-provider'); + }); + + test('should serialize to json correctly', () { + final device = Device(id: 'device-id', pushProvider: 'push-provider'); + + expect( + device.toJson(), + { + 'id': 'device-id', + 'push_provider': 'push-provider', + }, + ); + }); + }); +} diff --git a/packages/dart_client/test/src/models/event_test.dart b/packages/dart_client/test/src/models/event_test.dart new file mode 100644 index 00000000..eb7d0f5a --- /dev/null +++ b/packages/dart_client/test/src/models/event_test.dart @@ -0,0 +1,89 @@ +import 'dart:convert'; + +import 'package:flutter_test/flutter_test.dart'; +import 'package:stream_chat/src/models/event.dart'; +import 'package:stream_chat/src/models/own_user.dart'; +import 'package:stream_chat/stream_chat.dart'; + +void main() { + group('src/models/event', () { + const jsonExample = ''' + { + "type": "type", + "cid": "cid", + "connection_id": "connectionId", + "created_at": "2019-04-03T18:43:33.213374Z", + "me": { + "id": "dry-meadow-0", + "role": "user", + "created_at": "2019-03-27T17:40:17.155892Z", + "updated_at": "2020-01-29T03:22:47.641589Z", + "last_active": "2020-01-29T03:22:47.63613Z", + "banned": false, + "online": false, + "image": "https://getstream.io/random_svg/?name=Dry+meadow", + "name": "Dry meadow" + }, + "parent_id": null, + "user": { + "id": "dry-meadow-0", + "role": "user", + "created_at": "2019-03-27T17:40:17.155892Z", + "updated_at": "2020-01-29T03:22:47.641589Z", + "last_active": "2020-01-29T03:22:47.63613Z", + "banned": false, + "online": false, + "image": "https://getstream.io/random_svg/?name=Dry+meadow", + "name": "Dry meadow" + } + } + '''; + + test('should parse json correctly', () { + final event = Event.fromJson(json.decode(jsonExample)); + expect(event.type, 'type'); + expect(event.cid, 'cid'); + expect(event.connectionId, 'connectionId'); + expect(event.createdAt, isA()); + expect(event.me, isA()); + expect(event.user, isA()); + }); + + test('should serialize to json correctly', () { + final event = Event( + user: User(id: 'id'), + type: 'type', + cid: 'cid', + connectionId: 'connectionId', + createdAt: DateTime.parse("2020-01-29T03:22:47.63613Z"), + me: OwnUser(id: 'id2'), + totalUnreadCount: 1, + unreadChannels: 1, + online: true, + ); + + expect( + event.toJson(), + { + 'type': 'type', + 'cid': 'cid', + 'connection_id': 'connectionId', + 'created_at': '2020-01-29T03:22:47.636130Z', + 'me': {'id': 'id2'}, + 'user': {'id': 'id'}, + 'reaction': null, + 'message': null, + 'channel': null, + 'total_unread_count': 1, + 'unread_channels': 1, + 'online': true, + 'is_local': true, + 'member': null, + 'channel_id': null, + 'channel_type': null, + 'parent_id': null, + }, + ); + }); + }); +} diff --git a/packages/dart_client/test/src/models/member_test.dart b/packages/dart_client/test/src/models/member_test.dart new file mode 100644 index 00000000..121b470f --- /dev/null +++ b/packages/dart_client/test/src/models/member_test.dart @@ -0,0 +1,35 @@ +import 'dart:convert'; + +import 'package:flutter_test/flutter_test.dart'; +import 'package:stream_chat/src/models/member.dart'; +import 'package:stream_chat/src/models/user.dart'; + +void main() { + group('src/models/member', () { + const jsonExample = ''' + { + "user": { + "id": "bbb19d9a-ee50-45bc-84e5-0584e79d0c9e", + "role": "user", + "created_at": "2020-01-28T22:17:30.826259Z", + "updated_at": "2020-01-28T22:17:31.101222Z", + "banned": false, + "online": false, + "name": "Robin Papa", + "image": "https://pbs.twimg.com/profile_images/669512187778498560/L7wQctBt.jpg" + }, + "role": "member", + "created_at": "2020-01-28T22:17:30.95443Z", + "updated_at": "2020-01-28T22:17:30.95443Z" + } + '''; + + test('should parse json correctly', () { + final member = Member.fromJson(json.decode(jsonExample)); + expect(member.user, isA()); + expect(member.role, 'member'); + expect(member.createdAt, DateTime.parse("2020-01-28T22:17:30.95443Z")); + expect(member.updatedAt, DateTime.parse("2020-01-28T22:17:30.95443Z")); + }); + }); +} diff --git a/packages/dart_client/test/src/models/message_test.dart b/packages/dart_client/test/src/models/message_test.dart new file mode 100644 index 00000000..f318daac --- /dev/null +++ b/packages/dart_client/test/src/models/message_test.dart @@ -0,0 +1,153 @@ +import 'dart:convert'; + +import 'package:flutter_test/flutter_test.dart'; +import 'package:stream_chat/src/models/attachment.dart'; +import 'package:stream_chat/src/models/message.dart'; +import 'package:stream_chat/src/models/reaction.dart'; +import 'package:stream_chat/src/models/user.dart'; + +void main() { + group('src/models/message', () { + const jsonExample = r'''{ + "id": "4637f7e4-a06b-42db-ba5a-8d8270dd926f", + "text": "https://giphy.com/gifs/the-lion-king-live-action-5zvN79uTGfLMOVfQaA", + "type": "regular", + "silent": false, + "status": "SENT", + "user": { + "id": "c1c9b454-2bcc-402d-8bb0-2f3706ce1680", + "role": "user", + "created_at": "2020-01-28T22:17:30.83015Z", + "updated_at": "2020-01-28T22:17:31.19435Z", + "banned": false, + "online": false, + "image": "https://randomuser.me/api/portraits/women/2.jpg", + "name": "Mia Denys" + }, + "attachments": [ + { + "type": "video", + "author_name": "GIPHY", + "title": "The Lion King Disney GIF - Find \u0026 Share on GIPHY", + "title_link": "https://media.giphy.com/media/5zvN79uTGfLMOVfQaA/giphy.gif", + "text": "Discover \u0026 share this Lion King Live Action GIF with everyone you know. GIPHY is how you search, share, discover, and create GIFs.", + "image_url": "https://media.giphy.com/media/5zvN79uTGfLMOVfQaA/giphy.gif", + "thumb_url": "https://media.giphy.com/media/5zvN79uTGfLMOVfQaA/giphy.gif", + "asset_url": "https://media.giphy.com/media/5zvN79uTGfLMOVfQaA/giphy.mp4", + "og_scrape_url": "https://giphy.com/gifs/the-lion-king-live-action-5zvN79uTGfLMOVfQaA" + } + ], + "latest_reactions": [ + { + "message_id": "4637f7e4-a06b-42db-ba5a-8d8270dd926f", + "user_id": "c1c9b454-2bcc-402d-8bb0-2f3706ce1680", + "user": { + "id": "c1c9b454-2bcc-402d-8bb0-2f3706ce1680", + "role": "user", + "created_at": "2020-01-28T22:17:30.83015Z", + "updated_at": "2020-01-28T22:17:31.19435Z", + "banned": false, + "online": false, + "image": "https://randomuser.me/api/portraits/women/2.jpg", + "name": "Mia Denys" + }, + "type": "love", + "score": 1, + "created_at": "2020-01-28T22:17:31.128376Z", + "updated_at": "2020-01-28T22:17:31.128376Z" + } + ], + "own_reactions": [], + "reaction_counts": { + "love": 1 + }, + "reaction_scores": { + "love": 1 + }, + "reply_count": 0, + "created_at": "2020-01-28T22:17:31.107978Z", + "updated_at": "2020-01-28T22:17:31.130506Z", + "mentioned_users": [] + }'''; + + test('should parse json correctly', () { + final message = Message.fromJson(json.decode(jsonExample)); + expect(message.id, "4637f7e4-a06b-42db-ba5a-8d8270dd926f"); + expect(message.text, + "https://giphy.com/gifs/the-lion-king-live-action-5zvN79uTGfLMOVfQaA"); + expect(message.type, "regular"); + expect(message.user, isA()); + expect(message.silent, isA()); + expect(message.attachments, isA>()); + expect(message.latestReactions, isA>()); + expect(message.ownReactions, isA>()); + expect(message.reactionCounts, {'love': 1}); + expect(message.reactionScores, {'love': 1}); + expect(message.createdAt, DateTime.parse("2020-01-28T22:17:31.107978Z")); + expect(message.updatedAt, DateTime.parse("2020-01-28T22:17:31.130506Z")); + expect(message.mentionedUsers, isA>()); + }); + + test('should serialize to json correctly', () { + final message = Message( + id: "4637f7e4-a06b-42db-ba5a-8d8270dd926f", + text: + "https://giphy.com/gifs/the-lion-king-live-action-5zvN79uTGfLMOVfQaA", + silent: false, + attachments: [ + Attachment.fromJson({ + "type": "video", + "author_name": "GIPHY", + "title": "The Lion King Disney GIF - Find \u0026 Share on GIPHY", + "title_link": + "https://media.giphy.com/media/5zvN79uTGfLMOVfQaA/giphy.gif", + "text": + "Discover \u0026 share this Lion King Live Action GIF with everyone you know. GIPHY is how you search, share, discover, and create GIFs.", + "image_url": + "https://media.giphy.com/media/5zvN79uTGfLMOVfQaA/giphy.gif", + "thumb_url": + "https://media.giphy.com/media/5zvN79uTGfLMOVfQaA/giphy.gif", + "asset_url": + "https://media.giphy.com/media/5zvN79uTGfLMOVfQaA/giphy.mp4", + "og_scrape_url": + "https://giphy.com/gifs/the-lion-king-live-action-5zvN79uTGfLMOVfQaA" + }) + ], + showInChannel: true, + parentId: 'parentId', + extraData: {'hey': 'test'}, + status: MessageSendingStatus.SENT, + ); + + expect( + message.toJson(), + json.decode(r''' + { + "id": "4637f7e4-a06b-42db-ba5a-8d8270dd926f", + "text": "https://giphy.com/gifs/the-lion-king-live-action-5zvN79uTGfLMOVfQaA", + "silent": false, + "attachments": [ + { + "type": "video", + "title_link": "https://media.giphy.com/media/5zvN79uTGfLMOVfQaA/giphy.gif", + "title": "The Lion King Disney GIF - Find & Share on GIPHY", + "thumb_url": "https://media.giphy.com/media/5zvN79uTGfLMOVfQaA/giphy.gif", + "text": "Discover & share this Lion King Live Action GIF with everyone you know. GIPHY is how you search, share, discover, and create GIFs.", + "og_scrape_url": "https://giphy.com/gifs/the-lion-king-live-action-5zvN79uTGfLMOVfQaA", + "image_url": "https://media.giphy.com/media/5zvN79uTGfLMOVfQaA/giphy.gif", + "author_name": "GIPHY", + "asset_url": "https://media.giphy.com/media/5zvN79uTGfLMOVfQaA/giphy.mp4" + } + ], + "mentioned_users": null, + "parent_id": "parentId", + "quoted_message": null, + "quoted_message_id": null, + "show_in_channel": true, + "hey": "test" + } + '''), + ); + }); + }); +} diff --git a/packages/dart_client/test/src/models/reaction_test.dart b/packages/dart_client/test/src/models/reaction_test.dart new file mode 100644 index 00000000..2e8fe5f8 --- /dev/null +++ b/packages/dart_client/test/src/models/reaction_test.dart @@ -0,0 +1,72 @@ +import 'package:flutter_test/flutter_test.dart'; +import 'package:stream_chat/src/models/reaction.dart'; +import 'dart:convert'; + +import 'package:stream_chat/src/models/user.dart'; + +void main() { + group('src/models/reaction', () { + const jsonExample = ''' + { + "message_id": "76cd8c82-b557-4e48-9d12-87995d3a0e04", + "user_id": "2de0297c-f3f2-489d-b930-ef77342edccf", + "user": { + "id": "2de0297c-f3f2-489d-b930-ef77342edccf", + "role": "user", + "created_at": "2020-01-28T22:17:30.810011Z", + "updated_at": "2020-01-28T22:17:31.077195Z", + "banned": false, + "online": false, + "image": "https://randomuser.me/api/portraits/women/45.jpg", + "name": "Daisy Morgan" + }, + "type": "wow", + "score": 1, + "created_at": "2020-01-28T22:17:31.108742Z", + "updated_at": "2020-01-28T22:17:31.108742Z" + } + '''; + + test('should parse json correctly', () { + final reaction = Reaction.fromJson(json.decode(jsonExample)); + expect(reaction.messageId, '76cd8c82-b557-4e48-9d12-87995d3a0e04'); + expect(reaction.createdAt, DateTime.parse("2020-01-28T22:17:31.108742Z")); + expect(reaction.type, 'wow'); + expect( + reaction.user.toJson(), + User.init("2de0297c-f3f2-489d-b930-ef77342edccf", extraData: { + "image": "https://randomuser.me/api/portraits/women/45.jpg", + "name": "Daisy Morgan" + }).toJson(), + ); + expect(reaction.score, 1); + expect(reaction.userId, '2de0297c-f3f2-489d-b930-ef77342edccf'); + expect(reaction.extraData, {'updated_at': '2020-01-28T22:17:31.108742Z'}); + }); + + test('should serialize to json correctly', () { + final reaction = Reaction( + messageId: '76cd8c82-b557-4e48-9d12-87995d3a0e04', + createdAt: DateTime.parse("2020-01-28T22:17:31.108742Z"), + type: 'wow', + user: User.init("2de0297c-f3f2-489d-b930-ef77342edccf", extraData: { + "image": "https://randomuser.me/api/portraits/women/45.jpg", + "name": "Daisy Morgan" + }), + userId: "2de0297c-f3f2-489d-b930-ef77342edccf", + extraData: {'bananas': 'yes'}, + score: 1, + ); + + expect( + reaction.toJson(), + { + "message_id": "76cd8c82-b557-4e48-9d12-87995d3a0e04", + "type": "wow", + "score": 1, + "bananas": 'yes', + }, + ); + }); + }); +} diff --git a/packages/dart_client/test/src/models/read_test.dart b/packages/dart_client/test/src/models/read_test.dart new file mode 100644 index 00000000..83596170 --- /dev/null +++ b/packages/dart_client/test/src/models/read_test.dart @@ -0,0 +1,40 @@ +import 'dart:convert'; + +import 'package:flutter_test/flutter_test.dart'; +import 'package:stream_chat/src/models/read.dart'; +import 'package:stream_chat/src/models/user.dart'; + +void main() { + group('src/models/read', () { + const jsonExample = ''' + { + "user": { + "id": "bbb19d9a-ee50-45bc-84e5-0584e79d0c9e" + }, + "last_read": "2020-01-28T22:17:30.966485504Z", + "unread_messages": 10 + } + '''; + + test('should parse json correctly', () { + final read = Read.fromJson(json.decode(jsonExample)); + expect(read.lastRead, DateTime.parse('2020-01-28T22:17:30.966485504Z')); + expect(read.user.id, 'bbb19d9a-ee50-45bc-84e5-0584e79d0c9e'); + expect(read.unreadMessages, 10); + }); + + test('should serialize to json correctly', () { + final read = Read( + lastRead: DateTime.parse('2020-01-28T22:17:30.966485504Z'), + user: User.init('bbb19d9a-ee50-45bc-84e5-0584e79d0c9e'), + unreadMessages: 10, + ); + + expect(read.toJson(), { + "user": {"id": "bbb19d9a-ee50-45bc-84e5-0584e79d0c9e"}, + "last_read": "2020-01-28T22:17:30.966485Z", + 'unread_messages': 10, + }); + }); + }); +} diff --git a/packages/dart_client/test/src/models/serialization_test.dart b/packages/dart_client/test/src/models/serialization_test.dart new file mode 100644 index 00000000..c20d0012 --- /dev/null +++ b/packages/dart_client/test/src/models/serialization_test.dart @@ -0,0 +1,60 @@ +import 'package:flutter_test/flutter_test.dart'; +import 'package:stream_chat/src/models/serialization.dart'; + +void main() { + group('src/models/serialization', () { + test('should move unknown keys from root to dedicate property', () { + final json = { + 'prop1': 'test', + 'prop2': 123, + 'prop3': true, + }; + final result = Serialization.moveToExtraDataFromRoot(json, [ + 'prop1', + 'prop2', + ]); + + expect(result, { + 'prop1': 'test', + 'prop2': 123, + 'extra_data': { + 'prop3': true, + }, + }); + + expect(json, { + 'prop1': 'test', + 'prop2': 123, + 'prop3': true, + }); + }); + + test('should have empty extraData', () { + final result = Serialization.moveToExtraDataFromRoot({ + 'prop1': 'test', + 'prop2': 123, + 'prop3': true, + }, [ + 'prop1', + 'prop2', + 'prop3' + ]); + + expect(result, { + 'prop1': 'test', + 'prop2': 123, + 'prop3': true, + 'extra_data': {}, + }); + }); + + test('should return null', () { + final result = Serialization.moveToExtraDataFromRoot(null, [ + 'prop1', + 'prop2', + ]); + + expect(result, null); + }); + }); +} diff --git a/packages/dart_client/test/src/models/user_test.dart b/packages/dart_client/test/src/models/user_test.dart new file mode 100644 index 00000000..a148ec6e --- /dev/null +++ b/packages/dart_client/test/src/models/user_test.dart @@ -0,0 +1,28 @@ +import 'dart:convert'; + +import 'package:flutter_test/flutter_test.dart'; +import 'package:stream_chat/src/models/user.dart'; + +void main() { + group('src/models/user', () { + const jsonExample = ''' + { + "id": "bbb19d9a-ee50-45bc-84e5-0584e79d0c9e" + } + '''; + + test('should parse json correctly', () { + final user = User.fromJson(json.decode(jsonExample)); + expect(user.id, 'bbb19d9a-ee50-45bc-84e5-0584e79d0c9e'); + }); + + test('should serialize to json correctly', () { + final user = + User(id: 'bbb19d9a-ee50-45bc-84e5-0584e79d0c9e', role: "abc"); + + expect(user.toJson(), { + 'id': "bbb19d9a-ee50-45bc-84e5-0584e79d0c9e", + }); + }); + }); +} diff --git a/packages/dart_client/test/version_test.dart b/packages/dart_client/test/version_test.dart new file mode 100644 index 00000000..698f79e1 --- /dev/null +++ b/packages/dart_client/test/version_test.dart @@ -0,0 +1,23 @@ +import 'dart:io'; + +import 'package:flutter_test/flutter_test.dart'; +import 'package:stream_chat/version.dart'; + +void prepareTest() { + // https://github.com/flutter/flutter/issues/20907 + if (Directory.current.path.endsWith('/test')) { + Directory.current = Directory.current.parent; + } +} + +void main() { + prepareTest(); + test('stream chat version matches pubspec', () { + final String pubspecPath = '${Directory.current.path}/pubspec.yaml'; + final String pubspec = File(pubspecPath).readAsStringSync(); + final RegExp regex = RegExp('version:\s*(.*)'); + final RegExpMatch match = regex.firstMatch(pubspec); + expect(match, isNotNull); + expect(PACKAGE_VERSION, match.group(1).trim()); + }); +} diff --git a/packages/dart_client/test_integration/client_test.dart b/packages/dart_client/test_integration/client_test.dart new file mode 100644 index 00000000..98ec39cf --- /dev/null +++ b/packages/dart_client/test_integration/client_test.dart @@ -0,0 +1,21 @@ +import 'package:flutter_test/flutter_test.dart'; +import 'package:logging/logging.dart'; +import 'package:stream_chat/src/client.dart'; +import 'package:stream_chat/stream_chat.dart'; + +const API_KEY = '6xjf3dex3n7d'; +const TOKEN = + 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoid2lsZC1icmVlemUtNyJ9.VM2EX1EXOfgqa-bTH_3JzeY0T99ngWzWahSauP3dBMo'; + +void main() { + test('test', () async { + final client = Client( + '6xjf3dex3n7d', + logLevel: Level.INFO, + tokenProvider: (_) async => '', + ); + final user = User(id: 'wild-breeze-7'); + + await client.setGuestUser(user); + }); +} From d1ffe1f0e36ca3bb34941118484ff1a15744fd3e Mon Sep 17 00:00:00 2001 From: Neevash Ramdial Date: Thu, 7 Jan 2021 12:11:19 -0400 Subject: [PATCH 0802/1140] update dart client dependencies --- packages/dart_client/example/pubspec.yaml | 18 ++++++++-------- packages/dart_client/pubspec.yaml | 26 +++++++++++------------ 2 files changed, 22 insertions(+), 22 deletions(-) diff --git a/packages/dart_client/example/pubspec.yaml b/packages/dart_client/example/pubspec.yaml index 59a8bb96..f8733ee5 100644 --- a/packages/dart_client/example/pubspec.yaml +++ b/packages/dart_client/example/pubspec.yaml @@ -9,16 +9,16 @@ environment: dependencies: flutter: sdk: flutter - flutter_widgets: ^0.1.11 - timeago: ^2.0.26 + flutter_widgets: ^0.1.12 + timeago: ^2.0.29 jiffy: ^3.0.1 - date_format: ^1.0.8 - cached_network_image: ^2.0.0 - flutter_markdown: ^0.3.4 - url_launcher: ^5.4.2 - video_player: ^0.10.8+1 - chewie: ^0.9.10 - animations: ^1.0.0+5 + date_format: ^1.0.9 + cached_network_image: ^2.5.0 + flutter_markdown: ^0.5.2 + url_launcher: ^5.7.10 + video_player: ^1.0.1 + chewie: ^0.12.1+1 + animations: ^1.1.2 stream_chat: path: ../ diff --git a/packages/dart_client/pubspec.yaml b/packages/dart_client/pubspec.yaml index 2c28136d..0afc8bfd 100644 --- a/packages/dart_client/pubspec.yaml +++ b/packages/dart_client/pubspec.yaml @@ -11,26 +11,26 @@ environment: dependencies: flutter: sdk: flutter - json_annotation: ^3.0.1 - shared_preferences: ^0.5.7+3 + json_annotation: ^3.1.1 + shared_preferences: ^0.5.12+4 logging: ^0.11.4 dio: ^3.0.10 web_socket_channel: ^1.1.0 uuid: ^2.2.2 - async: ^2.4.1 + async: ^2.4.2 stream_channel: ^2.0.0 - moor: ^3.3.1 - path_provider: ^1.6.10 - path: ^1.6.4 - rxdart: ^0.24.1 - collection: ^1.14.12 + moor: ^3.4.0 + path_provider: ^1.6.24 + path: ^1.7.0 + rxdart: ^0.25.0 + collection: ^1.14.13 sqlite3_flutter_libs: ^0.3.0 dev_dependencies: - build_runner: ^1.10.0 - json_serializable: ^3.3.0 - moor_generator: ^3.1.0 + build_runner: ^1.10.11 + json_serializable: ^3.5.1 + moor_generator: ^3.4.0 flutter_test: sdk: flutter - pedantic: ^1.8.0+1 - mockito: ^4.1.1 + pedantic: ^1.9.2 + mockito: ^4.1.3 From 2bda49b88e7954a8ce81247826b7573ed26b6f75 Mon Sep 17 00:00:00 2001 From: Neevash Ramdial Date: Thu, 7 Jan 2021 12:13:51 -0400 Subject: [PATCH 0803/1140] update widgets dependencies --- packages/flutter_widgets/example/pubspec.yaml | 4 +-- packages/flutter_widgets/pubspec.yaml | 34 +++++++++---------- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/packages/flutter_widgets/example/pubspec.yaml b/packages/flutter_widgets/example/pubspec.yaml index c5f52233..29b38656 100644 --- a/packages/flutter_widgets/example/pubspec.yaml +++ b/packages/flutter_widgets/example/pubspec.yaml @@ -10,8 +10,8 @@ dependencies: sdk: flutter stream_chat_flutter: path: ../ - flutter_apns: ^1.3.1 - flutter_local_notifications: ^2.0.0 + flutter_apns: ^1.4.1 + flutter_local_notifications: ^2.0.2 flutter_svg: ^0.19.1 flutter_secure_storage: ^3.3.5 yaml: ^2.2.1 diff --git a/packages/flutter_widgets/pubspec.yaml b/packages/flutter_widgets/pubspec.yaml index e29042cb..20047087 100644 --- a/packages/flutter_widgets/pubspec.yaml +++ b/packages/flutter_widgets/pubspec.yaml @@ -1,7 +1,7 @@ name: stream_chat_flutter homepage: https://github.com/GetStream/stream-chat-flutter description: Stream Chat official Flutter SDK. Build your own chat experience using Dart and Flutter. -version: 0.2.20+2 +version: 0.2.13+1 repository: https://github.com/GetStream/stream-chat-flutter issue_tracker: https://github.com/GetStream/stream-chat-flutter/issues @@ -12,33 +12,33 @@ dependencies: flutter: sdk: flutter flutter_app_badger: ^1.1.2 - photo_view: ^0.10.1 - rxdart: ^0.24.1 + photo_view: ^0.10.3 + rxdart: ^0.25.0 scrollable_positioned_list: ^0.1.8 jiffy: ^3.0.1 flutter_svg: ^0.19.1 flutter_portal: ^0.3.0 - cached_network_image: ^2.2.0+1 + cached_network_image: ^2.5.0 shimmer: ^1.1.2 - flutter_markdown: ^0.5.0 - url_launcher: ^5.4.11 + flutter_markdown: ^0.5.2 + url_launcher: ^5.7.10 emojis: ^0.9.3 - video_player: ^1.0.0 - chewie: ^0.12.1 - file_picker: ^2.0.12 - image_picker: ^0.6.7+2 + video_player: ^1.0.1 + chewie: ^0.12.1+1 + file_picker: ^2.1.5 + image_picker: ^0.6.7+17 flutter_keyboard_visibility: ^4.0.2 - stream_chat: ^0.2.23 - mime: ^0.9.6+3 + stream_chat: ^0.2.23+1 + mime: ^0.9.7 video_compress: ^2.1.1 visibility_detector: ^0.1.5 http_parser: ^3.1.4 lottie: ^0.7.0+1 substring_highlight: ^0.1.2 - flutter_slidable: ^0.5.4 - carousel_slider: ^2.2.1 + flutter_slidable: ^0.5.7 + carousel_slider: ^2.3.1 clipboard: ^0.1.2+8 - image_gallery_saver: ^1.6.6 + image_gallery_saver: ^1.6.7 esys_flutter_share: ^1.0.2 photo_manager: ^0.5.8 transparent_image: ^1.0.0 @@ -53,7 +53,7 @@ flutter: - animations/ dev_dependencies: - pedantic: ^1.9.0 + pedantic: ^1.9.2 flutter_test: sdk: flutter - mockito: ^4.1.1 + mockito: ^4.1.3 From 5f1b84ccb7a3035fccbb41a168ddd6b832799f80 Mon Sep 17 00:00:00 2001 From: Neevash Ramdial Date: Thu, 7 Jan 2021 12:21:27 -0400 Subject: [PATCH 0804/1140] ignore ios build files --- .gitignore | 5 +- .../ios/Runner.xcodeproj/project.pbxproj | 584 ------------------ .../example/ios/Flutter/.last_build_id | 1 - 3 files changed, 4 insertions(+), 586 deletions(-) delete mode 100644 packages/dart_client/example/ios/Runner.xcodeproj/project.pbxproj delete mode 100644 packages/flutter_widgets/example/ios/Flutter/.last_build_id diff --git a/.gitignore b/.gitignore index 0ce95373..6d180702 100644 --- a/.gitignore +++ b/.gitignore @@ -46,4 +46,7 @@ build/ .settings /.fvm -.melos_tool/ \ No newline at end of file +.melos_tool/ +/packages/flutter_widgets/example/ios/Flutter/.last_build_id +/packages/dart_client/example/ios/Flutter/.last_build_id +/packages/dart_client/example/ios/Runner.xcodeproj/project.pbxproj diff --git a/packages/dart_client/example/ios/Runner.xcodeproj/project.pbxproj b/packages/dart_client/example/ios/Runner.xcodeproj/project.pbxproj deleted file mode 100644 index 7a054ad3..00000000 --- a/packages/dart_client/example/ios/Runner.xcodeproj/project.pbxproj +++ /dev/null @@ -1,584 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 46; - objects = { - -/* Begin PBXBuildFile section */ - 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; - 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; - 3B80C3941E831B6300D905FE /* App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; }; - 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; - 850BCB2A5C430C0BF58BF0DD /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2BA5904E77DC05E990FD1802 /* Pods_Runner.framework */; }; - 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; }; - 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; - 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; - 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; -/* End PBXBuildFile section */ - -/* Begin PBXCopyFilesBuildPhase section */ - 9705A1C41CF9048500538489 /* Embed Frameworks */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 2147483647; - dstPath = ""; - dstSubfolderSpec = 10; - files = ( - 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */, - 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */, - ); - name = "Embed Frameworks"; - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXCopyFilesBuildPhase section */ - -/* Begin PBXFileReference section */ - 0409BEB0CDB875557BCCDE42 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; - 1232C268B110F97C5CB93E3C /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; - 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; - 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; - 14A9392BD3E7B6A07FC5103E /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; - 2BA5904E77DC05E990FD1802 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; - 3B80C3931E831B6300D905FE /* App.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = App.framework; path = Flutter/App.framework; sourceTree = ""; }; - 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; - 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; - 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; - 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; - 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; - 9740EEBA1CF902C7004384FC /* Flutter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Flutter.framework; path = Flutter/Flutter.framework; sourceTree = ""; }; - 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; - 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; - 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; - 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; - 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; -/* End PBXFileReference section */ - -/* Begin PBXFrameworksBuildPhase section */ - 97C146EB1CF9000F007C117D /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */, - 3B80C3941E831B6300D905FE /* App.framework in Frameworks */, - 850BCB2A5C430C0BF58BF0DD /* Pods_Runner.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - 198533D8779F8F2800613F27 /* Frameworks */ = { - isa = PBXGroup; - children = ( - 2BA5904E77DC05E990FD1802 /* Pods_Runner.framework */, - ); - name = Frameworks; - sourceTree = ""; - }; - 9740EEB11CF90186004384FC /* Flutter */ = { - isa = PBXGroup; - children = ( - 3B80C3931E831B6300D905FE /* App.framework */, - 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, - 9740EEBA1CF902C7004384FC /* Flutter.framework */, - 9740EEB21CF90195004384FC /* Debug.xcconfig */, - 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, - 9740EEB31CF90195004384FC /* Generated.xcconfig */, - ); - name = Flutter; - sourceTree = ""; - }; - 97C146E51CF9000F007C117D = { - isa = PBXGroup; - children = ( - 9740EEB11CF90186004384FC /* Flutter */, - 97C146F01CF9000F007C117D /* Runner */, - 97C146EF1CF9000F007C117D /* Products */, - 9E7371E7FEDE0F7EBA0661C0 /* Pods */, - 198533D8779F8F2800613F27 /* Frameworks */, - ); - sourceTree = ""; - }; - 97C146EF1CF9000F007C117D /* Products */ = { - isa = PBXGroup; - children = ( - 97C146EE1CF9000F007C117D /* Runner.app */, - ); - name = Products; - sourceTree = ""; - }; - 97C146F01CF9000F007C117D /* Runner */ = { - isa = PBXGroup; - children = ( - 97C146FA1CF9000F007C117D /* Main.storyboard */, - 97C146FD1CF9000F007C117D /* Assets.xcassets */, - 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, - 97C147021CF9000F007C117D /* Info.plist */, - 97C146F11CF9000F007C117D /* Supporting Files */, - 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, - 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, - 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, - 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, - ); - path = Runner; - sourceTree = ""; - }; - 97C146F11CF9000F007C117D /* Supporting Files */ = { - isa = PBXGroup; - children = ( - ); - name = "Supporting Files"; - sourceTree = ""; - }; - 9E7371E7FEDE0F7EBA0661C0 /* Pods */ = { - isa = PBXGroup; - children = ( - 0409BEB0CDB875557BCCDE42 /* Pods-Runner.debug.xcconfig */, - 1232C268B110F97C5CB93E3C /* Pods-Runner.release.xcconfig */, - 14A9392BD3E7B6A07FC5103E /* Pods-Runner.profile.xcconfig */, - ); - name = Pods; - path = Pods; - sourceTree = ""; - }; -/* End PBXGroup section */ - -/* Begin PBXNativeTarget section */ - 97C146ED1CF9000F007C117D /* Runner */ = { - isa = PBXNativeTarget; - buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; - buildPhases = ( - 9233D2646E621705569E6ED8 /* [CP] Check Pods Manifest.lock */, - 9740EEB61CF901F6004384FC /* Run Script */, - 97C146EA1CF9000F007C117D /* Sources */, - 97C146EB1CF9000F007C117D /* Frameworks */, - 97C146EC1CF9000F007C117D /* Resources */, - 9705A1C41CF9048500538489 /* Embed Frameworks */, - 3B06AD1E1E4923F5004D2608 /* Thin Binary */, - 11808FAFAB0708F9F9320974 /* [CP] Embed Pods Frameworks */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = Runner; - productName = Runner; - productReference = 97C146EE1CF9000F007C117D /* Runner.app */; - productType = "com.apple.product-type.application"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - 97C146E61CF9000F007C117D /* Project object */ = { - isa = PBXProject; - attributes = { - LastUpgradeCheck = 1020; - ORGANIZATIONNAME = ""; - TargetAttributes = { - 97C146ED1CF9000F007C117D = { - CreatedOnToolsVersion = 7.3.1; - LastSwiftMigration = 1100; - }; - }; - }; - buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; - compatibilityVersion = "Xcode 3.2"; - developmentRegion = en; - hasScannedForEncodings = 0; - knownRegions = ( - en, - Base, - ); - mainGroup = 97C146E51CF9000F007C117D; - productRefGroup = 97C146EF1CF9000F007C117D /* Products */; - projectDirPath = ""; - projectRoot = ""; - targets = ( - 97C146ED1CF9000F007C117D /* Runner */, - ); - }; -/* End PBXProject section */ - -/* Begin PBXResourcesBuildPhase section */ - 97C146EC1CF9000F007C117D /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, - 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, - 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, - 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXResourcesBuildPhase section */ - -/* Begin PBXShellScriptBuildPhase section */ - 11808FAFAB0708F9F9320974 /* [CP] Embed Pods Frameworks */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - ); - name = "[CP] Embed Pods Frameworks"; - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; - showEnvVarsInLog = 0; - }; - 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - ); - name = "Thin Binary"; - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" thin"; - }; - 9233D2646E621705569E6ED8 /* [CP] Check Pods Manifest.lock */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - ); - inputPaths = ( - "${PODS_PODFILE_DIR_PATH}/Podfile.lock", - "${PODS_ROOT}/Manifest.lock", - ); - name = "[CP] Check Pods Manifest.lock"; - outputFileListPaths = ( - ); - outputPaths = ( - "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; - showEnvVarsInLog = 0; - }; - 9740EEB61CF901F6004384FC /* Run Script */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - ); - name = "Run Script"; - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; - }; -/* End PBXShellScriptBuildPhase section */ - -/* Begin PBXSourcesBuildPhase section */ - 97C146EA1CF9000F007C117D /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, - 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin PBXVariantGroup section */ - 97C146FA1CF9000F007C117D /* Main.storyboard */ = { - isa = PBXVariantGroup; - children = ( - 97C146FB1CF9000F007C117D /* Base */, - ); - name = Main.storyboard; - sourceTree = ""; - }; - 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { - isa = PBXVariantGroup; - children = ( - 97C147001CF9000F007C117D /* Base */, - ); - name = LaunchScreen.storyboard; - sourceTree = ""; - }; -/* End PBXVariantGroup section */ - -/* Begin XCBuildConfiguration section */ - 249021D3217E4FDB00AE95B9 /* Profile */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_NONNULL = YES; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_NO_COMMON_BLOCKS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; - MTL_ENABLE_DEBUG_INFO = NO; - SDKROOT = iphoneos; - SUPPORTED_PLATFORMS = iphoneos; - TARGETED_DEVICE_FAMILY = "1,2"; - VALIDATE_PRODUCT = YES; - }; - name = Profile; - }; - 249021D4217E4FDB00AE95B9 /* Profile */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CLANG_ENABLE_MODULES = YES; - CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; - ENABLE_BITCODE = NO; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Flutter", - ); - INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - LIBRARY_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Flutter", - ); - PRODUCT_BUNDLE_IDENTIFIER = com.example.streamChatDart; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; - SWIFT_VERSION = 5.0; - VERSIONING_SYSTEM = "apple-generic"; - }; - name = Profile; - }; - 97C147031CF9000F007C117D /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_NONNULL = YES; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = dwarf; - ENABLE_STRICT_OBJC_MSGSEND = YES; - ENABLE_TESTABILITY = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_DYNAMIC_NO_PIC = NO; - GCC_NO_COMMON_BLOCKS = YES; - GCC_OPTIMIZATION_LEVEL = 0; - GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG=1", - "$(inherited)", - ); - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; - MTL_ENABLE_DEBUG_INFO = YES; - ONLY_ACTIVE_ARCH = YES; - SDKROOT = iphoneos; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Debug; - }; - 97C147041CF9000F007C117D /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_NONNULL = YES; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_NO_COMMON_BLOCKS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; - MTL_ENABLE_DEBUG_INFO = NO; - SDKROOT = iphoneos; - SUPPORTED_PLATFORMS = iphoneos; - SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; - TARGETED_DEVICE_FAMILY = "1,2"; - VALIDATE_PRODUCT = YES; - }; - name = Release; - }; - 97C147061CF9000F007C117D /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CLANG_ENABLE_MODULES = YES; - CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; - ENABLE_BITCODE = NO; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Flutter", - ); - INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - LIBRARY_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Flutter", - ); - PRODUCT_BUNDLE_IDENTIFIER = com.example.streamChatDart; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 5.0; - VERSIONING_SYSTEM = "apple-generic"; - }; - name = Debug; - }; - 97C147071CF9000F007C117D /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CLANG_ENABLE_MODULES = YES; - CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; - ENABLE_BITCODE = NO; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Flutter", - ); - INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - LIBRARY_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Flutter", - ); - PRODUCT_BUNDLE_IDENTIFIER = com.example.streamChatDart; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; - SWIFT_VERSION = 5.0; - VERSIONING_SYSTEM = "apple-generic"; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 97C147031CF9000F007C117D /* Debug */, - 97C147041CF9000F007C117D /* Release */, - 249021D3217E4FDB00AE95B9 /* Profile */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 97C147061CF9000F007C117D /* Debug */, - 97C147071CF9000F007C117D /* Release */, - 249021D4217E4FDB00AE95B9 /* Profile */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - }; - rootObject = 97C146E61CF9000F007C117D /* Project object */; -} diff --git a/packages/flutter_widgets/example/ios/Flutter/.last_build_id b/packages/flutter_widgets/example/ios/Flutter/.last_build_id deleted file mode 100644 index f57e1e1f..00000000 --- a/packages/flutter_widgets/example/ios/Flutter/.last_build_id +++ /dev/null @@ -1 +0,0 @@ -c770358a10272b4ee1cdc2eb432445f6 \ No newline at end of file From 3216862b222954671b280c9cb827fd8df26ea9f5 Mon Sep 17 00:00:00 2001 From: Neevash Ramdial Date: Thu, 7 Jan 2021 12:39:21 -0400 Subject: [PATCH 0805/1140] add getting started --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index 916d0667..816e96a1 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,12 @@ Stream allows developers to rapidly deploy scalable feeds and chat messaging wit ## Structure Stream Chat Dart is a monorepo built using [Melos](https://docs.page/invertase/melos). Individual packages can be found in the `packages` directory while configuration and top level commands can be found in `melos.yaml`. +To get started, run `bootstrap` after cloning the project. + +```shell +melos bootstrap +``` + ## Available Commands ### Analyze > Requires `tuneup` to be activated globally. Please see https://pub.dev/packages/tuneup From cb69dd036a33b690f2ea9998c1fbff1652ceb6ef Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Fri, 8 Jan 2021 12:02:17 +0530 Subject: [PATCH 0806/1140] [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 0807/1140] 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 0808/1140] [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 eaa3ef0959515bd27e2445637839d320adb7582c Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Fri, 8 Jan 2021 14:21:38 +0530 Subject: [PATCH 0809/1140] feat: Added typing indicator design and styling fixes --- example/lib/main.dart | 6 ++++++ lib/src/typing_indicator.dart | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/example/lib/main.dart b/example/lib/main.dart index 6df1dafb..2bf460f8 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -578,6 +578,12 @@ class _ChannelPageState extends State { horizontal: 8, vertical: 4, ), + style: StreamChatTheme.of(context) + .textTheme + .footnote + .copyWith( + color: + StreamChatTheme.of(context).colorTheme.grey), ), ), ), diff --git a/lib/src/typing_indicator.dart b/lib/src/typing_indicator.dart index b13eade6..177e9e21 100644 --- a/lib/src/typing_indicator.dart +++ b/lib/src/typing_indicator.dart @@ -54,7 +54,7 @@ class TypingIndicator extends StatelessWidget { height: 4, ), Text( - ' ${snapshot.data.map((u) => u.name).join(',')} ${snapshot.data.length == 1 ? 'is' : 'are'} typing', + ' ${snapshot.data[0].name}${snapshot.data.length == 1 ? '' : ' and ${snapshot.data.length - 1} more'} ${snapshot.data.length == 1 ? 'is' : 'are'} typing', maxLines: 1, style: style, ), From b9f5dc395cc709907b6c41d76b5ad7d180de2bc4 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Fri, 8 Jan 2021 14:33:53 +0530 Subject: [PATCH 0810/1140] [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 0811/1140] [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 1662c14dd35f5f7a32a5b6285b917b232189aa7b Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Fri, 8 Jan 2021 15:26:16 +0530 Subject: [PATCH 0812/1140] fix: Fixed no permission modal --- lib/src/message_input.dart | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 0a959ffa..ee8763ba 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -974,9 +974,22 @@ class MessageInputState extends State { 'svgs/icon_picture_empty_state.svg', package: 'stream_chat_flutter', height: 140, - color: - StreamChatTheme.of(context).colorTheme.accentBlue, + color: StreamChatTheme.of(context) + .colorTheme + .greyGainsboro, ), + Text( + 'Please enable access to your photos \nand videos so you can share them with friends.', + style: StreamChatTheme.of(context) + .textTheme + .body + .copyWith( + color: StreamChatTheme.of(context) + .colorTheme + .grey), + textAlign: TextAlign.center, + ), + SizedBox(height: 6.0), Center( child: Text( 'Allow access to your gallery', From 2f3e6ced0d5dfd7c3952b99c33dc25dcb050fb79 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Fri, 8 Jan 2021 16:29:13 +0530 Subject: [PATCH 0813/1140] [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 68db556c0ff8ee955eb317d55b86a9a656f1880c Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Fri, 8 Jan 2021 16:32:53 +0530 Subject: [PATCH 0814/1140] fix: Fixed mention screen styling --- example/lib/main.dart | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/example/lib/main.dart b/example/lib/main.dart index 2f85d126..3f1112ba 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, @@ -323,10 +323,21 @@ class UserMentionPage extends StatelessWidget { padding: const EdgeInsets.all(24), child: StreamSvgIcon.mentions( size: 96, - color: Colors.grey, + color: StreamChatTheme.of(context) + .colorTheme + .greyGainsboro, ), ), - Text('No mentions exist yet...'), + Text( + 'No mentions exist yet...', + style: StreamChatTheme.of(context) + .textTheme + .body + .copyWith( + color: + StreamChatTheme.of(context).colorTheme.grey, + ), + ), ], ), ), From 11bb372011f555e4e99a090a6b008d7103a34746 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Fri, 8 Jan 2021 16:50:46 +0530 Subject: [PATCH 0815/1140] [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 0816/1140] [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 0817/1140] [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 d7aaa9614b9a3253873548a8bdced89dc7d3e987 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Fri, 8 Jan 2021 14:47:11 +0100 Subject: [PATCH 0818/1140] fix link image size --- lib/src/message_widget.dart | 2 ++ lib/src/url_attachment.dart | 8 ++++---- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/lib/src/message_widget.dart b/lib/src/message_widget.dart index 1200f38d..2a4ab364 100644 --- a/lib/src/message_widget.dart +++ b/lib/src/message_widget.dart @@ -842,6 +842,8 @@ class _MessageWidgetState extends State { } void onLongPress(BuildContext context) { + print( + 'widget.message.attachment[0].toJson(): ${widget.message.attachments[0].imageUrl}'); if (widget.message.isEphemeral || widget.message.status == MessageSendingStatus.SENDING) { return; diff --git a/lib/src/url_attachment.dart b/lib/src/url_attachment.dart index 1909fc33..130b1109 100644 --- a/lib/src/url_attachment.dart +++ b/lib/src/url_attachment.dart @@ -34,10 +34,10 @@ class UrlAttachment extends StatelessWidget { margin: EdgeInsets.symmetric(horizontal: 8.0), child: Stack( children: [ - Center( - child: CachedNetworkImage( - imageUrl: urlAttachment.imageUrl, - ), + CachedNetworkImage( + width: double.infinity, + imageUrl: urlAttachment.imageUrl, + fit: BoxFit.cover, ), Positioned( left: 0.0, From 26f30f06d09628aebf2e2a4a8adcc85b5593912d Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Fri, 8 Jan 2021 14:47:39 +0100 Subject: [PATCH 0819/1140] remove log --- lib/src/message_widget.dart | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/src/message_widget.dart b/lib/src/message_widget.dart index 2a4ab364..1200f38d 100644 --- a/lib/src/message_widget.dart +++ b/lib/src/message_widget.dart @@ -842,8 +842,6 @@ class _MessageWidgetState extends State { } void onLongPress(BuildContext context) { - print( - 'widget.message.attachment[0].toJson(): ${widget.message.attachments[0].imageUrl}'); if (widget.message.isEphemeral || widget.message.status == MessageSendingStatus.SENDING) { return; From d074bf8d9f182f72e7f970c34d3138bd23159dc7 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Fri, 8 Jan 2021 19:42:27 +0530 Subject: [PATCH 0820/1140] 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 0821/1140] [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 0822/1140] [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 0823/1140] [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 b93d616c86ec15b6c49eea57421ff2209c1593fe Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Fri, 8 Jan 2021 22:00:54 +0530 Subject: [PATCH 0824/1140] feat: Added message flagging --- lib/src/message_actions_modal.dart | 285 ++++++++++++++++++++++++----- lib/src/message_list_view.dart | 1 + lib/src/message_widget.dart | 3 + 3 files changed, 239 insertions(+), 50 deletions(-) diff --git a/lib/src/message_actions_modal.dart b/lib/src/message_actions_modal.dart index c7ff56e0..8390ce97 100644 --- a/lib/src/message_actions_modal.dart +++ b/lib/src/message_actions_modal.dart @@ -1,5 +1,6 @@ import 'dart:ui'; +import 'package:flutter/cupertino.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; @@ -13,7 +14,7 @@ import 'message_widget.dart'; import 'stream_chat.dart'; import 'stream_chat_theme.dart'; -class MessageActionsModal extends StatelessWidget { +class MessageActionsModal extends StatefulWidget { final Widget Function(BuildContext, Message) editMessageInputBuilder; final void Function(Message) onThreadReplyTap; final void Function(Message) onReplyTap; @@ -26,6 +27,7 @@ class MessageActionsModal extends StatelessWidget { final bool showResendMessage; final bool showReply; final bool showThreadReply; + final bool showFlagButton; final bool reverse; final ShapeBorder messageShape; final DisplayWidget showUserAvatar; @@ -43,22 +45,38 @@ class MessageActionsModal extends StatelessWidget { this.showReply = true, this.showResendMessage = true, this.showThreadReply = true, + this.showFlagButton = true, this.showUserAvatar = DisplayWidget.show, this.editMessageInputBuilder, this.messageShape, this.reverse = false, }) : super(key: key); + @override + _MessageActionsModalState createState() => _MessageActionsModalState(); +} + +class _MessageActionsModalState extends State { + bool showConfirmFlagModal = false; + @override Widget build(BuildContext context) { + if (showConfirmFlagModal) { + return _showFlagDialog(); + } else { + return _showMessageOptionsModal(); + } + } + + Widget _showMessageOptionsModal() { final size = MediaQuery.of(context).size; final user = StreamChat.of(context).user; final roughMaxSize = 2 * size.width / 3; - var messageTextLength = message.text.length; - if (message.quotedMessage != null) { - var quotedMessageLength = message.quotedMessage.text.length + 40; - if (message.quotedMessage.attachments?.isNotEmpty == true) { + var messageTextLength = widget.message.text.length; + if (widget.message.quotedMessage != null) { + var quotedMessageLength = widget.message.quotedMessage.text.length + 40; + if (widget.message.quotedMessage.attachments?.isNotEmpty == true) { quotedMessageLength += 40; } if (quotedMessageLength > messageTextLength) { @@ -66,8 +84,8 @@ class MessageActionsModal extends StatelessWidget { } } final roughSentenceSize = - messageTextLength * messageTheme.messageText.fontSize * 1.2; - final divFactor = message.attachments?.isNotEmpty == true + messageTextLength * widget.messageTheme.messageText.fontSize * 1.2; + final divFactor = widget.message.attachments?.isNotEmpty == true ? 1 : (roughSentenceSize == 0 ? 1 : (roughSentenceSize / roughMaxSize)); @@ -95,18 +113,18 @@ class MessageActionsModal extends StatelessWidget { mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.stretch, children: [ - if (showReactions && - (message.status == MessageSendingStatus.SENT || - message.status == null)) + if (widget.showReactions && + (widget.message.status == MessageSendingStatus.SENT || + widget.message.status == null)) Align( alignment: Alignment( - user.id == message.user.id + user.id == widget.message.user.id ? (divFactor > 1.0 ? 0.0 : (1.0 - divFactor)) : (divFactor > 1.0 ? 0.0 : -(1.0 - divFactor)), 0.0), child: ReactionPicker( - message: message, - messageTheme: messageTheme, + message: widget.message, + messageTheme: widget.messageTheme, ), ), TweenAnimationBuilder( @@ -118,27 +136,28 @@ class MessageActionsModal extends StatelessWidget { child: IgnorePointer( child: MessageWidget( key: Key('MessageWidget'), - reverse: reverse, - message: message.copyWith( - text: message.text.length > 200 - ? '${message.text.substring(0, 200)}...' - : message.text, + reverse: widget.reverse, + message: widget.message.copyWith( + text: widget.message.text.length > 200 + ? '${widget.message.text.substring(0, 200)}...' + : widget.message.text, ), - messageTheme: messageTheme, + messageTheme: widget.messageTheme, showReactions: false, showUsername: false, showThreadReplyIndicator: false, showReplyIndicator: false, - showUserAvatar: showUserAvatar, + showUserAvatar: widget.showUserAvatar, showTimestamp: false, translateUserAvatar: false, - showReactionPickerIndicator: showReactions && - (message.status == - MessageSendingStatus.SENT || - message.status == null), + showReactionPickerIndicator: + widget.showReactions && + (widget.message.status == + MessageSendingStatus.SENT || + widget.message.status == null), showInChannelIndicator: false, showSendingIndicator: DisplayWidget.gone, - shape: messageShape, + shape: widget.messageShape, ), ), ); @@ -172,26 +191,28 @@ class MessageActionsModal extends StatelessWidget { children: ListTile.divideTiles( context: context, tiles: [ - if (showReply && - (message.status == + if (widget.showReply && + (widget.message.status == MessageSendingStatus.SENT || - message.status == null) && - message.parentId == null) + widget.message.status == null) && + widget.message.parentId == null) _buildReplyButton(context), - if (showThreadReply && - (message.status == + if (widget.showThreadReply && + (widget.message.status == MessageSendingStatus.SENT || - message.status == null) && - message.parentId == null) + widget.message.status == null) && + widget.message.parentId == null) _buildThreadReplyButton(context), - if (showResendMessage) + if (widget.showResendMessage) _buildResendMessage(context), - if (showEditMessage) + if (widget.showEditMessage) _buildEditMessage(context), - if (showDeleteMessage) + if (widget.showDeleteMessage) _buildDeleteButton(context), - if (showCopyMessage) + if (widget.showCopyMessage) _buildCopyButton(context), + if (widget.showCopyMessage) + _buildFlagButton(context), ], ).toList(), ), @@ -209,6 +230,150 @@ class MessageActionsModal extends StatelessWidget { ); } + Widget _showFlagDialog() { + return GestureDetector( + behavior: HitTestBehavior.translucent, + onTap: () => Navigator.maybePop(context), + child: Stack( + children: [ + Positioned.fill( + child: BackdropFilter( + filter: ImageFilter.blur( + sigmaX: 10, + sigmaY: 10, + ), + child: Container( + color: StreamChatTheme.of(context).colorTheme.overlay, + ), + ), + ), + Center( + child: Opacity( + opacity: 0.9, + child: Material( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(16.0), + ), + clipBehavior: Clip.antiAlias, + child: Container( + width: 270.0, + height: 156.0, + alignment: Alignment.center, + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + SizedBox( + height: 19.0, + ), + Text( + 'Flag Message', + style: StreamChatTheme.of(context) + .textTheme + .bodyBold + .copyWith(fontSize: 17.0), + ), + SizedBox( + height: 4.0, + ), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 16.0), + child: Text( + 'Do you want to send a copy of this \nmessage to a moderator for further \ninvestigation?', + style: TextStyle(fontSize: 13.5), + textAlign: TextAlign.center, + ), + ), + SizedBox( + height: 21.0, + ), + Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + Expanded( + child: Center( + child: InkWell( + child: Container( + height: 44.0, + alignment: Alignment.center, + child: Text( + 'Cancel', + style: StreamChatTheme.of(context) + .textTheme + .body + .copyWith( + fontSize: 17.0, + color: StreamChatTheme.of(context) + .colorTheme + .accentBlue), + ), + decoration: BoxDecoration( + border: Border.symmetric( + horizontal: BorderSide( + color: StreamChatTheme.of(context) + .colorTheme + .grey), + ), + ), + ), + onTap: () { + setState(() { + showConfirmFlagModal = false; + }); + }, + ), + ), + ), + Expanded( + child: Center( + child: InkWell( + child: Container( + height: 44.0, + alignment: Alignment.center, + child: Text( + 'Flag', + style: StreamChatTheme.of(context) + .textTheme + .body + .copyWith( + fontWeight: FontWeight.bold, + fontSize: 17.0, + color: StreamChatTheme.of(context) + .colorTheme + .accentBlue), + ), + decoration: BoxDecoration( + border: Border.fromBorderSide( + BorderSide( + color: StreamChatTheme.of(context) + .colorTheme + .grey), + ), + ), + ), + onTap: () { + setState(() { + showConfirmFlagModal = false; + }); + final client = StreamChat.of(context).client; + client.flagMessage(widget.message.id); + }, + ), + ), + ), + ], + ), + ], + ), + ), + ), + ), + ), + ], + ), + ); + } + Widget _buildReplyButton(BuildContext context) { return ListTile( title: Text( @@ -220,15 +385,34 @@ class MessageActionsModal extends StatelessWidget { ), onTap: () { Navigator.pop(context); - if (onReplyTap != null) { - onReplyTap(message); + if (widget.onReplyTap != null) { + widget.onReplyTap(widget.message); } }, ); } + Widget _buildFlagButton(BuildContext context) { + return ListTile( + title: Text( + 'Flag', + style: Theme.of(context).textTheme.headline6, + ), + leading: StreamSvgIcon.flag( + color: StreamChatTheme.of(context).primaryIconTheme.color, + size: 24.0, + ), + onTap: () { + setState(() { + showConfirmFlagModal = true; + }); + }, + ); + } + Widget _buildDeleteButton(BuildContext context) { - final isDeleteFailed = message.status == MessageSendingStatus.FAILED_DELETE; + final isDeleteFailed = + widget.message.status == MessageSendingStatus.FAILED_DELETE; return ListTile( title: Text( isDeleteFailed ? 'Retry deleting message' : 'Delete message', @@ -241,7 +425,7 @@ class MessageActionsModal extends StatelessWidget { onTap: () { Navigator.pop(context); StreamChat.of(context).client.deleteMessage( - message, + widget.message, StreamChannel.of(context).channel.cid, ); }, @@ -258,7 +442,7 @@ class MessageActionsModal extends StatelessWidget { color: StreamChatTheme.of(context).primaryIconTheme.color, ), onTap: () async { - await Clipboard.setData(ClipboardData(text: message.text)); + await Clipboard.setData(ClipboardData(text: widget.message.text)); Navigator.pop(context); }, ); @@ -281,7 +465,8 @@ class MessageActionsModal extends StatelessWidget { } Widget _buildResendMessage(BuildContext context) { - final isUpdateFailed = message.status == MessageSendingStatus.FAILED_UPDATE; + final isUpdateFailed = + widget.message.status == MessageSendingStatus.FAILED_UPDATE; return ListTile( title: Text( isUpdateFailed ? 'Resend edited message' : 'Resend', @@ -295,9 +480,9 @@ class MessageActionsModal extends StatelessWidget { final client = StreamChat.of(context).client; final channel = StreamChannel.of(context).channel; if (isUpdateFailed) { - client.updateMessage(message, channel.cid); + client.updateMessage(widget.message, channel.cid); } else { - channel.sendMessage(message); + channel.sendMessage(widget.message); } }, ); @@ -354,10 +539,10 @@ class MessageActionsModal extends StatelessWidget { padding: EdgeInsets.only( bottom: MediaQuery.of(context).viewInsets.bottom, ), - child: editMessageInputBuilder != null - ? editMessageInputBuilder(context, message) + child: widget.editMessageInputBuilder != null + ? widget.editMessageInputBuilder(context, widget.message) : MessageInput( - editMessage: message, + editMessage: widget.message, preMessageSending: (m) { FocusScope.of(context).unfocus(); Navigator.pop(context); @@ -383,8 +568,8 @@ class MessageActionsModal extends StatelessWidget { ), onTap: () { Navigator.pop(context); - if (onThreadReplyTap != null) { - onThreadReplyTap(message); + if (widget.onThreadReplyTap != null) { + widget.onThreadReplyTap(widget.message); } }, ); diff --git a/lib/src/message_list_view.dart b/lib/src/message_list_view.dart index 9f4cbc0d..21aa9ed1 100644 --- a/lib/src/message_list_view.dart +++ b/lib/src/message_list_view.dart @@ -800,6 +800,7 @@ class _MessageListViewState extends State { showTimestamp: !isNextUser || readList?.isNotEmpty == true, showEditMessage: isMyMessage, showDeleteMessage: isMyMessage, + showFlagButton: !isMyMessage, borderSide: isMyMessage ? BorderSide.none : null, onThreadTap: _onThreadTap, onReplyTap: widget.onReplyTap, diff --git a/lib/src/message_widget.dart b/lib/src/message_widget.dart index 1200f38d..c687f36f 100644 --- a/lib/src/message_widget.dart +++ b/lib/src/message_widget.dart @@ -133,6 +133,7 @@ class MessageWidget extends StatefulWidget { final bool showTimestamp; final bool showDeleteMessage; final bool showEditMessage; + final bool showFlagButton; final Map attachmentBuilders; /// Center user avatar with bottom of the message @@ -168,6 +169,7 @@ class MessageWidget extends StatefulWidget { this.showReactions = true, this.showDeleteMessage = true, this.showEditMessage = true, + this.showFlagButton = true, this.onUserAvatarTap, this.onLinkTap, this.onMessageActions, @@ -718,6 +720,7 @@ class _MessageWidgetState extends State { widget.onReplyTap != null, showThreadReply: widget.showThreadReplyIndicator && widget.onThreadTap != null, + showFlagButton: widget.showFlagButton, ), ); }); From 81edc934f434f83ff5cb2189deee7c2f3e825f04 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Fri, 8 Jan 2021 17:45:41 +0100 Subject: [PATCH 0825/1140] update profiles --- example/ios/fastlane/report.xml | 22 +++++----------------- 1 file changed, 5 insertions(+), 17 deletions(-) diff --git a/example/ios/fastlane/report.xml b/example/ios/fastlane/report.xml index d6fdf2d7..3a11e14a 100644 --- a/example/ios/fastlane/report.xml +++ b/example/ios/fastlane/report.xml @@ -5,39 +5,27 @@ - + - + - + - + - - - - - - - - - - - - - + From a02aaaaa651971515cd6895365d1c7fd2e2153b1 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Fri, 8 Jan 2021 22:48:37 +0530 Subject: [PATCH 0826/1140] [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 0827/1140] 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 0828/1140] [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 0829/1140] [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 a2b5a408d57edcfee9e805e0c98de1438b38bb86 Mon Sep 17 00:00:00 2001 From: Neevash Ramdial Date: Fri, 8 Jan 2021 16:18:08 -0400 Subject: [PATCH 0830/1140] [WIP] github workflow --- .github/workflows/build.yml | 63 ------------- .github/workflows/flutter-analyze.yml | 24 ----- .github/workflows/scripts/install-flutter.sh | 13 +++ .github/workflows/scripts/install-tools.sh | 6 ++ .../workflows/scripts/validate-formatting.sh | 30 +++++++ .github/workflows/stream_flutter_workflow.yml | 88 +++++++++++++++++++ .github/workflows/test.yml | 30 ------- 7 files changed, 137 insertions(+), 117 deletions(-) delete mode 100644 .github/workflows/build.yml delete mode 100644 .github/workflows/flutter-analyze.yml create mode 100644 .github/workflows/scripts/install-flutter.sh create mode 100644 .github/workflows/scripts/install-tools.sh create mode 100644 .github/workflows/scripts/validate-formatting.sh create mode 100644 .github/workflows/stream_flutter_workflow.yml delete mode 100644 .github/workflows/test.yml diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml deleted file mode 100644 index e4c6f701..00000000 --- a/.github/workflows/build.yml +++ /dev/null @@ -1,63 +0,0 @@ -name: Build - -on: - push: - branches: - - master - - feature/new-ui - release: - types: - - created - -jobs: - build_and_deploy_ios: - runs-on: [macos-latest] - steps: - - uses: actions/checkout@v2 - - name: Install RubyGems - run: | - cd example/ios - bundle install - - uses: subosito/flutter-action@v1.4.0 - with: - channel: 'stable' - - name: Install firebase-tools - run: npm install -g firebase-tools - - name: Flutter setup - run: | - cd example - flutter pub get - - name: Build and release - env: - MATCH_PASSWORD: ${{ secrets.MATCH_PASSWORD }} - MATCH_GIT_BASIC_AUTHORIZATION: ${{ secrets.MATCH_GIT_BASIC_AUTHORIZATION }} - FIREBASE_TOKEN: ${{ secrets.FIREBASE_TOKEN }} - run: | - cd example - flutter build ios --release --no-codesign - cd ios - bundle exec fastlane deploy_to_firebase - build_and_deploy_android: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - uses: actions/setup-java@v1 - with: - java-version: '12.x' - - uses: subosito/flutter-action@v1.4.0 - with: - channel: 'stable' - - run: | - cd example - flutter pub get - - name: Build - run: | - cd example - flutter build apk - - name: Deploy - uses: wzieba/Firebase-Distribution-Github-Action@v1.2.1 - with: - appId: ${{secrets.FIREBASE_ANDROID_APPID}} - token: ${{secrets.FIREBASE_TOKEN}} - groups: stream-testers - file: example/build/app/outputs/apk/release/app-release.apk diff --git a/.github/workflows/flutter-analyze.yml b/.github/workflows/flutter-analyze.yml deleted file mode 100644 index 312a65ba..00000000 --- a/.github/workflows/flutter-analyze.yml +++ /dev/null @@ -1,24 +0,0 @@ -name: Flutter Analyze -on: - push: - branches: - - master - - pull_request: - branches: - - '*' - -jobs: - build: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - uses: subosito/flutter-action@v1 - with: - channel: 'beta' - - run: flutter pub get - - - name: 'Flutter Format Check' - run: flutter format --set-exit-if-changed --dry-run . - - - run: flutter analyze diff --git a/.github/workflows/scripts/install-flutter.sh b/.github/workflows/scripts/install-flutter.sh new file mode 100644 index 00000000..247d2797 --- /dev/null +++ b/.github/workflows/scripts/install-flutter.sh @@ -0,0 +1,13 @@ +#!/usr/bin/env bash + +BRANCH=$1 + +if [ "$BRANCH" == "dev" ] +then + # TODO Flutter dev branch is currently broken so we're unable to test MacOS. + echo "TODO: Skipping macOS testing due to Flutter dev branch issue. Switching branch to stable." + BRANCH=stable +fi + +git clone https://github.com/flutter/flutter.git --depth 1 -b $BRANCH _flutter +echo "::add-path::$GITHUB_WORKSPACE/_flutter/bin" \ No newline at end of file diff --git a/.github/workflows/scripts/install-tools.sh b/.github/workflows/scripts/install-tools.sh new file mode 100644 index 00000000..087cfecb --- /dev/null +++ b/.github/workflows/scripts/install-tools.sh @@ -0,0 +1,6 @@ +#!/bin/bash + +flutter pub global activate melos +echo "::add-path::$HOME/.pub-cache/bin" +echo "::add-path::$GITHUB_WORKSPACE/_flutter/.pub-cache/bin" +echo "::add-path::$GITHUB_WORKSPACE/_flutter/bin/cache/dart-sdk/bin" \ No newline at end of file diff --git a/.github/workflows/scripts/validate-formatting.sh b/.github/workflows/scripts/validate-formatting.sh new file mode 100644 index 00000000..27e33215 --- /dev/null +++ b/.github/workflows/scripts/validate-formatting.sh @@ -0,0 +1,30 @@ +#!/bin/bash +if [[ $(git ls-files --modified) ]]; then + echo "" + echo "" + echo "These files are not formatted correctly:" + for f in $(git ls-files --modified); do + echo "" + echo "" + echo "-----------------------------------------------------------------" + echo "$f" + echo "-----------------------------------------------------------------" + echo "" + git --no-pager diff --unified=0 --minimal $f + echo "" + echo "-----------------------------------------------------------------" + echo "" + echo "" + done + if [[ $GITHUB_WORKFLOW ]]; then + git checkout . > /dev/null 2>&1 + fi + echo "" + echo "❌ Some files are incorrectly formatted, see above output." + echo "" + echo "To fix these locally, run: 'melos run format'." + exit 1 +else + echo "" + echo "✅ All files are formatted correctly." +fi \ No newline at end of file diff --git a/.github/workflows/stream_flutter_workflow.yml b/.github/workflows/stream_flutter_workflow.yml new file mode 100644 index 00000000..282b2a8f --- /dev/null +++ b/.github/workflows/stream_flutter_workflow.yml @@ -0,0 +1,88 @@ + +name: stream_flutter_workflow + +env: + ACTIONS_ALLOW_UNSECURE_COMMANDS: 'true' + +on: + pull_request: + push: + branches: + - main + paths-ignore: + - 'docs/**' + +jobs: + analyze: + timeout-minutes: 15 + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v1 + with: + fetch-depth: 0 + - name: 'Install Flutter' + run: ./.github/workflows/scripts/install-flutter.sh stable + - name: 'Install Tools' + run: | + ./.github/workflows/scripts/install-tools.sh + flutter pub global activate tuneup + - name: 'Bootstrap Workspace' + run: melos bootstrap + - name: 'Dart Analyze' + run: | + melos exec -c 3 -- \ + tuneup check + - name: 'Pub Check' + run: | + melos exec -c 1 --no-private --ignore="*example*" -- \ + pub publish --dry-run + format: + runs-on: ubuntu-latest + timeout-minutes: 15 + steps: + - uses: actions/checkout@v1 + with: + fetch-depth: 0 + - name: 'Install Flutter' + run: ./.github/workflows/scripts/install-flutter.sh stable + - name: 'Install Tools' + run: | + ./.github/workflows/scripts/install-tools.sh + curl -sL https://github.com/google/google-java-format/releases/download/google-java-format-1.3/google-java-format-1.3-all-deps.jar -o $HOME/google-java-format.jar + - name: 'Bootstrap Workspace' + run: melos bootstrap + - name: 'Dart' + run: | + melos exec -c 1 -- \ + flutter format . + ./.github/workflows/scripts/validate-formatting.sh + - name: 'Objective-C' + if: ${{ success() || failure() }} + run: | + melos exec -c 4 --ignore="*platform_interface*" --ignore="*web*" -- \ + find . -maxdepth 3 -name "*.h" -o -name "*.m" -print0 \| xargs -0 clang-format -i --style=Google --verbose + ./.github/workflows/scripts/validate-formatting.sh + - name: 'Java' + if: ${{ success() || failure() }} + run: | + melos exec -c 4 --ignore="*platform_interface*" --ignore="*web*" -- \ + find . -maxdepth 12 -name "*.java" -print0 \| xargs -0 java -jar $HOME/google-java-format.jar --replace + ./.github/workflows/scripts/validate-formatting.sh + + test: + runs-on: ubuntu-latest + timeout-minutes: 15 + steps: + - uses: actions/checkout@v1 + with: + fetch-depth: 0 + - name: 'Install Flutter' + run: ./.github/workflows/scripts/install-flutter.sh stable + - name: 'Install Tools' + run: ./.github/workflows/scripts/install-tools.sh + - name: 'Bootstrap Workspace' + run: melos bootstrap + - name: 'Flutter Test' + run: | + melos exec -c 3 --dir-exists=test --ignore="*example*" --ignore="*web*" -- \ + flutter test \ No newline at end of file diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml deleted file mode 100644 index a76cc4c8..00000000 --- a/.github/workflows/test.yml +++ /dev/null @@ -1,30 +0,0 @@ -name: Test - -on: - pull_request: -jobs: - test: - runs-on: [ubuntu-latest] - steps: - - uses: actions/checkout@v2 - - name: Flutter action - uses: subosito/flutter-action@v1.4.0 - with: - channel: 'stable' - - name: Get dependencies - run: flutter pub get - - name: Run formatter - run: flutter format -n --set-exit-if-changed . - - name: Coverage fix - run: | - file=test/coverage_helper_test.dart - echo "// Helper file to make coverage work for all dart files\n" > $file - echo "// ignore_for_file: unused_import" >> $file - find lib -name '*.dart' | grep -e '[^g]\.dart' | grep -v '_html.dart' | cut -c4- | awk -v package=stream_chat_flutter '{printf "import '\''package:%s%s'\'';\n", package, $1}' >> $file - echo "" >> $file - echo "void main(){}" >> $file - cat $file - - name: Run tests - run: flutter test --coverage - - name: Codecov - run: bash <(curl -s https://codecov.io/bash) -c -t ${{ secrets.CODECOV_TOKEN }} -f coverage/lcov.info -F flutter_tool From 8e285df0245f64a09a425f894435654830344b32 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Mon, 11 Jan 2021 12:38:29 +0530 Subject: [PATCH 0831/1140] [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: [ From bd73a8b6db86b66051b4ee85e6bd51fa494c14c8 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Mon, 11 Jan 2021 14:37:53 +0530 Subject: [PATCH 0832/1140] feat: Added end dialog and animations --- lib/src/message_actions_modal.dart | 450 +++++++++++++++++++---------- lib/src/message_widget.dart | 5 +- 2 files changed, 309 insertions(+), 146 deletions(-) diff --git a/lib/src/message_actions_modal.dart b/lib/src/message_actions_modal.dart index 8390ce97..cc29527e 100644 --- a/lib/src/message_actions_modal.dart +++ b/lib/src/message_actions_modal.dart @@ -14,6 +14,12 @@ import 'message_widget.dart'; import 'stream_chat.dart'; import 'stream_chat_theme.dart'; +enum ActionsModalState { + modal, + confirmDialog, + dismissMessage, +} + class MessageActionsModal extends StatefulWidget { final Widget Function(BuildContext, Message) editMessageInputBuilder; final void Function(Message) onThreadReplyTap; @@ -57,14 +63,20 @@ class MessageActionsModal extends StatefulWidget { } class _MessageActionsModalState extends State { - bool showConfirmFlagModal = false; + ActionsModalState state = ActionsModalState.modal; @override Widget build(BuildContext context) { - if (showConfirmFlagModal) { - return _showFlagDialog(); - } else { - return _showMessageOptionsModal(); + switch (state) { + case ActionsModalState.modal: + return _showMessageOptionsModal(); + break; + case ActionsModalState.confirmDialog: + return _showFlagDialog(); + break; + case ActionsModalState.dismissMessage: + return _showDismissAlert(); + break; } } @@ -211,7 +223,7 @@ class _MessageActionsModalState extends State { _buildDeleteButton(context), if (widget.showCopyMessage) _buildCopyButton(context), - if (widget.showCopyMessage) + if (widget.showFlagButton) _buildFlagButton(context), ], ).toList(), @@ -231,147 +243,295 @@ class _MessageActionsModalState extends State { } Widget _showFlagDialog() { - return GestureDetector( - behavior: HitTestBehavior.translucent, - onTap: () => Navigator.maybePop(context), - child: Stack( - children: [ - Positioned.fill( - child: BackdropFilter( - filter: ImageFilter.blur( - sigmaX: 10, - sigmaY: 10, - ), - child: Container( - color: StreamChatTheme.of(context).colorTheme.overlay, - ), - ), - ), - Center( - child: Opacity( - opacity: 0.9, - child: Material( - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(16.0), - ), - clipBehavior: Clip.antiAlias, - child: Container( - width: 270.0, - height: 156.0, - alignment: Alignment.center, - child: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - SizedBox( - height: 19.0, - ), - Text( - 'Flag Message', - style: StreamChatTheme.of(context) - .textTheme - .bodyBold - .copyWith(fontSize: 17.0), - ), - SizedBox( - height: 4.0, - ), - Padding( - padding: const EdgeInsets.symmetric(horizontal: 16.0), - child: Text( - 'Do you want to send a copy of this \nmessage to a moderator for further \ninvestigation?', - style: TextStyle(fontSize: 13.5), - textAlign: TextAlign.center, - ), - ), - SizedBox( - height: 21.0, - ), - Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - Expanded( - child: Center( - child: InkWell( - child: Container( - height: 44.0, - alignment: Alignment.center, - child: Text( - 'Cancel', - style: StreamChatTheme.of(context) - .textTheme - .body - .copyWith( - fontSize: 17.0, - color: StreamChatTheme.of(context) - .colorTheme - .accentBlue), - ), - decoration: BoxDecoration( - border: Border.symmetric( - horizontal: BorderSide( - color: StreamChatTheme.of(context) - .colorTheme - .grey), - ), - ), - ), - onTap: () { - setState(() { - showConfirmFlagModal = false; - }); - }, - ), - ), - ), - Expanded( - child: Center( - child: InkWell( - child: Container( - height: 44.0, - alignment: Alignment.center, - child: Text( - 'Flag', - style: StreamChatTheme.of(context) - .textTheme - .body - .copyWith( - fontWeight: FontWeight.bold, - fontSize: 17.0, - color: StreamChatTheme.of(context) - .colorTheme - .accentBlue), - ), - decoration: BoxDecoration( - border: Border.fromBorderSide( - BorderSide( - color: StreamChatTheme.of(context) - .colorTheme - .grey), - ), - ), - ), - onTap: () { - setState(() { - showConfirmFlagModal = false; - }); - final client = StreamChat.of(context).client; - client.flagMessage(widget.message.id); - }, - ), - ), - ), - ], - ), - ], + return TweenAnimationBuilder( + tween: Tween(begin: 0.0, end: 1.0), + duration: Duration(milliseconds: 300), + curve: Curves.easeInOut, + builder: (context, value, _) { + return GestureDetector( + behavior: HitTestBehavior.translucent, + onTap: () => Navigator.maybePop(context), + child: Stack( + children: [ + Positioned.fill( + child: BackdropFilter( + filter: ImageFilter.blur( + sigmaX: 10, + sigmaY: 10, + ), + child: Container( + color: StreamChatTheme.of(context).colorTheme.overlay, + ), ), ), - ), + Transform.scale( + scale: value, + child: Center( + child: Opacity( + opacity: 0.9, + child: Material( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(16.0), + ), + clipBehavior: Clip.antiAlias, + child: Container( + width: 270.0, + height: 156.0, + alignment: Alignment.center, + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + SizedBox( + height: 19.0, + ), + Text( + 'Flag Message', + style: StreamChatTheme.of(context) + .textTheme + .bodyBold + .copyWith(fontSize: 17.0), + ), + SizedBox( + height: 4.0, + ), + Padding( + padding: const EdgeInsets.symmetric( + horizontal: 16.0), + child: Text( + 'Do you want to send a copy of this \nmessage to a moderator for further \ninvestigation?', + style: TextStyle(fontSize: 13.5), + textAlign: TextAlign.center, + ), + ), + SizedBox( + height: 21.0, + ), + Row( + mainAxisAlignment: + MainAxisAlignment.spaceEvenly, + children: [ + Expanded( + child: Center( + child: InkWell( + child: Container( + height: 44.0, + alignment: Alignment.center, + child: Text( + 'Cancel', + style: StreamChatTheme.of(context) + .textTheme + .body + .copyWith( + fontSize: 17.0, + color: StreamChatTheme.of( + context) + .colorTheme + .accentBlue), + ), + decoration: BoxDecoration( + border: Border( + top: BorderSide( + color: StreamChatTheme.of( + context) + .colorTheme + .grey + .withOpacity(0.8)), + right: BorderSide( + color: StreamChatTheme.of( + context) + .colorTheme + .grey + .withOpacity(0.8)), + ), + ), + ), + onTap: () { + setState(() { + state = ActionsModalState.modal; + }); + }, + ), + ), + ), + Expanded( + child: Center( + child: InkWell( + child: Container( + height: 44.0, + alignment: Alignment.center, + child: Text( + 'Flag', + style: StreamChatTheme.of(context) + .textTheme + .body + .copyWith( + fontWeight: FontWeight.bold, + fontSize: 17.0, + color: StreamChatTheme.of( + context) + .colorTheme + .accentBlue), + ), + decoration: BoxDecoration( + border: Border( + top: BorderSide( + color: StreamChatTheme.of( + context) + .colorTheme + .grey + .withOpacity(0.8)), + ), + ), + ), + onTap: () { + setState(() { + state = ActionsModalState + .dismissMessage; + }); + final client = + StreamChat.of(context).client; + client.flagMessage(widget.message.id); + }, + ), + ), + ), + ], + ), + ], + ), + ), + ), + ), + ), + ), + ], ), - ), - ], - ), - ); + ); + }); + } + + Widget _showDismissAlert() { + return TweenAnimationBuilder( + key: GlobalKey(), + tween: Tween(begin: 0.0, end: 1.0), + duration: Duration(milliseconds: 300), + curve: Curves.easeInOut, + builder: (context, value, _) { + return GestureDetector( + behavior: HitTestBehavior.translucent, + onTap: () => Navigator.maybePop(context), + child: Stack( + children: [ + Positioned.fill( + child: BackdropFilter( + filter: ImageFilter.blur( + sigmaX: 10, + sigmaY: 10, + ), + child: Container( + color: StreamChatTheme.of(context).colorTheme.overlay, + ), + ), + ), + Transform.scale( + scale: value, + child: Center( + child: Opacity( + opacity: 0.9, + child: Material( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(16.0), + ), + clipBehavior: Clip.antiAlias, + child: Container( + width: 270.0, + height: 156.0, + alignment: Alignment.center, + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + SizedBox( + height: 19.0, + ), + Text( + 'Message Flagged', + style: StreamChatTheme.of(context) + .textTheme + .bodyBold + .copyWith(fontSize: 17.0), + ), + SizedBox( + height: 4.0, + ), + Padding( + padding: const EdgeInsets.symmetric( + horizontal: 16.0), + child: Text( + 'This message has been reported to a\nmoderator.', + style: TextStyle(fontSize: 13.5), + textAlign: TextAlign.center, + ), + ), + SizedBox( + height: 21.0, + ), + Row( + mainAxisAlignment: + MainAxisAlignment.spaceEvenly, + children: [ + Expanded( + child: Center( + child: InkWell( + child: Container( + height: 44.0, + alignment: Alignment.center, + child: Text( + 'Dismiss', + style: StreamChatTheme.of(context) + .textTheme + .body + .copyWith( + fontWeight: FontWeight.bold, + fontSize: 17.0, + color: StreamChatTheme.of( + context) + .colorTheme + .accentBlue), + ), + decoration: BoxDecoration( + border: Border( + top: BorderSide( + color: StreamChatTheme.of( + context) + .colorTheme + .grey + .withOpacity(0.8)), + ), + ), + ), + onTap: () { + setState(() { + state = ActionsModalState.modal; + }); + }, + ), + ), + ), + ], + ), + ], + ), + ), + ), + ), + ), + ), + ], + ), + ); + }); } Widget _buildReplyButton(BuildContext context) { @@ -404,7 +564,7 @@ class _MessageActionsModalState extends State { ), onTap: () { setState(() { - showConfirmFlagModal = true; + state = ActionsModalState.confirmDialog; }); }, ); diff --git a/lib/src/message_widget.dart b/lib/src/message_widget.dart index c687f36f..e26524f8 100644 --- a/lib/src/message_widget.dart +++ b/lib/src/message_widget.dart @@ -686,6 +686,9 @@ class _MessageWidgetState extends State { void _showMessageActionModalBottomSheet(BuildContext context) { final channel = StreamChannel.of(context).channel; + final isMyMessage = + widget.message.user.id == StreamChat.of(context).user.id; + showDialog( context: context, barrierColor: StreamChatTheme.of(context).colorTheme.overlay, @@ -720,7 +723,7 @@ class _MessageWidgetState extends State { widget.onReplyTap != null, showThreadReply: widget.showThreadReplyIndicator && widget.onThreadTap != null, - showFlagButton: widget.showFlagButton, + showFlagButton: widget.showFlagButton && !isMyMessage, ), ); }); From aca3918786f6e77626bacae8fa2443d550b95ec8 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Mon, 11 Jan 2021 14:50:31 +0530 Subject: [PATCH 0833/1140] fix: Fixed dialog styling --- lib/src/message_actions_modal.dart | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/lib/src/message_actions_modal.dart b/lib/src/message_actions_modal.dart index cc29527e..486bc83d 100644 --- a/lib/src/message_actions_modal.dart +++ b/lib/src/message_actions_modal.dart @@ -268,8 +268,12 @@ class _MessageActionsModalState extends State { scale: value, child: Center( child: Opacity( - opacity: 0.9, + opacity: 0.8, child: Material( + color: StreamChatTheme.of(context) + .colorTheme + .whiteSnow + .withOpacity(0.8), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(16.0), ), @@ -332,12 +336,14 @@ class _MessageActionsModalState extends State { decoration: BoxDecoration( border: Border( top: BorderSide( + width: 0.5, color: StreamChatTheme.of( context) .colorTheme .grey .withOpacity(0.8)), right: BorderSide( + width: 0.5, color: StreamChatTheme.of( context) .colorTheme @@ -376,6 +382,7 @@ class _MessageActionsModalState extends State { decoration: BoxDecoration( border: Border( top: BorderSide( + width: 0.5, color: StreamChatTheme.of( context) .colorTheme @@ -438,8 +445,12 @@ class _MessageActionsModalState extends State { scale: value, child: Center( child: Opacity( - opacity: 0.9, + opacity: 0.8, child: Material( + color: StreamChatTheme.of(context) + .colorTheme + .whiteSnow + .withOpacity(0.8), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(16.0), ), @@ -503,6 +514,7 @@ class _MessageActionsModalState extends State { decoration: BoxDecoration( border: Border( top: BorderSide( + width: 0.5, color: StreamChatTheme.of( context) .colorTheme From 43006b61848086d02dd3972c8352e4b229b86019 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Mon, 11 Jan 2021 15:13:01 +0530 Subject: [PATCH 0834/1140] fix: merge and tile styling change --- lib/src/message_actions_modal.dart | 54 +++++++++++++++++------------- 1 file changed, 31 insertions(+), 23 deletions(-) diff --git a/lib/src/message_actions_modal.dart b/lib/src/message_actions_modal.dart index 37c0aeae..0953c789 100644 --- a/lib/src/message_actions_modal.dart +++ b/lib/src/message_actions_modal.dart @@ -123,7 +123,7 @@ class _MessageActionsModalState extends State { child: Padding( padding: const EdgeInsets.symmetric(vertical: 8.0), child: Column( - crossAxisAlignment: reverse + crossAxisAlignment: widget.reverse ? CrossAxisAlignment.end : CrossAxisAlignment.start, children: [ @@ -185,13 +185,13 @@ class _MessageActionsModalState extends State { transform: Matrix4.identity() ..scale(val) ..rotateZ(-1.0 + val), - alignment: reverse + alignment: widget.reverse ? Alignment.topRight : Alignment.topLeft, child: Padding( padding: EdgeInsets.only( - right: reverse ? 16 : 0, - left: reverse ? 0 : 48, + right: widget.reverse ? 16 : 0, + left: widget.reverse ? 0 : 48, ), child: SizedBox( width: MediaQuery.of(context).size.width * 0.75, @@ -212,27 +212,29 @@ class _MessageActionsModalState extends State { .greyWhisper, context: context, tiles: [ - if (showReply && - (message.status == + if (widget.showReply && + (widget.message.status == MessageSendingStatus.SENT || - message.status == null) && - message.parentId == null) + widget.message.status == + null) && + widget.message.parentId == null) _buildReplyButton(context), - if (showThreadReply && - (message.status == + if (widget.showThreadReply && + (widget.message.status == MessageSendingStatus.SENT || - message.status == null) && - message.parentId == null) + widget.message.status == + null) && + widget.message.parentId == null) _buildThreadReplyButton(context), - if (showResendMessage) + if (widget.showResendMessage) _buildResendMessage(context), - if (showEditMessage) + if (widget.showEditMessage) _buildEditMessage(context), - if (showCopyMessage) + if (widget.showCopyMessage) _buildCopyButton(context), if (widget.showFlagButton) _buildFlagButton(context), - if (showDeleteMessage) + if (widget.showDeleteMessage) _buildDeleteButton(context), ], ).toList(), @@ -570,13 +572,19 @@ class _MessageActionsModalState extends State { Widget _buildFlagButton(BuildContext context) { return ListTile( - title: Text( - 'Flag', - style: Theme.of(context).textTheme.headline6, - ), - leading: StreamSvgIcon.flag( - color: StreamChatTheme.of(context).primaryIconTheme.color, - size: 24.0, + dense: true, + title: Row( + children: [ + StreamSvgIcon.flag( + color: StreamChatTheme.of(context).primaryIconTheme.color, + size: 23.0, + ), + const SizedBox(width: 16), + Text( + 'Flag', + style: StreamChatTheme.of(context).textTheme.headline, + ), + ], ), onTap: () { setState(() { From 6e52cc700c2766ccaa19cf25a4bd7d0050856c39 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Mon, 11 Jan 2021 11:17:27 +0100 Subject: [PATCH 0835/1140] add moon icon to change theme --- example/lib/advanced_options_page.dart | 63 ++++++++++++++++---- example/lib/main.dart | 80 ++++++++++++++++++-------- example/pubspec.yaml | 1 + lib/src/image_footer.dart | 2 +- lib/src/stream_svg_icon.dart | 14 ++++- lib/svgs/icon_moon.svg | 3 + 6 files changed, 128 insertions(+), 35 deletions(-) create mode 100644 lib/svgs/icon_moon.svg diff --git a/example/lib/advanced_options_page.dart b/example/lib/advanced_options_page.dart index 7555f286..2da11406 100644 --- a/example/lib/advanced_options_page.dart +++ b/example/lib/advanced_options_page.dart @@ -1,13 +1,16 @@ import 'dart:io'; +import 'package:example/routes/app_routes.dart'; +import 'package:example/routes/routes.dart'; import 'package:example/stream_version.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; import 'package:flutter_secure_storage/flutter_secure_storage.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; +import 'package:streaming_shared_preferences/streaming_shared_preferences.dart'; import 'choose_user_page.dart'; -import 'main.dart'; import 'notifications_service.dart'; class AdvancedOptionsPage extends StatefulWidget { @@ -312,17 +315,57 @@ class _AdvancedOptionsPageState extends State { context, MaterialPageRoute( builder: (context) { - return MaterialApp( - theme: ThemeData.light(), - darkTheme: ThemeData.dark(), - themeMode: ThemeMode.system, - builder: (context, widget) { - return StreamChat( - child: widget, - client: client, + return FutureBuilder( + future: StreamingSharedPreferences.instance, + builder: (context, snapshot) { + if (!snapshot.hasData) { + return SizedBox(); + } + return PreferenceBuilder( + preference: snapshot.data.getInt( + 'theme', + defaultValue: 0, + ), + builder: (context, snapshot) => MaterialApp( + builder: (context, child) { + return StreamChat( + client: client, + child: Builder( + builder: (context) => + AnnotatedRegion< + SystemUiOverlayStyle>( + child: child, + value: SystemUiOverlayStyle( + systemNavigationBarColor: + StreamChatTheme.of(context) + .colorTheme + .white, + systemNavigationBarIconBrightness: + Theme.of(context) + .brightness == + Brightness.dark + ? Brightness.light + : Brightness.dark, + ), + ), + ), + ); + }, + debugShowCheckedModeBanner: false, + theme: ThemeData.light(), + darkTheme: ThemeData.dark(), + themeMode: { + -1: ThemeMode.dark, + 0: ThemeMode.system, + 1: ThemeMode.light, + }[snapshot], + onGenerateRoute: AppRoutes.generateRoute, + initialRoute: client.state.user == null + ? Routes.CHOOSE_USER + : Routes.HOME, + ), ); }, - home: ChannelListPage(), ); }, ), diff --git a/example/lib/main.dart b/example/lib/main.dart index 25282335..8cc511fc 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -10,6 +10,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_secure_storage/flutter_secure_storage.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; +import 'package:streaming_shared_preferences/streaming_shared_preferences.dart'; import 'notifications_service.dart'; import 'routes/app_routes.dart'; @@ -52,32 +53,50 @@ class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { - return MaterialApp( - builder: (context, child) { - return StreamChat( - client: client, - child: Builder( - builder: (context) => AnnotatedRegion( - child: child, - value: SystemUiOverlayStyle( - systemNavigationBarColor: - StreamChatTheme.of(context).colorTheme.white, - systemNavigationBarIconBrightness: - Theme.of(context).brightness == Brightness.dark - ? Brightness.light - : Brightness.dark, - ), - ), + return FutureBuilder( + future: StreamingSharedPreferences.instance, + builder: (context, snapshot) { + if (!snapshot.hasData) { + return SizedBox(); + } + return PreferenceBuilder( + preference: snapshot.data.getInt( + 'theme', + defaultValue: 0, + ), + builder: (context, snapshot) => MaterialApp( + builder: (context, child) { + return StreamChat( + client: client, + child: Builder( + builder: (context) => AnnotatedRegion( + child: child, + value: SystemUiOverlayStyle( + systemNavigationBarColor: + StreamChatTheme.of(context).colorTheme.white, + systemNavigationBarIconBrightness: + Theme.of(context).brightness == Brightness.dark + ? Brightness.light + : Brightness.dark, + ), + ), + ), + ); + }, + debugShowCheckedModeBanner: false, + theme: ThemeData.light(), + darkTheme: ThemeData.dark(), + themeMode: { + -1: ThemeMode.dark, + 0: ThemeMode.system, + 1: ThemeMode.light, + }[snapshot], + onGenerateRoute: AppRoutes.generateRoute, + initialRoute: + client.state.user == null ? Routes.CHOOSE_USER : Routes.HOME, ), ); }, - debugShowCheckedModeBanner: false, - theme: ThemeData.light(), - darkTheme: ThemeData.dark(), - themeMode: ThemeMode.system, - onGenerateRoute: AppRoutes.generateRoute, - initialRoute: - client.state.user == null ? Routes.CHOOSE_USER : Routes.HOME, ); } } @@ -269,6 +288,21 @@ class _HomePageState extends State { fontSize: 14.5, ), ), + trailing: IconButton( + icon: StreamSvgIcon.Icon_moon( + size: 24, + ), + color: StreamChatTheme.of(context).colorTheme.grey, + onPressed: () async { + final sp = await StreamingSharedPreferences.instance; + sp.setInt( + 'theme', + Theme.of(context).brightness == Brightness.dark + ? 1 + : -1, + ); + }, + ), ), ), ), diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 539166ec..16bc8108 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -16,6 +16,7 @@ dependencies: flutter_secure_storage: ^3.3.5 yaml: ^2.2.1 uuid: ^2.2.2 + streaming_shared_preferences: ^1.0.2 dev_dependencies: flutter_test: diff --git a/lib/src/image_footer.dart b/lib/src/image_footer.dart index 7ee9a128..e43eb3fb 100644 --- a/lib/src/image_footer.dart +++ b/lib/src/image_footer.dart @@ -116,7 +116,7 @@ class _ImageFooterState extends State { mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ IconButton( - icon: StreamSvgIcon.icon_SHARE( + icon: StreamSvgIcon.Icon_SHARE( size: 24.0, color: StreamChatTheme.of(context).colorTheme.black, ), diff --git a/lib/src/stream_svg_icon.dart b/lib/src/stream_svg_icon.dart index 3e8cfae2..fcef384f 100644 --- a/lib/src/stream_svg_icon.dart +++ b/lib/src/stream_svg_icon.dart @@ -470,7 +470,19 @@ class StreamSvgIcon extends StatelessWidget { ); } - factory StreamSvgIcon.icon_SHARE({ + factory StreamSvgIcon.Icon_moon({ + double size, + Color color, + }) { + return StreamSvgIcon( + assetName: 'icon_moon.svg', + color: color, + width: size, + height: size, + ); + } + + factory StreamSvgIcon.Icon_SHARE({ double size, Color color, }) { diff --git a/lib/svgs/icon_moon.svg b/lib/svgs/icon_moon.svg new file mode 100644 index 00000000..ebc3279c --- /dev/null +++ b/lib/svgs/icon_moon.svg @@ -0,0 +1,3 @@ + + + From 2879b491fff44894b4525f78fc9ae0b6863d310f Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Mon, 11 Jan 2021 16:20:42 +0530 Subject: [PATCH 0836/1140] fix: Added correct icon in modal --- example/ios/Podfile.lock | 2 +- lib/src/message_actions_modal.dart | 3 +-- lib/src/stream_svg_icon.dart | 12 ++++++++++++ lib/svgs/icon_flag.svg | 3 +++ 4 files changed, 17 insertions(+), 3 deletions(-) create mode 100644 lib/svgs/icon_flag.svg diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock index f266b656..af57742c 100644 --- a/example/ios/Podfile.lock +++ b/example/ios/Podfile.lock @@ -296,4 +296,4 @@ SPEC CHECKSUMS: PODFILE CHECKSUM: eb001256612a59f8f9e4d083ad8b9671e69dd184 -COCOAPODS: 1.10.0 +COCOAPODS: 1.8.3 diff --git a/lib/src/message_actions_modal.dart b/lib/src/message_actions_modal.dart index 0953c789..5c2f16bb 100644 --- a/lib/src/message_actions_modal.dart +++ b/lib/src/message_actions_modal.dart @@ -575,9 +575,8 @@ class _MessageActionsModalState extends State { dense: true, title: Row( children: [ - StreamSvgIcon.flag( + StreamSvgIcon.icon_flag( color: StreamChatTheme.of(context).primaryIconTheme.color, - size: 23.0, ), const SizedBox(width: 16), Text( diff --git a/lib/src/stream_svg_icon.dart b/lib/src/stream_svg_icon.dart index 3e8cfae2..e8af3436 100644 --- a/lib/src/stream_svg_icon.dart +++ b/lib/src/stream_svg_icon.dart @@ -877,4 +877,16 @@ class StreamSvgIcon extends StatelessWidget { height: size, ); } + + factory StreamSvgIcon.icon_flag({ + double size, + Color color, + }) { + return StreamSvgIcon( + assetName: 'icon_flag.svg', + color: color, + width: size, + height: size, + ); + } } diff --git a/lib/svgs/icon_flag.svg b/lib/svgs/icon_flag.svg new file mode 100644 index 00000000..0f382e94 --- /dev/null +++ b/lib/svgs/icon_flag.svg @@ -0,0 +1,3 @@ + + + From 0eb482e96669165d3ecd79aaf405eb160f58be02 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Mon, 11 Jan 2021 16:21:15 +0530 Subject: [PATCH 0837/1140] fix: Added correct icon in modal --- example/ios/Podfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock index af57742c..f266b656 100644 --- a/example/ios/Podfile.lock +++ b/example/ios/Podfile.lock @@ -296,4 +296,4 @@ SPEC CHECKSUMS: PODFILE CHECKSUM: eb001256612a59f8f9e4d083ad8b9671e69dd184 -COCOAPODS: 1.8.3 +COCOAPODS: 1.10.0 From 062c38af624eefc1054ab969f51e01eeb00680ec Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Mon, 11 Jan 2021 12:20:30 +0100 Subject: [PATCH 0838/1140] fix emoji sizing --- lib/src/deleted_message.dart | 5 +---- lib/src/message_widget.dart | 12 ++++++++---- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/lib/src/deleted_message.dart b/lib/src/deleted_message.dart index 5921df43..bd014770 100644 --- a/lib/src/deleted_message.dart +++ b/lib/src/deleted_message.dart @@ -63,10 +63,7 @@ class DeletedMessage extends StatelessWidget { 'Message deleted', style: messageTheme.messageText.copyWith( fontStyle: FontStyle.italic, - color: (Theme.of(context).brightness == Brightness.dark - ? StreamChatTheme.of(context).colorTheme.white - : StreamChatTheme.of(context).colorTheme.black) - .withOpacity(.5), + color: messageTheme.createdAt.color, ), ), ), diff --git a/lib/src/message_widget.dart b/lib/src/message_widget.dart index 12137c64..3632fca2 100644 --- a/lib/src/message_widget.dart +++ b/lib/src/message_widget.dart @@ -280,9 +280,6 @@ class _MessageWidgetState extends State { var leftPadding = widget.showUserAvatar != DisplayWidget.gone ? avatarWidth + 8.5 : 0.5; - final isOnlyEmoji = - widget.message.text.characters.every((c) => Emoji.byChar(c) != null); - final hasFiles = widget.message.attachments?.any((element) => element.type == 'file') == true; @@ -939,9 +936,16 @@ class _MessageWidgetState extends State { ); } + final _emojis = Emoji.all(); bool get isOnlyEmoji => widget.message.text.characters.isNotEmpty && - widget.message.text.characters.every((c) => Emoji.byChar(c) != null); + widget.message.text.trim().characters.every((c) => + _emojis.firstWhere( + (Emoji emoji) => emoji.char.contains(c), + orElse: () => null, + ) != + null) && + widget.message.text.characters.length < 4; Color _getBackgroundColor() { if (hasQuotedMessage) { From db1f28134ae9394c219a51d46c22979a75047733 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Mon, 11 Jan 2021 12:21:54 +0100 Subject: [PATCH 0839/1140] fix drawer background --- example/lib/main.dart | 223 +++++++++++++++++++++--------------------- 1 file changed, 113 insertions(+), 110 deletions(-) diff --git a/example/lib/main.dart b/example/lib/main.dart index 8cc511fc..98fa71a2 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -185,128 +185,131 @@ class _HomePageState extends State { Drawer _buildDrawer(BuildContext context, User user) { return Drawer( - 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: 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, + ), ), ), - ), - ], - ), - ), - 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, + 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, + ), ), ), - ), - 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), + 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, ), - title: Text( - 'Sign out', - style: TextStyle( - fontSize: 14.5, - ), - ), - trailing: IconButton( - icon: StreamSvgIcon.Icon_moon( - size: 24, - ), - color: StreamChatTheme.of(context).colorTheme.grey, - onPressed: () async { - final sp = await StreamingSharedPreferences.instance; - sp.setInt( - 'theme', - Theme.of(context).brightness == Brightness.dark - ? 1 - : -1, + ), + ), + 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, + ), + ), + trailing: IconButton( + icon: StreamSvgIcon.Icon_moon( + size: 24, + ), + color: StreamChatTheme.of(context).colorTheme.grey, + onPressed: () async { + final sp = await StreamingSharedPreferences.instance; + sp.setInt( + 'theme', + Theme.of(context).brightness == Brightness.dark + ? 1 + : -1, + ); + }, + ), ), ), ), - ), - ], + ], + ), ), ), ), From 7b32379d07e5b4f9705216cf89381d71680f0dda Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Mon, 11 Jan 2021 17:20:29 +0530 Subject: [PATCH 0840/1140] fix: Removed unnecessary check --- lib/src/message_widget.dart | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/lib/src/message_widget.dart b/lib/src/message_widget.dart index 38d2f1e2..ebf57c94 100644 --- a/lib/src/message_widget.dart +++ b/lib/src/message_widget.dart @@ -694,8 +694,6 @@ class _MessageWidgetState extends State { void _showMessageActionModalBottomSheet(BuildContext context) { final channel = StreamChannel.of(context).channel; - final isMyMessage = - widget.message.user.id == StreamChat.of(context).user.id; showDialog( context: context, @@ -731,7 +729,7 @@ class _MessageWidgetState extends State { widget.onReplyTap != null, showThreadReply: widget.showThreadReplyIndicator && widget.onThreadTap != null, - showFlagButton: widget.showFlagButton && !isMyMessage, + showFlagButton: widget.showFlagButton, ), ); }); From 0aa58cf660ffaa92daf44f4f1db6e5512a9aebb6 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Mon, 11 Jan 2021 18:11:51 +0530 Subject: [PATCH 0841/1140] [MessageWidget] Refactor Signed-off-by: Sahil Kumar --- example/lib/customize_message_widget.dart | 2 +- lib/src/message_actions_modal.dart | 3 +- lib/src/message_list_view.dart | 81 ++++++----- lib/src/message_reactions_modal.dart | 2 +- lib/src/message_widget.dart | 161 +++++++++++----------- 5 files changed, 129 insertions(+), 120 deletions(-) diff --git a/example/lib/customize_message_widget.dart b/example/lib/customize_message_widget.dart index a3713b69..84e65eab 100644 --- a/example/lib/customize_message_widget.dart +++ b/example/lib/customize_message_widget.dart @@ -120,7 +120,7 @@ class ChannelPage extends StatelessWidget { top: !details.isLastUser ? Radius.circular(16) : Radius.zero, bottom: !details.isNextUser ? Radius.circular(16) : Radius.zero, ), - showSendingIndicator: DisplayWidget.gone, + showSendingIndicator: false, reverse: false, showUserAvatar: details.isNextUser ? DisplayWidget.hide : DisplayWidget.show, diff --git a/lib/src/message_actions_modal.dart b/lib/src/message_actions_modal.dart index d7497676..0aa53824 100644 --- a/lib/src/message_actions_modal.dart +++ b/lib/src/message_actions_modal.dart @@ -1,4 +1,3 @@ -import 'dart:math'; import 'dart:ui'; import 'package:flutter/foundation.dart'; @@ -139,7 +138,7 @@ class MessageActionsModal extends StatelessWidget { MessageSendingStatus.SENT || message.status == null), showInChannelIndicator: false, - showSendingIndicator: DisplayWidget.gone, + showSendingIndicator: false, shape: messageShape, ), ), diff --git a/lib/src/message_list_view.dart b/lib/src/message_list_view.dart index 415539b8..41792390 100644 --- a/lib/src/message_list_view.dart +++ b/lib/src/message_list_view.dart @@ -220,6 +220,8 @@ class _MessageListViewState extends State { bool get _upToDate => streamChannel.channel.state.isUpToDate; + bool get _isThreadConversation => widget.parentMessage != null; + bool _topPaginationActive = false; bool _bottomPaginationActive = false; @@ -234,7 +236,7 @@ class _MessageListViewState extends State { @override Widget build(BuildContext context) { - final messagesStream = widget.parentMessage != null + final messagesStream = _isThreadConversation ? streamChannel.channel.state.threadsStream .where((threads) => threads.containsKey(widget.parentMessage.id)) .map((threads) => threads[widget.parentMessage.id]) @@ -333,9 +335,8 @@ class _MessageListViewState extends State { physics: widget.scrollPhysics, itemScrollController: _scrollController, reverse: true, - itemCount: messages.length + - 2 + - (widget.parentMessage != null ? 1 : 0), + itemCount: + messages.length + 2 + (_isThreadConversation ? 1 : 0), separatorBuilder: (context, i) { if (i == messages.length) return Offstage(); if (i == messages.length + 2) return Offstage(); @@ -497,7 +498,7 @@ class _MessageListViewState extends State { Future _paginateData( StreamChannelState channel, QueryDirection direction) { - if (widget.parentMessage == null) { + if (!_isThreadConversation) { return channel.queryMessages(direction: direction); } else { return channel.getReplies(widget.parentMessage.id); @@ -722,7 +723,7 @@ class _MessageListViewState extends State { right: 8.0, bottom: 16.0, ), - showSendingIndicator: DisplayWidget.hide, + showSendingIndicator: false, onThreadTap: _onThreadTap, showEditMessage: false, showDeleteMessage: false, @@ -768,32 +769,60 @@ class _MessageListViewState extends State { } final channel = streamChannel.channel; - final readList = channel.state?.read - ?.where((element) => element.user.id != userId) - ?.where((read) => - (read.lastRead.isAfter(message.createdAt) || - read.lastRead.isAtSameMomentAs(message.createdAt)) && - (index == 0 || - read.lastRead.isBefore(messages[index - 1].createdAt))) - ?.toList() ?? + final readList = channel.state?.read?.where((read) { + if (read.user.id == userId) return false; + return (read.lastRead.isAfter(message.createdAt) || + read.lastRead.isAtSameMomentAs(message.createdAt)) && + (index == 0 || + read.lastRead.isBefore(messages[index - 1].createdAt)); + })?.toList() ?? []; final allRead = readList.length >= (channel.memberCount ?? 0) - 1; - - final isThreadMessage = - widget.parentMessage != null || message?.showInChannel == true; - final hasFileAttachment = message.attachments.any((it) => it.type == 'file'); + final isThreadMessage = + message?.parentId != null && message?.showInChannel == true; + + final hasReplies = message.replyCount > 0; + final attachmentBorderRadius = hasFileAttachment ? 12.0 : 14.0; + final showTimeStamp = message.createdAt != null && + (!isThreadMessage || _isThreadConversation) && + !hasReplies && + (timeDiff >= 1 || !isNextUserSame); + + final showUsername = !isMyMessage && + (!isThreadMessage || _isThreadConversation) && + !hasReplies && + (timeDiff >= 1 || !isNextUserSame); + + final showUserAvatar = isMyMessage + ? DisplayWidget.gone + : (timeDiff >= 1 || !isNextUserSame) + ? DisplayWidget.show + : DisplayWidget.hide; + + final showSendingIndicator = + isMyMessage && (index == 0 || timeDiff >= 1 || !isNextUserSame); + + bool showInChannelIndicator = !_isThreadConversation && isThreadMessage; + bool showThreadReplyIndicator = !_isThreadConversation && hasReplies; + Widget child = MessageWidget( key: ValueKey('MESSAGE-${message.id}'), message: message, reverse: isMyMessage, showReactions: !message.isDeleted, padding: const EdgeInsets.symmetric(horizontal: 8.0), + showInChannelIndicator: showInChannelIndicator, + showThreadReplyIndicator: showThreadReplyIndicator, + showUsername: showUsername, + showTimestamp: showTimeStamp, + showSendingIndicator: showSendingIndicator, + showUserAvatar: showUserAvatar, onQuotedMessageTap: (quotedMessageId) async { final scrollToIndex = () { final index = messages.indexWhere((m) => m.id == quotedMessageId); @@ -814,15 +843,6 @@ class _MessageListViewState extends State { }); } }, - showInChannelIndicator: widget.parentMessage == null, - showThreadReplyIndicator: widget.parentMessage == null, - 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, @@ -842,11 +862,6 @@ class _MessageListViewState extends State { topRight: Radius.circular(16), bottomRight: Radius.circular(16), ), - showUserAvatar: isMyMessage - ? DisplayWidget.gone - : (timeDiff >= 1 || !isNextUserSame - ? DisplayWidget.show - : DisplayWidget.hide), messageTheme: isMyMessage ? StreamChatTheme.of(context).ownMessageTheme : StreamChatTheme.of(context).otherMessageTheme, @@ -918,7 +933,7 @@ class _MessageListViewState extends State { } }); - if (widget.parentMessage != null) { + if (_isThreadConversation) { streamChannel.getReplies(widget.parentMessage.id); } diff --git a/lib/src/message_reactions_modal.dart b/lib/src/message_reactions_modal.dart index 702bb0ed..5c24e047 100644 --- a/lib/src/message_reactions_modal.dart +++ b/lib/src/message_reactions_modal.dart @@ -116,7 +116,7 @@ class MessageReactionsModal extends StatelessWidget { showThreadReplyIndicator: false, showTimestamp: false, translateUserAvatar: false, - showSendingIndicator: DisplayWidget.gone, + showSendingIndicator: false, shape: messageShape, showInChannelIndicator: false, showReactionPickerIndicator: showReactions && diff --git a/lib/src/message_widget.dart b/lib/src/message_widget.dart index 12137c64..22f91b95 100644 --- a/lib/src/message_widget.dart +++ b/lib/src/message_widget.dart @@ -96,7 +96,7 @@ class MessageWidget extends StatefulWidget { final DisplayWidget showUserAvatar; /// It controls the display behaviour of the sending indicator - final DisplayWidget showSendingIndicator; + final bool showSendingIndicator; /// If true the widget will show the reactions final bool showReactions; @@ -157,7 +157,7 @@ class MessageWidget extends StatefulWidget { this.onMentionTap, this.showReactionPickerIndicator = false, this.showUserAvatar = DisplayWidget.show, - this.showSendingIndicator = DisplayWidget.show, + this.showSendingIndicator = true, this.showThreadReplyIndicator = true, this.showInChannelIndicator = true, this.showReplyIndicator = true, @@ -239,18 +239,17 @@ class MessageWidget extends StatefulWidget { } class _MessageWidgetState extends State { - bool get showThreadReplyIndicator => - widget.showThreadReplyIndicator && widget.message.replyCount > 0; + bool get showThreadReplyIndicator => widget.showThreadReplyIndicator; + + bool get showSendingIndicator => widget.showSendingIndicator; bool get showUsername => widget.showUsername; - bool get showTimeStamp => - widget.message.createdAt != null && widget.showTimestamp; + bool get showTimeStamp => widget.showTimestamp; bool get isMessageRead => widget.readList?.isNotEmpty == true; - bool get showInChannel => - widget.showInChannelIndicator && widget.message?.showInChannel == true; + bool get showInChannel => widget.showInChannelIndicator; bool get hasQuotedMessage => widget.message?.quotedMessage != null; @@ -494,88 +493,84 @@ class _MessageWidgetState extends State { } Widget _buildBottomRow(double leftPadding) { - final deleted = widget.message.isDeleted; - var children = []; - if (deleted) { - children.add( - Row( - mainAxisSize: MainAxisSize.min, - children: [ - StreamSvgIcon.eye( - 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.grey), - ), - ], + if (widget.message.isDeleted) { + return Padding( + padding: EdgeInsets.only(left: leftPadding), + child: Transform( + transform: Matrix4.rotationY(widget.reverse ? pi : 0), + alignment: Alignment.center, + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + StreamSvgIcon.eye( + 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.grey), + ), + ], + ), ), ); - } else if (showInChannel) { - final onThreadTap = () async { - try { + } + + var children = []; + + final threadParticipants = widget.message.threadParticipants; + final showThreadParticipants = threadParticipants?.isNotEmpty == true; + final replyCount = widget.message.replyCount; + + var msg = 'Thread Reply'; + if (showThreadReplyIndicator && replyCount > 1) { + msg = '$replyCount Thread Replies'; + } + + final onThreadTap = () async { + try { + var message = widget.message; + if (showInChannel) { final channel = StreamChannel.of(context); - final message = await channel.getMessage(widget.message.parentId); - return widget.onThreadTap(message); - } catch (e, stk) { - print(e); - print(stk); - return null; + message = await channel.getMessage(widget.message.parentId); } - }; - children.add( + return widget.onThreadTap(message); + } catch (e, stk) { + print(e); + print(stk); + return null; + } + }; + + children.addAll([ + if (showSendingIndicator) _buildSendingIndicator(), + if (showInChannel || showThreadReplyIndicator) ...[ + if (showThreadParticipants) + SizedBox.fromSize( + size: Size((threadParticipants.length * 8.0) + 10, 16), + child: _buildThreadParticipantsIndicator(), + ), InkWell( onTap: widget.onThreadTap != null ? onThreadTap : null, - child: Text('Thread Reply', style: widget.messageTheme?.replies), + child: Text(msg, style: widget.messageTheme?.replies), ), - ); - } else { - final showSendingIndicator = - widget.showSendingIndicator == DisplayWidget.show; - final threadParticipants = widget.message.threadParticipants; - final showThreadParticipants = threadParticipants?.isNotEmpty == true; - final replyCount = widget.message.replyCount; - final msg = replyCount != 0 - ? '$replyCount ${replyCount > 1 ? 'Thread Replies' : 'Thread Reply'}' - : 'Thread Reply'; + ], + if (showUsername) + Text( + widget.message.user.name, + style: widget.messageTheme.replies.copyWith( + color: widget.messageTheme.createdAt.color, + ), + ), + if (showTimeStamp) + Text( + Jiffy(widget.message.createdAt.toLocal()).jm, + style: widget.messageTheme.createdAt, + ), + ]); - final onThreadTap = () async { - var message = widget.message; - return widget.onThreadTap(message); - }; - - children.addAll([ - if (showSendingIndicator) _buildSendingIndicator(), - if (showThreadReplyIndicator) ...[ - if (showThreadParticipants) - SizedBox.fromSize( - size: Size((threadParticipants.length * 8.0) + 10, 16), - child: _buildThreadParticipantsIndicator(), - ), - InkWell( - onTap: widget.onThreadTap != null ? onThreadTap : null, - child: Text(msg, style: widget.messageTheme?.replies), - ), - ], - if (showUsername) - Text( - widget.message.user.name, - style: widget.messageTheme.replies.copyWith( - color: widget.messageTheme.createdAt.color, - ), - ), - if (showTimeStamp) - Text( - Jiffy(widget.message.createdAt.toLocal()).jm, - style: widget.messageTheme.createdAt, - ), - ]); - } if (widget.reverse) children = children.reversed.toList(); return Padding( @@ -585,7 +580,7 @@ class _MessageWidgetState extends State { clipBehavior: Clip.none, crossAxisAlignment: CrossAxisAlignment.end, children: [ - if (!deleted && (showThreadReplyIndicator || showInChannel)) + if (showThreadReplyIndicator || showInChannel) Container( margin: EdgeInsets.only( bottom: widget.messageTheme.replies.fontSize / 2, From 4d419c9b53a7f13cd0931487fb8025e693a405b7 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Mon, 11 Jan 2021 18:19:48 +0530 Subject: [PATCH 0842/1140] [MessageWidget] Move bottomRow padding to upper layer Signed-off-by: Sahil Kumar --- lib/src/message_widget.dart | 104 ++++++++++++++++++------------------ 1 file changed, 52 insertions(+), 52 deletions(-) diff --git a/lib/src/message_widget.dart b/lib/src/message_widget.dart index 22f91b95..5180a329 100644 --- a/lib/src/message_widget.dart +++ b/lib/src/message_widget.dart @@ -449,7 +449,11 @@ class _MessageWidgetState extends State { if (showBottomRow) SizedBox(height: 20.0), ], ), - if (showBottomRow) _buildBottomRow(leftPadding), + if (showBottomRow) + Padding( + padding: EdgeInsets.only(left: leftPadding), + child: _bottomRow, + ), if (isFailedState) Positioned( left: widget.reverse ? -3 : null, @@ -492,28 +496,27 @@ class _MessageWidgetState extends State { ); } - Widget _buildBottomRow(double leftPadding) { + Widget get _bottomRow { if (widget.message.isDeleted) { - return Padding( - padding: EdgeInsets.only(left: leftPadding), - child: Transform( - transform: Matrix4.rotationY(widget.reverse ? pi : 0), - alignment: Alignment.center, - child: Row( - mainAxisSize: MainAxisSize.min, - children: [ - StreamSvgIcon.eye( - 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.grey), - ), - ], - ), + return Transform( + transform: Matrix4.rotationY(widget.reverse ? pi : 0), + alignment: Alignment.center, + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + StreamSvgIcon.eye( + 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.grey), + ), + ], ), ); } @@ -573,40 +576,37 @@ class _MessageWidgetState extends State { if (widget.reverse) children = children.reversed.toList(); - return Padding( - padding: EdgeInsets.only(left: leftPadding), - child: Flex( - direction: Axis.horizontal, - clipBehavior: Clip.none, - crossAxisAlignment: CrossAxisAlignment.end, - children: [ - if (showThreadReplyIndicator || showInChannel) - Container( - margin: EdgeInsets.only( - bottom: widget.messageTheme.replies.fontSize / 2, - ), - child: CustomPaint( - size: const Size(16, 32), - painter: _ThreadReplyPainter( - context: context, - color: widget.messageTheme.messageBorderColor, - ), - ), + return Flex( + direction: Axis.horizontal, + clipBehavior: Clip.none, + crossAxisAlignment: CrossAxisAlignment.end, + children: [ + if (showThreadReplyIndicator || showInChannel) + Container( + margin: EdgeInsets.only( + bottom: widget.messageTheme.replies.fontSize / 2, ), - ...children.map( - (child) => Transform( - transform: Matrix4.rotationY(widget.reverse ? pi : 0), - alignment: Alignment.center, - child: Container( - height: 16, - child: Center( - child: child, - ), + child: CustomPaint( + size: const Size(16, 32), + painter: _ThreadReplyPainter( + context: context, + color: widget.messageTheme.messageBorderColor, ), ), ), - ].insertBetween(const SizedBox(width: 8.0)), - ), + ...children.map( + (child) => Transform( + transform: Matrix4.rotationY(widget.reverse ? pi : 0), + alignment: Alignment.center, + child: Container( + height: 16, + child: Center( + child: child, + ), + ), + ), + ), + ].insertBetween(const SizedBox(width: 8.0)), ); } From 81f8295f7f966a8e52b4ae249e76079ffb21b33d Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Mon, 11 Jan 2021 14:24:01 +0100 Subject: [PATCH 0843/1140] extract isonlyemoji --- lib/src/message_widget.dart | 12 +----------- lib/src/quoted_message_widget.dart | 6 ++---- lib/src/utils.dart | 17 +++++++++++++++-- 3 files changed, 18 insertions(+), 17 deletions(-) diff --git a/lib/src/message_widget.dart b/lib/src/message_widget.dart index 3632fca2..a883201a 100644 --- a/lib/src/message_widget.dart +++ b/lib/src/message_widget.dart @@ -1,7 +1,6 @@ import 'dart:math'; import 'dart:ui'; -import 'package:emojis/emoji.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; @@ -936,16 +935,7 @@ class _MessageWidgetState extends State { ); } - final _emojis = Emoji.all(); - bool get isOnlyEmoji => - widget.message.text.characters.isNotEmpty && - widget.message.text.trim().characters.every((c) => - _emojis.firstWhere( - (Emoji emoji) => emoji.char.contains(c), - orElse: () => null, - ) != - null) && - widget.message.text.characters.length < 4; + bool get isOnlyEmoji => textIsOnlyEmoji(widget.message.text); Color _getBackgroundColor() { if (hasQuotedMessage) { diff --git a/lib/src/quoted_message_widget.dart b/lib/src/quoted_message_widget.dart index c0439d46..7621174f 100644 --- a/lib/src/quoted_message_widget.dart +++ b/lib/src/quoted_message_widget.dart @@ -1,18 +1,17 @@ import 'dart:math'; import 'package:cached_network_image/cached_network_image.dart'; -import 'package:emojis/emoji.dart'; import 'package:flutter/material.dart'; import 'package:stream_chat/stream_chat.dart'; import 'package:video_player/video_player.dart'; import 'attachment_error.dart'; +import 'extension.dart'; import 'image_attachment.dart'; import 'message_text.dart'; import 'stream_chat_theme.dart'; import 'user_avatar.dart'; import 'utils.dart'; -import 'extension.dart'; typedef QuotedMessageAttachmentThumbnailBuilder = Widget Function( BuildContext, @@ -126,8 +125,7 @@ class QuotedMessageWidget extends StatelessWidget { } Widget _buildMessage(BuildContext context) { - final isOnlyEmoji = - message.text.characters.every((c) => Emoji.byChar(c) != null); + final isOnlyEmoji = textIsOnlyEmoji(message.text); var msg = _hasAttachments && !_containsText ? message.copyWith(text: message.attachments.last?.title ?? '') : message; diff --git a/lib/src/utils.dart b/lib/src/utils.dart index f573b77b..be10263e 100644 --- a/lib/src/utils.dart +++ b/lib/src/utils.dart @@ -1,10 +1,10 @@ +import 'package:emojis/emoji.dart'; import 'package:flutter/material.dart'; import 'package:stream_chat/stream_chat.dart'; import 'package:url_launcher/url_launcher.dart'; -import 'stream_svg_icon.dart'; - import '../stream_chat_flutter.dart'; +import 'stream_svg_icon.dart'; Future launchURL(BuildContext context, String url) async { if (await canLaunch(url)) { @@ -215,3 +215,16 @@ StreamSvgIcon getFileTypeImage(String type) { break; } } + +final _emojis = Emoji.all(); + +bool textIsOnlyEmoji(String text) { + return text.trim().characters.isNotEmpty && + text.trim().characters.every((c) => + _emojis.firstWhere( + (Emoji emoji) => emoji.char.contains(c), + orElse: () => null, + ) != + null) && + text.characters.length < 4; +} From 7404bbd64dd7d36906200c28010632d0d92e872e Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Mon, 11 Jan 2021 19:42:45 +0530 Subject: [PATCH 0844/1140] [MessageWidget] Move action modal options visibility one layer up Signed-off-by: Sahil Kumar --- lib/src/message_actions_modal.dart | 14 +++---- lib/src/message_list_view.dart | 18 ++++++--- lib/src/message_widget.dart | 50 ++++++++++++++----------- test/src/message_action_modal_test.dart | 4 +- 4 files changed, 51 insertions(+), 35 deletions(-) diff --git a/lib/src/message_actions_modal.dart b/lib/src/message_actions_modal.dart index 0aa53824..9896edc4 100644 --- a/lib/src/message_actions_modal.dart +++ b/lib/src/message_actions_modal.dart @@ -24,8 +24,8 @@ class MessageActionsModal extends StatelessWidget { final bool showCopyMessage; final bool showEditMessage; final bool showResendMessage; - final bool showReply; - final bool showThreadReply; + final bool showReplyMessage; + final bool showThreadReplyMessage; final bool reverse; final ShapeBorder messageShape; final DisplayWidget showUserAvatar; @@ -40,9 +40,9 @@ class MessageActionsModal extends StatelessWidget { this.onReplyTap, this.onThreadReplyTap, this.showCopyMessage = true, - this.showReply = true, + this.showReplyMessage = true, this.showResendMessage = true, - this.showThreadReply = true, + this.showThreadReplyMessage = true, this.showUserAvatar = DisplayWidget.show, this.editMessageInputBuilder, this.messageShape, @@ -129,7 +129,7 @@ class MessageActionsModal extends StatelessWidget { showReactions: false, showUsername: false, showThreadReplyIndicator: false, - showReplyIndicator: false, + showReplyMessage: false, showUserAvatar: showUserAvatar, showTimestamp: false, translateUserAvatar: false, @@ -180,13 +180,13 @@ class MessageActionsModal extends StatelessWidget { .greyWhisper, context: context, tiles: [ - if (showReply && + if (showReplyMessage && (message.status == MessageSendingStatus.SENT || message.status == null) && message.parentId == null) _buildReplyButton(context), - if (showThreadReply && + if (showThreadReplyMessage && (message.status == MessageSendingStatus.SENT || message.status == null) && diff --git a/lib/src/message_list_view.dart b/lib/src/message_list_view.dart index 41792390..bea2ad0b 100644 --- a/lib/src/message_list_view.dart +++ b/lib/src/message_list_view.dart @@ -369,7 +369,11 @@ class _MessageListViewState extends State { final isNextUserSame = message.user.id == nextMessage.user?.id; final isThread = message.replyCount > 0; - if (timeDiff >= 1 || !isNextUserSame || isThread) { + final isDeleted = message.isDeleted; + if (timeDiff >= 1 || + !isNextUserSame || + isThread || + isDeleted) { return SizedBox(height: 8); } return SizedBox(height: 2); @@ -713,7 +717,12 @@ class _MessageListViewState extends State { return MessageWidget( showThreadReplyIndicator: false, showInChannelIndicator: false, - showReplyIndicator: false, + showReplyMessage: false, + showResendMessage: false, + showThreadReplyMessage: false, + showCopyMessage: false, + showDeleteMessage: false, + showEditMessage: false, message: message, reverse: isMyMessage, showUsername: !isMyMessage, @@ -725,8 +734,6 @@ class _MessageListViewState extends State { ), showSendingIndicator: false, onThreadTap: _onThreadTap, - showEditMessage: false, - showDeleteMessage: false, borderRadiusGeometry: BorderRadius.only( topLeft: Radius.circular(16), bottomLeft: Radius.circular(2), @@ -845,6 +852,7 @@ class _MessageListViewState extends State { }, showEditMessage: isMyMessage, showDeleteMessage: isMyMessage, + showThreadReplyMessage: !isThreadMessage, borderSide: isMyMessage ? BorderSide.none : null, onThreadTap: _onThreadTap, onReplyTap: widget.onReplyTap, @@ -870,7 +878,7 @@ class _MessageListViewState extends State { onShowMessage: widget.onShowMessage, ); - if (!isThreadMessage) { + if (!message.isDeleted && !message.isSystem && !message.isEphemeral) { child = Swipeable( onSwipeEnd: () => widget.onMessageSwiped(message), backgroundIcon: StreamSvgIcon.reply( diff --git a/lib/src/message_widget.dart b/lib/src/message_widget.dart index 5180a329..f990288a 100644 --- a/lib/src/message_widget.dart +++ b/lib/src/message_widget.dart @@ -106,9 +106,6 @@ class MessageWidget extends StatefulWidget { /// If true the widget will show the thread reply indicator final bool showThreadReplyIndicator; - /// If true the widget will show the reply indicator - final bool showReplyIndicator; - /// If true the widget will show the show in channel indicator final bool showInChannelIndicator; @@ -121,9 +118,6 @@ class MessageWidget extends StatefulWidget { /// Used in [MessageReactionsModal] and [MessageActionsModal] final bool showReactionPickerIndicator; - /// If true the widget will show the resendMessage indicator - final bool showResendMessage; - final List readList; final ShowMessageCallback onShowMessage; @@ -131,8 +125,14 @@ class MessageWidget extends StatefulWidget { /// If true show the users username next to the timestamp of the message final bool showUsername; final bool showTimestamp; - final bool showDeleteMessage; + + final bool showReplyMessage; + final bool showThreadReplyMessage; final bool showEditMessage; + final bool showCopyMessage; + final bool showDeleteMessage; + final bool showResendMessage; + final Map attachmentBuilders; /// Center user avatar with bottom of the message @@ -160,7 +160,6 @@ class MessageWidget extends StatefulWidget { this.showSendingIndicator = true, this.showThreadReplyIndicator = true, this.showInChannelIndicator = true, - this.showReplyIndicator = true, this.onReplyTap, this.onThreadTap, this.showUsername = true, @@ -168,6 +167,10 @@ class MessageWidget extends StatefulWidget { this.showReactions = true, this.showDeleteMessage = true, this.showEditMessage = true, + this.showReplyMessage = true, + this.showThreadReplyMessage = true, + this.showResendMessage = true, + this.showCopyMessage = true, this.onUserAvatarTap, this.onLinkTap, this.onMessageActions, @@ -175,7 +178,6 @@ class MessageWidget extends StatefulWidget { this.editMessageInputBuilder, this.textBuilder, Map customAttachmentBuilders, - this.showResendMessage = true, this.readList, this.padding, this.textPadding = const EdgeInsets.symmetric( @@ -243,6 +245,8 @@ class _MessageWidgetState extends State { bool get showSendingIndicator => widget.showSendingIndicator; + bool get isDeleted => widget.message.isDeleted; + bool get showUsername => widget.showUsername; bool get showTimeStamp => widget.showTimestamp; @@ -271,7 +275,9 @@ class _MessageWidgetState extends State { showThreadReplyIndicator || showUsername || showTimeStamp || - showInChannel; + showInChannel || + showSendingIndicator || + isDeleted; @override Widget build(BuildContext context) { @@ -482,12 +488,12 @@ class _MessageWidgetState extends State { Widget _buildQuotedMessage() { final isMyMessage = widget.message.user.id == StreamChat.of(context).user.id; + final onTap = widget.message?.quotedMessage?.isDeleted != true && + widget.onQuotedMessageTap != null + ? () => widget.onQuotedMessageTap(widget.message.quotedMessageId) + : null; return QuotedMessageWidget( - onTap: () { - if (widget.onQuotedMessageTap != null) { - widget.onQuotedMessageTap(widget.message.quotedMessageId); - } - }, + onTap: onTap, message: widget.message.quotedMessage, messageTheme: isMyMessage ? StreamChatTheme.of(context).otherMessageTheme @@ -497,7 +503,7 @@ class _MessageWidgetState extends State { } Widget get _bottomRow { - if (widget.message.isDeleted) { + if (isDeleted) { return Transform( transform: Matrix4.rotationY(widget.reverse ? pi : 0), alignment: Alignment.center, @@ -701,14 +707,15 @@ class _MessageWidgetState extends State { messageTheme: widget.messageTheme, messageShape: widget.shape ?? _getDefaultShape(context), reverse: widget.reverse, - showDeleteMessage: widget.showDeleteMessage, + showDeleteMessage: widget.showDeleteMessage || isDeleteFailed, message: widget.message, editMessageInputBuilder: widget.editMessageInputBuilder, onReplyTap: widget.onReplyTap, onThreadReplyTap: widget.onThreadTap, showResendMessage: widget.showResendMessage && (isSendFailed || isUpdateFailed), - showCopyMessage: !isFailedState && + showCopyMessage: widget.showCopyMessage && + !isFailedState && widget.message.text?.trim()?.isNotEmpty == true, showEditMessage: widget.showEditMessage && !isDeleteFailed && @@ -716,11 +723,12 @@ class _MessageWidgetState extends State { ?.any((element) => element.type == 'giphy') != true, showReactions: widget.showReactions, - showReply: widget.showReplyIndicator && + showReplyMessage: widget.showReplyMessage && !isFailedState && widget.onReplyTap != null, - showThreadReply: - widget.showThreadReplyIndicator && widget.onThreadTap != null, + showThreadReplyMessage: widget.showThreadReplyMessage && + !isFailedState && + widget.onThreadTap != null, ), ); }); diff --git a/test/src/message_action_modal_test.dart b/test/src/message_action_modal_test.dart index 7da2095d..3cb916d1 100644 --- a/test/src/message_action_modal_test.dart +++ b/test/src/message_action_modal_test.dart @@ -70,8 +70,8 @@ void main() { showEditMessage: false, showCopyMessage: false, showDeleteMessage: false, - showReply: false, - showThreadReply: false, + showReplyMessage: false, + showThreadReplyMessage: false, message: Message( text: 'test', user: User( From ff2653bea31ef3dee21f86351bbbda9526cba1d0 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Mon, 11 Jan 2021 15:53:18 +0100 Subject: [PATCH 0845/1140] fix thread unread indicator --- lib/src/back_button.dart | 8 +++++++- lib/src/message_list_view.dart | 4 +--- lib/src/thread_header.dart | 2 ++ lib/src/unread_indicator.dart | 12 ++++++++++-- 4 files changed, 20 insertions(+), 6 deletions(-) diff --git a/lib/src/back_button.dart b/lib/src/back_button.dart index 52adeade..9d787517 100644 --- a/lib/src/back_button.dart +++ b/lib/src/back_button.dart @@ -9,11 +9,15 @@ class StreamBackButton extends StatelessWidget { Key key, this.onPressed, this.showUnreads = false, + this.cid, }) : super(key: key); final VoidCallback onPressed; final bool showUnreads; + /// Channel cid used to retrieve unread count + final String cid; + @override Widget build(BuildContext context) { return Stack( @@ -45,7 +49,9 @@ class StreamBackButton extends StatelessWidget { Positioned( top: 7, right: 7, - child: UnreadIndicator(), + child: UnreadIndicator( + cid: cid, + ), ), ], ); diff --git a/lib/src/message_list_view.dart b/lib/src/message_list_view.dart index bea2ad0b..cda0d64c 100644 --- a/lib/src/message_list_view.dart +++ b/lib/src/message_list_view.dart @@ -187,7 +187,6 @@ class MessageListView extends StatefulWidget { class _MessageListViewState extends State { ItemScrollController _scrollController; - bool _bottomWasVisible = false; Function _onThreadTap; bool _showScrollToBottom = false; ItemPositionsListener _itemPositionListener; @@ -692,14 +691,13 @@ class _MessageListViewState extends State { key: ValueKey('BOTTOM-MESSAGE'), onVisibilityChanged: (visibility) { final isVisible = visibility.visibleBounds != Rect.zero; - if (isVisible && !_bottomWasVisible) { + if (isVisible) { final channel = streamChannel.channel; if (_upToDate && channel.config?.readEvents == true && channel.state.unreadCount > 0) { streamChannel.channel.markRead(); } - _bottomWasVisible = !isVisible; } if (mounted) { setState(() => _showScrollToBottom = !isVisible); diff --git a/lib/src/thread_header.dart b/lib/src/thread_header.dart index 8e165af7..eb748272 100644 --- a/lib/src/thread_header.dart +++ b/lib/src/thread_header.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:stream_chat/stream_chat.dart'; import 'package:stream_chat_flutter/src/stream_chat_theme.dart'; +import 'package:stream_chat_flutter/stream_chat_flutter.dart'; import 'back_button.dart'; import 'channel_name.dart'; @@ -81,6 +82,7 @@ class ThreadHeader extends StatelessWidget implements PreferredSizeWidget { elevation: 1, leading: showBackButton ? StreamBackButton( + cid: StreamChannel.of(context).channel.cid, onPressed: onBackPressed, showUnreads: true, ) diff --git a/lib/src/unread_indicator.dart b/lib/src/unread_indicator.dart index c9f42fad..cf115f3b 100644 --- a/lib/src/unread_indicator.dart +++ b/lib/src/unread_indicator.dart @@ -5,14 +5,22 @@ import 'package:stream_chat_flutter/stream_chat_flutter.dart'; class UnreadIndicator extends StatelessWidget { const UnreadIndicator({ Key key, + this.cid, }) : super(key: key); + /// Channel cid used to retrieve unread count + final String cid; + @override Widget build(BuildContext context) { final client = StreamChat.of(context).client; return StreamBuilder( - stream: client.state.totalUnreadCountStream, - initialData: client.state.totalUnreadCount, + stream: cid != null + ? client.state.channels[cid].state.unreadCountStream + : client.state.totalUnreadCountStream, + initialData: cid != null + ? client.state.channels[cid].state.unreadCount + : client.state.totalUnreadCount, builder: (context, snapshot) { if (!snapshot.hasData || snapshot.data == 0) { return SizedBox(); From 2b24aa39288b294ddb284e0b73a165cc49ed212a Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Mon, 11 Jan 2021 16:44:37 +0100 Subject: [PATCH 0846/1140] fix permissions --- .github/workflows/scripts/install-flutter.sh | 0 .github/workflows/scripts/install-tools.sh | 0 .github/workflows/scripts/validate-formatting.sh | 0 3 files changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 .github/workflows/scripts/install-flutter.sh mode change 100644 => 100755 .github/workflows/scripts/install-tools.sh mode change 100644 => 100755 .github/workflows/scripts/validate-formatting.sh diff --git a/.github/workflows/scripts/install-flutter.sh b/.github/workflows/scripts/install-flutter.sh old mode 100644 new mode 100755 diff --git a/.github/workflows/scripts/install-tools.sh b/.github/workflows/scripts/install-tools.sh old mode 100644 new mode 100755 diff --git a/.github/workflows/scripts/validate-formatting.sh b/.github/workflows/scripts/validate-formatting.sh old mode 100644 new mode 100755 From c987066329c740aa03aa08fbbffa379592a3d973 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Mon, 11 Jan 2021 21:22:32 +0530 Subject: [PATCH 0847/1140] fix: Added modals instead --- lib/src/message_actions_modal.dart | 444 ++++++++++------------------- lib/src/utils.dart | 73 ++++- 2 files changed, 216 insertions(+), 301 deletions(-) diff --git a/lib/src/message_actions_modal.dart b/lib/src/message_actions_modal.dart index 5c2f16bb..e4db71f5 100644 --- a/lib/src/message_actions_modal.dart +++ b/lib/src/message_actions_modal.dart @@ -1,4 +1,3 @@ -import 'dart:math'; import 'dart:ui'; import 'package:flutter/cupertino.dart'; @@ -9,6 +8,7 @@ import 'package:stream_chat/stream_chat.dart'; import 'package:stream_chat_flutter/src/reaction_picker.dart'; import 'package:stream_chat_flutter/src/stream_channel.dart'; import 'package:stream_chat_flutter/src/stream_svg_icon.dart'; +import 'package:stream_chat_flutter/src/utils.dart'; import 'message_input.dart'; import 'message_widget.dart'; @@ -64,21 +64,9 @@ class MessageActionsModal extends StatefulWidget { } class _MessageActionsModalState extends State { - ActionsModalState state = ActionsModalState.modal; - @override Widget build(BuildContext context) { - switch (state) { - case ActionsModalState.modal: - return _showMessageOptionsModal(); - break; - case ActionsModalState.confirmDialog: - return _showFlagDialog(); - break; - case ActionsModalState.dismissMessage: - return _showDismissAlert(); - break; - } + return _showMessageOptionsModal(); } Widget _showMessageOptionsModal() { @@ -254,296 +242,154 @@ class _MessageActionsModalState extends State { ); } - Widget _showFlagDialog() { - return TweenAnimationBuilder( - tween: Tween(begin: 0.0, end: 1.0), - duration: Duration(milliseconds: 300), - curve: Curves.easeInOut, - builder: (context, value, _) { - return GestureDetector( - behavior: HitTestBehavior.translucent, - onTap: () => Navigator.maybePop(context), - child: Stack( - children: [ - Positioned.fill( - child: BackdropFilter( - filter: ImageFilter.blur( - sigmaX: 10, - sigmaY: 10, - ), - child: Container( - color: StreamChatTheme.of(context).colorTheme.overlay, - ), - ), - ), - Transform.scale( - scale: value, - child: Center( - child: Opacity( - opacity: 0.9, - child: Material( - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(16.0), - ), - clipBehavior: Clip.antiAlias, - child: Container( - width: 270.0, - height: 156.0, - alignment: Alignment.center, - child: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - SizedBox( - height: 19.0, - ), - Text( - 'Flag Message', - style: StreamChatTheme.of(context) - .textTheme - .bodyBold - .copyWith(fontSize: 17.0), - ), - SizedBox( - height: 4.0, - ), - Padding( - padding: const EdgeInsets.symmetric( - horizontal: 16.0), - child: Text( - 'Do you want to send a copy of this \nmessage to a moderator for further \ninvestigation?', - style: TextStyle(fontSize: 13.5), - textAlign: TextAlign.center, - ), - ), - SizedBox( - height: 21.0, - ), - Row( - mainAxisAlignment: - MainAxisAlignment.spaceEvenly, - children: [ - Expanded( - child: Center( - child: InkWell( - child: Container( - height: 44.0, - alignment: Alignment.center, - child: Text( - 'Cancel', - style: StreamChatTheme.of(context) - .textTheme - .body - .copyWith( - fontSize: 17.0, - color: StreamChatTheme.of( - context) - .colorTheme - .accentBlue), - ), - decoration: BoxDecoration( - border: Border( - top: BorderSide( - color: StreamChatTheme.of( - context) - .colorTheme - .grey - .withOpacity(0.8)), - right: BorderSide( - color: StreamChatTheme.of( - context) - .colorTheme - .grey - .withOpacity(0.8)), - ), - ), - ), - onTap: () { - setState(() { - state = ActionsModalState.modal; - }); - }, - ), - ), - ), - Expanded( - child: Center( - child: InkWell( - child: Container( - height: 44.0, - alignment: Alignment.center, - child: Text( - 'Flag', - style: StreamChatTheme.of(context) - .textTheme - .body - .copyWith( - fontWeight: FontWeight.bold, - fontSize: 17.0, - color: StreamChatTheme.of( - context) - .colorTheme - .accentBlue), - ), - decoration: BoxDecoration( - border: Border( - top: BorderSide( - color: StreamChatTheme.of( - context) - .colorTheme - .grey - .withOpacity(0.8)), - ), - ), - ), - onTap: () { - setState(() { - state = ActionsModalState - .dismissMessage; - }); - final client = - StreamChat.of(context).client; - client.flagMessage(widget.message.id); - }, - ), - ), - ), - ], - ), - ], - ), - ), - ), - ), - ), - ), - ], - ), - ); - }); + void _showFlagDialog() async { + final client = StreamChat.of(context).client; + + var answer = await showConfirmationDialog(context, + title: 'Flag Message', + icon: StreamSvgIcon.flag( + color: StreamChatTheme.of(context).colorTheme.accentRed, + size: 24.0, + ), + question: + 'Do you want to send a copy of this message to a\nmoderator for further investigation?', + okText: 'FLAG', + cancelText: 'CANCEL'); + + if (answer) { + try { + await client.flagMessage(widget.message.id); + _showDismissAlert(); + } catch (err) { + _showErrorAlert(); + } + } else { + Navigator.pop(context); + } } - Widget _showDismissAlert() { - return TweenAnimationBuilder( - key: GlobalKey(), - tween: Tween(begin: 0.0, end: 1.0), - duration: Duration(milliseconds: 300), - curve: Curves.easeInOut, - builder: (context, value, _) { - return GestureDetector( - behavior: HitTestBehavior.translucent, - onTap: () => Navigator.maybePop(context), - child: Stack( + void _showDismissAlert() { + showModalBottomSheet( + backgroundColor: StreamChatTheme.of(context).colorTheme.white, + context: context, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.only( + topLeft: Radius.circular(16.0), + topRight: Radius.circular(16.0), + )), + builder: (context) { + return Column( + mainAxisSize: MainAxisSize.min, + children: [ + SizedBox( + height: 26.0, + ), + StreamSvgIcon.flag( + color: StreamChatTheme.of(context).colorTheme.accentRed, + size: 24.0, + ), + SizedBox( + height: 26.0, + ), + Text( + 'Message flagged', + style: StreamChatTheme.of(context).textTheme.headlineBold, + ), + SizedBox( + height: 7.0, + ), + Text('The message has been reported to a moderator.'), + SizedBox( + height: 36.0, + ), + Container( + color: + StreamChatTheme.of(context).colorTheme.black.withOpacity(.08), + height: 1.0, + ), + Row( + mainAxisAlignment: MainAxisAlignment.center, children: [ - Positioned.fill( - child: BackdropFilter( - filter: ImageFilter.blur( - sigmaX: 10, - sigmaY: 10, - ), - child: Container( - color: StreamChatTheme.of(context).colorTheme.overlay, - ), - ), - ), - Transform.scale( - scale: value, - child: Center( - child: Opacity( - opacity: 0.9, - child: Material( - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(16.0), - ), - clipBehavior: Clip.antiAlias, - child: Container( - width: 270.0, - height: 156.0, - alignment: Alignment.center, - child: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - SizedBox( - height: 19.0, - ), - Text( - 'Message Flagged', - style: StreamChatTheme.of(context) - .textTheme - .bodyBold - .copyWith(fontSize: 17.0), - ), - SizedBox( - height: 4.0, - ), - Padding( - padding: const EdgeInsets.symmetric( - horizontal: 16.0), - child: Text( - 'This message has been reported to a\nmoderator.', - style: TextStyle(fontSize: 13.5), - textAlign: TextAlign.center, - ), - ), - SizedBox( - height: 21.0, - ), - Row( - mainAxisAlignment: - MainAxisAlignment.spaceEvenly, - children: [ - Expanded( - child: Center( - child: InkWell( - child: Container( - height: 44.0, - alignment: Alignment.center, - child: Text( - 'Dismiss', - style: StreamChatTheme.of(context) - .textTheme - .body - .copyWith( - fontWeight: FontWeight.bold, - fontSize: 17.0, - color: StreamChatTheme.of( - context) - .colorTheme - .accentBlue), - ), - decoration: BoxDecoration( - border: Border( - top: BorderSide( - color: StreamChatTheme.of( - context) - .colorTheme - .grey - .withOpacity(0.8)), - ), - ), - ), - onTap: () { - setState(() { - state = ActionsModalState.modal; - }); - }, - ), - ), - ), - ], - ), - ], - ), - ), - ), - ), + FlatButton( + child: Text( + 'OK', + style: TextStyle( + color: + StreamChatTheme.of(context).colorTheme.accentBlue, + fontWeight: FontWeight.w400), ), + onPressed: () { + Navigator.of(context).pop(); + }, ), ], ), - ); - }); + ], + ); + }, + ); + } + + void _showErrorAlert() { + showModalBottomSheet( + backgroundColor: StreamChatTheme.of(context).colorTheme.white, + context: context, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.only( + topLeft: Radius.circular(16.0), + topRight: Radius.circular(16.0), + )), + builder: (context) { + return Column( + mainAxisSize: MainAxisSize.min, + children: [ + SizedBox( + height: 26.0, + ), + StreamSvgIcon.error( + color: StreamChatTheme.of(context).colorTheme.accentRed, + size: 24.0, + ), + SizedBox( + height: 26.0, + ), + Text( + 'Something went wrong', + style: StreamChatTheme.of(context).textTheme.headlineBold, + ), + SizedBox( + height: 7.0, + ), + Text('The operation couldn\'t be completed.'), + SizedBox( + height: 36.0, + ), + Container( + color: + StreamChatTheme.of(context).colorTheme.black.withOpacity(.08), + height: 1.0, + ), + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + FlatButton( + child: Text( + 'OK', + style: TextStyle( + color: + StreamChatTheme.of(context).colorTheme.accentBlue, + fontWeight: FontWeight.w400), + ), + onPressed: () { + Navigator.of(context).pop(); + }, + ), + ], + ), + ], + ); + }, + ); } Widget _buildReplyButton(BuildContext context) { @@ -586,9 +432,7 @@ class _MessageActionsModalState extends State { ], ), onTap: () { - setState(() { - state = ActionsModalState.confirmDialog; - }); + _showFlagDialog(); }, ); } diff --git a/lib/src/utils.dart b/lib/src/utils.dart index f573b77b..21ca8114 100644 --- a/lib/src/utils.dart +++ b/lib/src/utils.dart @@ -75,7 +75,7 @@ Future showConfirmationDialog( fontWeight: FontWeight.w400), ), onPressed: () { - Navigator.of(context).pop(); + Navigator.of(context).pop(false); }, ), FlatButton( @@ -95,6 +95,77 @@ Future showConfirmationDialog( }); } +Future showInfoDialog( + BuildContext context, { + String title, + Widget icon, + String question, + String okText, + StreamChatThemeData theme, +}) { + return showModalBottomSheet( + backgroundColor: + theme.colorTheme.white ?? StreamChatTheme.of(context).colorTheme.white, + context: context, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.only( + topLeft: Radius.circular(16.0), + topRight: Radius.circular(16.0), + )), + builder: (context) { + return Column( + mainAxisSize: MainAxisSize.min, + children: [ + SizedBox( + height: 26.0, + ), + if (icon != null) icon, + SizedBox( + height: 26.0, + ), + Text( + title, + style: theme.textTheme.headlineBold ?? + StreamChatTheme.of(context).textTheme.headlineBold, + ), + SizedBox( + height: 7.0, + ), + Text(question), + SizedBox( + height: 36.0, + ), + Container( + color: theme.colorTheme.black.withOpacity(.08) ?? + StreamChatTheme.of(context).colorTheme.black.withOpacity(.08), + height: 1.0, + ), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + FlatButton( + child: Text( + okText, + style: TextStyle( + color: theme.colorTheme.black.withOpacity(0.5) ?? + StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(0.5), + fontWeight: FontWeight.w400), + ), + onPressed: () { + Navigator.of(context).pop(); + }, + ), + ], + ), + ], + ); + }, + ); +} + /// Get random png with initials String getRandomPicUrl(User user) => 'https://getstream.io/random_png/?id=${user.id}&name=${user.name}'; From 6274f1437e9d48bdca37ed49ed2929201f5002ff Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Mon, 11 Jan 2021 21:29:31 +0530 Subject: [PATCH 0848/1140] feat: corrected text styles --- lib/src/message_actions_modal.dart | 22 ++++++++++++++-------- lib/src/utils.dart | 19 +++++++++++-------- 2 files changed, 25 insertions(+), 16 deletions(-) diff --git a/lib/src/message_actions_modal.dart b/lib/src/message_actions_modal.dart index e4db71f5..4db2dd73 100644 --- a/lib/src/message_actions_modal.dart +++ b/lib/src/message_actions_modal.dart @@ -313,10 +313,13 @@ class _MessageActionsModalState extends State { FlatButton( child: Text( 'OK', - style: TextStyle( - color: - StreamChatTheme.of(context).colorTheme.accentBlue, - fontWeight: FontWeight.w400), + style: StreamChatTheme.of(context) + .textTheme + .bodyBold + .copyWith( + color: StreamChatTheme.of(context) + .colorTheme + .accentBlue), ), onPressed: () { Navigator.of(context).pop(); @@ -375,10 +378,13 @@ class _MessageActionsModalState extends State { FlatButton( child: Text( 'OK', - style: TextStyle( - color: - StreamChatTheme.of(context).colorTheme.accentBlue, - fontWeight: FontWeight.w400), + style: StreamChatTheme.of(context) + .textTheme + .bodyBold + .copyWith( + color: StreamChatTheme.of(context) + .colorTheme + .accentBlue), ), onPressed: () { Navigator.of(context).pop(); diff --git a/lib/src/utils.dart b/lib/src/utils.dart index 21ca8114..4e55111f 100644 --- a/lib/src/utils.dart +++ b/lib/src/utils.dart @@ -67,12 +67,10 @@ Future showConfirmationDialog( FlatButton( child: Text( cancelText, - style: TextStyle( - color: StreamChatTheme.of(context) - .colorTheme - .black - .withOpacity(0.5), - fontWeight: FontWeight.w400), + style: StreamChatTheme.of(context) + .textTheme + .bodyBold + .copyWith(color: Colors.black.withOpacity(0.5)), ), onPressed: () { Navigator.of(context).pop(false); @@ -81,8 +79,13 @@ Future showConfirmationDialog( FlatButton( child: Text( okText, - style: TextStyle( - color: Colors.red, fontWeight: FontWeight.w400), + style: StreamChatTheme.of(context) + .textTheme + .bodyBold + .copyWith( + color: StreamChatTheme.of(context) + .colorTheme + .accentRed), ), onPressed: () { Navigator.pop(context, true); From 746688e04d9d5fcab23bef7619891e836ef0bfec Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Mon, 11 Jan 2021 21:43:47 +0530 Subject: [PATCH 0849/1140] fix: merge --- lib/src/message_actions_modal.dart | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/lib/src/message_actions_modal.dart b/lib/src/message_actions_modal.dart index fa7b8da1..d1f6e0ff 100644 --- a/lib/src/message_actions_modal.dart +++ b/lib/src/message_actions_modal.dart @@ -1,6 +1,5 @@ import 'dart:ui'; -import 'package:flutter/cupertino.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; @@ -15,12 +14,6 @@ import 'message_widget.dart'; import 'stream_chat.dart'; import 'stream_chat_theme.dart'; -enum ActionsModalState { - modal, - confirmDialog, - dismissMessage, -} - class MessageActionsModal extends StatefulWidget { final Widget Function(BuildContext, Message) editMessageInputBuilder; final void Function(Message) onThreadReplyTap; @@ -149,7 +142,7 @@ class _MessageActionsModalState extends State { showUsername: false, showThreadReplyIndicator: false, showReplyMessage: false, - showUserAvatar: showUserAvatar, + showUserAvatar: widget.showUserAvatar, showTimestamp: false, translateUserAvatar: false, showReactionPickerIndicator: @@ -158,7 +151,7 @@ class _MessageActionsModalState extends State { MessageSendingStatus.SENT || widget.message.status == null), showInChannelIndicator: false, - showSendingIndicator: DisplayWidget.gone, + showSendingIndicator: false, shape: widget.messageShape, ), ), From 4f41f6be7f46b2266f96a4443128fb581a4f08c5 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Mon, 11 Jan 2021 21:45:31 +0530 Subject: [PATCH 0850/1140] fix: color and fmt --- lib/src/utils.dart | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/src/utils.dart b/lib/src/utils.dart index 27559f7a..0b59e54c 100644 --- a/lib/src/utils.dart +++ b/lib/src/utils.dart @@ -70,7 +70,11 @@ Future showConfirmationDialog( style: StreamChatTheme.of(context) .textTheme .bodyBold - .copyWith(color: Colors.black.withOpacity(0.5)), + .copyWith( + color: StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(0.5)), ), onPressed: () { Navigator.of(context).pop(false); From 1556564ea7ebafa5ccc5a2b2f1b788c089f15d0b Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Mon, 11 Jan 2021 21:49:34 +0530 Subject: [PATCH 0851/1140] fix: Cancel behaviour --- lib/src/message_actions_modal.dart | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/src/message_actions_modal.dart b/lib/src/message_actions_modal.dart index d1f6e0ff..f288fa7a 100644 --- a/lib/src/message_actions_modal.dart +++ b/lib/src/message_actions_modal.dart @@ -256,8 +256,6 @@ class _MessageActionsModalState extends State { } catch (err) { _showErrorAlert(); } - } else { - Navigator.pop(context); } } From bc1761867d73a7fd73c1f326b94e4465ea4e4e1c Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Tue, 12 Jan 2021 12:27:42 +0530 Subject: [PATCH 0852/1140] [MessageListView] Make thread type messages all corners rounded Signed-off-by: Sahil Kumar --- lib/src/message_list_view.dart | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/lib/src/message_list_view.dart b/lib/src/message_list_view.dart index cda0d64c..2e45dff7 100644 --- a/lib/src/message_list_view.dart +++ b/lib/src/message_list_view.dart @@ -857,14 +857,21 @@ class _MessageListViewState extends State { attachmentBorderRadiusGeometry: BorderRadius.only( topLeft: Radius.circular(attachmentBorderRadius), bottomLeft: Radius.circular( - timeDiff >= 1 || !isNextUserSame ? 0 : attachmentBorderRadius), + (timeDiff >= 1 || !isNextUserSame) && !hasReplies && !isThreadMessage + ? 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(timeDiff >= 1 || !isNextUserSame ? 0 : 16), + bottomLeft: Radius.circular( + (timeDiff >= 1 || !isNextUserSame) && !hasReplies && !isThreadMessage + ? 0 + : 16, + ), topRight: Radius.circular(16), bottomRight: Radius.circular(16), ), From 4a7350530ebb2ba4a0aae634f484ef34db37172e Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Tue, 12 Jan 2021 12:52:52 +0530 Subject: [PATCH 0853/1140] [MessageListView] Remove topMessage extra top padding in thread conversation. Signed-off-by: Sahil Kumar --- lib/src/message_list_view.dart | 107 ++++++++++++++++----------------- 1 file changed, 52 insertions(+), 55 deletions(-) diff --git a/lib/src/message_list_view.dart b/lib/src/message_list_view.dart index 2e45dff7..aa557c6a 100644 --- a/lib/src/message_list_view.dart +++ b/lib/src/message_list_view.dart @@ -338,9 +338,28 @@ class _MessageListViewState extends State { messages.length + 2 + (_isThreadConversation ? 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); + if (i == messages.length + 1) { + final replyCount = widget.parentMessage.replyCount; + return Container( + decoration: BoxDecoration( + gradient: + StreamChatTheme.of(context).colorTheme.bgGradient, + ), + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Text( + '$replyCount ${replyCount == 1 ? 'Reply' : 'Replies'}', + textAlign: TextAlign.center, + style: StreamChatTheme.of(context) + .channelTheme + .channelHeaderTheme + .lastMessageAt, + ), + ), + ); + } + final message = messages[i]; final nextMessage = messages[i - 1]; if (!Jiffy(message.createdAt.toLocal()).isSame( @@ -385,30 +404,7 @@ class _MessageListViewState extends State { widget.parentMessage, ); } else { - return Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - buildParentMessage(widget.parentMessage), - Container( - decoration: BoxDecoration( - gradient: StreamChatTheme.of(context) - .colorTheme - .bgGradient, - ), - child: Padding( - padding: const EdgeInsets.all(8.0), - child: Text( - '${widget.parentMessage.replyCount} ${widget.parentMessage.replyCount == 1 ? 'Reply' : 'Replies'}', - textAlign: TextAlign.center, - style: StreamChatTheme.of(context) - .channelTheme - .channelHeaderTheme - .lastMessageAt, - ), - ), - ), - ], - ); + return buildParentMessage(widget.parentMessage); } } if (i == messages.length + 1) { @@ -602,37 +598,38 @@ class _MessageListViewState extends State { ? streamChannel.queryTopMessages : streamChannel.queryBottomMessages; return StreamBuilder( - key: Key('LOADING-INDICATOR'), - stream: stream, - initialData: false, - builder: (context, snapshot) { - if (snapshot.hasError) { - return Container( - color: StreamChatTheme.of(context) - .colorTheme - .accentRed - .withOpacity(.2), - child: Center( - child: Text('Error loading messages'), - ), - ); - } - if (!snapshot.data) { - if (direction == QueryDirection.top) { - return Container( - height: 52, - width: double.infinity, - ); - } - return Offstage(); - } - return Center( - child: Padding( - padding: const EdgeInsets.all(8.0), - child: const CircularProgressIndicator(), + key: Key('LOADING-INDICATOR'), + stream: stream, + initialData: false, + builder: (context, snapshot) { + if (snapshot.hasError) { + return Container( + color: StreamChatTheme.of(context) + .colorTheme + .accentRed + .withOpacity(.2), + child: Center( + child: Text('Error loading messages'), ), ); - }); + } + if (!snapshot.data) { + if (!_isThreadConversation && direction == QueryDirection.top) { + return Container( + height: 52, + width: double.infinity, + ); + } + return Offstage(); + } + return Center( + child: Padding( + padding: const EdgeInsets.all(8.0), + child: const CircularProgressIndicator(), + ), + ); + }, + ); } Widget _buildTopMessage( From 9379c4672701689e31a2c36c1a091f740a37a921 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Tue, 12 Jan 2021 14:32:02 +0530 Subject: [PATCH 0854/1140] [QuotedMessageWidget] Fix attachment getting cropped by border side Signed-off-by: Sahil Kumar --- lib/src/quoted_message_widget.dart | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/lib/src/quoted_message_widget.dart b/lib/src/quoted_message_widget.dart index 7621174f..d012e15a 100644 --- a/lib/src/quoted_message_widget.dart +++ b/lib/src/quoted_message_widget.dart @@ -235,9 +235,7 @@ class QuotedMessageWidget extends StatelessWidget { ShapeBorder _getDefaultShape(BuildContext context) { return RoundedRectangleBorder( - side: BorderSide( - color: StreamChatTheme.of(context).colorTheme.greyWhisper, - ), + side: BorderSide(width: 0.0, color: Colors.transparent), borderRadius: BorderRadius.circular(8), ); } From 53b73ef8defcf0a0290ae333c82be821cbc8d8a8 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Tue, 12 Jan 2021 10:10:39 +0100 Subject: [PATCH 0855/1140] bump version --- example/pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 16bc8108..4719a6e5 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -1,6 +1,6 @@ name: example description: A new Flutter project. -version: 1.0.113+116 +version: 1.1.0 environment: sdk: ">=2.2.2 <3.0.0" From f9ac3fe6faf6d4d2c58b9e293b3684b58399cd04 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Tue, 12 Jan 2021 14:58:43 +0530 Subject: [PATCH 0856/1140] [MessageListView] minor fixes Signed-off-by: Sahil Kumar --- lib/src/message_list_view.dart | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/lib/src/message_list_view.dart b/lib/src/message_list_view.dart index aa557c6a..ba9c499e 100644 --- a/lib/src/message_list_view.dart +++ b/lib/src/message_list_view.dart @@ -708,6 +708,7 @@ class _MessageListViewState extends State { Message message, ) { final isMyMessage = message.user.id == StreamChat.of(context).user.id; + final isOnlyEmoji = textIsOnlyEmoji(message.text); return MessageWidget( showThreadReplyIndicator: false, @@ -721,12 +722,7 @@ class _MessageListViewState extends State { message: message, reverse: isMyMessage, showUsername: !isMyMessage, - padding: EdgeInsets.only( - top: 8.0, - left: 8.0, - right: 8.0, - bottom: 16.0, - ), + padding: const EdgeInsets.all(8.0), showSendingIndicator: false, onThreadTap: _onThreadTap, borderRadiusGeometry: BorderRadius.only( @@ -735,7 +731,7 @@ class _MessageListViewState extends State { topRight: Radius.circular(16), bottomRight: Radius.circular(16), ), - borderSide: isMyMessage ? BorderSide.none : null, + borderSide: isMyMessage && !isOnlyEmoji ? BorderSide.none : null, showUserAvatar: isMyMessage ? DisplayWidget.gone : DisplayWidget.show, messageTheme: isMyMessage ? StreamChatTheme.of(context).ownMessageTheme @@ -810,8 +806,9 @@ class _MessageListViewState extends State { final showSendingIndicator = isMyMessage && (index == 0 || timeDiff >= 1 || !isNextUserSame); - bool showInChannelIndicator = !_isThreadConversation && isThreadMessage; - bool showThreadReplyIndicator = !_isThreadConversation && hasReplies; + final showInChannelIndicator = !_isThreadConversation && isThreadMessage; + final showThreadReplyIndicator = !_isThreadConversation && hasReplies; + final isOnlyEmoji = textIsOnlyEmoji(message.text); Widget child = MessageWidget( key: ValueKey('MESSAGE-${message.id}'), @@ -848,7 +845,7 @@ class _MessageListViewState extends State { showEditMessage: isMyMessage, showDeleteMessage: isMyMessage, showThreadReplyMessage: !isThreadMessage, - borderSide: isMyMessage ? BorderSide.none : null, + borderSide: isMyMessage && !isOnlyEmoji ? BorderSide.none : null, onThreadTap: _onThreadTap, onReplyTap: widget.onReplyTap, attachmentBorderRadiusGeometry: BorderRadius.only( From 81589778fae7d4c3c990765f0fb65c5dac457e70 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Tue, 12 Jan 2021 10:33:18 +0100 Subject: [PATCH 0857/1140] fix gihpy dark mode --- example/pubspec.yaml | 2 +- lib/src/giphy_attachment.dart | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 4719a6e5..cdc07de7 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -1,6 +1,6 @@ name: example description: A new Flutter project. -version: 1.1.0 +version: 1.1.0+1 environment: sdk: ">=2.2.2 <3.0.0" diff --git a/lib/src/giphy_attachment.dart b/lib/src/giphy_attachment.dart index c879cd5b..df5a5705 100644 --- a/lib/src/giphy_attachment.dart +++ b/lib/src/giphy_attachment.dart @@ -45,6 +45,7 @@ class GiphyAttachment extends StatelessWidget { mainAxisSize: MainAxisSize.min, children: [ Card( + color: StreamChatTheme.of(context).colorTheme.white, elevation: 2, clipBehavior: Clip.antiAlias, shape: RoundedRectangleBorder( @@ -160,6 +161,7 @@ class GiphyAttachment extends StatelessWidget { mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Card( + color: Colors.white, elevation: 2, child: IconButton( padding: const EdgeInsets.all(0), @@ -187,6 +189,7 @@ class GiphyAttachment extends StatelessWidget { ), ), Card( + color: Colors.white, elevation: 2, child: IconButton( padding: const EdgeInsets.all(0), From 85aaf9eab89bc1dd1c1191166d370fc18fdaa3d9 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Tue, 12 Jan 2021 15:05:50 +0530 Subject: [PATCH 0858/1140] [MessageListView] simplify some conditions Signed-off-by: Sahil Kumar --- lib/src/message_list_view.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/src/message_list_view.dart b/lib/src/message_list_view.dart index ba9c499e..6f61e261 100644 --- a/lib/src/message_list_view.dart +++ b/lib/src/message_list_view.dart @@ -851,7 +851,7 @@ class _MessageListViewState extends State { attachmentBorderRadiusGeometry: BorderRadius.only( topLeft: Radius.circular(attachmentBorderRadius), bottomLeft: Radius.circular( - (timeDiff >= 1 || !isNextUserSame) && !hasReplies && !isThreadMessage + (timeDiff >= 1 || !isNextUserSame) && !(hasReplies || isThreadMessage) ? 0 : attachmentBorderRadius, ), @@ -862,7 +862,7 @@ class _MessageListViewState extends State { borderRadiusGeometry: BorderRadius.only( topLeft: Radius.circular(16), bottomLeft: Radius.circular( - (timeDiff >= 1 || !isNextUserSame) && !hasReplies && !isThreadMessage + (timeDiff >= 1 || !isNextUserSame) && !(hasReplies || isThreadMessage) ? 0 : 16, ), From 58d93a7a6965c3ec8e0090ad1374bdc6ba36beea Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Tue, 12 Jan 2021 10:41:19 +0100 Subject: [PATCH 0859/1140] add build action --- .github/workflows/build.yml | 64 +++++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 .github/workflows/build.yml diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 00000000..46bf0c61 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,64 @@ +name: Build + +on: + push: + branches: + - master + - feature/new-ui + - feature/mono-repo + release: + types: + - created + +jobs: + build_and_deploy_ios: + runs-on: [macos-latest] + steps: + - uses: actions/checkout@v2 + - name: Install RubyGems + run: | + cd packages/flutter_widgets/example/ios + bundle install + - uses: subosito/flutter-action@v1.4.0 + with: + channel: 'stable' + - name: Install firebase-tools + run: npm install -g firebase-tools + - name: Flutter setup + run: | + cd packages/flutter_widgets/example + flutter pub get + - name: Build and release + env: + MATCH_PASSWORD: ${{ secrets.MATCH_PASSWORD }} + MATCH_GIT_BASIC_AUTHORIZATION: ${{ secrets.MATCH_GIT_BASIC_AUTHORIZATION }} + FIREBASE_TOKEN: ${{ secrets.FIREBASE_TOKEN }} + run: | + cd packages/flutter_widgets/example + flutter build ios --release --no-codesign + cd ios + bundle exec fastlane deploy_to_firebase + build_and_deploy_android: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-java@v1 + with: + java-version: '12.x' + - uses: subosito/flutter-action@v1.4.0 + with: + channel: 'stable' + - run: | + cd packages/flutter_widgets/example + flutter pub get + - name: Build + run: | + cd packages/flutter_widgets/example + flutter build apk + - name: Deploy + uses: wzieba/Firebase-Distribution-Github-Action@v1.2.1 + with: + appId: ${{secrets.FIREBASE_ANDROID_APPID}} + token: ${{secrets.FIREBASE_TOKEN}} + groups: stream-testers + file: example/build/app/outputs/apk/release/app-release.apk \ No newline at end of file From b402add586ed080fc5e2e1f5339b79fc21594270 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Tue, 12 Jan 2021 15:11:52 +0530 Subject: [PATCH 0860/1140] feat: Added delete dialog and added dismiss dialog in case of message flagged --- lib/src/message_actions_modal.dart | 35 +++++++++++++++++++++++++----- 1 file changed, 30 insertions(+), 5 deletions(-) diff --git a/lib/src/message_actions_modal.dart b/lib/src/message_actions_modal.dart index f288fa7a..95ecdea5 100644 --- a/lib/src/message_actions_modal.dart +++ b/lib/src/message_actions_modal.dart @@ -1,3 +1,4 @@ +import 'dart:convert'; import 'dart:ui'; import 'package:flutter/foundation.dart'; @@ -253,6 +254,34 @@ class _MessageActionsModalState extends State { try { await client.flagMessage(widget.message.id); _showDismissAlert(); + } catch (err) { + if (json.decode(err?.body ?? {})['code'] == 4) { + _showDismissAlert(); + } else { + _showErrorAlert(); + } + } + } + } + + void _showDeleteDialog() async { + var answer = await showConfirmationDialog(context, + title: 'Delete message', + icon: StreamSvgIcon.flag( + color: StreamChatTheme.of(context).colorTheme.accentRed, + size: 24.0, + ), + question: 'Are you sure you want to permanently delete this\nmessage?', + okText: 'DELETE', + cancelText: 'CANCEL'); + + if (answer) { + try { + Navigator.pop(context); + StreamChat.of(context).client.deleteMessage( + widget.message, + StreamChannel.of(context).channel.cid, + ); } catch (err) { _showErrorAlert(); } @@ -455,11 +484,7 @@ class _MessageActionsModalState extends State { ], ), onTap: () { - Navigator.pop(context); - StreamChat.of(context).client.deleteMessage( - widget.message, - StreamChannel.of(context).channel.cid, - ); + _showDeleteDialog(); }, ); } From ffd539ff1789c145781fc607d3055b964c62f578 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Tue, 12 Jan 2021 10:54:07 +0100 Subject: [PATCH 0861/1140] fix rxdart package version --- packages/flutter_widgets/pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/flutter_widgets/pubspec.yaml b/packages/flutter_widgets/pubspec.yaml index 20047087..454e9f24 100644 --- a/packages/flutter_widgets/pubspec.yaml +++ b/packages/flutter_widgets/pubspec.yaml @@ -13,7 +13,7 @@ dependencies: sdk: flutter flutter_app_badger: ^1.1.2 photo_view: ^0.10.3 - rxdart: ^0.25.0 + rxdart: ^0.24.1 scrollable_positioned_list: ^0.1.8 jiffy: ^3.0.1 flutter_svg: ^0.19.1 From 0605cbc3b4ffcfd68464c8be3afb812922a1431f Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Tue, 12 Jan 2021 15:30:45 +0530 Subject: [PATCH 0862/1140] Move `isOnlyEmoji` utility function into String extension Signed-off-by: Sahil Kumar --- lib/src/extension.dart | 21 +++++++++++++++++++++ lib/src/message_list_view.dart | 5 +++-- lib/src/message_widget.dart | 2 +- lib/src/quoted_message_widget.dart | 2 +- lib/src/utils.dart | 14 -------------- 5 files changed, 26 insertions(+), 18 deletions(-) diff --git a/lib/src/extension.dart b/lib/src/extension.dart index 71edefe6..3ffd0e24 100644 --- a/lib/src/extension.dart +++ b/lib/src/extension.dart @@ -1,7 +1,28 @@ +import 'package:emojis/emoji.dart'; +import 'package:characters/characters.dart'; + +final _emojis = Emoji.all(); + extension StringExtension on String { String capitalize() { return "${this[0].toUpperCase()}${this.substring(1)}"; } + + // Emojis guidelines + // 1 to 3 emojis: big size with no text bubble. + // 4+ emojis or emojis+text: standard size with text bubble. + bool get isOnlyEmoji { + final characters = this.trim().characters; + if (characters.isEmpty) return false; + if (characters.length > 3) return false; + return characters.every((c) { + return _emojis.firstWhere( + (Emoji emoji) => emoji.char.contains(c), + orElse: () => null, + ) != + null; + }); + } } /// List extension diff --git a/lib/src/message_list_view.dart b/lib/src/message_list_view.dart index 6f61e261..095b6b73 100644 --- a/lib/src/message_list_view.dart +++ b/lib/src/message_list_view.dart @@ -17,6 +17,7 @@ import '../stream_chat_flutter.dart'; import 'date_divider.dart'; import 'stream_channel.dart'; import 'swipeable.dart'; +import 'extension.dart'; typedef MessageBuilder = Widget Function( BuildContext, @@ -708,7 +709,7 @@ class _MessageListViewState extends State { Message message, ) { final isMyMessage = message.user.id == StreamChat.of(context).user.id; - final isOnlyEmoji = textIsOnlyEmoji(message.text); + final isOnlyEmoji = message.text.isOnlyEmoji; return MessageWidget( showThreadReplyIndicator: false, @@ -808,7 +809,7 @@ class _MessageListViewState extends State { final showInChannelIndicator = !_isThreadConversation && isThreadMessage; final showThreadReplyIndicator = !_isThreadConversation && hasReplies; - final isOnlyEmoji = textIsOnlyEmoji(message.text); + final isOnlyEmoji = message.text.isOnlyEmoji; Widget child = MessageWidget( key: ValueKey('MESSAGE-${message.id}'), diff --git a/lib/src/message_widget.dart b/lib/src/message_widget.dart index e9ea4873..cd14ac40 100644 --- a/lib/src/message_widget.dart +++ b/lib/src/message_widget.dart @@ -938,7 +938,7 @@ class _MessageWidgetState extends State { ); } - bool get isOnlyEmoji => textIsOnlyEmoji(widget.message.text); + bool get isOnlyEmoji => widget.message.text.isOnlyEmoji; Color _getBackgroundColor() { if (hasQuotedMessage) { diff --git a/lib/src/quoted_message_widget.dart b/lib/src/quoted_message_widget.dart index d012e15a..8a102635 100644 --- a/lib/src/quoted_message_widget.dart +++ b/lib/src/quoted_message_widget.dart @@ -125,7 +125,7 @@ class QuotedMessageWidget extends StatelessWidget { } Widget _buildMessage(BuildContext context) { - final isOnlyEmoji = textIsOnlyEmoji(message.text); + final isOnlyEmoji = message.text.isOnlyEmoji; var msg = _hasAttachments && !_containsText ? message.copyWith(text: message.attachments.last?.title ?? '') : message; diff --git a/lib/src/utils.dart b/lib/src/utils.dart index be10263e..333b96f1 100644 --- a/lib/src/utils.dart +++ b/lib/src/utils.dart @@ -1,4 +1,3 @@ -import 'package:emojis/emoji.dart'; import 'package:flutter/material.dart'; import 'package:stream_chat/stream_chat.dart'; import 'package:url_launcher/url_launcher.dart'; @@ -215,16 +214,3 @@ StreamSvgIcon getFileTypeImage(String type) { break; } } - -final _emojis = Emoji.all(); - -bool textIsOnlyEmoji(String text) { - return text.trim().characters.isNotEmpty && - text.trim().characters.every((c) => - _emojis.firstWhere( - (Emoji emoji) => emoji.char.contains(c), - orElse: () => null, - ) != - null) && - text.characters.length < 4; -} From fbc8fd9a5937f5b0826cbb625183c6fa95091bc5 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Tue, 12 Jan 2021 15:38:54 +0530 Subject: [PATCH 0863/1140] [QuotedMessageWidget, MessageWidget] Fix emoji and regular text size Signed-off-by: Sahil Kumar --- lib/src/message_widget.dart | 2 +- lib/src/quoted_message_widget.dart | 7 +++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/lib/src/message_widget.dart b/lib/src/message_widget.dart index cd14ac40..a40556a2 100644 --- a/lib/src/message_widget.dart +++ b/lib/src/message_widget.dart @@ -923,7 +923,7 @@ class _MessageWidgetState extends State { ? widget.messageTheme.copyWith( messageText: widget.messageTheme.messageText.copyWith( - fontSize: 40, + fontSize: 42, )) : widget.messageTheme, ), diff --git a/lib/src/quoted_message_widget.dart b/lib/src/quoted_message_widget.dart index 8a102635..c718cdb5 100644 --- a/lib/src/quoted_message_widget.dart +++ b/lib/src/quoted_message_widget.dart @@ -145,9 +145,12 @@ class QuotedMessageWidget extends StatelessWidget { messageTheme: isOnlyEmoji && _containsText ? messageTheme.copyWith( messageText: messageTheme.messageText.copyWith( - fontSize: 24, + fontSize: 32, )) - : messageTheme, + : messageTheme.copyWith( + messageText: messageTheme.messageText.copyWith( + fontSize: 12, + )), ), ), ), From 919c12290d1ab6a64210dc50bcfec96118ba3869 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Tue, 12 Jan 2021 11:11:52 +0100 Subject: [PATCH 0864/1140] fix build action --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 46bf0c61..c83f3635 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -61,4 +61,4 @@ jobs: appId: ${{secrets.FIREBASE_ANDROID_APPID}} token: ${{secrets.FIREBASE_TOKEN}} groups: stream-testers - file: example/build/app/outputs/apk/release/app-release.apk \ No newline at end of file + file: packages/flutter_widgets/example/build/app/outputs/apk/release/app-release.apk \ No newline at end of file From 317de62925d79a8dd735db9507e77d05f82bd94c Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Tue, 12 Jan 2021 11:23:31 +0100 Subject: [PATCH 0865/1140] fix deleted message preview --- lib/src/channel_preview.dart | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/lib/src/channel_preview.dart b/lib/src/channel_preview.dart index eac6e3c2..3564be7a 100644 --- a/lib/src/channel_preview.dart +++ b/lib/src/channel_preview.dart @@ -96,12 +96,16 @@ class ChannelPreview extends StatelessWidget { Flexible(child: _buildSubtitle(context)), Builder( builder: (context) { - if (channel.state.lastMessage?.user?.id == + final lastMessage = channel.state.messages.lastWhere( + (m) => !m.isDeleted && m.shadowed != true, + orElse: () => null, + ); + if (lastMessage?.user?.id == StreamChat.of(context).user.id) { return Padding( padding: const EdgeInsets.only(right: 4.0), child: SendingIndicator( - message: channel.state.lastMessage, + message: lastMessage, size: StreamChatTheme.of(context) .channelPreviewTheme .indicatorIconSize, @@ -110,8 +114,7 @@ class ChannelPreview extends StatelessWidget { element.user.id != channel.client.state.user.id) ?.where((element) => element.lastRead - .isAfter(channel - .state.lastMessage.createdAt)) + .isAfter(lastMessage.createdAt)) ?.isNotEmpty == true, ), @@ -201,16 +204,15 @@ class ChannelPreview extends StatelessWidget { stream: channel.state.messagesStream, initialData: channel.state.messages, builder: (context, snapshot) { - final lastMessage = snapshot.data - ?.lastWhere((m) => m.shadowed != true, orElse: () => null); + final lastMessage = snapshot.data?.lastWhere( + (m) => m.shadowed != true && !m.isDeleted, + orElse: () => null); if (lastMessage == null) { return SizedBox(); } var text = lastMessage.text; - if (lastMessage.isDeleted) { - text = 'This message was deleted.'; - } else if (lastMessage.attachments != null) { + if (lastMessage.attachments != null) { final parts = [ ...lastMessage.attachments.map((e) { if (e.type == 'image') { From d9a50ae42eee303eae2bdbfbb21559fa18ff8e09 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Tue, 12 Jan 2021 12:05:01 +0100 Subject: [PATCH 0866/1140] fix animations --- example/pubspec.yaml | 2 +- lib/src/message_actions_modal.dart | 283 +++++++++++++-------------- lib/src/message_reactions_modal.dart | 265 ++++++++++++------------- lib/src/reaction_picker.dart | 30 +-- 4 files changed, 284 insertions(+), 296 deletions(-) diff --git a/example/pubspec.yaml b/example/pubspec.yaml index cdc07de7..46dc8820 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -1,6 +1,6 @@ name: example description: A new Flutter project. -version: 1.1.0+1 +version: 1.1.0+2 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 95ecdea5..7f9c5e85 100644 --- a/lib/src/message_actions_modal.dart +++ b/lib/src/message_actions_modal.dart @@ -84,155 +84,146 @@ class _MessageActionsModalState extends State { ? 1 : (roughSentenceSize == 0 ? 1 : (roughSentenceSize / roughMaxSize)); - return GestureDetector( - behavior: HitTestBehavior.translucent, - onTap: () => Navigator.maybePop(context), - child: Stack( - children: [ - Positioned.fill( - child: BackdropFilter( - filter: ImageFilter.blur( - sigmaX: 10, - sigmaY: 10, - ), - child: Container( - color: StreamChatTheme.of(context).colorTheme.overlay, - ), - ), - ), - Center( - child: SingleChildScrollView( - child: Padding( - padding: const EdgeInsets.symmetric(vertical: 8.0), - child: Column( - crossAxisAlignment: widget.reverse - ? CrossAxisAlignment.end - : CrossAxisAlignment.start, - children: [ - if (widget.showReactions && - (widget.message.status == MessageSendingStatus.SENT || - widget.message.status == null)) - Align( - alignment: Alignment( - user.id == widget.message.user.id - ? (divFactor > 1.0 ? 0.0 : (1.0 - divFactor)) - : (divFactor > 1.0 ? 0.0 : -(1.0 - divFactor)), - 0.0), - child: ReactionPicker( - message: widget.message, - messageTheme: widget.messageTheme, - ), - ), - TweenAnimationBuilder( - tween: Tween(begin: 0.0, end: 1.0), - duration: Duration(milliseconds: 300), - builder: (context, val, snapshot) { - return Transform.scale( - scale: val, - child: IgnorePointer( - child: MessageWidget( - key: Key('MessageWidget'), - reverse: widget.reverse, - message: widget.message.copyWith( - text: widget.message.text.length > 200 - ? '${widget.message.text.substring(0, 200)}...' - : widget.message.text, - ), - messageTheme: widget.messageTheme, - showReactions: false, - showUsername: false, - showThreadReplyIndicator: false, - showReplyMessage: false, - showUserAvatar: widget.showUserAvatar, - showTimestamp: false, - translateUserAvatar: false, - showReactionPickerIndicator: - widget.showReactions && - (widget.message.status == - MessageSendingStatus.SENT || - widget.message.status == null), - showInChannelIndicator: false, - showSendingIndicator: false, - shape: widget.messageShape, - ), - ), - ); - }), - TweenAnimationBuilder( - tween: Tween(begin: 0.0, end: 1.0), - duration: Duration(milliseconds: 300), - curve: Curves.easeInOut, - builder: (context, val, wid) { - return Transform( - transform: Matrix4.identity() - ..scale(val) - ..rotateZ(-1.0 + val), - alignment: widget.reverse - ? Alignment.topRight - : Alignment.topLeft, - child: Padding( - padding: EdgeInsets.only( - right: widget.reverse ? 16 : 0, - left: widget.reverse ? 0 : 48, - ), - 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 (widget.showReplyMessage && - (widget.message.status == - MessageSendingStatus.SENT || - widget.message.status == - null) && - widget.message.parentId == null) - _buildReplyButton(context), - if (widget.showThreadReplyMessage && - (widget.message.status == - MessageSendingStatus.SENT || - widget.message.status == - null) && - widget.message.parentId == null) - _buildThreadReplyButton(context), - if (widget.showResendMessage) - _buildResendMessage(context), - if (widget.showEditMessage) - _buildEditMessage(context), - if (widget.showCopyMessage) - _buildCopyButton(context), - if (widget.showFlagButton) - _buildFlagButton(context), - if (widget.showDeleteMessage) - _buildDeleteButton(context), - ], - ).toList(), - ), - ), - ), - ), - ); - }) - ], + return TweenAnimationBuilder( + tween: Tween(begin: 0.0, end: 1.0), + duration: Duration(milliseconds: 300), + curve: Curves.easeInOutBack, + builder: (context, val, snapshot) { + return GestureDetector( + behavior: HitTestBehavior.translucent, + onTap: () => Navigator.maybePop(context), + child: Stack( + children: [ + Positioned.fill( + child: BackdropFilter( + filter: ImageFilter.blur( + sigmaX: 10, + sigmaY: 10, + ), + child: Container( + color: StreamChatTheme.of(context).colorTheme.overlay, + ), ), ), - ), + Transform.scale( + scale: val, + child: Center( + child: SingleChildScrollView( + child: Padding( + padding: const EdgeInsets.symmetric(vertical: 8.0), + child: Column( + crossAxisAlignment: widget.reverse + ? CrossAxisAlignment.end + : CrossAxisAlignment.start, + children: [ + if (widget.showReactions && + (widget.message.status == + MessageSendingStatus.SENT || + widget.message.status == null)) + Align( + alignment: Alignment( + user.id == widget.message.user.id + ? (divFactor > 1.0 + ? 0.0 + : (1.0 - divFactor)) + : (divFactor > 1.0 + ? 0.0 + : -(1.0 - divFactor)), + 0.0), + child: ReactionPicker( + message: widget.message, + messageTheme: widget.messageTheme, + ), + ), + IgnorePointer( + child: MessageWidget( + key: Key('MessageWidget'), + reverse: widget.reverse, + message: widget.message.copyWith( + text: widget.message.text.length > 200 + ? '${widget.message.text.substring(0, 200)}...' + : widget.message.text, + ), + messageTheme: widget.messageTheme, + showReactions: false, + showUsername: false, + showThreadReplyIndicator: false, + showReplyMessage: false, + showUserAvatar: widget.showUserAvatar, + showTimestamp: false, + translateUserAvatar: false, + showReactionPickerIndicator: + widget.showReactions && + (widget.message.status == + MessageSendingStatus.SENT || + widget.message.status == null), + showInChannelIndicator: false, + showSendingIndicator: false, + shape: widget.messageShape, + ), + ), + Padding( + padding: EdgeInsets.only( + right: widget.reverse ? 16 : 0, + left: widget.reverse ? 0 : 48, + ), + 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 (widget.showReplyMessage && + (widget.message.status == + MessageSendingStatus.SENT || + widget.message.status == null) && + widget.message.parentId == null) + _buildReplyButton(context), + if (widget.showThreadReplyMessage && + (widget.message.status == + MessageSendingStatus.SENT || + widget.message.status == null) && + widget.message.parentId == null) + _buildThreadReplyButton(context), + if (widget.showResendMessage) + _buildResendMessage(context), + if (widget.showEditMessage) + _buildEditMessage(context), + if (widget.showCopyMessage) + _buildCopyButton(context), + if (widget.showFlagButton) + _buildFlagButton(context), + if (widget.showDeleteMessage) + _buildDeleteButton(context), + ], + ).toList(), + ), + ), + ), + ), + ], + ), + ), + ), + ), + ), + ], ), - ], - ), + ); + }, ); } diff --git a/lib/src/message_reactions_modal.dart b/lib/src/message_reactions_modal.dart index 5c24e047..15a301cc 100644 --- a/lib/src/message_reactions_modal.dart +++ b/lib/src/message_reactions_modal.dart @@ -56,86 +56,92 @@ class MessageReactionsModal extends StatelessWidget { ? 1 : (roughSentenceSize == 0 ? 1 : (roughSentenceSize / roughMaxSize)); - return GestureDetector( - behavior: HitTestBehavior.translucent, - onTap: () => Navigator.maybePop(context), - child: Stack( - children: [ - Positioned.fill( - child: BackdropFilter( - filter: ImageFilter.blur( - sigmaX: 10, - sigmaY: 10, - ), - child: Container( - color: StreamChatTheme.of(context).colorTheme.overlay, - ), - ), - ), - Center( - child: SingleChildScrollView( - child: 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)) - Align( - alignment: Alignment( - user.id == message.user.id - ? (divFactor > 1.0 ? 0.0 : (1.0 - divFactor)) - : (divFactor > 1.0 ? 0.0 : -(1.0 - divFactor)), - 0.0), - child: ReactionPicker( - message: message, - messageTheme: messageTheme, - ), - ), - TweenAnimationBuilder( - tween: Tween(begin: 0.0, end: 1.0), - duration: Duration(milliseconds: 300), - builder: (context, val, snapshot) { - return Transform.scale( - scale: val, - child: 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, - showUserAvatar: showUserAvatar, - showThreadReplyIndicator: false, - showTimestamp: false, - translateUserAvatar: false, - showSendingIndicator: false, - shape: messageShape, - showInChannelIndicator: false, - showReactionPickerIndicator: showReactions && - (message.status == - MessageSendingStatus.SENT || - message.status == null), - ), - ), - ); - }), - if (message.latestReactions?.isNotEmpty == true) - _buildReactionCard(context), - ], + return TweenAnimationBuilder( + tween: Tween(begin: 0.0, end: 1.0), + duration: Duration(milliseconds: 300), + curve: Curves.easeInOutBack, + builder: (context, val, snapshot) { + return GestureDetector( + behavior: HitTestBehavior.translucent, + onTap: () => Navigator.maybePop(context), + child: Stack( + children: [ + Positioned.fill( + child: BackdropFilter( + filter: ImageFilter.blur( + sigmaX: 10, + sigmaY: 10, + ), + child: Container( + color: StreamChatTheme.of(context).colorTheme.overlay, + ), ), ), - ), + Transform.scale( + scale: val, + child: Center( + child: SingleChildScrollView( + child: 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)) + Align( + alignment: Alignment( + user.id == message.user.id + ? (divFactor > 1.0 + ? 0.0 + : (1.0 - divFactor)) + : (divFactor > 1.0 + ? 0.0 + : -(1.0 - divFactor)), + 0.0), + 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, + showUserAvatar: showUserAvatar, + showThreadReplyIndicator: false, + showTimestamp: false, + translateUserAvatar: false, + showSendingIndicator: false, + shape: messageShape, + showInChannelIndicator: false, + showReactionPickerIndicator: showReactions && + (message.status == + MessageSendingStatus.SENT || + message.status == null), + ), + ), + if (message.latestReactions?.isNotEmpty == true) + _buildReactionCard(context), + ], + ), + ), + ), + ), + ), + ], ), - ], - ), + ); + }, ); } @@ -191,64 +197,53 @@ class MessageReactionsModal extends StatelessWidget { BuildContext context, ) { final isCurrentUser = reaction.user.id == currentUser.id; - return TweenAnimationBuilder( - tween: Tween(begin: 0.0, end: 1.0), - duration: Duration(milliseconds: 300), - curve: Curves.easeInOut, - builder: (context, val, snapshot) { - return Transform.scale( - scale: val, - child: 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), - ), - Positioned( - child: Align( - alignment: reverse - ? Alignment.centerRight - : Alignment.centerLeft, - child: ReactionBubble( - reactions: [reaction], - flipTail: !reverse, - borderColor: messageTheme.reactionsBorderColor, - backgroundColor: - messageTheme.reactionsBackgroundColor, - highlightOwnReactions: false, - ), - ), - bottom: 6, - left: isCurrentUser ? 0 : null, - right: isCurrentUser ? 0 : null, - ), - ], - ), - const SizedBox(height: 8), - Text( - reaction.user.name, - style: StreamChatTheme.of(context).textTheme.footnoteBold, - textAlign: TextAlign.center, - ), - ], + 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), ), - ), - ); - }); + Positioned( + child: Align( + alignment: + reverse ? Alignment.centerRight : Alignment.centerLeft, + child: ReactionBubble( + reactions: [reaction], + flipTail: !reverse, + borderColor: messageTheme.reactionsBorderColor, + backgroundColor: messageTheme.reactionsBackgroundColor, + highlightOwnReactions: false, + ), + ), + bottom: 6, + left: isCurrentUser ? 0 : null, + right: isCurrentUser ? 0 : null, + ), + ], + ), + const SizedBox(height: 8), + Text( + reaction.user.name, + style: StreamChatTheme.of(context).textTheme.footnoteBold, + textAlign: TextAlign.center, + ), + ], + ), + ); } } diff --git a/lib/src/reaction_picker.dart b/lib/src/reaction_picker.dart index c5c42bd1..bca74a99 100644 --- a/lib/src/reaction_picker.dart +++ b/lib/src/reaction_picker.dart @@ -1,3 +1,5 @@ +import 'dart:math'; + import 'package:ezanimation/ezanimation.dart'; import 'package:flutter/material.dart'; import 'package:stream_chat_flutter/src/stream_svg_icon.dart'; @@ -36,13 +38,10 @@ class _ReactionPickerState extends State if (animations.isEmpty && reactionIcons.isNotEmpty) { reactionIcons.forEach((element) { animations.add( - EzAnimation.sequence( - [ - SequenceItem(0.0, 1.4), - SequenceItem(1.4, 1.0), - ], + EzAnimation.tween( + Tween(begin: 0.0, end: 1.0), Duration(milliseconds: 500), - vsync: this, + curve: Curves.easeInOutBack, ), ); }); @@ -52,7 +51,7 @@ class _ReactionPickerState extends State return TweenAnimationBuilder( tween: Tween(begin: 0.0, end: 1.0), - curve: Curves.easeInOutExpo, + curve: Curves.easeInOutBack, duration: Duration(milliseconds: 500), builder: (context, val, wid) { return Transform.scale( @@ -81,15 +80,18 @@ class _ReactionPickerState extends State 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), + return Transform.scale( + scale: animations[index].value, child: StreamSvgIcon( assetName: reactionIcon.assetName, - height: animations[index].value * 24.0, - width: animations[index].value * 24.0, + height: max( + 0, + animations[index].value * 24.0, + ), + width: max( + 0, + animations[index].value * 24.0, + ), color: ownReactionIndex != -1 ? StreamChatTheme.of(context) .colorTheme From 47a3a94c93b38112c19612017f876d8383b34346 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Tue, 12 Jan 2021 16:57:04 +0530 Subject: [PATCH 0867/1140] [MessageInput] Fix iconButtons and textField paddings and text sizes Signed-off-by: Sahil Kumar --- lib/src/message_input.dart | 559 ++++++++++++++++++------------------- 1 file changed, 271 insertions(+), 288 deletions(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index ee8763ba..8bb20302 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -358,31 +358,31 @@ class MessageInputState extends State { ); } - AnimatedCrossFade _animateSendButton(BuildContext context) { - return AnimatedCrossFade( - crossFadeState: ((_messageIsPresent || _attachments.isNotEmpty) && - _attachments.every((a) => a.uploaded == true)) - ? CrossFadeState.showFirst - : CrossFadeState.showSecond, - firstChild: _buildSendButton(context), - secondChild: _buildIdleSendButton(context), - duration: Duration(milliseconds: 300), - alignment: Alignment.center, + Widget _animateSendButton(BuildContext context) { + return Padding( + padding: const EdgeInsets.all(8.0), + child: AnimatedCrossFade( + crossFadeState: ((_messageIsPresent || _attachments.isNotEmpty) && + _attachments.every((a) => a.uploaded == true)) + ? CrossFadeState.showFirst + : CrossFadeState.showSecond, + firstChild: _buildSendButton(context), + secondChild: _buildIdleSendButton(context), + duration: Duration(milliseconds: 300), + alignment: Alignment.center, + ), ); } Widget _buildExpandActionsButton() { - return AnimatedCrossFade( - crossFadeState: - _actionsShrunk ? CrossFadeState.showFirst : CrossFadeState.showSecond, - firstChild: Padding( - padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 8), - child: IconButton( - onPressed: () { - setState(() { - _actionsShrunk = false; - }); - }, + return Padding( + padding: const EdgeInsets.all(8.0), + child: AnimatedCrossFade( + crossFadeState: _actionsShrunk + ? CrossFadeState.showFirst + : CrossFadeState.showSecond, + firstChild: IconButton( + onPressed: () => setState(() => _actionsShrunk = false), icon: StreamSvgIcon.emptyCircleLeft( color: StreamChatTheme.of(context).colorTheme.accentBlue, ), @@ -393,34 +393,36 @@ class MessageInputState extends State { ), splashRadius: 24, ), + secondChild: Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + if (!widget.disableAttachments) _buildAttachmentButton(), + if (widget.editMessage == null && + StreamChannel.of(context) + .channel + ?.config + ?.commands + ?.isNotEmpty == + true) + _buildCommandButton(), + ].insertBetween(const SizedBox(width: 8)), + ), + duration: Duration(milliseconds: 300), + alignment: Alignment.center, ), - secondChild: Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - if (!widget.disableAttachments) _buildAttachmentButton(), - if (widget.editMessage == null && - StreamChannel.of(context).channel?.config?.commands?.isNotEmpty == - true) - _buildCommandButton(), - ], - ), - duration: Duration(milliseconds: 300), - alignment: Alignment.center, ); } Expanded _buildTextInput(BuildContext context) { + final theme = StreamChatTheme.of(context); return Expanded( child: Center( child: Container( clipBehavior: Clip.antiAlias, decoration: BoxDecoration( - borderRadius: BorderRadius.circular(24.0), - border: Border.all( - color: StreamChatTheme.of(context).colorTheme.greyGainsboro, - ), + borderRadius: BorderRadius.circular(20.0), + border: Border.all(color: theme.colorTheme.greyGainsboro), ), - padding: _attachments.isEmpty ? null : EdgeInsets.all(6.0), child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, @@ -429,52 +431,48 @@ class MessageInputState extends State { _buildAttachments(), LimitedBox( maxHeight: widget.maxHeight, - child: TextField( - key: Key('messageInputText'), - enabled: _inputEnabled, - minLines: null, - maxLines: null, - onSubmitted: (_) { - sendMessage(); - }, - keyboardType: widget.keyboardType, - controller: textEditingController, - focusNode: _focusNode, - style: Theme.of(context).textTheme.bodyText2, - autofocus: false, - textAlignVertical: TextAlignVertical.center, - decoration: InputDecoration( - isDense: true, - hintText: _getHint(), - prefixText: _commandEnabled ? null : ' ', - border: OutlineInputBorder( - borderSide: BorderSide(color: Colors.transparent)), - focusedBorder: OutlineInputBorder( - borderSide: BorderSide(color: Colors.transparent)), - enabledBorder: OutlineInputBorder( - borderSide: BorderSide(color: Colors.transparent)), - errorBorder: OutlineInputBorder( - borderSide: BorderSide(color: Colors.transparent)), - disabledBorder: OutlineInputBorder( - borderSide: BorderSide(color: Colors.transparent)), - contentPadding: EdgeInsets.symmetric( - horizontal: 16, - vertical: 13, - ), - prefixIcon: _commandEnabled - ? Padding( - padding: - const EdgeInsets.symmetric(horizontal: 8.0), - child: Chip( - backgroundColor: StreamChatTheme.of(context) - .colorTheme - .accentBlue, - padding: EdgeInsets.zero, - labelPadding: - EdgeInsets.symmetric(horizontal: 8.0), - label: Row( + child: SizedBox( + height: 40, + child: TextField( + key: Key('messageInputText'), + enabled: _inputEnabled, + minLines: null, + maxLines: null, + onSubmitted: (_) => sendMessage(), + keyboardType: widget.keyboardType, + controller: textEditingController, + focusNode: _focusNode, + style: theme.textTheme.body, + autofocus: false, + textAlignVertical: TextAlignVertical.center, + decoration: InputDecoration( + isDense: true, + hintText: _getHint(), + hintStyle: theme.textTheme.body.copyWith( + color: theme.colorTheme.grey, + ), + border: OutlineInputBorder( + borderSide: BorderSide(color: Colors.transparent)), + focusedBorder: OutlineInputBorder( + borderSide: BorderSide(color: Colors.transparent)), + enabledBorder: OutlineInputBorder( + borderSide: BorderSide(color: Colors.transparent)), + errorBorder: OutlineInputBorder( + borderSide: BorderSide(color: Colors.transparent)), + disabledBorder: OutlineInputBorder( + borderSide: BorderSide(color: Colors.transparent)), + contentPadding: const EdgeInsets.fromLTRB(16, 12, 13, 11), + prefixIcon: _commandEnabled + ? Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(12), + color: theme.colorTheme.accentBlue, + ), + height: 24, + margin: const EdgeInsets.all(8.0), + padding: const EdgeInsets.only(right: 8, left: 4), + child: Row( mainAxisSize: MainAxisSize.min, - mainAxisAlignment: MainAxisAlignment.center, children: [ StreamSvgIcon.lightning( color: Colors.white, @@ -484,27 +482,32 @@ class MessageInputState extends State { _chosenCommand?.name?.toUpperCase() ?? '', style: StreamChatTheme.of(context) .textTheme - .footnote + .footnoteBold .copyWith( color: Colors.white, ), ), ], ), - ), - ) - : null, - suffixIcon: _commandEnabled - ? IconButton( - icon: StreamSvgIcon.close_small(), - splashRadius: 24, - onPressed: () { - setState(() => _commandEnabled = false); - }, - ) - : null, + ) + : null, + suffixIcon: _commandEnabled + ? IconButton( + icon: StreamSvgIcon.close_small(), + splashRadius: 24, + padding: const EdgeInsets.all(0), + constraints: BoxConstraints.tightFor( + height: 24, + width: 24, + ), + onPressed: () { + setState(() => _commandEnabled = false); + }, + ) + : null, + ), + textCapitalization: TextCapitalization.sentences, ), - textCapitalization: TextCapitalization.sentences, ), ) ], @@ -1515,9 +1518,7 @@ class MessageInputState extends State { } Widget _buildReplyToMessage() { - if (!_hasQuotedMessage) { - return Offstage(); - } + if (!_hasQuotedMessage) return Offstage(); final containsUrl = widget.quotedMessage.attachments ?.any((element) => element.ogScrapeUrl != null) == true; @@ -1534,109 +1535,104 @@ class MessageInputState extends State { } Widget _buildAttachments() { - return _attachments.isEmpty - ? Container() - : Column( - children: [ - if (_attachments.any((e) => e.attachment?.type == 'file')) - LimitedBox( - maxHeight: 136.0, - child: ListView( - reverse: true, - shrinkWrap: true, - children: _attachments.reversed - .where((e) => e.attachment?.type == 'file') - .map( - (e) => Padding( - padding: - const EdgeInsets.symmetric(horizontal: 8.0), - child: ClipRRect( - borderRadius: BorderRadius.circular(10), - clipBehavior: Clip.antiAlias, - child: FileAttachment( - attachment: e.attachment, - attachmentType: FileAttachmentType.local, - file: e.file, - size: Size( - MediaQuery.of(context).size.width * 0.65, - 56.0, + if (_attachments.isEmpty) return Offstage(); + return Column( + children: [ + if (_attachments.any((e) => e.attachment?.type == 'file')) + LimitedBox( + maxHeight: 136.0, + child: ListView( + reverse: true, + shrinkWrap: true, + children: _attachments.reversed + .where((e) => e.attachment?.type == 'file') + .map( + (e) => Padding( + padding: const EdgeInsets.symmetric(horizontal: 8.0), + child: ClipRRect( + borderRadius: BorderRadius.circular(10), + clipBehavior: Clip.antiAlias, + child: FileAttachment( + attachment: e.attachment, + attachmentType: FileAttachmentType.local, + file: e.file, + size: Size( + MediaQuery.of(context).size.width * 0.65, + 56.0, + ), + trailing: Padding( + padding: const EdgeInsets.all(8.0), + child: InkWell( + child: CircleAvatar( + backgroundColor: StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(0.6), + maxRadius: 12.0, + child: StreamSvgIcon.close( + color: StreamChatTheme.of(context) + .colorTheme + .white, ), - trailing: Padding( - padding: const EdgeInsets.all(8.0), - child: InkWell( - child: CircleAvatar( - backgroundColor: - StreamChatTheme.of(context) - .colorTheme - .black - .withOpacity(0.6), - maxRadius: 12.0, - child: StreamSvgIcon.close( - color: StreamChatTheme.of(context) - .colorTheme - .white, + ), + onTap: () { + setState(() { + _attachments.remove(e); + }); + }, + ), + ), + ), + ), + ), + ) + .toList(), + ), + ), + if (_attachments.any((e) => e.attachment?.type != 'file')) + LimitedBox( + maxHeight: 104.0, + child: ListView( + scrollDirection: Axis.horizontal, + children: _attachments + .where((e) => e.attachment?.type != 'file') + .map( + (attachment) => Padding( + padding: const EdgeInsets.all(8.0), + child: ClipRRect( + borderRadius: BorderRadius.circular(10), + clipBehavior: Clip.antiAlias, + child: Stack( + children: [ + AspectRatio( + aspectRatio: 1.0, + child: Container( + height: 104, + width: 104, + child: _buildAttachment(attachment), + ), + ), + _buildRemoveButton(attachment), + attachment.uploaded + ? SizedBox() + : Positioned.fill( + child: Center( + child: Padding( + padding: const EdgeInsets.all(16.0), + child: CircularProgressIndicator(), ), ), - onTap: () { - setState(() { - _attachments.remove(e); - }); - }, ), - ), - ), - ), - ), - ) - .toList(), - ), - ), - if (_attachments.any((e) => e.attachment?.type != 'file')) - LimitedBox( - maxHeight: 104.0, - child: ListView( - scrollDirection: Axis.horizontal, - children: _attachments - .where((e) => e.attachment?.type != 'file') - .map( - (attachment) => Padding( - padding: const EdgeInsets.all(8.0), - child: ClipRRect( - borderRadius: BorderRadius.circular(10), - clipBehavior: Clip.antiAlias, - child: Stack( - children: [ - AspectRatio( - aspectRatio: 1.0, - child: Container( - height: 104, - width: 104, - child: _buildAttachment(attachment), - ), - ), - _buildRemoveButton(attachment), - attachment.uploaded - ? SizedBox() - : Positioned.fill( - child: Center( - child: Padding( - padding: - const EdgeInsets.all(16.0), - child: - CircularProgressIndicator(), - ), - ), - ), - ], - ), - ), - ), - ) - .toList(), - ), - ), - ], - ); + ], + ), + ), + ), + ) + .toList(), + ), + ), + ], + ); } Positioned _buildRemoveButton(_SendingAttachment attachment) { @@ -1746,80 +1742,74 @@ class MessageInputState extends State { } Widget _buildCommandButton() { - return Padding( - padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 8), - child: IconButton( - icon: StreamSvgIcon.lightning( - color: _commandsOverlay != null - ? StreamChatTheme.of(context).colorTheme.accentBlue - : StreamChatTheme.of(context).colorTheme.grey, - ), - padding: const EdgeInsets.all(0), - constraints: BoxConstraints.tightFor( - height: 24, - width: 24, - ), - splashRadius: 24, - onPressed: () async { - if (_openFilePickerSection) { - setState(() { - _animateContainer = false; - _openFilePickerSection = false; - _filePickerSize = _kMinMediaPickerSize; - }); - await Future.delayed(Duration(milliseconds: 300)); - } - - if (_commandsOverlay == null) { - setState(() { - _commandsOverlay = _buildCommandsOverlayEntry(); - Overlay.of(context).insert(_commandsOverlay); - }); - } else { - setState(() { - _commandsOverlay?.remove(); - _commandsOverlay = null; - }); - } - }, + return IconButton( + icon: StreamSvgIcon.lightning( + color: _commandsOverlay != null + ? StreamChatTheme.of(context).colorTheme.accentBlue + : StreamChatTheme.of(context).colorTheme.grey, ), + padding: const EdgeInsets.all(0), + constraints: BoxConstraints.tightFor( + height: 24, + width: 24, + ), + splashRadius: 24, + onPressed: () async { + if (_openFilePickerSection) { + setState(() { + _animateContainer = false; + _openFilePickerSection = false; + _filePickerSize = _kMinMediaPickerSize; + }); + await Future.delayed(Duration(milliseconds: 300)); + } + + if (_commandsOverlay == null) { + setState(() { + _commandsOverlay = _buildCommandsOverlayEntry(); + Overlay.of(context).insert(_commandsOverlay); + }); + } else { + setState(() { + _commandsOverlay?.remove(); + _commandsOverlay = null; + }); + } + }, ); } Widget _buildAttachmentButton() { - return Padding( - padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 8), - child: IconButton( - icon: StreamSvgIcon.attach( - color: _openFilePickerSection - ? StreamChatTheme.of(context).colorTheme.accentBlue - : StreamChatTheme.of(context).colorTheme.grey, - ), - padding: const EdgeInsets.all(0), - constraints: BoxConstraints.tightFor( - height: 24, - width: 24, - ), - splashRadius: 24, - onPressed: () async { - _emojiOverlay?.remove(); - _emojiOverlay = null; - _commandsOverlay?.remove(); - _commandsOverlay = null; - _mentionsOverlay?.remove(); - _mentionsOverlay = null; - - if (_openFilePickerSection) { - setState(() { - _animateContainer = true; - _openFilePickerSection = false; - _filePickerSize = _kMinMediaPickerSize; - }); - } else { - showAttachmentModal(); - } - }, + return IconButton( + icon: StreamSvgIcon.attach( + color: _openFilePickerSection + ? StreamChatTheme.of(context).colorTheme.accentBlue + : StreamChatTheme.of(context).colorTheme.grey, ), + padding: const EdgeInsets.all(0), + constraints: BoxConstraints.tightFor( + height: 24, + width: 24, + ), + splashRadius: 24, + onPressed: () async { + _emojiOverlay?.remove(); + _emojiOverlay = null; + _commandsOverlay?.remove(); + _commandsOverlay = null; + _mentionsOverlay?.remove(); + _mentionsOverlay = null; + + if (_openFilePickerSection) { + setState(() { + _animateContainer = true; + _openFilePickerSection = false; + _filePickerSize = _kMinMediaPickerSize; + }); + } else { + showAttachmentModal(); + } + }, ); } @@ -2118,31 +2108,24 @@ class MessageInputState extends State { } Widget _buildIdleSendButton(BuildContext context) { - return Padding( - padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 8), - child: StreamSvgIcon( - assetName: _getIdleSendIcon(), - color: StreamChatTheme.of(context).colorTheme.greyGainsboro, - ), + return StreamSvgIcon( + assetName: _getIdleSendIcon(), + color: StreamChatTheme.of(context).colorTheme.greyGainsboro, ); } Widget _buildSendButton(BuildContext context) { - return Padding( - padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 8), - child: IconButton( - onPressed: sendMessage, - visualDensity: VisualDensity.compact, - padding: const EdgeInsets.all(0), - splashRadius: 24, - constraints: BoxConstraints.tightFor( - height: 24, - width: 24, - ), - icon: StreamSvgIcon( - assetName: _getSendIcon(), - color: StreamChatTheme.of(context).colorTheme.accentBlue, - ), + return IconButton( + onPressed: sendMessage, + padding: const EdgeInsets.all(0), + splashRadius: 24, + constraints: BoxConstraints.tightFor( + height: 24, + width: 24, + ), + icon: StreamSvgIcon( + assetName: _getSendIcon(), + color: StreamChatTheme.of(context).colorTheme.accentBlue, ), ); } From c5f245808378e685af2daec504cc8989233706c2 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Tue, 12 Jan 2021 18:03:24 +0530 Subject: [PATCH 0868/1140] [MessageWidget] Move messageBorderSide handling one level up Signed-off-by: Sahil Kumar --- lib/src/message_list_view.dart | 10 +++++++++- lib/src/message_widget.dart | 7 ++----- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/lib/src/message_list_view.dart b/lib/src/message_list_view.dart index 095b6b73..dab8eda1 100644 --- a/lib/src/message_list_view.dart +++ b/lib/src/message_list_view.dart @@ -811,6 +811,14 @@ class _MessageListViewState extends State { final showThreadReplyIndicator = !_isThreadConversation && hasReplies; final isOnlyEmoji = message.text.isOnlyEmoji; + final borderSide = isMyMessage + ? !(showThreadReplyIndicator || showInChannelIndicator) + ? BorderSide.none + : null + : isOnlyEmoji + ? BorderSide.none + : null; + Widget child = MessageWidget( key: ValueKey('MESSAGE-${message.id}'), message: message, @@ -846,7 +854,7 @@ class _MessageListViewState extends State { showEditMessage: isMyMessage, showDeleteMessage: isMyMessage, showThreadReplyMessage: !isThreadMessage, - borderSide: isMyMessage && !isOnlyEmoji ? BorderSide.none : null, + borderSide: borderSide, onThreadTap: _onThreadTap, onReplyTap: widget.onReplyTap, attachmentBorderRadiusGeometry: BorderRadius.only( diff --git a/lib/src/message_widget.dart b/lib/src/message_widget.dart index a40556a2..ba458a7e 100644 --- a/lib/src/message_widget.dart +++ b/lib/src/message_widget.dart @@ -383,11 +383,8 @@ class _MessageWidgetState extends State { ), shape: widget.shape ?? RoundedRectangleBorder( - side: isOnlyEmoji && - !(showThreadReplyIndicator || - showInChannel) - ? BorderSide.none - : widget.borderSide ?? + side: + widget.borderSide ?? BorderSide( color: widget .messageTheme From f04452cbc9cfa27c8a6b8d37c47209b56fb0e8dd Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Tue, 12 Jan 2021 18:04:39 +0530 Subject: [PATCH 0869/1140] feat: Added info tile and wrapped channel list and channel header --- lib/src/channel_header.dart | 121 +++++++++++++++---------- lib/src/channel_list_header.dart | 147 ++++++++++++++++++------------- lib/src/info_tile.dart | 35 ++++++++ lib/src/stream_chat.dart | 35 ++++---- 4 files changed, 218 insertions(+), 120 deletions(-) create mode 100644 lib/src/info_tile.dart diff --git a/lib/src/channel_header.dart b/lib/src/channel_header.dart index 4517d7a0..fe624473 100644 --- a/lib/src/channel_header.dart +++ b/lib/src/channel_header.dart @@ -3,6 +3,7 @@ import 'package:stream_chat/stream_chat.dart'; import 'package:stream_chat_flutter/src/back_button.dart'; import 'package:stream_chat_flutter/src/channel_info.dart'; import 'package:stream_chat_flutter/src/channel_name.dart'; +import 'package:stream_chat_flutter/src/info_tile.dart'; import 'package:stream_chat_flutter/src/stream_chat_theme.dart'; import '../stream_chat_flutter.dart'; @@ -82,54 +83,84 @@ class ChannelHeader extends StatelessWidget implements PreferredSizeWidget { @override Widget build(BuildContext context) { final channel = StreamChannel.of(context).channel; - return AppBar( - brightness: Theme.of(context).brightness, - elevation: 1, - leading: showBackButton - ? StreamBackButton( - onPressed: onBackPressed, - showUnreads: true, - ) - : SizedBox(), - backgroundColor: - StreamChatTheme.of(context).channelTheme.channelHeaderTheme.color, - actions: [ - Padding( - padding: const EdgeInsets.only(right: 10.0), - child: Center( - child: ChannelImage( - onTap: onImageTap, - ), - ), - ), - ], - centerTitle: true, - title: InkWell( - onTap: onTitleTap, - child: Container( - height: preferredSize.height, - width: preferredSize.width, - child: Column( - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisAlignment: MainAxisAlignment.center, - children: [ - ChannelName( - textStyle: StreamChatTheme.of(context) - .channelTheme - .channelHeaderTheme - .title, - ), - SizedBox(height: 2), - ChannelInfo( - showTypingIndicator: showTypingIndicator, - channel: channel, - textStyle: - StreamChatTheme.of(context).channelPreviewTheme.subtitle, + final _client = StreamChat.of(context).client; + + return ValueListenableBuilder( + valueListenable: _client.wsConnectionStatus, + builder: (context, status, _) { + String statusString = ''; + bool showStatus = true; + + switch (status) { + case ConnectionStatus.connected: + statusString = 'Connected'; + showStatus = false; + break; + case ConnectionStatus.connecting: + statusString = 'Connecting'; + break; + case ConnectionStatus.disconnected: + statusString = 'Disconnected'; + break; + } + + return InfoTile( + showMessage: showStatus, + message: statusString, + child: AppBar( + brightness: Theme.of(context).brightness, + elevation: 1, + leading: showBackButton + ? StreamBackButton( + onPressed: onBackPressed, + showUnreads: true, + ) + : SizedBox(), + backgroundColor: StreamChatTheme.of(context) + .channelTheme + .channelHeaderTheme + .color, + actions: [ + Padding( + padding: const EdgeInsets.only(right: 10.0), + child: Center( + child: ChannelImage( + onTap: onImageTap, + ), + ), ), ], + centerTitle: true, + title: InkWell( + onTap: onTitleTap, + child: Container( + height: preferredSize.height, + width: preferredSize.width, + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + ChannelName( + textStyle: StreamChatTheme.of(context) + .channelTheme + .channelHeaderTheme + .title, + ), + SizedBox(height: 2), + ChannelInfo( + showTypingIndicator: showTypingIndicator, + channel: channel, + textStyle: StreamChatTheme.of(context) + .channelPreviewTheme + .subtitle, + ), + ], + ), + ), + ), ), - ), - ), + ); + }, ); } diff --git a/lib/src/channel_list_header.dart b/lib/src/channel_list_header.dart index 34f3cc76..e7fc9f9a 100644 --- a/lib/src/channel_list_header.dart +++ b/lib/src/channel_list_header.dart @@ -6,6 +6,7 @@ import 'package:stream_chat/stream_chat.dart'; import 'package:stream_chat_flutter/src/stream_neumorphic_button.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; +import 'info_tile.dart'; import 'stream_chat.dart'; typedef _TitleBuilder = Widget Function( @@ -72,73 +73,101 @@ class ChannelListHeader extends StatelessWidget implements PreferredSizeWidget { Widget build(BuildContext context) { final _client = client ?? StreamChat.of(context).client; final user = _client.state.user; - return AppBar( - brightness: Theme.of(context).brightness, - elevation: 1, - backgroundColor: - StreamChatTheme.of(context).channelTheme.channelHeaderTheme.color, - centerTitle: true, - leading: Center( - child: UserAvatar( - user: user, - showOnlineStatus: false, - onTap: onUserAvatarTap ?? (_) => Scaffold.of(context).openDrawer(), - borderRadius: BorderRadius.circular(20), - constraints: BoxConstraints.tightFor( - height: 40, - width: 40, - ), - ), - ), - actions: [ - StreamNeumorphicButton( - child: IconButton( - icon: ValueListenableBuilder( - valueListenable: _client.wsConnectionStatus, - builder: (context, status, child) { - var color; + return ValueListenableBuilder( + valueListenable: _client.wsConnectionStatus, + builder: (context, status, child) { + String statusString = ''; + bool showStatus = true; + + switch (status) { + case ConnectionStatus.connected: + statusString = 'Connected'; + showStatus = false; + break; + case ConnectionStatus.connecting: + statusString = 'Connecting'; + break; + case ConnectionStatus.disconnected: + statusString = 'Disconnected'; + break; + } + + return InfoTile( + showMessage: showStatus, + message: statusString, + child: AppBar( + brightness: Theme.of(context).brightness, + elevation: 1, + backgroundColor: StreamChatTheme.of(context) + .channelTheme + .channelHeaderTheme + .color, + centerTitle: true, + leading: Center( + child: UserAvatar( + user: user, + showOnlineStatus: false, + onTap: + onUserAvatarTap ?? (_) => Scaffold.of(context).openDrawer(), + borderRadius: BorderRadius.circular(20), + constraints: BoxConstraints.tightFor( + height: 40, + width: 40, + ), + ), + ), + actions: [ + StreamNeumorphicButton( + child: IconButton( + icon: ValueListenableBuilder( + valueListenable: _client.wsConnectionStatus, + builder: (context, status, child) { + var color; + switch (status) { + case ConnectionStatus.connected: + color = + StreamChatTheme.of(context).colorTheme.accentBlue; + break; + case ConnectionStatus.connecting: + color = Colors.grey; + break; + case ConnectionStatus.disconnected: + color = Colors.grey; + break; + } + return SvgPicture.asset( + 'svgs/icon_pen_write.svg', + package: 'stream_chat_flutter', + width: 24.0, + height: 24.0, + color: color, + ); + }, + ), + onPressed: onNewChatButtonTap, + ), + ) + ], + title: Builder( + builder: (context) { + if (titleBuilder != null) { + return titleBuilder(context, status, _client); + } switch (status) { case ConnectionStatus.connected: - color = StreamChatTheme.of(context).colorTheme.accentBlue; - break; + return _buildConnectedTitleState(context); case ConnectionStatus.connecting: - color = Colors.grey; - break; + return _buildConnectingTitleState(context); case ConnectionStatus.disconnected: - color = Colors.grey; - break; + return _buildDisconnectedTitleState(context, _client); + default: + return Offstage(); } - return SvgPicture.asset( - 'svgs/icon_pen_write.svg', - package: 'stream_chat_flutter', - width: 24.0, - height: 24.0, - color: color, - ); }, ), - onPressed: onNewChatButtonTap, ), - ) - ], - title: ValueListenableBuilder( - valueListenable: _client.wsConnectionStatus, - builder: (context, status, child) { - if (titleBuilder != null) { - return titleBuilder(context, status, _client); - } - switch (status) { - case ConnectionStatus.connected: - return _buildConnectedTitleState(context); - case ConnectionStatus.connecting: - return _buildConnectingTitleState(context); - case ConnectionStatus.disconnected: - return _buildDisconnectedTitleState(context, _client); - default: - return Offstage(); - } - }, - ), + ); + }, ); } diff --git a/lib/src/info_tile.dart b/lib/src/info_tile.dart new file mode 100644 index 00000000..c3905b91 --- /dev/null +++ b/lib/src/info_tile.dart @@ -0,0 +1,35 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_portal/flutter_portal.dart'; +import 'package:stream_chat_flutter/src/stream_chat_theme.dart'; + +class InfoTile extends StatelessWidget { + final String message; + final Widget child; + final bool showMessage; + + InfoTile({this.message, this.child, this.showMessage}); + + @override + Widget build(BuildContext context) { + return PortalEntry( + visible: showMessage, + portalAnchor: Alignment.topCenter, + childAnchor: Alignment.bottomCenter, + portal: Container( + height: 25.0, + color: StreamChatTheme.of(context).colorTheme.grey, + child: Center( + child: Text( + message, + style: StreamChatTheme.of(context).textTheme.body.copyWith( + color: Colors.white, + ), + maxLines: 1, + overflow: TextOverflow.ellipsis, + ), + ), + ), + child: child, + ); + } +} diff --git a/lib/src/stream_chat.dart b/lib/src/stream_chat.dart index 317dfec6..3ebdf6e9 100644 --- a/lib/src/stream_chat.dart +++ b/lib/src/stream_chat.dart @@ -3,6 +3,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:flutter_portal/flutter_portal.dart'; import 'package:stream_chat/stream_chat.dart'; import 'package:stream_chat_flutter/src/stream_chat_theme.dart'; @@ -67,22 +68,24 @@ class StreamChatState extends State with WidgetsBindingObserver { @override Widget build(BuildContext context) { final theme = _getTheme(context, widget.streamChatThemeData); - return StreamChatTheme( - data: theme, - child: Builder( - builder: (context) { - final materialTheme = Theme.of(context); - final streamTheme = StreamChatTheme.of(context); - return Theme( - data: materialTheme.copyWith( - primaryIconTheme: streamTheme.primaryIconTheme, - accentColor: streamTheme.colorTheme.accentBlue, - scaffoldBackgroundColor: streamTheme.colorTheme.white, - buttonTheme: streamTheme.buttonTheme, - ), - child: widget.child, - ); - }, + return Portal( + child: StreamChatTheme( + data: theme, + child: Builder( + builder: (context) { + final materialTheme = Theme.of(context); + final streamTheme = StreamChatTheme.of(context); + return Theme( + data: materialTheme.copyWith( + primaryIconTheme: streamTheme.primaryIconTheme, + accentColor: streamTheme.colorTheme.accentBlue, + scaffoldBackgroundColor: streamTheme.colorTheme.white, + buttonTheme: streamTheme.buttonTheme, + ), + child: widget.child, + ); + }, + ), ), ); } From 7e8def27072acc5231bb826a5036848b533402a6 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Tue, 12 Jan 2021 18:08:50 +0530 Subject: [PATCH 0870/1140] [MessageListView] Minor border visibility condition fixes Signed-off-by: Sahil Kumar --- lib/src/message_list_view.dart | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/lib/src/message_list_view.dart b/lib/src/message_list_view.dart index dab8eda1..6242bd8a 100644 --- a/lib/src/message_list_view.dart +++ b/lib/src/message_list_view.dart @@ -732,7 +732,7 @@ class _MessageListViewState extends State { topRight: Radius.circular(16), bottomRight: Radius.circular(16), ), - borderSide: isMyMessage && !isOnlyEmoji ? BorderSide.none : null, + borderSide: isMyMessage || isOnlyEmoji ? BorderSide.none : null, showUserAvatar: isMyMessage ? DisplayWidget.gone : DisplayWidget.show, messageTheme: isMyMessage ? StreamChatTheme.of(context).ownMessageTheme @@ -811,11 +811,13 @@ class _MessageListViewState extends State { final showThreadReplyIndicator = !_isThreadConversation && hasReplies; final isOnlyEmoji = message.text.isOnlyEmoji; + final showMessageBorder = + showThreadReplyIndicator || showInChannelIndicator; final borderSide = isMyMessage - ? !(showThreadReplyIndicator || showInChannelIndicator) + ? !showMessageBorder ? BorderSide.none : null - : isOnlyEmoji + : isOnlyEmoji && !showMessageBorder ? BorderSide.none : null; From 53587a86553342db4d93133ac79d9d71f28f2e07 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Tue, 12 Jan 2021 18:14:00 +0530 Subject: [PATCH 0871/1140] fix: Added alignment customisation --- lib/src/info_tile.dart | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/lib/src/info_tile.dart b/lib/src/info_tile.dart index c3905b91..80595601 100644 --- a/lib/src/info_tile.dart +++ b/lib/src/info_tile.dart @@ -6,15 +6,23 @@ class InfoTile extends StatelessWidget { final String message; final Widget child; final bool showMessage; + final Alignment tileAnchor; + final Alignment childAnchor; - InfoTile({this.message, this.child, this.showMessage}); + InfoTile({ + this.message, + this.child, + this.showMessage, + this.tileAnchor, + this.childAnchor, + }); @override Widget build(BuildContext context) { return PortalEntry( visible: showMessage, - portalAnchor: Alignment.topCenter, - childAnchor: Alignment.bottomCenter, + portalAnchor: tileAnchor ?? Alignment.topCenter, + childAnchor: childAnchor ?? Alignment.bottomCenter, portal: Container( height: 25.0, color: StreamChatTheme.of(context).colorTheme.grey, From 1cf15f1b61484a08af1005b169c270fd54b5469f Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Tue, 12 Jan 2021 18:17:08 +0530 Subject: [PATCH 0872/1140] fix: Fixed opacity --- lib/src/info_tile.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/info_tile.dart b/lib/src/info_tile.dart index 80595601..46d111e7 100644 --- a/lib/src/info_tile.dart +++ b/lib/src/info_tile.dart @@ -25,7 +25,7 @@ class InfoTile extends StatelessWidget { childAnchor: childAnchor ?? Alignment.bottomCenter, portal: Container( height: 25.0, - color: StreamChatTheme.of(context).colorTheme.grey, + color: StreamChatTheme.of(context).colorTheme.grey.withOpacity(0.9), child: Center( child: Text( message, From 0bb76bab39484dc7ef87b63600fa811e0fd7b36a Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Tue, 12 Jan 2021 18:18:33 +0530 Subject: [PATCH 0873/1140] fix: Added better customisation --- lib/src/info_tile.dart | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/lib/src/info_tile.dart b/lib/src/info_tile.dart index 46d111e7..2e12d6b3 100644 --- a/lib/src/info_tile.dart +++ b/lib/src/info_tile.dart @@ -8,14 +8,17 @@ class InfoTile extends StatelessWidget { final bool showMessage; final Alignment tileAnchor; final Alignment childAnchor; + final TextStyle textStyle; + final Color backgroundColor; - InfoTile({ - this.message, - this.child, - this.showMessage, - this.tileAnchor, - this.childAnchor, - }); + InfoTile( + {this.message, + this.child, + this.showMessage, + this.tileAnchor, + this.childAnchor, + this.textStyle, + this.backgroundColor}); @override Widget build(BuildContext context) { @@ -25,13 +28,15 @@ class InfoTile extends StatelessWidget { childAnchor: childAnchor ?? Alignment.bottomCenter, portal: Container( height: 25.0, - color: StreamChatTheme.of(context).colorTheme.grey.withOpacity(0.9), + color: backgroundColor ?? + StreamChatTheme.of(context).colorTheme.grey.withOpacity(0.9), child: Center( child: Text( message, - style: StreamChatTheme.of(context).textTheme.body.copyWith( - color: Colors.white, - ), + style: textStyle ?? + StreamChatTheme.of(context).textTheme.body.copyWith( + color: Colors.white, + ), maxLines: 1, overflow: TextOverflow.ellipsis, ), From 40910f93f1e82b49291e44e0868d1a62b8fbccca Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Tue, 12 Jan 2021 13:49:44 +0100 Subject: [PATCH 0874/1140] fix reaction picker spacing and size --- example/pubspec.yaml | 2 +- lib/src/reaction_picker.dart | 123 ++++++++++++++++++++--------------- 2 files changed, 71 insertions(+), 54 deletions(-) diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 46dc8820..6c4ae4dc 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -1,6 +1,6 @@ name: example description: A new Flutter project. -version: 1.1.0+2 +version: 1.1.0+3 environment: sdk: ">=2.2.2 <3.0.0" diff --git a/lib/src/reaction_picker.dart b/lib/src/reaction_picker.dart index bca74a99..804b1559 100644 --- a/lib/src/reaction_picker.dart +++ b/lib/src/reaction_picker.dart @@ -5,6 +5,7 @@ import 'package:flutter/material.dart'; import 'package:stream_chat_flutter/src/stream_svg_icon.dart'; import '../stream_chat_flutter.dart'; +import 'extension.dart'; /// ![screenshot](https://raw.githubusercontent.com/GetStream/stream-chat-flutter/master/screenshots/reaction_picker.png) /// ![screenshot](https://raw.githubusercontent.com/GetStream/stream-chat-flutter/master/screenshots/reaction_picker_paint.png) @@ -57,67 +58,83 @@ class _ReactionPickerState extends State return Transform.scale( scale: val, child: Material( + borderRadius: BorderRadius.circular(24), color: StreamChatTheme.of(context).colorTheme.white, clipBehavior: Clip.hardEdge, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(24), - ), child: Padding( - padding: const EdgeInsets.symmetric(horizontal: 8.0), + padding: const EdgeInsets.symmetric( + horizontal: 16.0, + vertical: 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); + 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.scale( - scale: animations[index].value, - child: StreamSvgIcon( - assetName: reactionIcon.assetName, - height: max( - 0, - animations[index].value * 24.0, - ), - width: max( - 0, - 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], - ); - } else { - sendReaction( - context, - reactionIcon.type, - ); - } - }, - ); - }).toList(), + return RawMaterialButton( + elevation: 0, + padding: const EdgeInsets.all(0), + clipBehavior: Clip.none, + shape: ContinuousRectangleBorder( + borderRadius: BorderRadius.circular(16), + ), + constraints: BoxConstraints.tightFor( + height: 24, + width: 24, + ), + child: AnimatedBuilder( + animation: animations[index], + builder: (context, val) { + return Transform.scale( + alignment: Alignment.center, + scale: animations[index].value, + child: StreamSvgIcon( + assetName: reactionIcon.assetName, + height: max( + 0, + animations[index].value * 24.0, + ), + width: max( + 0, + 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], + ); + } else { + sendReaction( + context, + reactionIcon.type, + ); + } + }, + ); + }) + .insertBetween(SizedBox( + width: 16, + )) + .toList(), ), ), ), From 294c9edafb455813ceda4cb74cb9ed13091c199e Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Tue, 12 Jan 2021 14:35:29 +0100 Subject: [PATCH 0875/1140] fix reaction picker spacing and size --- lib/src/reaction_picker.dart | 96 +++++++++++++++++++----------------- 1 file changed, 51 insertions(+), 45 deletions(-) diff --git a/lib/src/reaction_picker.dart b/lib/src/reaction_picker.dart index 804b1559..b0aa51ce 100644 --- a/lib/src/reaction_picker.dart +++ b/lib/src/reaction_picker.dart @@ -78,57 +78,63 @@ class _ReactionPickerState extends State -1; var index = reactionIcons.indexOf(reactionIcon); - return RawMaterialButton( - elevation: 0, - padding: const EdgeInsets.all(0), - clipBehavior: Clip.none, - shape: ContinuousRectangleBorder( - borderRadius: BorderRadius.circular(16), - ), + return ConstrainedBox( constraints: BoxConstraints.tightFor( height: 24, width: 24, ), - child: AnimatedBuilder( - animation: animations[index], - builder: (context, val) { - return Transform.scale( - alignment: Alignment.center, - scale: animations[index].value, - child: StreamSvgIcon( - assetName: reactionIcon.assetName, - height: max( - 0, - animations[index].value * 24.0, + child: RawMaterialButton( + elevation: 0, + padding: const EdgeInsets.all(0), + clipBehavior: Clip.none, + shape: ContinuousRectangleBorder( + borderRadius: BorderRadius.circular(16), + ), + constraints: BoxConstraints.tightFor( + height: 24, + width: 24, + ), + child: AnimatedBuilder( + animation: animations[index], + builder: (context, val) { + return Transform.scale( + alignment: Alignment.center, + scale: animations[index].value, + child: StreamSvgIcon( + assetName: reactionIcon.assetName, + height: max( + 0, + animations[index].value * 24.0, + ), + width: max( + 0, + animations[index].value * 24.0, + ), + color: ownReactionIndex != -1 + ? StreamChatTheme.of(context) + .colorTheme + .accentBlue + : Theme.of(context) + .iconTheme + .color + .withOpacity(.5), ), - width: max( - 0, - 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, - ); - } - }, + } else { + sendReaction( + context, + reactionIcon.type, + ); + } + }, + ), ); }) .insertBetween(SizedBox( From 04902f6a8124c40e68d325c9987c6e28e79ee400 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Tue, 12 Jan 2021 14:50:47 +0100 Subject: [PATCH 0876/1140] fix indicator --- 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 8118af01..ccf7dc83 100644 --- a/lib/src/message_widget.dart +++ b/lib/src/message_widget.dart @@ -428,7 +428,7 @@ class _MessageWidgetState extends State { if (widget.showReactionPickerIndicator) Positioned( right: 0, - top: -6, + top: -8, child: Transform( transform: Matrix4.rotationY( widget.reverse ? pi : 0), From 16bedf87287d845a2a765f114b016c62419ef9d6 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Tue, 12 Jan 2021 19:36:12 +0530 Subject: [PATCH 0877/1140] [QuotedMessageWidget, MessageWidget] Fix quoted message padding in case of attachments Signed-off-by: Sahil Kumar --- lib/src/message_widget.dart | 33 +++++++++++++++++++++-------- lib/src/quoted_message_widget.dart | 34 ++++++++++++------------------ 2 files changed, 38 insertions(+), 29 deletions(-) diff --git a/lib/src/message_widget.dart b/lib/src/message_widget.dart index c4b03ce2..8f4b0158 100644 --- a/lib/src/message_widget.dart +++ b/lib/src/message_widget.dart @@ -272,6 +272,12 @@ class _MessageWidgetState extends State { widget.message.attachments?.any((element) => element.type == 'giphy') == true; + bool get hasNonUrlAttachments => + widget.message.attachments + ?.where((it) => it.ogScrapeUrl == null) + ?.isNotEmpty == + true; + bool get showBottomRow => showThreadReplyIndicator || showUsername || @@ -409,8 +415,9 @@ class _MessageWidgetState extends State { children: [ if (hasQuotedMessage) _buildQuotedMessage(), - ..._parseAttachments( - context), + if (hasNonUrlAttachments) + ..._parseAttachments( + context), if (widget.message.text .trim() .isNotEmpty && @@ -487,13 +494,21 @@ class _MessageWidgetState extends State { widget.onQuotedMessageTap != null ? () => widget.onQuotedMessageTap(widget.message.quotedMessageId) : null; - return QuotedMessageWidget( - onTap: onTap, - message: widget.message.quotedMessage, - messageTheme: isMyMessage - ? StreamChatTheme.of(context).otherMessageTheme - : StreamChatTheme.of(context).ownMessageTheme, - reverse: widget.reverse, + return Padding( + padding: EdgeInsets.only( + right: 8, + left: 8, + top: 8, + bottom: hasNonUrlAttachments ? 8 : 0, + ), + child: QuotedMessageWidget( + onTap: onTap, + message: widget.message.quotedMessage, + messageTheme: isMyMessage + ? StreamChatTheme.of(context).otherMessageTheme + : StreamChatTheme.of(context).ownMessageTheme, + reverse: widget.reverse, + ), ); } diff --git a/lib/src/quoted_message_widget.dart b/lib/src/quoted_message_widget.dart index c718cdb5..309df703 100644 --- a/lib/src/quoted_message_widget.dart +++ b/lib/src/quoted_message_widget.dart @@ -109,17 +109,14 @@ class QuotedMessageWidget extends StatelessWidget { Widget build(BuildContext context) { return InkWell( onTap: onTap, - child: Padding( - padding: const EdgeInsets.only(top: 8, right: 4, left: 8), - child: Row( - crossAxisAlignment: CrossAxisAlignment.end, - mainAxisSize: MainAxisSize.min, - children: [ - Flexible(child: _buildMessage(context)), - SizedBox(width: 4), - _buildUserAvatar(), - ], - ), + child: Row( + crossAxisAlignment: CrossAxisAlignment.end, + mainAxisSize: MainAxisSize.min, + children: [ + Flexible(child: _buildMessage(context)), + SizedBox(width: 8), + _buildUserAvatar(), + ], ), ); } @@ -247,16 +244,13 @@ class QuotedMessageWidget extends StatelessWidget { return Transform( transform: Matrix4.rotationY(reverse ? pi : 0), alignment: Alignment.center, - child: Padding( - padding: const EdgeInsets.symmetric(horizontal: 4.0), - child: UserAvatar( - user: message.user, - constraints: BoxConstraints.tightFor( - height: 24, - width: 24, - ), - showOnlineStatus: false, + child: UserAvatar( + user: message.user, + constraints: BoxConstraints.tightFor( + height: 24, + width: 24, ), + showOnlineStatus: false, ), ); } From 80d8c48826a7f1da7b9ab8f6bd6813bdc28e0ea2 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Tue, 12 Jan 2021 19:46:19 +0530 Subject: [PATCH 0878/1140] Minor ui fixes Signed-off-by: Sahil Kumar --- lib/src/message_actions_modal.dart | 6 ++---- lib/src/message_input.dart | 13 ++++++++----- lib/src/utils.dart | 22 ++++++++-------------- 3 files changed, 18 insertions(+), 23 deletions(-) diff --git a/lib/src/message_actions_modal.dart b/lib/src/message_actions_modal.dart index 7f9c5e85..2d125bab 100644 --- a/lib/src/message_actions_modal.dart +++ b/lib/src/message_actions_modal.dart @@ -164,7 +164,7 @@ class _MessageActionsModalState extends State { ), Padding( padding: EdgeInsets.only( - right: widget.reverse ? 16 : 0, + right: widget.reverse ? 8 : 0, left: widget.reverse ? 0 : 48, ), child: SizedBox( @@ -448,9 +448,7 @@ class _MessageActionsModalState extends State { ), ], ), - onTap: () { - _showFlagDialog(); - }, + onTap: () => _showFlagDialog(), ); } diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 8bb20302..4561372e 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -1525,11 +1525,14 @@ class MessageInputState extends State { return Transform( transform: Matrix4.rotationY(pi), alignment: Alignment.center, - child: QuotedMessageWidget( - reverse: true, - showBorder: !containsUrl, - message: widget.quotedMessage, - messageTheme: StreamChatTheme.of(context).otherMessageTheme, + child: Padding( + padding: const EdgeInsets.fromLTRB(8, 8, 8, 0), + child: QuotedMessageWidget( + reverse: true, + showBorder: !containsUrl, + message: widget.quotedMessage, + messageTheme: StreamChatTheme.of(context).otherMessageTheme, + ), ), ); } diff --git a/lib/src/utils.dart b/lib/src/utils.dart index 6548b987..d1dec9c8 100644 --- a/lib/src/utils.dart +++ b/lib/src/utils.dart @@ -37,27 +37,21 @@ Future showConfirmationDialog( return Column( mainAxisSize: MainAxisSize.min, children: [ - SizedBox( - height: 26.0, - ), + SizedBox(height: 26.0), if (icon != null) icon, - SizedBox( - height: 26.0, - ), + SizedBox(height: 26.0), Text( title, style: StreamChatTheme.of(context).textTheme.headlineBold, ), - SizedBox( - height: 7.0, - ), - Text(question), - SizedBox( - height: 36.0, + SizedBox(height: 7.0), + Text( + question, + textAlign: TextAlign.center, ), + SizedBox(height: 36.0), Container( - color: - StreamChatTheme.of(context).colorTheme.black.withOpacity(.08), + color: StreamChatTheme.of(context).colorTheme.greyGainsboro, height: 1.0, ), Row( From 74e9ec648c0ea56b398cc459e21a33342d025d45 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Tue, 12 Jan 2021 15:24:53 +0100 Subject: [PATCH 0879/1140] remove add member for distinct channels --- example/lib/group_info_screen.dart | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/example/lib/group_info_screen.dart b/example/lib/group_info_screen.dart index ed5f2c61..bde4c0df 100644 --- a/example/lib/group_info_screen.dart +++ b/example/lib/group_info_screen.dart @@ -137,20 +137,21 @@ class _GroupInfoScreenState extends State { ), centerTitle: true, actions: [ - StreamNeumorphicButton( - child: InkWell( - onTap: () { - _buildAddUserModal(context); - }, - child: Padding( - padding: const EdgeInsets.all(8.0), - child: StreamSvgIcon.userAdd( - color: StreamChatTheme.of(context) - .colorTheme - .accentBlue), + if (!channel.channel.isDistinct) + StreamNeumorphicButton( + child: InkWell( + onTap: () { + _buildAddUserModal(context); + }, + child: Padding( + padding: const EdgeInsets.all(8.0), + child: StreamSvgIcon.userAdd( + color: StreamChatTheme.of(context) + .colorTheme + .accentBlue), + ), ), ), - ), ], ), body: ListView( From 18d3cbcc86cad354e5fe1785a0ecc7249593dbab Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Tue, 12 Jan 2021 15:25:25 +0100 Subject: [PATCH 0880/1140] version bump --- example/pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 6c4ae4dc..1605cdd5 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -1,6 +1,6 @@ name: example description: A new Flutter project. -version: 1.1.0+3 +version: 1.1.1 environment: sdk: ">=2.2.2 <3.0.0" From fad38a513ac0a50ca521363af74132063a618044 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Tue, 12 Jan 2021 21:13:38 +0530 Subject: [PATCH 0881/1140] feat: Added a way to disable info tiles and added info tile to message list view --- lib/src/channel_header.dart | 7 +- lib/src/channel_list_header.dart | 7 +- lib/src/message_list_view.dart | 345 +++++++++++++++++-------------- 3 files changed, 201 insertions(+), 158 deletions(-) diff --git a/lib/src/channel_header.dart b/lib/src/channel_header.dart index fe624473..8b920f23 100644 --- a/lib/src/channel_header.dart +++ b/lib/src/channel_header.dart @@ -69,6 +69,8 @@ class ChannelHeader extends StatelessWidget implements PreferredSizeWidget { /// If true the typing indicator will be rendered if a user is typing final bool showTypingIndicator; + final bool showConnectionStateTile; + /// Creates a channel header ChannelHeader({ Key key, @@ -77,6 +79,7 @@ class ChannelHeader extends StatelessWidget implements PreferredSizeWidget { this.onTitleTap, this.showTypingIndicator = true, this.onImageTap, + this.showConnectionStateTile = false, }) : preferredSize = Size.fromHeight(kToolbarHeight), super(key: key); @@ -97,7 +100,7 @@ class ChannelHeader extends StatelessWidget implements PreferredSizeWidget { showStatus = false; break; case ConnectionStatus.connecting: - statusString = 'Connecting'; + statusString = 'Reconnecting...'; break; case ConnectionStatus.disconnected: statusString = 'Disconnected'; @@ -105,7 +108,7 @@ class ChannelHeader extends StatelessWidget implements PreferredSizeWidget { } return InfoTile( - showMessage: showStatus, + showMessage: showConnectionStateTile ? showStatus : false, message: statusString, child: AppBar( brightness: Theme.of(context).brightness, diff --git a/lib/src/channel_list_header.dart b/lib/src/channel_list_header.dart index e7fc9f9a..b6bf3ca7 100644 --- a/lib/src/channel_list_header.dart +++ b/lib/src/channel_list_header.dart @@ -54,6 +54,7 @@ class ChannelListHeader extends StatelessWidget implements PreferredSizeWidget { this.titleBuilder, this.onUserAvatarTap, this.onNewChatButtonTap, + this.showConnectionStateTile = false, }) : super(key: key); /// Pass this if you don't have a [Client] in your widget tree. @@ -69,6 +70,8 @@ class ChannelListHeader extends StatelessWidget implements PreferredSizeWidget { /// Callback to call when pressing the new chat button. final VoidCallback onNewChatButtonTap; + final bool showConnectionStateTile; + @override Widget build(BuildContext context) { final _client = client ?? StreamChat.of(context).client; @@ -85,7 +88,7 @@ class ChannelListHeader extends StatelessWidget implements PreferredSizeWidget { showStatus = false; break; case ConnectionStatus.connecting: - statusString = 'Connecting'; + statusString = 'Reconnecting...'; break; case ConnectionStatus.disconnected: statusString = 'Disconnected'; @@ -93,7 +96,7 @@ class ChannelListHeader extends StatelessWidget implements PreferredSizeWidget { } return InfoTile( - showMessage: showStatus, + showMessage: showConnectionStateTile ? showStatus : false, message: statusString, child: AppBar( brightness: Theme.of(context).brightness, diff --git a/lib/src/message_list_view.dart b/lib/src/message_list_view.dart index cda0d64c..f1d2ca12 100644 --- a/lib/src/message_list_view.dart +++ b/lib/src/message_list_view.dart @@ -7,6 +7,7 @@ import 'package:jiffy/jiffy.dart'; import 'package:rxdart/rxdart.dart'; import 'package:scrollable_positioned_list/scrollable_positioned_list.dart'; import 'package:stream_chat/stream_chat.dart'; +import 'package:stream_chat_flutter/src/info_tile.dart'; import 'package:stream_chat_flutter/src/lazy_load_scroll_view.dart'; import 'package:stream_chat_flutter/src/message_widget.dart'; import 'package:stream_chat_flutter/src/stream_svg_icon.dart'; @@ -124,6 +125,7 @@ class MessageListView extends StatefulWidget { this.highlightInitialMessage = false, this.messageHighlightColor, this.onShowMessage, + this.showConnectionStateTile = false, }) : super(key: key); /// Function used to build a custom message widget @@ -181,6 +183,8 @@ class MessageListView extends StatefulWidget { final ShowMessageCallback onShowMessage; + final bool showConnectionStateTile; + @override _MessageListViewState createState() => _MessageListViewState(); } @@ -297,172 +301,205 @@ class _MessageListViewState extends State { } _messageListLength = newMessagesListLength; + final _client = StreamChat.of(context).client; return Stack( alignment: Alignment.center, children: [ - LazyLoadScrollView( - onStartOfPage: () async { - _inBetweenList = false; - if (!_upToDate) { - _topPaginationActive = false; - _bottomPaginationActive = true; - return _paginateData( - streamChannel, - QueryDirection.bottom, - ); - } - }, - onEndOfPage: () async { - _inBetweenList = false; - _topPaginationActive = true; - _bottomPaginationActive = false; - return _paginateData( - streamChannel, - QueryDirection.top, - ); - }, - onInBetweenOfPage: () { - _inBetweenList = true; - }, - child: ScrollablePositionedList.separated( - key: ValueKey(initialIndex + initialAlignment), - itemPositionsListener: _itemPositionListener, - addAutomaticKeepAlives: true, - initialScrollIndex: initialIndex ?? 0, - initialAlignment: initialAlignment ?? 0, - physics: widget.scrollPhysics, - itemScrollController: _scrollController, - reverse: true, - itemCount: - messages.length + 2 + (_isThreadConversation ? 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 = messages[i - 1]; - if (!Jiffy(message.createdAt.toLocal()).isSame( - nextMessage.createdAt.toLocal(), - Units.DAY, - )) { - final divider = widget.dateDividerBuilder != null - ? widget.dateDividerBuilder( + ValueListenableBuilder( + valueListenable: _client.wsConnectionStatus, + builder: (context, status, _) { + String statusString = ''; + bool showStatus = true; + + switch (status) { + case ConnectionStatus.connected: + statusString = 'Connected'; + showStatus = false; + break; + case ConnectionStatus.connecting: + statusString = 'Reconnecting...'; + break; + case ConnectionStatus.disconnected: + statusString = 'Disconnected'; + break; + } + + return InfoTile( + showMessage: + widget.showConnectionStateTile ? showStatus : false, + tileAnchor: Alignment.topCenter, + childAnchor: Alignment.topCenter, + message: statusString, + child: LazyLoadScrollView( + onStartOfPage: () async { + _inBetweenList = false; + if (!_upToDate) { + _topPaginationActive = false; + _bottomPaginationActive = true; + return _paginateData( + streamChannel, + QueryDirection.bottom, + ); + } + }, + onEndOfPage: () async { + _inBetweenList = false; + _topPaginationActive = true; + _bottomPaginationActive = false; + return _paginateData( + streamChannel, + QueryDirection.top, + ); + }, + onInBetweenOfPage: () { + _inBetweenList = true; + }, + child: ScrollablePositionedList.separated( + key: ValueKey(initialIndex + initialAlignment), + itemPositionsListener: _itemPositionListener, + addAutomaticKeepAlives: true, + initialScrollIndex: initialIndex ?? 0, + initialAlignment: initialAlignment ?? 0, + physics: widget.scrollPhysics, + itemScrollController: _scrollController, + reverse: true, + itemCount: messages.length + + 2 + + (_isThreadConversation ? 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 = messages[i - 1]; + if (!Jiffy(message.createdAt.toLocal()).isSame( nextMessage.createdAt.toLocal(), - ) - : DateDivider( - dateTime: 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, + ); + } + final timeDiff = + Jiffy(nextMessage.createdAt.toLocal()).diff( + message.createdAt.toLocal(), + Units.MINUTE, ); - return Padding( - padding: const EdgeInsets.symmetric(vertical: 12.0), - child: divider, - ); - } - 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; - final isDeleted = message.isDeleted; - if (timeDiff >= 1 || - !isNextUserSame || - isThread || - isDeleted) { - return SizedBox(height: 8); - } - return SizedBox(height: 2); - }, - itemBuilder: (context, i) { - if (i == messages.length + 2) { - if (widget.parentMessageBuilder != null) { - return widget.parentMessageBuilder( - context, - widget.parentMessage, - ); - } else { - return Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - buildParentMessage(widget.parentMessage), - Container( - decoration: BoxDecoration( - gradient: StreamChatTheme.of(context) - .colorTheme - .bgGradient, - ), - child: Padding( - padding: const EdgeInsets.all(8.0), - child: Text( - '${widget.parentMessage.replyCount} ${widget.parentMessage.replyCount == 1 ? 'Reply' : 'Replies'}', - textAlign: TextAlign.center, - style: StreamChatTheme.of(context) - .channelTheme - .channelHeaderTheme - .lastMessageAt, - ), - ), - ), - ], - ); - } - } - if (i == messages.length + 1) { - return _buildLoadingIndicator( - streamChannel, - QueryDirection.top, - ); - } - if (i == 0) { - return _buildLoadingIndicator( - streamChannel, - QueryDirection.bottom, - ); - } - final message = messages[i - 1]; + final isNextUserSame = + message.user.id == nextMessage.user?.id; + final isThread = message.replyCount > 0; + final isDeleted = message.isDeleted; + if (timeDiff >= 1 || + !isNextUserSame || + isThread || + isDeleted) { + return SizedBox(height: 8); + } + return SizedBox(height: 2); + }, + itemBuilder: (context, i) { + if (i == messages.length + 2) { + if (widget.parentMessageBuilder != null) { + return widget.parentMessageBuilder( + context, + widget.parentMessage, + ); + } else { + return Column( + crossAxisAlignment: + CrossAxisAlignment.stretch, + children: [ + buildParentMessage(widget.parentMessage), + Container( + decoration: BoxDecoration( + gradient: StreamChatTheme.of(context) + .colorTheme + .bgGradient, + ), + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Text( + '${widget.parentMessage.replyCount} ${widget.parentMessage.replyCount == 1 ? 'Reply' : 'Replies'}', + textAlign: TextAlign.center, + style: StreamChatTheme.of(context) + .channelTheme + .channelHeaderTheme + .lastMessageAt, + ), + ), + ), + ], + ); + } + } + if (i == messages.length + 1) { + return _buildLoadingIndicator( + streamChannel, + QueryDirection.top, + ); + } + if (i == 0) { + return _buildLoadingIndicator( + streamChannel, + QueryDirection.bottom, + ); + } + final message = messages[i - 1]; - Widget messageWidget; + Widget messageWidget; - if (i == 1) { - messageWidget = _buildBottomMessage( - context, - message, - messages, - streamChannel, - ); - } else if (i == messages.length - 1) { - messageWidget = _buildTopMessage( - context, - message, - messages, - streamChannel, - ); - } else { - if (widget.messageBuilder != null) { - messageWidget = Builder( - key: ValueKey('MESSAGE-${message.id}'), - builder: (context) => widget.messageBuilder( - context, - MessageDetails( + if (i == 1) { + messageWidget = _buildBottomMessage( context, message, messages, - i, - ), - messages), - ); - } else { - messageWidget = buildMessage(message, messages, i); - } - } - return messageWidget; - }, - ), - ), + streamChannel, + ); + } else if (i == messages.length - 1) { + messageWidget = _buildTopMessage( + context, + message, + messages, + streamChannel, + ); + } else { + if (widget.messageBuilder != null) { + messageWidget = Builder( + key: + ValueKey('MESSAGE-${message.id}'), + builder: (context) => widget.messageBuilder( + context, + MessageDetails( + context, + message, + messages, + i, + ), + messages), + ); + } else { + messageWidget = + buildMessage(message, messages, i); + } + } + return messageWidget; + }, + ), + ), + ); + }), if (widget.showScrollToBottom) _buildScrollToBottom(), Positioned( top: 20.0, From 3e1766940acf177489f6b6031807252102ce2df6 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Tue, 12 Jan 2021 21:24:46 +0530 Subject: [PATCH 0882/1140] feat: Added error tile for message search list view --- lib/src/message_search_list_view.dart | 76 +++++++++++++++------------ lib/stream_chat_flutter.dart | 1 + 2 files changed, 44 insertions(+), 33 deletions(-) diff --git a/lib/src/message_search_list_view.dart b/lib/src/message_search_list_view.dart index 73a98a2d..b176e148 100644 --- a/lib/src/message_search_list_view.dart +++ b/lib/src/message_search_list_view.dart @@ -2,6 +2,7 @@ import 'dart:convert'; import 'package:flutter/material.dart'; import 'package:stream_chat/stream_chat.dart'; +import 'package:stream_chat_flutter/src/info_tile.dart'; import 'package:stream_chat_flutter/src/message_search_item.dart'; import '../stream_chat_flutter.dart'; @@ -63,6 +64,7 @@ class MessageSearchListView extends StatefulWidget { this.onItemTap, this.showResultCount = true, this.pullToRefresh = true, + this.showErrorTile = false, }) : super(key: key); /// Message String to search on @@ -111,6 +113,8 @@ class MessageSearchListView extends StatefulWidget { /// Set it to false to disable the pull-to-refresh widget final bool pullToRefresh; + final bool showErrorTile; + @override _MessageSearchListViewState createState() => _MessageSearchListViewState(); } @@ -205,41 +209,47 @@ class _MessageSearchListViewState extends State { message = 'Check your connection and retry'; } } - return Center( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text.rich( - TextSpan( - children: [ - WidgetSpan( - child: Padding( - padding: const EdgeInsets.only(right: 2.0), - child: Icon(Icons.error_outline), + return InfoTile( + showMessage: widget.showErrorTile, + tileAnchor: Alignment.topCenter, + childAnchor: Alignment.topCenter, + message: 'An error occurred.', + child: Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text.rich( + TextSpan( + children: [ + WidgetSpan( + child: Padding( + padding: const EdgeInsets.only(right: 2.0), + child: Icon(Icons.error_outline), + ), ), - ), - TextSpan(text: 'Error loading messages'), - ], + TextSpan(text: 'Error loading messages'), + ], + ), + style: Theme.of(context).textTheme.headline6, ), - style: Theme.of(context).textTheme.headline6, - ), - Padding( - padding: const EdgeInsets.only(top: 16.0), - child: Text(message), - ), - RaisedButton( - onPressed: () { - messageSearchBloc.search( - filter: widget.filters, - sort: widget.sortOptions, - query: widget.messageQuery, - pagination: widget.paginationParams, - messageFilter: widget.messageFilters, - ); - }, - child: Text('Retry'), - ), - ], + Padding( + padding: const EdgeInsets.only(top: 16.0), + child: Text(message), + ), + RaisedButton( + onPressed: () { + messageSearchBloc.search( + filter: widget.filters, + sort: widget.sortOptions, + query: widget.messageQuery, + pagination: widget.paginationParams, + messageFilter: widget.messageFilters, + ); + }, + child: Text('Retry'), + ), + ], + ), ), ); } diff --git a/lib/stream_chat_flutter.dart b/lib/stream_chat_flutter.dart index 09eab2a4..df113234 100644 --- a/lib/stream_chat_flutter.dart +++ b/lib/stream_chat_flutter.dart @@ -46,3 +46,4 @@ export 'src/unread_indicator.dart'; export 'src/option_list_tile.dart'; export 'src/channel_file_display_screen.dart'; export 'src/channel_media_display_screen.dart'; +export 'src/info_tile.dart'; From 4aa224a5e6dba291da80dac2c0c6a9a286abe62f Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Tue, 12 Jan 2021 16:58:52 +0100 Subject: [PATCH 0883/1140] fix messageinput focus --- example/lib/main.dart | 7 +++++-- example/pubspec.yaml | 2 +- lib/src/message_input.dart | 5 ++++- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/example/lib/main.dart b/example/lib/main.dart index 98fa71a2..49ee3fdc 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -623,8 +623,8 @@ class _ChannelPageState extends State { @override void initState() { - super.initState(); _focusNode = FocusNode(); + super.initState(); } @override @@ -635,7 +635,9 @@ class _ChannelPageState extends State { void _reply(Message message) { setState(() => _quotedMessage = message); - _focusNode.requestFocus(); + WidgetsBinding.instance.addPostFrameCallback((timeStamp) { + _focusNode.requestFocus(); + }); } @override @@ -752,6 +754,7 @@ class _ChannelPageState extends State { quotedMessage: _quotedMessage, onQuotedMessageCleared: () { setState(() => _quotedMessage = null); + _focusNode.unfocus(); }, ), ], diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 1605cdd5..2b8859ea 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -1,6 +1,6 @@ name: example description: A new Flutter project. -version: 1.1.1 +version: 1.1.1+1 environment: sdk: ">=2.2.2 <3.0.0" diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 4561372e..cc12fbd9 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -203,6 +203,8 @@ class MessageInputState extends State { bool _openFilePickerSection = false; int _filePickerIndex = 0; double _filePickerSize = _kMinMediaPickerSize; + KeyboardVisibilityController _keyboardVisibilityController = + KeyboardVisibilityController(); /// The editing controller passed to the input TextField TextEditingController textEditingController; @@ -2249,7 +2251,8 @@ class MessageInputState extends State { _emojiNames = Emoji.all().map((e) => e.name); if (!kIsWeb) { - _keyboardListener = KeyboardVisibility.onChange.listen((visible) { + _keyboardListener = + _keyboardVisibilityController.onChange.listen((visible) { if (_focusNode.hasFocus) { _onChanged(context, textEditingController.text); } From 8245d13cc4e50fe3d622f47a8b8b3115172805a2 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Wed, 13 Jan 2021 11:15:31 +0530 Subject: [PATCH 0884/1140] [QuotedMessageWidget] Move padding inside widget Signed-off-by: Sahil Kumar --- lib/src/message_input.dart | 12 +++++------- lib/src/message_widget.dart | 22 ++++++++-------------- lib/src/quoted_message_widget.dart | 26 ++++++++++++++++---------- 3 files changed, 29 insertions(+), 31 deletions(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index cc12fbd9..db21c206 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -1527,14 +1527,12 @@ class MessageInputState extends State { return Transform( transform: Matrix4.rotationY(pi), alignment: Alignment.center, - child: Padding( + child: QuotedMessageWidget( + reverse: true, + showBorder: !containsUrl, + message: widget.quotedMessage, + messageTheme: StreamChatTheme.of(context).otherMessageTheme, padding: const EdgeInsets.fromLTRB(8, 8, 8, 0), - child: QuotedMessageWidget( - reverse: true, - showBorder: !containsUrl, - message: widget.quotedMessage, - messageTheme: StreamChatTheme.of(context).otherMessageTheme, - ), ), ); } diff --git a/lib/src/message_widget.dart b/lib/src/message_widget.dart index ccefce6e..f4f8944f 100644 --- a/lib/src/message_widget.dart +++ b/lib/src/message_widget.dart @@ -494,21 +494,15 @@ class _MessageWidgetState extends State { widget.onQuotedMessageTap != null ? () => widget.onQuotedMessageTap(widget.message.quotedMessageId) : null; - return Padding( + return QuotedMessageWidget( + onTap: onTap, + message: widget.message.quotedMessage, + messageTheme: isMyMessage + ? StreamChatTheme.of(context).otherMessageTheme + : StreamChatTheme.of(context).ownMessageTheme, + reverse: widget.reverse, padding: EdgeInsets.only( - right: 8, - left: 8, - top: 8, - bottom: hasNonUrlAttachments ? 8 : 0, - ), - child: QuotedMessageWidget( - onTap: onTap, - message: widget.message.quotedMessage, - messageTheme: isMyMessage - ? StreamChatTheme.of(context).otherMessageTheme - : StreamChatTheme.of(context).ownMessageTheme, - reverse: widget.reverse, - ), + right: 8, left: 8, top: 8, bottom: hasNonUrlAttachments ? 8 : 0), ); } diff --git a/lib/src/quoted_message_widget.dart b/lib/src/quoted_message_widget.dart index 309df703..e4e10e17 100644 --- a/lib/src/quoted_message_widget.dart +++ b/lib/src/quoted_message_widget.dart @@ -83,6 +83,8 @@ class QuotedMessageWidget extends StatelessWidget { final Map attachmentThumbnailBuilders; + final EdgeInsetsGeometry padding; + final GestureTapCallback onTap; /// @@ -94,6 +96,7 @@ class QuotedMessageWidget extends StatelessWidget { this.showBorder = false, this.textLimit = 170, this.attachmentThumbnailBuilders, + this.padding = const EdgeInsets.all(8), this.onTap, }) : super(key: key); @@ -107,16 +110,19 @@ class QuotedMessageWidget extends StatelessWidget { @override Widget build(BuildContext context) { - return InkWell( - onTap: onTap, - child: Row( - crossAxisAlignment: CrossAxisAlignment.end, - mainAxisSize: MainAxisSize.min, - children: [ - Flexible(child: _buildMessage(context)), - SizedBox(width: 8), - _buildUserAvatar(), - ], + return Padding( + padding: padding, + child: InkWell( + onTap: onTap, + child: Row( + crossAxisAlignment: CrossAxisAlignment.end, + mainAxisSize: MainAxisSize.min, + children: [ + Flexible(child: _buildMessage(context)), + SizedBox(width: 8), + _buildUserAvatar(), + ], + ), ), ); } From 18c31a666b7b55a174f8ba3745c1c8f23ad7a27d Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Wed, 13 Jan 2021 11:22:03 +0530 Subject: [PATCH 0885/1140] [MessageInput] Fix attachments padding Signed-off-by: Sahil Kumar --- lib/src/message_input.dart | 61 ++++++++++++++++++-------------------- 1 file changed, 29 insertions(+), 32 deletions(-) diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index db21c206..22a36882 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -1542,17 +1542,17 @@ class MessageInputState extends State { return Column( children: [ if (_attachments.any((e) => e.attachment?.type == 'file')) - LimitedBox( - maxHeight: 136.0, - child: ListView( - reverse: true, - shrinkWrap: true, - children: _attachments.reversed - .where((e) => e.attachment?.type == 'file') - .map( - (e) => Padding( - padding: const EdgeInsets.symmetric(horizontal: 8.0), - child: ClipRRect( + Padding( + padding: const EdgeInsets.fromLTRB(8, 8, 8, 0), + child: LimitedBox( + maxHeight: 136.0, + child: ListView( + reverse: true, + shrinkWrap: true, + children: _attachments.reversed + .where((e) => e.attachment?.type == 'file') + .map( + (e) => ClipRRect( borderRadius: BorderRadius.circular(10), clipBehavior: Clip.antiAlias, child: FileAttachment( @@ -1578,31 +1578,28 @@ class MessageInputState extends State { .white, ), ), - onTap: () { - setState(() { - _attachments.remove(e); - }); - }, + onTap: () => + setState(() => _attachments.remove(e)), ), ), ), ), - ), - ) - .toList(), + ) + .insertBetween(const SizedBox(width: 8)), + ), ), ), if (_attachments.any((e) => e.attachment?.type != 'file')) - LimitedBox( - maxHeight: 104.0, - child: ListView( - scrollDirection: Axis.horizontal, - children: _attachments - .where((e) => e.attachment?.type != 'file') - .map( - (attachment) => Padding( - padding: const EdgeInsets.all(8.0), - child: ClipRRect( + Padding( + padding: const EdgeInsets.fromLTRB(8, 8, 8, 0), + child: LimitedBox( + maxHeight: 104.0, + child: ListView( + scrollDirection: Axis.horizontal, + children: _attachments + .where((e) => e.attachment?.type != 'file') + .map( + (attachment) => ClipRRect( borderRadius: BorderRadius.circular(10), clipBehavior: Clip.antiAlias, child: Stack( @@ -1629,9 +1626,9 @@ class MessageInputState extends State { ], ), ), - ), - ) - .toList(), + ) + .insertBetween(const SizedBox(width: 8)), + ), ), ), ], From c22c6d29f5cfa0dc8c73048fc52c7c6d2dce051f Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Wed, 13 Jan 2021 11:33:59 +0530 Subject: [PATCH 0886/1140] [MessageListView] Fix message borders Signed-off-by: Sahil Kumar --- lib/src/message_list_view.dart | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/lib/src/message_list_view.dart b/lib/src/message_list_view.dart index 741ba6ef..35956729 100644 --- a/lib/src/message_list_view.dart +++ b/lib/src/message_list_view.dart @@ -811,15 +811,11 @@ class _MessageListViewState extends State { final showThreadReplyIndicator = !_isThreadConversation && hasReplies; final isOnlyEmoji = message.text.isOnlyEmoji; - final showMessageBorder = - showThreadReplyIndicator || showInChannelIndicator; - final borderSide = isMyMessage - ? !showMessageBorder - ? BorderSide.none - : null - : isOnlyEmoji && !showMessageBorder - ? BorderSide.none - : null; + final hasUrlAttachment = + message.attachments?.any((it) => it.ogScrapeUrl != null) == true; + + final borderSide = + isOnlyEmoji || hasUrlAttachment || isMyMessage ? BorderSide.none : null; Widget child = MessageWidget( key: ValueKey('MESSAGE-${message.id}'), From a9c52c66549e58790bfc8e16448c4112e86e0996 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Wed, 13 Jan 2021 11:40:46 +0530 Subject: [PATCH 0887/1140] [MessageWidget] Fix thread tail Signed-off-by: Sahil Kumar --- lib/src/message_widget.dart | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/lib/src/message_widget.dart b/lib/src/message_widget.dart index f4f8944f..b6fc1bb6 100644 --- a/lib/src/message_widget.dart +++ b/lib/src/message_widget.dart @@ -278,6 +278,9 @@ class _MessageWidgetState extends State { ?.isNotEmpty == true; + bool get hasUrlAttachments => + widget.message.attachments?.any((it) => it.ogScrapeUrl != null) == true; + bool get showBottomRow => showThreadReplyIndicator || showUsername || @@ -586,12 +589,15 @@ class _MessageWidgetState extends State { if (widget.reverse) children = children.reversed.toList(); + final showThreadTail = !(hasUrlAttachments || isGiphy || isOnlyEmoji) && + (showThreadReplyIndicator || showInChannel); + return Flex( direction: Axis.horizontal, clipBehavior: Clip.none, crossAxisAlignment: CrossAxisAlignment.end, children: [ - if (showThreadReplyIndicator || showInChannel) + if (showThreadTail) Container( margin: EdgeInsets.only( bottom: widget.messageTheme.replies.fontSize / 2, @@ -938,11 +944,7 @@ class _MessageWidgetState extends State { : widget.messageTheme, ), ), - if (widget.message.attachments - ?.any((element) => element.ogScrapeUrl != null) == - true && - !hasQuotedMessage) - _buildUrlAttachment(), + if (hasUrlAttachments && !hasQuotedMessage) _buildUrlAttachment(), ], ), ); @@ -955,9 +957,7 @@ class _MessageWidgetState extends State { return widget.messageTheme.messageBackgroundColor; } - if (widget.message.attachments - ?.any((element) => element.ogScrapeUrl != null) == - true) { + if (hasUrlAttachments) { return StreamChatTheme.of(context).colorTheme.blueAlice; } From f353e02c0321d102c5b433bfce5aae00a6824b74 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Wed, 13 Jan 2021 11:57:45 +0530 Subject: [PATCH 0888/1140] [MessageWidget] Fix threadParticipants indicator Signed-off-by: Sahil Kumar --- lib/src/message_widget.dart | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/lib/src/message_widget.dart b/lib/src/message_widget.dart index b6fc1bb6..989de8c8 100644 --- a/lib/src/message_widget.dart +++ b/lib/src/message_widget.dart @@ -565,7 +565,7 @@ class _MessageWidgetState extends State { if (showInChannel || showThreadReplyIndicator) ...[ if (showThreadParticipants) SizedBox.fromSize( - size: Size((threadParticipants.length * 8.0) + 10, 16), + size: Size((threadParticipants.length * 8.0) + 8, 16), child: _buildThreadParticipantsIndicator(), ), InkWell( @@ -587,7 +587,7 @@ class _MessageWidgetState extends State { ), ]); - if (widget.reverse) children = children.reversed.toList(); + // if (widget.reverse) children = children.reversed.toList(); final showThreadTail = !(hasUrlAttachments || isGiphy || isOnlyEmoji) && (showThreadReplyIndicator || showInChannel); @@ -648,18 +648,20 @@ class _MessageWidgetState extends State { var padding = 0.0; return Stack( children: widget.message.threadParticipants.map((user) { - padding += 10.0; + padding += 8.0; return Positioned( - left: padding - 10, + right: padding - 8, bottom: 0, top: 0, - child: Material( - color: Colors.white, - clipBehavior: Clip.antiAlias, - shape: CircleBorder(), + child: Container( + decoration: BoxDecoration( + shape: BoxShape.circle, + color: StreamChatTheme.of(context).colorTheme.white, + ), + padding: const EdgeInsets.all(1), child: UserAvatar( user: user, - constraints: BoxConstraints.loose(Size.fromRadius(8)), + constraints: BoxConstraints.loose(Size.fromRadius(7)), showOnlineStatus: false, ), ), From b27f04bf362b1efa1143ff643e0f36345ec3dd92 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Wed, 13 Jan 2021 12:09:36 +0530 Subject: [PATCH 0889/1140] [MessageWidget] Fix bottomRow children position Signed-off-by: Sahil Kumar --- lib/src/message_widget.dart | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/lib/src/message_widget.dart b/lib/src/message_widget.dart index 989de8c8..a74477b2 100644 --- a/lib/src/message_widget.dart +++ b/lib/src/message_widget.dart @@ -561,7 +561,6 @@ class _MessageWidgetState extends State { }; children.addAll([ - if (showSendingIndicator) _buildSendingIndicator(), if (showInChannel || showThreadReplyIndicator) ...[ if (showThreadParticipants) SizedBox.fromSize( @@ -585,10 +584,9 @@ class _MessageWidgetState extends State { Jiffy(widget.message.createdAt.toLocal()).jm, style: widget.messageTheme.createdAt, ), + if (showSendingIndicator) _buildSendingIndicator(), ]); - // if (widget.reverse) children = children.reversed.toList(); - final showThreadTail = !(hasUrlAttachments || isGiphy || isOnlyEmoji) && (showThreadReplyIndicator || showInChannel); From f3ff7588946e8eae6c2a0defa789b4171ef949d4 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Wed, 13 Jan 2021 13:14:36 +0530 Subject: [PATCH 0890/1140] feat: Added error message to new group and info tiles to new chat and merged --- example/lib/group_chat_details_screen.dart | 104 ++++- example/lib/new_chat_screen.dart | 500 +++++++++++---------- lib/src/message_list_view.dart | 334 +++++++------- 3 files changed, 541 insertions(+), 397 deletions(-) diff --git a/example/lib/group_chat_details_screen.dart b/example/lib/group_chat_details_screen.dart index 31ccc703..f59b5c4f 100644 --- a/example/lib/group_chat_details_screen.dart +++ b/example/lib/group_chat_details_screen.dart @@ -123,23 +123,28 @@ class _GroupChatDetailsScreenState extends State { onPressed: _isGroupNameEmpty ? null : () async { - final groupName = _groupNameController.text; - final client = StreamChat.of(context).client; - final channel = client - .channel('messaging', id: Uuid().v4(), extraData: { - 'members': [ - client.state.user.id, - ..._selectedUsers.map((e) => e.id), - ], - 'name': groupName, - }); - await channel.watch(); - Navigator.pushNamedAndRemoveUntil( - context, - Routes.CHANNEL_PAGE, - ModalRoute.withName(Routes.HOME), - arguments: ChannelPageArgs(channel: channel), - ); + try { + final groupName = _groupNameController.text; + final client = StreamChat.of(context).client; + final channel = client.channel('messaging', + id: Uuid().v4(), + extraData: { + 'members': [ + client.state.user.id, + ..._selectedUsers.map((e) => e.id), + ], + 'name': groupName, + }); + await channel.watch(); + Navigator.pushNamedAndRemoveUntil( + context, + Routes.CHANNEL_PAGE, + ModalRoute.withName(Routes.HOME), + arguments: ChannelPageArgs(channel: channel), + ); + } catch (err) { + _showErrorAlert(); + } }, ), ), @@ -227,4 +232,69 @@ class _GroupChatDetailsScreenState extends State { ), ); } + + void _showErrorAlert() { + showModalBottomSheet( + backgroundColor: StreamChatTheme.of(context).colorTheme.white, + context: context, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.only( + topLeft: Radius.circular(16.0), + topRight: Radius.circular(16.0), + )), + builder: (context) { + return Column( + mainAxisSize: MainAxisSize.min, + children: [ + SizedBox( + height: 26.0, + ), + StreamSvgIcon.error( + color: StreamChatTheme.of(context).colorTheme.accentRed, + size: 24.0, + ), + SizedBox( + height: 26.0, + ), + Text( + 'Something went wrong', + style: StreamChatTheme.of(context).textTheme.headlineBold, + ), + SizedBox( + height: 7.0, + ), + Text('The operation couldn\'t be completed.'), + SizedBox( + height: 36.0, + ), + Container( + color: + StreamChatTheme.of(context).colorTheme.black.withOpacity(.08), + height: 1.0, + ), + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + FlatButton( + child: Text( + 'OK', + style: StreamChatTheme.of(context) + .textTheme + .bodyBold + .copyWith( + color: StreamChatTheme.of(context) + .colorTheme + .accentBlue), + ), + onPressed: () { + Navigator.of(context).pop(); + }, + ), + ], + ), + ], + ); + }, + ); + } } diff --git a/example/lib/new_chat_screen.dart b/example/lib/new_chat_screen.dart index 1de36b46..5772f5e2 100644 --- a/example/lib/new_chat_screen.dart +++ b/example/lib/new_chat_screen.dart @@ -134,248 +134,288 @@ class _NewChatScreenState extends State { ), centerTitle: true, ), - body: StreamChannel( - showLoading: false, - channel: channel, - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - ChipsInputTextField( - key: _chipInputTextFieldStateKey, - controller: _controller, - focusNode: _searchFocusNode, - chipBuilder: (context, user) { - return GestureDetector( - onTap: () { - _chipInputTextFieldState.removeItem(user); - _searchFocusNode.requestFocus(); - }, - child: Stack( - alignment: AlignmentDirectional.centerStart, - children: [ - Container( - decoration: BoxDecoration( - color: StreamChatTheme.of(context) - .colorTheme - .greyGainsboro, - borderRadius: BorderRadius.circular(12), - ), - padding: const EdgeInsets.only(left: 24), - child: Padding( - padding: const EdgeInsets.fromLTRB(8, 4, 12, 4), - child: Text( - user.name, - maxLines: 1, - style: TextStyle( - color: - StreamChatTheme.of(context).colorTheme.black, - ), - ), - ), - ), - Container( - foregroundDecoration: BoxDecoration( - color: StreamChatTheme.of(context).colorTheme.overlay, - shape: BoxShape.circle, - ), - child: UserAvatar( - showOnlineStatus: false, - user: user, - constraints: BoxConstraints.tightFor( - height: 24, - width: 24, - ), - ), - ), - StreamSvgIcon.close(), - ], - ), - ); - }, - onChipAdded: (user) { - setState(() => _selectedUsers.add(user)); - }, - onChipRemoved: (user) { - setState(() => _selectedUsers.remove(user)); - }, - ), - if (!_isSearchActive && !_selectedUsers.isNotEmpty) - Container( - child: InkWell( - onTap: () { - Navigator.pushNamed( - context, - Routes.NEW_GROUP_CHAT, - ); - }, - child: Padding( - padding: const EdgeInsets.symmetric(vertical: 8), - child: Row( - children: [ - StreamNeumorphicButton( - child: Center( - child: StreamSvgIcon.contacts( - color: StreamChatTheme.of(context) - .colorTheme - .accentBlue, - size: 24, - ), - ), - ), - SizedBox(width: 8), - Text( - 'Create a Group', - style: StreamChatTheme.of(context).textTheme.bodyBold, - ), - ], - ), - ), - ), - ), - if (_showUserList) - Container( - width: double.maxFinite, - decoration: BoxDecoration( - gradient: StreamChatTheme.of(context).colorTheme.bgGradient, - ), - child: Padding( - padding: const EdgeInsets.symmetric( - vertical: 8, - horizontal: 8, - ), - child: Text( - _isSearchActive - ? "Matches for \"$_userNameQuery\"" - : 'On the platform', - style: StreamChatTheme.of(context) - .textTheme - .footnote - .copyWith( - color: StreamChatTheme.of(context) - .colorTheme - .black - .withOpacity(.5))), - ), - ), - Expanded( - child: _showUserList - ? GestureDetector( - behavior: HitTestBehavior.opaque, - onPanDown: (_) => FocusScope.of(context).unfocus(), - child: UsersBloc( - child: UserListView( - selectedUsers: _selectedUsers, - groupAlphabetically: _isSearchActive ? false : true, - onUserTap: (user, _) { - _controller.clear(); - if (!_selectedUsers.contains(user)) { - _chipInputTextFieldState - ..addItem(user) - ..pauseItemAddition(); - } else { - _chipInputTextFieldState.removeItem(user); - } + body: ValueListenableBuilder( + valueListenable: StreamChat.of(context).client.wsConnectionStatus, + builder: (context, status, _) { + String statusString = ''; + bool showStatus = true; + + switch (status) { + case ConnectionStatus.connected: + statusString = 'Connected'; + showStatus = false; + break; + case ConnectionStatus.connecting: + statusString = 'Reconnecting...'; + break; + case ConnectionStatus.disconnected: + statusString = 'Disconnected'; + break; + } + return InfoTile( + showMessage: showStatus, + tileAnchor: Alignment.topCenter, + childAnchor: Alignment.topCenter, + message: statusString, + child: StreamChannel( + showLoading: false, + channel: channel, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + ChipsInputTextField( + key: _chipInputTextFieldStateKey, + controller: _controller, + focusNode: _searchFocusNode, + chipBuilder: (context, user) { + return GestureDetector( + onTap: () { + _chipInputTextFieldState.removeItem(user); + _searchFocusNode.requestFocus(); }, - pagination: PaginationParams( - limit: 25, - ), - filter: { - if (_userNameQuery.isNotEmpty) - 'name': { - r'$autocomplete': _userNameQuery, - }, - 'id': { - r'$ne': StreamChat.of(context).user.id, - }, - }, - sort: [ - SortOption( - 'name', - direction: 1, - ), - ], - emptyBuilder: (_) { - return LayoutBuilder( - builder: (context, viewportConstraints) { - return SingleChildScrollView( - physics: AlwaysScrollableScrollPhysics(), - child: ConstrainedBox( - constraints: BoxConstraints( - minHeight: viewportConstraints.maxHeight, + child: Stack( + alignment: AlignmentDirectional.centerStart, + children: [ + Container( + decoration: BoxDecoration( + color: StreamChatTheme.of(context) + .colorTheme + .greyGainsboro, + borderRadius: BorderRadius.circular(12), + ), + padding: const EdgeInsets.only(left: 24), + child: Padding( + padding: + const EdgeInsets.fromLTRB(8, 4, 12, 4), + child: Text( + user.name, + maxLines: 1, + style: TextStyle( + color: StreamChatTheme.of(context) + .colorTheme + .black, ), - child: Center( - child: Column( - children: [ - Padding( - padding: const EdgeInsets.all(24), - child: StreamSvgIcon.search( - size: 96, - color: Colors.grey, + ), + ), + ), + Container( + foregroundDecoration: BoxDecoration( + color: StreamChatTheme.of(context) + .colorTheme + .overlay, + shape: BoxShape.circle, + ), + child: UserAvatar( + showOnlineStatus: false, + user: user, + constraints: BoxConstraints.tightFor( + height: 24, + width: 24, + ), + ), + ), + StreamSvgIcon.close(), + ], + ), + ); + }, + onChipAdded: (user) { + setState(() => _selectedUsers.add(user)); + }, + onChipRemoved: (user) { + setState(() => _selectedUsers.remove(user)); + }, + ), + if (!_isSearchActive && !_selectedUsers.isNotEmpty) + Container( + child: InkWell( + onTap: () { + Navigator.pushNamed( + context, + Routes.NEW_GROUP_CHAT, + ); + }, + child: Padding( + padding: const EdgeInsets.symmetric(vertical: 8), + child: Row( + children: [ + StreamNeumorphicButton( + child: Center( + child: StreamSvgIcon.contacts( + color: StreamChatTheme.of(context) + .colorTheme + .accentBlue, + size: 24, + ), + ), + ), + SizedBox(width: 8), + Text( + 'Create a Group', + style: StreamChatTheme.of(context) + .textTheme + .bodyBold, + ), + ], + ), + ), + ), + ), + if (_showUserList) + Container( + width: double.maxFinite, + decoration: BoxDecoration( + gradient: + StreamChatTheme.of(context).colorTheme.bgGradient, + ), + child: Padding( + padding: const EdgeInsets.symmetric( + vertical: 8, + horizontal: 8, + ), + child: Text( + _isSearchActive + ? "Matches for \"$_userNameQuery\"" + : 'On the platform', + style: StreamChatTheme.of(context) + .textTheme + .footnote + .copyWith( + color: StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(.5))), + ), + ), + Expanded( + child: _showUserList + ? GestureDetector( + behavior: HitTestBehavior.opaque, + onPanDown: (_) => + FocusScope.of(context).unfocus(), + child: UsersBloc( + child: UserListView( + selectedUsers: _selectedUsers, + groupAlphabetically: + _isSearchActive ? false : true, + onUserTap: (user, _) { + _controller.clear(); + if (!_selectedUsers.contains(user)) { + _chipInputTextFieldState + ..addItem(user) + ..pauseItemAddition(); + } else { + _chipInputTextFieldState.removeItem(user); + } + }, + pagination: PaginationParams( + limit: 25, + ), + filter: { + if (_userNameQuery.isNotEmpty) + 'name': { + r'$autocomplete': _userNameQuery, + }, + 'id': { + r'$ne': StreamChat.of(context).user.id, + }, + }, + sort: [ + SortOption( + 'name', + direction: 1, + ), + ], + emptyBuilder: (_) { + return LayoutBuilder( + builder: (context, viewportConstraints) { + return SingleChildScrollView( + physics: + AlwaysScrollableScrollPhysics(), + child: ConstrainedBox( + constraints: BoxConstraints( + minHeight: + viewportConstraints.maxHeight, + ), + child: Center( + child: Column( + children: [ + Padding( + padding: + const EdgeInsets.all( + 24), + child: StreamSvgIcon.search( + size: 96, + color: Colors.grey, + ), + ), + Text( + 'No user matches these keywords...', + style: StreamChatTheme.of( + context) + .textTheme + .footnote + .copyWith( + color: StreamChatTheme + .of(context) + .colorTheme + .black + .withOpacity( + .5)), + ), + ], + ), ), ), - Text( - 'No user matches these keywords...', - style: StreamChatTheme.of(context) - .textTheme - .footnote - .copyWith( - color: StreamChatTheme.of( - context) - .colorTheme - .black - .withOpacity(.5)), - ), - ], - ), + ); + }, + ); + }, + ), + ), + ) + : FutureBuilder( + future: channel.initialized, + builder: (context, snapshot) { + if (snapshot.data == true) { + return MessageListView(); + } + + return Center( + child: Text( + 'No chats here yet...', + style: TextStyle( + fontSize: 12, + color: StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(.5), ), ), ); }, - ); - }, - ), - ), - ) - : FutureBuilder( - future: channel.initialized, - builder: (context, snapshot) { - if (snapshot.data == true) { - return MessageListView(); - } - - return Center( - child: Text( - 'No chats here yet...', - style: TextStyle( - fontSize: 12, - color: StreamChatTheme.of(context) - .colorTheme - .black - .withOpacity(.5), ), - ), + ), + MessageInput( + focusNode: _messageInputFocusNode, + preMessageSending: (message) async { + await channel.watch(); + return message; + }, + onMessageSent: (m) { + Navigator.pushNamedAndRemoveUntil( + context, + Routes.CHANNEL_PAGE, + ModalRoute.withName(Routes.HOME), + arguments: ChannelPageArgs(channel: channel), ); }, ), - ), - MessageInput( - focusNode: _messageInputFocusNode, - preMessageSending: (message) async { - await channel.watch(); - return message; - }, - onMessageSent: (m) { - Navigator.pushNamedAndRemoveUntil( - context, - Routes.CHANNEL_PAGE, - ModalRoute.withName(Routes.HOME), - arguments: ChannelPageArgs(channel: channel), - ); - }, - ), - ], - ), - ), + ], + ), + ), + ); + }), ); } } diff --git a/lib/src/message_list_view.dart b/lib/src/message_list_view.dart index 7cd4ad28..f60b9f5e 100644 --- a/lib/src/message_list_view.dart +++ b/lib/src/message_list_view.dart @@ -307,164 +307,198 @@ class _MessageListViewState extends State { return Stack( alignment: Alignment.center, children: [ - LazyLoadScrollView( - onStartOfPage: () async { - _inBetweenList = false; - if (!_upToDate) { - _topPaginationActive = false; - _bottomPaginationActive = true; - return _paginateData( - streamChannel, - QueryDirection.bottom, - ); - } - }, - onEndOfPage: () async { - _inBetweenList = false; - _topPaginationActive = true; - _bottomPaginationActive = false; - return _paginateData( - streamChannel, - QueryDirection.top, - ); - }, - onInBetweenOfPage: () { - _inBetweenList = true; - }, - child: ScrollablePositionedList.separated( - key: ValueKey(initialIndex + initialAlignment), - itemPositionsListener: _itemPositionListener, - addAutomaticKeepAlives: true, - initialScrollIndex: initialIndex ?? 0, - initialAlignment: initialAlignment ?? 0, - physics: widget.scrollPhysics, - itemScrollController: _scrollController, - reverse: true, - itemCount: - messages.length + 2 + (_isThreadConversation ? 1 : 0), - separatorBuilder: (context, i) { - if (i == messages.length) return Offstage(); - if (i == 0) return SizedBox(height: 30); - if (i == messages.length + 1) { - final replyCount = widget.parentMessage.replyCount; - return Container( - decoration: BoxDecoration( - gradient: - StreamChatTheme.of(context).colorTheme.bgGradient, - ), - child: Padding( - padding: const EdgeInsets.all(8.0), - child: Text( - '$replyCount ${replyCount == 1 ? 'Reply' : 'Replies'}', - textAlign: TextAlign.center, - style: StreamChatTheme.of(context) - .channelTheme - .channelHeaderTheme - .lastMessageAt, - ), - ), - ); + ValueListenableBuilder( + valueListenable: _client.wsConnectionStatus, + builder: (context, status, _) { + String statusString = ''; + bool showStatus = true; + + switch (status) { + case ConnectionStatus.connected: + statusString = 'Connected'; + showStatus = false; + break; + case ConnectionStatus.connecting: + statusString = 'Reconnecting...'; + break; + case ConnectionStatus.disconnected: + statusString = 'Disconnected'; + break; } - final message = messages[i]; - 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(), - ) - : DateDivider( - dateTime: nextMessage.createdAt.toLocal(), + return InfoTile( + showMessage: + widget.showConnectionStateTile ? showStatus : false, + tileAnchor: Alignment.topCenter, + childAnchor: Alignment.topCenter, + message: statusString, + child: LazyLoadScrollView( + child: LazyLoadScrollView( + onStartOfPage: () async { + _inBetweenList = false; + if (!_upToDate) { + _topPaginationActive = false; + _bottomPaginationActive = true; + return _paginateData( + streamChannel, + QueryDirection.bottom, + ); + } + }, + onEndOfPage: () async { + _inBetweenList = false; + _topPaginationActive = true; + _bottomPaginationActive = false; + return _paginateData( + streamChannel, + QueryDirection.top, ); - return Padding( - padding: const EdgeInsets.symmetric(vertical: 12.0), - child: divider, - ); - } - final timeDiff = - Jiffy(nextMessage.createdAt.toLocal()).diff( - message.createdAt.toLocal(), - Units.MINUTE, - ); + }, + onInBetweenOfPage: () { + _inBetweenList = true; + }, + child: ScrollablePositionedList.separated( + key: ValueKey(initialIndex + initialAlignment), + itemPositionsListener: _itemPositionListener, + addAutomaticKeepAlives: true, + initialScrollIndex: initialIndex ?? 0, + initialAlignment: initialAlignment ?? 0, + physics: widget.scrollPhysics, + itemScrollController: _scrollController, + reverse: true, + itemCount: messages.length + + 2 + + (_isThreadConversation ? 1 : 0), + separatorBuilder: (context, i) { + if (i == messages.length) return Offstage(); + if (i == 0) return SizedBox(height: 30); + if (i == messages.length + 1) { + final replyCount = + widget.parentMessage.replyCount; + return Container( + decoration: BoxDecoration( + gradient: StreamChatTheme.of(context) + .colorTheme + .bgGradient, + ), + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Text( + '$replyCount ${replyCount == 1 ? 'Reply' : 'Replies'}', + textAlign: TextAlign.center, + style: StreamChatTheme.of(context) + .channelTheme + .channelHeaderTheme + .lastMessageAt, + ), + ), + ); + } - final isNextUserSame = - message.user.id == nextMessage.user?.id; - final isThread = message.replyCount > 0; - final isDeleted = message.isDeleted; - if (timeDiff >= 1 || - !isNextUserSame || - isThread || - isDeleted) { - return SizedBox(height: 8); - } - return SizedBox(height: 2); - }, - itemBuilder: (context, i) { - if (i == messages.length + 2) { - if (widget.parentMessageBuilder != null) { - return widget.parentMessageBuilder( - context, - widget.parentMessage, - ); - } else { - return buildParentMessage(widget.parentMessage); - } - } - if (i == messages.length + 1) { - return _buildLoadingIndicator( - streamChannel, - QueryDirection.top, - ); - } - if (i == 0) { - return _buildLoadingIndicator( - streamChannel, - QueryDirection.bottom, - ); - } - final message = messages[i - 1]; - - Widget messageWidget; - - if (i == 1) { - messageWidget = _buildBottomMessage( - context, - message, - messages, - streamChannel, + final message = messages[i]; + 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(), + ) + : DateDivider( + dateTime: + nextMessage.createdAt.toLocal(), + ); + return Padding( + padding: const EdgeInsets.symmetric( + vertical: 12.0), + child: divider, + ); + } + final timeDiff = + Jiffy(nextMessage.createdAt.toLocal()).diff( + message.createdAt.toLocal(), + Units.MINUTE, ); - } else if (i == messages.length - 1) { - messageWidget = _buildTopMessage( - context, - message, - messages, - streamChannel, - ); - } else { - if (widget.messageBuilder != null) { - messageWidget = Builder( - key: - ValueKey('MESSAGE-${message.id}'), - builder: (context) => widget.messageBuilder( - context, - MessageDetails( - context, - message, - messages, - i, - ), - messages), + + final isNextUserSame = + message.user.id == nextMessage.user?.id; + final isThread = message.replyCount > 0; + final isDeleted = message.isDeleted; + if (timeDiff >= 1 || + !isNextUserSame || + isThread || + isDeleted) { + return SizedBox(height: 8); + } + return SizedBox(height: 2); + }, + itemBuilder: (context, i) { + if (i == messages.length + 2) { + if (widget.parentMessageBuilder != null) { + return widget.parentMessageBuilder( + context, + widget.parentMessage, + ); + } else { + return buildParentMessage( + widget.parentMessage); + } + } + if (i == messages.length + 1) { + return _buildLoadingIndicator( + streamChannel, + QueryDirection.top, + ); + } + if (i == 0) { + return _buildLoadingIndicator( + streamChannel, + QueryDirection.bottom, + ); + } + final message = messages[i - 1]; + + Widget messageWidget; + + if (i == 1) { + messageWidget = _buildBottomMessage( + context, + message, + messages, + streamChannel, + ); + } else if (i == messages.length - 1) { + messageWidget = _buildTopMessage( + context, + message, + messages, + streamChannel, ); } else { - messageWidget = - buildMessage(message, messages, i); + if (widget.messageBuilder != null) { + messageWidget = Builder( + key: ValueKey( + 'MESSAGE-${message.id}'), + builder: (context) => widget.messageBuilder( + context, + MessageDetails( + context, + message, + messages, + i, + ), + messages), + ); + } else { + messageWidget = + buildMessage(message, messages, i); + } } - } - return messageWidget; - }, + return messageWidget; + }, + ), ), ), ); From 7c8bd11fd2a41d9810b7dd7a01e92fee7e661d7d Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Wed, 13 Jan 2021 13:25:38 +0530 Subject: [PATCH 0891/1140] [ImageActionsModal] Remove cross icon and fix dividers Signed-off-by: Sahil Kumar --- lib/src/image_actions_modal.dart | 206 +++++++++++++++---------------- 1 file changed, 102 insertions(+), 104 deletions(-) diff --git a/lib/src/image_actions_modal.dart b/lib/src/image_actions_modal.dart index 332117d4..97729ca1 100644 --- a/lib/src/image_actions_modal.dart +++ b/lib/src/image_actions_modal.dart @@ -8,6 +8,7 @@ import 'package:image_gallery_saver/image_gallery_saver.dart'; import 'package:path_provider/path_provider.dart'; import '../stream_chat_flutter.dart'; +import 'extension.dart'; class ImageActionsModal extends StatelessWidget { final Message message; @@ -35,127 +36,124 @@ class ImageActionsModal extends StatelessWidget { } Widget _buildPage(context) { - return Material( - color: Colors.transparent, - child: Column( - crossAxisAlignment: CrossAxisAlignment.end, - children: [ - SizedBox( - height: kToolbarHeight, - child: IconButton( - icon: StreamSvgIcon.close(), - onPressed: () => Navigator.maybePop(context), + return Column( + crossAxisAlignment: CrossAxisAlignment.end, + children: [ + SizedBox(height: kToolbarHeight), + Padding( + padding: const EdgeInsets.only(right: 8.0), + child: Container( + width: MediaQuery.of(context).size.width * 0.5, + clipBehavior: Clip.hardEdge, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(16.0), ), - ), - Align( - alignment: Alignment.centerRight, child: Container( - width: MediaQuery.of(context).size.width / 1.8, - child: Padding( - padding: const EdgeInsets.all(8.0), - child: Material( - clipBehavior: Clip.hardEdge, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.end, + mainAxisSize: MainAxisSize.min, + children: [ + _buildButton( + context, + 'Reply', + StreamSvgIcon.Icon_curve_line_left_up( + size: 24.0, + color: StreamChatTheme.of(context).colorTheme.grey, + ), + () {}, ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: ListTile.divideTiles( - color: StreamChatTheme.of(context).colorTheme.greyWhisper, - context: context, - tiles: [ - _buildButton( - context, - 'Reply', - StreamSvgIcon.Icon_curve_line_left_up( - size: 24.0, - color: - StreamChatTheme.of(context).colorTheme.grey, - ), - () {}), - _buildButton( - context, - 'Show in Chat', - StreamSvgIcon.eye( - size: 24.0, - color: - StreamChatTheme.of(context).colorTheme.black, - ), - onShowMessage), - _buildButton( - context, - 'Save ${urls[currentIndex].type == 'video' ? 'Video' : 'Image'}', - StreamSvgIcon.Icon_save( - size: 24.0, - color: - StreamChatTheme.of(context).colorTheme.grey, - ), () async { - var url = urls[currentIndex].imageUrl ?? - urls[currentIndex].assetUrl ?? - urls[currentIndex].thumbUrl; + _buildButton( + context, + 'Show in Chat', + StreamSvgIcon.eye( + size: 24.0, + color: StreamChatTheme.of(context).colorTheme.black, + ), + onShowMessage, + ), + _buildButton( + context, + 'Save ${urls[currentIndex].type == 'video' ? 'Video' : 'Image'}', + StreamSvgIcon.Icon_save( + size: 24.0, + color: StreamChatTheme.of(context).colorTheme.grey, + ), + () async { + var url = urls[currentIndex].imageUrl ?? + urls[currentIndex].assetUrl ?? + urls[currentIndex].thumbUrl; - if (urls[currentIndex].type == 'video') { - await _saveVideo(url); - Navigator.pop(context); - } else { - await _saveImage(url); - Navigator.pop(context); - } - }), - if (StreamChat.of(context).user.id == message.user.id) - _buildButton( - context, - 'Delete', - StreamSvgIcon.delete( - size: 24.0, - color: StreamChatTheme.of(context) - .colorTheme - .accentRed, - ), - () { - Navigator.pop(context); - Navigator.pop(context); - StreamChat.of(context).client.deleteMessage( - message, - StreamChannel.of(context).channel.cid, - ); - }, - color: StreamChatTheme.of(context) - .colorTheme - .accentRed, - ), - ], - ).toList(), + if (urls[currentIndex].type == 'video') { + await _saveVideo(url); + Navigator.pop(context); + } else { + await _saveImage(url); + Navigator.pop(context); + } + }, ), - ), + if (StreamChat.of(context).user.id == message.user.id) + _buildButton( + context, + 'Delete', + StreamSvgIcon.delete( + size: 24.0, + color: StreamChatTheme.of(context).colorTheme.accentRed, + ), + () { + Navigator.pop(context); + Navigator.pop(context); + StreamChat.of(context).client.deleteMessage( + message, + StreamChannel.of(context).channel.cid, + ); + }, + color: StreamChatTheme.of(context).colorTheme.accentRed, + ), + ] + .map((e) => + Align(alignment: Alignment.centerRight, child: e)) + .insertBetween( + Container( + height: 1, + color: + StreamChatTheme.of(context).colorTheme.greyWhisper, + ), + ), ), ), ), - ], - ), + ) + ], ); } Widget _buildButton( - context, String title, StreamSvgIcon icon, VoidCallback onTap, - {Color color}) { - var titleStyle = TextStyle( - fontSize: 14.5, - color: StreamChatTheme.of(context).colorTheme.black, - ); - + context, + String title, + StreamSvgIcon icon, + VoidCallback onTap, { + Color color, + }) { return Material( color: StreamChatTheme.of(context).colorTheme.white, child: InkWell( onTap: onTap, - child: ListTile( - dense: true, - title: Text( - title, - style: - color == null ? titleStyle : titleStyle.copyWith(color: color), + child: Padding( + padding: const EdgeInsets.symmetric(vertical: 8.0, horizontal: 16.0), + child: Row( + children: [ + icon, + SizedBox(width: 16), + Text( + title, + style: StreamChatTheme.of(context) + .textTheme + .body + .copyWith(color: color), + ), + ], ), - leading: icon, ), ), ); From 987f6991fe082f12763e69af24f7cb1364b5e298 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Wed, 13 Jan 2021 13:39:27 +0530 Subject: [PATCH 0892/1140] [FileAttachment] Fix trailing icon padding and minor fixes Signed-off-by: Sahil Kumar --- lib/src/file_attachment.dart | 47 +++++++++++++++++++----------------- 1 file changed, 25 insertions(+), 22 deletions(-) diff --git a/lib/src/file_attachment.dart b/lib/src/file_attachment.dart index ca51bf76..303b2b25 100644 --- a/lib/src/file_attachment.dart +++ b/lib/src/file_attachment.dart @@ -72,6 +72,7 @@ class _FileAttachmentState extends State { : null, ), child: Row( + crossAxisAlignment: CrossAxisAlignment.start, children: [ Container( child: _getFileTypeImage(), @@ -79,9 +80,7 @@ class _FileAttachmentState extends State { width: 33.33, margin: EdgeInsets.all(8.0), ), - SizedBox( - width: 6.0, - ), + SizedBox(width: 8.0), Expanded( child: Column( mainAxisAlignment: MainAxisAlignment.center, @@ -93,32 +92,36 @@ class _FileAttachmentState extends State { maxLines: 1, overflow: TextOverflow.ellipsis, ), - SizedBox( - height: 3.0, - ), + SizedBox(height: 3.0), Text( '${getSizeText(widget.attachment.extraData['file_size'])}', - style: StreamChatTheme.of(context).textTheme.body.copyWith( - color: StreamChatTheme.of(context) - .colorTheme - .black - .withOpacity(0.5)), + style: StreamChatTheme.of(context) + .textTheme + .footnote + .copyWith( + color: StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(0.5)), ), ], ), ), - Column( - children: [ - widget.trailing ?? - IconButton( - icon: StreamSvgIcon.cloud_download( - color: StreamChatTheme.of(context).colorTheme.black, - ), - onPressed: () { - launchURL(context, widget.attachment.assetUrl); - }, + SizedBox(width: 8.0), + Material( + type: MaterialType.transparency, + child: widget.trailing ?? + IconButton( + icon: StreamSvgIcon.cloud_download( + color: StreamChatTheme.of(context).colorTheme.black, ), - ], + padding: const EdgeInsets.all(8), + visualDensity: VisualDensity.compact, + splashRadius: 16, + onPressed: () { + launchURL(context, widget.attachment.assetUrl); + }, + ), ), ], ), From 3432b7c5eef27337fd7eb8be16db860fe5fe819b Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Wed, 13 Jan 2021 15:09:28 +0530 Subject: [PATCH 0893/1140] [MessageWidget] Fix attachment padding and border sides Signed-off-by: Sahil Kumar --- lib/src/file_attachment.dart | 10 +---- lib/src/message_list_view.dart | 9 ++-- lib/src/message_widget.dart | 77 +++++++++++++++++----------------- 3 files changed, 45 insertions(+), 51 deletions(-) diff --git a/lib/src/file_attachment.dart b/lib/src/file_attachment.dart index 303b2b25..96061cab 100644 --- a/lib/src/file_attachment.dart +++ b/lib/src/file_attachment.dart @@ -62,15 +62,7 @@ class _FileAttachmentState extends State { child: Container( width: widget.size?.width ?? 100, height: 56.0, - decoration: BoxDecoration( - color: StreamChatTheme.of(context).colorTheme.white, - borderRadius: - widget.trailing != null ? BorderRadius.circular(16.0) : null, - border: widget.trailing != null - ? Border.fromBorderSide(BorderSide( - color: StreamChatTheme.of(context).colorTheme.greyWhisper)) - : null, - ), + color: StreamChatTheme.of(context).colorTheme.white, child: Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ diff --git a/lib/src/message_list_view.dart b/lib/src/message_list_view.dart index 35956729..021b2a15 100644 --- a/lib/src/message_list_view.dart +++ b/lib/src/message_list_view.dart @@ -815,7 +815,9 @@ class _MessageListViewState extends State { message.attachments?.any((it) => it.ogScrapeUrl != null) == true; final borderSide = - isOnlyEmoji || hasUrlAttachment || isMyMessage ? BorderSide.none : null; + isOnlyEmoji || hasUrlAttachment || (isMyMessage && !hasFileAttachment) + ? BorderSide.none + : null; Widget child = MessageWidget( key: ValueKey('MESSAGE-${message.id}'), @@ -859,14 +861,15 @@ class _MessageListViewState extends State { attachmentBorderRadiusGeometry: BorderRadius.only( topLeft: Radius.circular(attachmentBorderRadius), bottomLeft: Radius.circular( - (timeDiff >= 1 || !isNextUserSame) && !(hasReplies || isThreadMessage) + (timeDiff >= 1 || !isNextUserSame) && + !(hasReplies || isThreadMessage || hasFileAttachment) ? 0 : attachmentBorderRadius, ), topRight: Radius.circular(attachmentBorderRadius), bottomRight: Radius.circular(attachmentBorderRadius), ), - attachmentPadding: const EdgeInsets.all(2), + attachmentPadding: EdgeInsets.all(hasFileAttachment ? 4 : 2), borderRadiusGeometry: BorderRadius.only( topLeft: Radius.circular(16), bottomLeft: Radius.circular( diff --git a/lib/src/message_widget.dart b/lib/src/message_widget.dart index a74477b2..2157aa32 100644 --- a/lib/src/message_widget.dart +++ b/lib/src/message_widget.dart @@ -419,7 +419,7 @@ class _MessageWidgetState extends State { if (hasQuotedMessage) _buildQuotedMessage(), if (hasNonUrlAttachments) - ..._parseAttachments( + _parseAttachments( context), if (widget.message.text .trim() @@ -777,7 +777,7 @@ class _MessageWidgetState extends State { side: widget.attachmentBorderSide ?? widget.borderSide ?? BorderSide( - color: StreamChatTheme.of(context).colorTheme.greyGainsboro, + color: StreamChatTheme.of(context).colorTheme.greyWhisper, ), borderRadius: widget.attachmentBorderRadiusGeometry ?? widget.borderRadiusGeometry ?? @@ -785,7 +785,7 @@ class _MessageWidgetState extends State { ); } - List _parseAttachments(BuildContext context) { + Widget _parseAttachments(BuildContext context) { final images = widget.message.attachments ?.where((element) => element.type == 'image' && element.ogScrapeUrl == null) @@ -793,8 +793,9 @@ class _MessageWidgetState extends State { []; if (images.length > 1) { - return [ - wrapAttachmentWidget( + return Padding( + padding: widget.attachmentPadding, + child: wrapAttachmentWidget( context, Material( color: widget.messageTheme.messageBackgroundColor, @@ -809,30 +810,36 @@ class _MessageWidgetState extends State { ), ), ), - ]; + ); } - return widget.message.attachments - ?.where((element) => element.ogScrapeUrl == null) - ?.map((attachment) { - final attachmentBuilder = widget.attachmentBuilders[attachment.type]; + return Padding( + padding: widget.attachmentPadding, + child: Column( + mainAxisSize: MainAxisSize.min, + children: widget.message.attachments + ?.where((element) => element.ogScrapeUrl == null) + ?.map((attachment) { + final attachmentBuilder = + widget.attachmentBuilders[attachment.type]; - if (attachmentBuilder == null) { - return SizedBox(); - } - - final attachmentWidget = attachmentBuilder( - context, - widget.message, - attachment, - ); - return wrapAttachmentWidget( - context, - attachmentWidget, - attachment: attachment, - ); - })?.toList() ?? - []; + if (attachmentBuilder == null) return SizedBox(); + final attachmentWidget = attachmentBuilder( + context, + widget.message, + attachment, + ); + return wrapAttachmentWidget( + context, + attachmentWidget, + attachment: attachment, + ); + })?.insertBetween(SizedBox( + height: widget.attachmentPadding.vertical / 2, + )) ?? + [], + ), + ); } Widget wrapAttachmentWidget( @@ -843,21 +850,13 @@ class _MessageWidgetState extends State { final attachmentShape = widget.attachmentShape ?? widget.shape ?? _getDefaultShape(context); return Material( - color: _getBackgroundColor(), clipBehavior: Clip.antiAlias, shape: attachmentShape, - child: Padding( - padding: widget.attachmentPadding, - child: Material( - clipBehavior: Clip.hardEdge, - shape: attachmentShape, - type: MaterialType.transparency, - child: Transform( - transform: Matrix4.rotationY(widget.reverse ? pi : 0), - alignment: Alignment.center, - child: attachmentWidget, - ), - ), + type: MaterialType.transparency, + child: Transform( + transform: Matrix4.rotationY(widget.reverse ? pi : 0), + alignment: Alignment.center, + child: attachmentWidget, ), ); } From e07a07d91025a68fc3e463d09b9576d2aad470b2 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Wed, 13 Jan 2021 15:21:58 +0530 Subject: [PATCH 0894/1140] Remove message text horizontal padding if it's only emoji Signed-off-by: Sahil Kumar --- lib/src/message_actions_modal.dart | 6 ++++++ lib/src/message_list_view.dart | 8 ++++++++ lib/src/message_reactions_modal.dart | 5 +++++ 3 files changed, 19 insertions(+) diff --git a/lib/src/message_actions_modal.dart b/lib/src/message_actions_modal.dart index 2d125bab..9d9670cf 100644 --- a/lib/src/message_actions_modal.dart +++ b/lib/src/message_actions_modal.dart @@ -14,6 +14,7 @@ import 'message_input.dart'; import 'message_widget.dart'; import 'stream_chat.dart'; import 'stream_chat_theme.dart'; +import 'extension.dart'; class MessageActionsModal extends StatefulWidget { final Widget Function(BuildContext, Message) editMessageInputBuilder; @@ -152,6 +153,11 @@ class _MessageActionsModalState extends State { showUserAvatar: widget.showUserAvatar, showTimestamp: false, translateUserAvatar: false, + textPadding: EdgeInsets.symmetric( + vertical: 8.0, + horizontal: + widget.message.text.isOnlyEmoji ? 0 : 16.0, + ), showReactionPickerIndicator: widget.showReactions && (widget.message.status == diff --git a/lib/src/message_list_view.dart b/lib/src/message_list_view.dart index 021b2a15..b659845e 100644 --- a/lib/src/message_list_view.dart +++ b/lib/src/message_list_view.dart @@ -732,6 +732,10 @@ class _MessageListViewState extends State { topRight: Radius.circular(16), bottomRight: Radius.circular(16), ), + textPadding: EdgeInsets.symmetric( + vertical: 8.0, + horizontal: isOnlyEmoji ? 0 : 16.0, + ), borderSide: isMyMessage || isOnlyEmoji ? BorderSide.none : null, showUserAvatar: isMyMessage ? DisplayWidget.gone : DisplayWidget.show, messageTheme: isMyMessage @@ -880,6 +884,10 @@ class _MessageListViewState extends State { topRight: Radius.circular(16), bottomRight: Radius.circular(16), ), + textPadding: EdgeInsets.symmetric( + vertical: 8.0, + horizontal: isOnlyEmoji ? 0 : 16.0, + ), messageTheme: isMyMessage ? StreamChatTheme.of(context).ownMessageTheme : StreamChatTheme.of(context).otherMessageTheme, diff --git a/lib/src/message_reactions_modal.dart b/lib/src/message_reactions_modal.dart index 15a301cc..0f056dde 100644 --- a/lib/src/message_reactions_modal.dart +++ b/lib/src/message_reactions_modal.dart @@ -9,6 +9,7 @@ import 'package:stream_chat_flutter/src/user_avatar.dart'; import 'message_widget.dart'; import 'stream_chat_theme.dart'; +import 'extension.dart'; class MessageReactionsModal extends StatelessWidget { final Widget Function(BuildContext, Message) editMessageInputBuilder; @@ -124,6 +125,10 @@ class MessageReactionsModal extends StatelessWidget { showSendingIndicator: false, shape: messageShape, showInChannelIndicator: false, + textPadding: EdgeInsets.symmetric( + vertical: 8.0, + horizontal: message.text.isOnlyEmoji ? 0 : 16.0, + ), showReactionPickerIndicator: showReactions && (message.status == MessageSendingStatus.SENT || From 1fd81adbf43460dfab156a5ec16378e309d01748 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Wed, 13 Jan 2021 16:09:23 +0530 Subject: [PATCH 0895/1140] feat: Added info tile to group screens --- example/lib/group_chat_details_screen.dart | 179 ++++++---- example/lib/new_group_chat_screen.dart | 389 +++++++++++---------- 2 files changed, 315 insertions(+), 253 deletions(-) diff --git a/example/lib/group_chat_details_screen.dart b/example/lib/group_chat_details_screen.dart index f59b5c4f..83ec94bb 100644 --- a/example/lib/group_chat_details_screen.dart +++ b/example/lib/group_chat_details_screen.dart @@ -150,85 +150,116 @@ class _GroupChatDetailsScreenState extends State { ), ], ), - body: Column( - children: [ - Container( - width: double.maxFinite, - decoration: BoxDecoration( - gradient: StreamChatTheme.of(context).colorTheme.bgGradient, - ), - child: Padding( - padding: const EdgeInsets.symmetric( - vertical: 8, - horizontal: 8, - ), - child: Text( - '$_totalUsers ${_totalUsers > 1 ? 'Members' : 'Member'}', - style: TextStyle( - color: StreamChatTheme.of(context).colorTheme.grey, - ), - ), - ), - ), - Expanded( - child: GestureDetector( - behavior: HitTestBehavior.opaque, - onPanDown: (_) => FocusScope.of(context).unfocus(), - child: ListView.separated( - itemCount: _selectedUsers.length + 1, - separatorBuilder: (_, __) => Container( - height: 1, - color: StreamChatTheme.of(context).colorTheme.greyWhisper, - ), - itemBuilder: (_, index) { - if (index == _selectedUsers.length) { - return Container( - height: 1, - color: - StreamChatTheme.of(context).colorTheme.greyWhisper, - ); - } - final user = _selectedUsers[index]; - return ListTile( - key: ObjectKey(user), - leading: UserAvatar( - user: user, - constraints: BoxConstraints.tightFor( - width: 40, - height: 40, + body: ValueListenableBuilder( + valueListenable: StreamChat.of(context).client.wsConnectionStatus, + builder: (context, status, _) { + String statusString = ''; + bool showStatus = true; + + switch (status) { + case ConnectionStatus.connected: + statusString = 'Connected'; + showStatus = false; + break; + case ConnectionStatus.connecting: + statusString = 'Reconnecting...'; + break; + case ConnectionStatus.disconnected: + statusString = 'Disconnected'; + break; + } + return InfoTile( + showMessage: showStatus, + tileAnchor: Alignment.topCenter, + childAnchor: Alignment.topCenter, + message: statusString, + child: Column( + children: [ + Container( + width: double.maxFinite, + decoration: BoxDecoration( + gradient: + StreamChatTheme.of(context).colorTheme.bgGradient, + ), + child: Padding( + padding: const EdgeInsets.symmetric( + vertical: 8, + horizontal: 8, + ), + child: Text( + '$_totalUsers ${_totalUsers > 1 ? 'Members' : 'Member'}', + style: TextStyle( + color: StreamChatTheme.of(context).colorTheme.grey, + ), ), ), - title: Text( - user.name, - style: TextStyle(fontWeight: FontWeight.bold), - ), - contentPadding: const EdgeInsets.symmetric( - horizontal: 12, - vertical: 8, - ), - trailing: IconButton( - icon: Icon( - Icons.clear_rounded, - color: StreamChatTheme.of(context).colorTheme.black, + ), + Expanded( + child: GestureDetector( + behavior: HitTestBehavior.opaque, + onPanDown: (_) => FocusScope.of(context).unfocus(), + child: ListView.separated( + itemCount: _selectedUsers.length + 1, + separatorBuilder: (_, __) => Container( + height: 1, + color: StreamChatTheme.of(context) + .colorTheme + .greyWhisper, + ), + itemBuilder: (_, index) { + if (index == _selectedUsers.length) { + return Container( + height: 1, + color: StreamChatTheme.of(context) + .colorTheme + .greyWhisper, + ); + } + final user = _selectedUsers[index]; + return ListTile( + key: ObjectKey(user), + leading: UserAvatar( + user: user, + constraints: BoxConstraints.tightFor( + width: 40, + height: 40, + ), + ), + title: Text( + user.name, + style: TextStyle(fontWeight: FontWeight.bold), + ), + contentPadding: const EdgeInsets.symmetric( + horizontal: 12, + vertical: 8, + ), + trailing: IconButton( + icon: Icon( + Icons.clear_rounded, + color: StreamChatTheme.of(context) + .colorTheme + .black, + ), + padding: const EdgeInsets.all(0), + splashRadius: 24, + onPressed: () { + setState(() { + _selectedUsers.remove(user); + }); + if (_selectedUsers.isEmpty) { + Navigator.pop(context, _selectedUsers); + } + }, + ), + ); + }, ), - padding: const EdgeInsets.all(0), - splashRadius: 24, - onPressed: () { - setState(() { - _selectedUsers.remove(user); - }); - if (_selectedUsers.isEmpty) { - Navigator.pop(context, _selectedUsers); - } - }, ), - ); - }, + ), + ], ), - ), - ), - ], - ), + ); + }), ), ); } diff --git a/example/lib/new_group_chat_screen.dart b/example/lib/new_group_chat_screen.dart index ceb91473..4d0274e2 100644 --- a/example/lib/new_group_chat_screen.dart +++ b/example/lib/new_group_chat_screen.dart @@ -87,196 +87,227 @@ class _NewGroupChatScreenState extends State { ) ], ), - body: NestedScrollView( - floatHeaderSlivers: true, - headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) { - return [ - SliverToBoxAdapter( - child: SearchTextField( - controller: _controller, - ), - ), - if (_selectedUsers.isNotEmpty) - SliverToBoxAdapter( - child: Container( - height: 104, - child: ListView.separated( - scrollDirection: Axis.horizontal, - itemCount: _selectedUsers.length, - padding: const EdgeInsets.all(8), - separatorBuilder: (_, __) => SizedBox(width: 16), - itemBuilder: (_, index) { - final user = _selectedUsers.elementAt(index); - return Column( - children: [ - Stack( - children: [ - UserAvatar( - onlineIndicatorAlignment: Alignment(0.9, 0.9), - user: user, - showOnlineStatus: true, - borderRadius: BorderRadius.circular(32), - constraints: BoxConstraints.tightFor( - height: 64, - width: 64, - ), - ), - Positioned( - top: -4, - right: -4, - child: GestureDetector( - onTap: () { - if (_selectedUsers.contains(user)) { - setState( - () => _selectedUsers.remove(user)); - } - }, - child: Container( - decoration: BoxDecoration( - color: StreamChatTheme.of(context) - .colorTheme - .white, - shape: BoxShape.circle, - border: Border.all( - color: StreamChatTheme.of(context) - .colorTheme - .whiteSnow, + body: ValueListenableBuilder( + valueListenable: StreamChat.of(context).client.wsConnectionStatus, + builder: (context, status, _) { + String statusString = ''; + bool showStatus = true; + + switch (status) { + case ConnectionStatus.connected: + statusString = 'Connected'; + showStatus = false; + break; + case ConnectionStatus.connecting: + statusString = 'Reconnecting...'; + break; + case ConnectionStatus.disconnected: + statusString = 'Disconnected'; + break; + } + return InfoTile( + showMessage: showStatus, + tileAnchor: Alignment.topCenter, + childAnchor: Alignment.topCenter, + message: statusString, + child: NestedScrollView( + floatHeaderSlivers: true, + headerSliverBuilder: + (BuildContext context, bool innerBoxIsScrolled) { + return [ + SliverToBoxAdapter( + child: SearchTextField( + controller: _controller, + ), + ), + if (_selectedUsers.isNotEmpty) + SliverToBoxAdapter( + child: Container( + height: 104, + child: ListView.separated( + scrollDirection: Axis.horizontal, + itemCount: _selectedUsers.length, + padding: const EdgeInsets.all(8), + separatorBuilder: (_, __) => SizedBox(width: 16), + itemBuilder: (_, index) { + final user = _selectedUsers.elementAt(index); + return Column( + children: [ + Stack( + children: [ + UserAvatar( + onlineIndicatorAlignment: + Alignment(0.9, 0.9), + user: user, + showOnlineStatus: true, + borderRadius: BorderRadius.circular(32), + constraints: BoxConstraints.tightFor( + height: 64, + width: 64, + ), ), - ), - child: StreamSvgIcon.close( - color: StreamChatTheme.of(context) - .colorTheme - .black, - size: 24, + Positioned( + top: -4, + right: -4, + child: GestureDetector( + onTap: () { + if (_selectedUsers.contains(user)) { + setState(() => + _selectedUsers.remove(user)); + } + }, + child: Container( + decoration: BoxDecoration( + color: StreamChatTheme.of(context) + .colorTheme + .white, + shape: BoxShape.circle, + border: Border.all( + color: + StreamChatTheme.of(context) + .colorTheme + .whiteSnow, + ), + ), + child: StreamSvgIcon.close( + color: StreamChatTheme.of(context) + .colorTheme + .black, + size: 24, + ), + ), + ), + ) + ], + ), + SizedBox(height: 4), + Text( + user.name.split(' ')[0], + style: TextStyle( + fontWeight: FontWeight.bold, + fontSize: 12, ), ), - ), - ) - ], + ], + ); + }, ), - SizedBox(height: 4), - Text( - user.name.split(' ')[0], - style: TextStyle( - fontWeight: FontWeight.bold, - fontSize: 12, + ), + ), + SliverPersistentHeader( + pinned: true, + delegate: _HeaderDelegate( + height: 30, + child: Container( + width: double.maxFinite, + decoration: BoxDecoration( + gradient: StreamChatTheme.of(context) + .colorTheme + .bgGradient, + ), + child: Padding( + padding: const EdgeInsets.symmetric( + vertical: 8, + horizontal: 8, + ), + child: Text( + _isSearchActive + ? 'Matches for \"$_userNameQuery\"' + : 'On the platform', + style: TextStyle( + color: + StreamChatTheme.of(context).colorTheme.grey, + ), ), ), - ], - ); - }, - ), - ), - ), - SliverPersistentHeader( - pinned: true, - delegate: _HeaderDelegate( - height: 30, - child: Container( - width: double.maxFinite, - decoration: BoxDecoration( - gradient: StreamChatTheme.of(context).colorTheme.bgGradient, - ), - child: Padding( - padding: const EdgeInsets.symmetric( - vertical: 8, - horizontal: 8, - ), - child: Text( - _isSearchActive - ? 'Matches for \"$_userNameQuery\"' - : 'On the platform', - style: TextStyle( - color: StreamChatTheme.of(context).colorTheme.grey, + ), ), ), - ), - ), - ), - ), - ]; - }, - body: GestureDetector( - behavior: HitTestBehavior.opaque, - onPanDown: (_) => FocusScope.of(context).unfocus(), - child: UsersBloc( - child: UserListView( - selectedUsers: _selectedUsers, - pullToRefresh: false, - groupAlphabetically: _isSearchActive ? false : true, - onUserTap: (user, _) { - if (!_selectedUsers.contains(user)) { - setState(() { - _selectedUsers.add(user); - }); - } else { - setState(() { - _selectedUsers.remove(user); - }); - } - }, - pagination: PaginationParams( - limit: 25, - ), - filter: { - if (_userNameQuery.isNotEmpty) - 'name': { - r'$autocomplete': _userNameQuery, - }, - 'id': { - r'$ne': StreamChat.of(context).user.id, - } - }, - sort: [ - SortOption( - 'name', - direction: 1, - ), - ], - emptyBuilder: (_) { - return LayoutBuilder( - builder: (context, viewportConstraints) { - return SingleChildScrollView( - physics: AlwaysScrollableScrollPhysics(), - child: ConstrainedBox( - constraints: BoxConstraints( - minHeight: viewportConstraints.maxHeight, + ]; + }, + body: GestureDetector( + behavior: HitTestBehavior.opaque, + onPanDown: (_) => FocusScope.of(context).unfocus(), + child: UsersBloc( + child: UserListView( + selectedUsers: _selectedUsers, + pullToRefresh: false, + groupAlphabetically: _isSearchActive ? false : true, + onUserTap: (user, _) { + if (!_selectedUsers.contains(user)) { + setState(() { + _selectedUsers.add(user); + }); + } else { + setState(() { + _selectedUsers.remove(user); + }); + } + }, + pagination: PaginationParams( + limit: 25, + ), + filter: { + if (_userNameQuery.isNotEmpty) + 'name': { + r'$autocomplete': _userNameQuery, + }, + 'id': { + r'$ne': StreamChat.of(context).user.id, + } + }, + sort: [ + SortOption( + 'name', + direction: 1, ), - child: Center( - child: Column( - children: [ - Padding( - padding: const EdgeInsets.all(24), - child: StreamSvgIcon.search( - size: 96, - color: StreamChatTheme.of(context) - .colorTheme - .grey, + ], + emptyBuilder: (_) { + return LayoutBuilder( + builder: (context, viewportConstraints) { + return SingleChildScrollView( + physics: AlwaysScrollableScrollPhysics(), + child: ConstrainedBox( + constraints: BoxConstraints( + minHeight: viewportConstraints.maxHeight, + ), + child: Center( + child: Column( + children: [ + Padding( + padding: const EdgeInsets.all(24), + child: StreamSvgIcon.search( + size: 96, + color: StreamChatTheme.of(context) + .colorTheme + .grey, + ), + ), + Text( + 'No user matches these keywords...', + style: StreamChatTheme.of(context) + .textTheme + .footnote + .copyWith( + color: StreamChatTheme.of(context) + .colorTheme + .grey, + ), + ), + ], + ), ), ), - Text( - 'No user matches these keywords...', - style: StreamChatTheme.of(context) - .textTheme - .footnote - .copyWith( - color: StreamChatTheme.of(context) - .colorTheme - .grey, - ), - ), - ], - ), - ), - ), - ); - }, - ); - }, - ), - ), - ), - ), + ); + }, + ); + }, + ), + ), + ), + ), + ); + }), ); } } From 829dddb5e095be9c7b234d677facacd79168846a Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Wed, 13 Jan 2021 16:14:45 +0530 Subject: [PATCH 0896/1140] [ReactionBubble] Add masked spacing Signed-off-by: Sahil Kumar --- lib/src/message_reactions_modal.dart | 1 + lib/src/message_widget.dart | 4 + lib/src/reaction_bubble.dart | 128 +++++++++++++++++++-------- lib/src/stream_chat_theme.dart | 7 ++ 4 files changed, 102 insertions(+), 38 deletions(-) diff --git a/lib/src/message_reactions_modal.dart b/lib/src/message_reactions_modal.dart index 0f056dde..8520e8ec 100644 --- a/lib/src/message_reactions_modal.dart +++ b/lib/src/message_reactions_modal.dart @@ -232,6 +232,7 @@ class MessageReactionsModal extends StatelessWidget { flipTail: !reverse, borderColor: messageTheme.reactionsBorderColor, backgroundColor: messageTheme.reactionsBackgroundColor, + maskColor: messageTheme.reactionsMaskColor, highlightOwnReactions: false, ), ), diff --git a/lib/src/message_widget.dart b/lib/src/message_widget.dart index 2157aa32..3a718471 100644 --- a/lib/src/message_widget.dart +++ b/lib/src/message_widget.dart @@ -447,6 +447,9 @@ class _MessageWidgetState extends State { StreamChatTheme.of(context) .colorTheme .white, + StreamChatTheme.of(context) + .colorTheme + .white, ), ), ), @@ -694,6 +697,7 @@ class _MessageWidgetState extends State { flipTail: widget.reverse, backgroundColor: widget.messageTheme.reactionsBackgroundColor, borderColor: widget.messageTheme.reactionsBorderColor, + maskColor: widget.messageTheme.reactionsMaskColor, reactions: reactionsList, ), ) diff --git a/lib/src/reaction_bubble.dart b/lib/src/reaction_bubble.dart index 9eee9997..61cca62e 100644 --- a/lib/src/reaction_bubble.dart +++ b/lib/src/reaction_bubble.dart @@ -12,6 +12,7 @@ class ReactionBubble extends StatelessWidget { @required this.reactions, @required this.borderColor, @required this.backgroundColor, + @required this.maskColor, this.reverse = false, this.flipTail = false, this.highlightOwnReactions = true, @@ -20,6 +21,7 @@ class ReactionBubble extends StatelessWidget { final List reactions; final Color borderColor; final Color backgroundColor; + final Color maskColor; final bool reverse; final bool flipTail; final bool highlightOwnReactions; @@ -38,51 +40,58 @@ class ReactionBubble extends StatelessWidget { Transform.translate( offset: Offset(reverse ? offset : -offset, 0), child: Container( - padding: EdgeInsets.symmetric( - vertical: 4, - horizontal: totalReactions > 1 ? 4 : 0, - ), + padding: const EdgeInsets.all(2), decoration: BoxDecoration( - border: Border.all( - color: borderColor, - ), - color: backgroundColor, + color: maskColor, borderRadius: BorderRadius.all(Radius.circular(14)), ), - 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(), - ], - ); - }, + child: Container( + padding: EdgeInsets.symmetric( + vertical: 4, + horizontal: totalReactions > 1 ? 4 : 0, + ), + decoration: BoxDecoration( + border: Border.all( + color: borderColor, + ), + color: backgroundColor, + borderRadius: BorderRadius.all(Radius.circular(14)), + ), + 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(), + ], + ); + }, + ), ), ), ), Positioned( - bottom: 0, - left: reverse ? null : 11, - right: !reverse ? null : 11, + bottom: 2, + left: reverse ? null : 13, + right: !reverse ? null : 13, child: _buildReactionsTail(context), ), ], @@ -136,6 +145,7 @@ class ReactionBubble extends StatelessWidget { painter: ReactionBubblePainter( backgroundColor, borderColor, + maskColor, ), ); return Transform( @@ -149,14 +159,20 @@ class ReactionBubble extends StatelessWidget { class ReactionBubblePainter extends CustomPainter { final Color color; final Color borderColor; + final Color maskColor; ReactionBubblePainter( this.color, this.borderColor, + this.maskColor, ); @override void paint(Canvas canvas, Size size) { + _drawOvalMask(size, canvas); + + _drawMask(size, canvas); + _drawOval(size, canvas); _drawOvalBorder(size, canvas); @@ -166,6 +182,21 @@ class ReactionBubblePainter extends CustomPainter { _drawBorder(size, canvas); } + void _drawOvalMask(Size size, Canvas canvas) { + final paint = Paint() + ..color = maskColor + ..style = PaintingStyle.fill; + + final path = Path(); + path.addOval( + Rect.fromCircle( + center: Offset(4, 3), + radius: 4, + ), + ); + canvas.drawPath(path, paint); + } + void _drawOvalBorder(Size size, Canvas canvas) { final paint = Paint() ..color = borderColor @@ -236,6 +267,27 @@ class ReactionBubblePainter extends CustomPainter { canvas.drawPath(path, paint); } + void _drawMask(Size size, Canvas canvas) { + final paint = Paint() + ..color = maskColor + ..strokeWidth = 1 + ..style = PaintingStyle.fill; + + final dy = -2.2; + final startAngle = 1.1; + final sweepAngle = 1.2; + final path = Path(); + path.addArc( + Rect.fromCircle( + center: Offset(1, dy), + radius: 6, + ), + -pi * startAngle, + -pi / sweepAngle, + ); + canvas.drawPath(path, paint); + } + @override bool shouldRepaint(CustomPainter oldDelegate) { return true; diff --git a/lib/src/stream_chat_theme.dart b/lib/src/stream_chat_theme.dart index c6d2d72f..70845ba9 100644 --- a/lib/src/stream_chat_theme.dart +++ b/lib/src/stream_chat_theme.dart @@ -234,6 +234,7 @@ class StreamChatThemeData { messageBackgroundColor: colorTheme.greyGainsboro, reactionsBackgroundColor: colorTheme.white, reactionsBorderColor: colorTheme.greyWhisper, + reactionsMaskColor: colorTheme.whiteSnow, messageBorderColor: colorTheme.greyGainsboro, avatarTheme: AvatarTheme( borderRadius: BorderRadius.circular(20), @@ -249,6 +250,7 @@ class StreamChatThemeData { otherMessageTheme: MessageTheme( reactionsBackgroundColor: colorTheme.greyGainsboro, reactionsBorderColor: colorTheme.white, + reactionsMaskColor: colorTheme.whiteSnow, messageText: textTheme.body, createdAt: textTheme.footnote.copyWith(color: colorTheme.grey), replies: textTheme.footnoteBold.copyWith(color: accentColor), @@ -710,6 +712,7 @@ class MessageTheme { final Color messageBorderColor; final Color reactionsBackgroundColor; final Color reactionsBorderColor; + final Color reactionsMaskColor; final AvatarTheme avatarTheme; const MessageTheme({ @@ -721,6 +724,7 @@ class MessageTheme { this.messageBorderColor, this.reactionsBackgroundColor, this.reactionsBorderColor, + this.reactionsMaskColor, this.avatarTheme, this.createdAt, }); @@ -736,6 +740,7 @@ class MessageTheme { AvatarTheme avatarTheme, Color reactionsBackgroundColor, Color reactionsBorderColor, + Color reactionsMaskColor, }) => MessageTheme( messageText: messageText ?? this.messageText, @@ -750,6 +755,7 @@ class MessageTheme { reactionsBackgroundColor: reactionsBackgroundColor ?? this.reactionsBackgroundColor, reactionsBorderColor: reactionsBorderColor ?? this.reactionsBorderColor, + reactionsMaskColor: reactionsMaskColor ?? this.reactionsMaskColor, ); MessageTheme merge(MessageTheme other) { @@ -767,6 +773,7 @@ class MessageTheme { avatarTheme: avatarTheme?.merge(other.avatarTheme) ?? other.avatarTheme, reactionsBackgroundColor: other.reactionsBackgroundColor, reactionsBorderColor: other.reactionsBorderColor, + reactionsMaskColor: other.reactionsMaskColor, ); } } From 854aea1fa2a5a226c82e3f8569d02191f3c02c8a Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Wed, 13 Jan 2021 16:24:55 +0530 Subject: [PATCH 0897/1140] [MessageActionModal] Fix action tile padding and divider Signed-off-by: Sahil Kumar --- lib/src/message_actions_modal.dart | 281 +++++++++++++++-------------- 1 file changed, 147 insertions(+), 134 deletions(-) diff --git a/lib/src/message_actions_modal.dart b/lib/src/message_actions_modal.dart index 9d9670cf..f0d378cf 100644 --- a/lib/src/message_actions_modal.dart +++ b/lib/src/message_actions_modal.dart @@ -186,36 +186,37 @@ class _MessageActionsModalState extends State { child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, - children: ListTile.divideTiles( - color: StreamChatTheme.of(context) - .colorTheme - .greyWhisper, - context: context, - tiles: [ - if (widget.showReplyMessage && - (widget.message.status == - MessageSendingStatus.SENT || - widget.message.status == null) && - widget.message.parentId == null) - _buildReplyButton(context), - if (widget.showThreadReplyMessage && - (widget.message.status == - MessageSendingStatus.SENT || - widget.message.status == null) && - widget.message.parentId == null) - _buildThreadReplyButton(context), - if (widget.showResendMessage) - _buildResendMessage(context), - if (widget.showEditMessage) - _buildEditMessage(context), - if (widget.showCopyMessage) - _buildCopyButton(context), - if (widget.showFlagButton) - _buildFlagButton(context), - if (widget.showDeleteMessage) - _buildDeleteButton(context), - ], - ).toList(), + children: [ + if (widget.showReplyMessage && + (widget.message.status == + MessageSendingStatus.SENT || + widget.message.status == null) && + widget.message.parentId == null) + _buildReplyButton(context), + if (widget.showThreadReplyMessage && + (widget.message.status == + MessageSendingStatus.SENT || + widget.message.status == null) && + widget.message.parentId == null) + _buildThreadReplyButton(context), + if (widget.showResendMessage) + _buildResendMessage(context), + if (widget.showEditMessage) + _buildEditMessage(context), + if (widget.showCopyMessage) + _buildCopyButton(context), + if (widget.showFlagButton) + _buildFlagButton(context), + if (widget.showDeleteMessage) + _buildDeleteButton(context), + ].insertBetween( + Container( + height: 1, + color: StreamChatTheme.of(context) + .colorTheme + .greyWhisper, + ), + ), ), ), ), @@ -416,136 +417,131 @@ class _MessageActionsModalState extends State { } Widget _buildReplyButton(BuildContext context) { - return ListTile( - 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, - ), - ], - ), + return InkWell( onTap: () { Navigator.pop(context); if (widget.onReplyTap != null) { widget.onReplyTap(widget.message); } }, + child: Padding( + padding: const EdgeInsets.symmetric(vertical: 8.0, horizontal: 16.0), + child: Row( + children: [ + StreamSvgIcon.reply( + color: StreamChatTheme.of(context).primaryIconTheme.color, + ), + const SizedBox(width: 16), + Text( + 'Reply', + style: StreamChatTheme.of(context).textTheme.body, + ), + ], + ), + ), ); } Widget _buildFlagButton(BuildContext context) { - return ListTile( - dense: true, - title: Row( - children: [ - StreamSvgIcon.icon_flag( - color: StreamChatTheme.of(context).primaryIconTheme.color, - ), - const SizedBox(width: 16), - Text( - 'Flag', - style: StreamChatTheme.of(context).textTheme.headline, - ), - ], - ), + return InkWell( onTap: () => _showFlagDialog(), + child: Padding( + padding: const EdgeInsets.symmetric(vertical: 8.0, horizontal: 16.0), + child: Row( + children: [ + StreamSvgIcon.icon_flag( + color: StreamChatTheme.of(context).primaryIconTheme.color, + ), + const SizedBox(width: 16), + Text( + 'Flag', + style: StreamChatTheme.of(context).textTheme.body, + ), + ], + ), + ), ); } Widget _buildDeleteButton(BuildContext context) { final isDeleteFailed = widget.message.status == MessageSendingStatus.FAILED_DELETE; - return ListTile( - 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), - ), - ], + return InkWell( + onTap: () => _showDeleteDialog(), + child: Padding( + padding: const EdgeInsets.symmetric(vertical: 8.0, horizontal: 16.0), + child: Row( + children: [ + StreamSvgIcon.delete( + color: Colors.red, + ), + const SizedBox(width: 16), + Text( + isDeleteFailed ? 'Retry Deleting Message' : 'Delete Message', + style: StreamChatTheme.of(context) + .textTheme + .body + .copyWith(color: Colors.red), + ), + ], + ), ), - onTap: () { - _showDeleteDialog(); - }, ); } Widget _buildCopyButton(BuildContext context) { - return ListTile( - 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, - ), - ], - ), + return InkWell( onTap: () async { await Clipboard.setData(ClipboardData(text: widget.message.text)); Navigator.pop(context); }, + child: Padding( + padding: const EdgeInsets.symmetric(vertical: 8.0, horizontal: 16.0), + child: Row( + children: [ + StreamSvgIcon.copy( + size: 24, + color: StreamChatTheme.of(context).primaryIconTheme.color, + ), + const SizedBox(width: 16), + Text( + 'Copy Message', + style: StreamChatTheme.of(context).textTheme.body, + ), + ], + ), + ), ); } Widget _buildEditMessage(BuildContext context) { - return ListTile( - 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, - ), - ], - ), + return InkWell( onTap: () async { Navigator.pop(context); _showEditBottomSheet(context); }, + child: Padding( + padding: const EdgeInsets.symmetric(vertical: 8.0, horizontal: 16.0), + child: Row( + children: [ + StreamSvgIcon.edit( + color: StreamChatTheme.of(context).primaryIconTheme.color, + ), + const SizedBox(width: 16), + Text( + 'Edit Message', + style: StreamChatTheme.of(context).textTheme.body, + ), + ], + ), + ), ); } Widget _buildResendMessage(BuildContext context) { final isUpdateFailed = widget.message.status == MessageSendingStatus.FAILED_UPDATE; - return ListTile( - 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, - ), - ], - ), + return InkWell( onTap: () { Navigator.pop(context); final client = StreamChat.of(context).client; @@ -556,6 +552,21 @@ class _MessageActionsModalState extends State { channel.sendMessage(widget.message); } }, + child: Padding( + padding: const EdgeInsets.symmetric(vertical: 8.0, horizontal: 16.0), + child: 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.body, + ), + ], + ), + ), ); } @@ -629,26 +640,28 @@ class _MessageActionsModalState extends State { } Widget _buildThreadReplyButton(BuildContext context) { - return ListTile( - 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, - ), - ], - ), + return InkWell( onTap: () { Navigator.pop(context); if (widget.onThreadReplyTap != null) { widget.onThreadReplyTap(widget.message); } }, + child: Padding( + padding: const EdgeInsets.symmetric(vertical: 8.0, horizontal: 16.0), + child: Row( + children: [ + StreamSvgIcon.thread( + color: StreamChatTheme.of(context).primaryIconTheme.color, + ), + const SizedBox(width: 16), + Text( + 'Thread Reply', + style: StreamChatTheme.of(context).textTheme.body, + ), + ], + ), + ), ); } } From 9cba3d6f2b11f8e6feb4a043c53898543e82ecb4 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Wed, 13 Jan 2021 12:07:39 +0100 Subject: [PATCH 0898/1140] update version --- example/pubspec.yaml | 2 +- pubspec.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 2b8859ea..941d8bcd 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -1,6 +1,6 @@ name: example description: A new Flutter project. -version: 1.1.1+1 +version: 1.1.1+2 environment: sdk: ">=2.2.2 <3.0.0" diff --git a/pubspec.yaml b/pubspec.yaml index e29042cb..9ef7a80a 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -28,7 +28,7 @@ dependencies: file_picker: ^2.0.12 image_picker: ^0.6.7+2 flutter_keyboard_visibility: ^4.0.2 - stream_chat: ^0.2.23 + stream_chat: ^0.2.23+2 mime: ^0.9.6+3 video_compress: ^2.1.1 visibility_detector: ^0.1.5 From b609be4ba9d4e7ee319fe05b3126d8dd4b127c4d Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Wed, 13 Jan 2021 12:10:12 +0100 Subject: [PATCH 0899/1140] fix rxdart version --- packages/dart_client/pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/dart_client/pubspec.yaml b/packages/dart_client/pubspec.yaml index 0afc8bfd..31c4d555 100644 --- a/packages/dart_client/pubspec.yaml +++ b/packages/dart_client/pubspec.yaml @@ -22,7 +22,7 @@ dependencies: moor: ^3.4.0 path_provider: ^1.6.24 path: ^1.7.0 - rxdart: ^0.25.0 + rxdart: ^0.24.1 collection: ^1.14.13 sqlite3_flutter_libs: ^0.3.0 From 3b0c2a9a73f671a033473f82ca5143cb7a58c837 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Wed, 13 Jan 2021 16:40:28 +0530 Subject: [PATCH 0900/1140] [ReactionBubble] Added Customization for the spacing between the bottom circles Signed-off-by: Sahil Kumar --- lib/src/message_widget.dart | 9 +++------ lib/src/reaction_bubble.dart | 15 ++++++++++----- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/lib/src/message_widget.dart b/lib/src/message_widget.dart index 3a718471..95753d09 100644 --- a/lib/src/message_widget.dart +++ b/lib/src/message_widget.dart @@ -444,12 +444,9 @@ class _MessageWidgetState extends State { StreamChatTheme.of(context) .colorTheme .white, - StreamChatTheme.of(context) - .colorTheme - .white, - StreamChatTheme.of(context) - .colorTheme - .white, + Colors.transparent, + Colors.transparent, + tailCirclesSpace: 1, ), ), ), diff --git a/lib/src/reaction_bubble.dart b/lib/src/reaction_bubble.dart index 61cca62e..3811bace 100644 --- a/lib/src/reaction_bubble.dart +++ b/lib/src/reaction_bubble.dart @@ -16,6 +16,7 @@ class ReactionBubble extends StatelessWidget { this.reverse = false, this.flipTail = false, this.highlightOwnReactions = true, + this.tailCirclesSpace = 0, }) : super(key: key); final List reactions; @@ -25,6 +26,7 @@ class ReactionBubble extends StatelessWidget { final bool reverse; final bool flipTail; final bool highlightOwnReactions; + final double tailCirclesSpace; @override Widget build(BuildContext context) { @@ -146,6 +148,7 @@ class ReactionBubble extends StatelessWidget { backgroundColor, borderColor, maskColor, + tailCirclesSpace: tailCirclesSpace, ), ); return Transform( @@ -160,12 +163,14 @@ class ReactionBubblePainter extends CustomPainter { final Color color; final Color borderColor; final Color maskColor; + final double tailCirclesSpace; ReactionBubblePainter( this.color, this.borderColor, - this.maskColor, - ); + this.maskColor, { + this.tailCirclesSpace = 0, + }); @override void paint(Canvas canvas, Size size) { @@ -190,7 +195,7 @@ class ReactionBubblePainter extends CustomPainter { final path = Path(); path.addOval( Rect.fromCircle( - center: Offset(4, 3), + center: Offset(4, 3) + Offset(tailCirclesSpace, tailCirclesSpace), radius: 4, ), ); @@ -206,7 +211,7 @@ class ReactionBubblePainter extends CustomPainter { final path = Path(); path.addOval( Rect.fromCircle( - center: Offset(4, 3), + center: Offset(4, 3) + Offset(tailCirclesSpace, tailCirclesSpace), radius: 2, ), ); @@ -220,7 +225,7 @@ class ReactionBubblePainter extends CustomPainter { final path = Path(); path.addOval(Rect.fromCircle( - center: Offset(4, 3), + center: Offset(4, 3) + Offset(tailCirclesSpace, tailCirclesSpace), radius: 2, )); canvas.drawPath(path, paint); From 2fedf8de1f77cbd5c957d89472ae817fec97b96b Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Wed, 13 Jan 2021 12:21:04 +0100 Subject: [PATCH 0901/1140] try using working-directory --- .github/workflows/build.yml | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index c83f3635..48f6df96 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -9,6 +9,9 @@ on: release: types: - created +defaults: + run: + working-directory: packages/flutter_widgets jobs: build_and_deploy_ios: @@ -17,7 +20,7 @@ jobs: - uses: actions/checkout@v2 - name: Install RubyGems run: | - cd packages/flutter_widgets/example/ios + cd example/ios bundle install - uses: subosito/flutter-action@v1.4.0 with: @@ -26,7 +29,7 @@ jobs: run: npm install -g firebase-tools - name: Flutter setup run: | - cd packages/flutter_widgets/example + cd example flutter pub get - name: Build and release env: @@ -34,7 +37,7 @@ jobs: MATCH_GIT_BASIC_AUTHORIZATION: ${{ secrets.MATCH_GIT_BASIC_AUTHORIZATION }} FIREBASE_TOKEN: ${{ secrets.FIREBASE_TOKEN }} run: | - cd packages/flutter_widgets/example + cd example flutter build ios --release --no-codesign cd ios bundle exec fastlane deploy_to_firebase @@ -49,11 +52,11 @@ jobs: with: channel: 'stable' - run: | - cd packages/flutter_widgets/example + cd example flutter pub get - name: Build run: | - cd packages/flutter_widgets/example + cd example flutter build apk - name: Deploy uses: wzieba/Firebase-Distribution-Github-Action@v1.2.1 @@ -61,4 +64,4 @@ jobs: appId: ${{secrets.FIREBASE_ANDROID_APPID}} token: ${{secrets.FIREBASE_TOKEN}} groups: stream-testers - file: packages/flutter_widgets/example/build/app/outputs/apk/release/app-release.apk \ No newline at end of file + file: example/build/app/outputs/apk/release/app-release.apk \ No newline at end of file From aaf2d3947304d6fe72701cec1f31f2763059d4db Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Wed, 13 Jan 2021 13:47:59 +0100 Subject: [PATCH 0902/1140] add quoted messages to threads --- example/lib/main.dart | 43 ++++++++++++++++++++++++++++++++++++------- 1 file changed, 36 insertions(+), 7 deletions(-) diff --git a/example/lib/main.dart b/example/lib/main.dart index 49ee3fdc..7b2f578a 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -763,7 +763,7 @@ class _ChannelPageState extends State { } } -class ThreadPage extends StatelessWidget { +class ThreadPage extends StatefulWidget { final Message parent; final int initialScrollIndex; final double initialAlignment; @@ -775,25 +775,54 @@ class ThreadPage extends StatelessWidget { this.initialAlignment, }) : super(key: key); + @override + _ThreadPageState createState() => _ThreadPageState(); +} + +class _ThreadPageState extends State { + Message _quotedMessage; + FocusNode _focusNode = FocusNode(); + + @override + void dispose() { + _focusNode.dispose(); + super.dispose(); + } + + void _reply(Message message) { + setState(() => _quotedMessage = message); + WidgetsBinding.instance.addPostFrameCallback((timeStamp) { + _focusNode.requestFocus(); + }); + } + @override Widget build(BuildContext context) { return Scaffold( backgroundColor: StreamChatTheme.of(context).colorTheme.whiteSnow, appBar: ThreadHeader( - parent: parent, + parent: widget.parent, ), body: Column( children: [ Expanded( child: MessageListView( - parentMessage: parent, - initialScrollIndex: initialScrollIndex, - initialAlignment: initialAlignment, + parentMessage: widget.parent, + initialScrollIndex: widget.initialScrollIndex, + initialAlignment: widget.initialAlignment, + onMessageSwiped: _reply, + onReplyTap: _reply, ), ), - if (parent.type != 'deleted') + if (widget.parent.type != 'deleted') MessageInput( - parentMessage: parent, + parentMessage: widget.parent, + focusNode: _focusNode, + quotedMessage: _quotedMessage, + onQuotedMessageCleared: () { + setState(() => _quotedMessage = null); + _focusNode.unfocus(); + }, ), ], ), From ab29edd89e1ba4708d019cd56a2b63ef5b0ca4f3 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Wed, 13 Jan 2021 18:21:02 +0530 Subject: [PATCH 0903/1140] Minor ui fixes Signed-off-by: Sahil Kumar --- lib/src/message_actions_modal.dart | 13 ++++- lib/src/message_list_view.dart | 2 +- lib/src/message_reactions_modal.dart | 82 +++++++++++++++------------- lib/src/message_widget.dart | 4 +- 4 files changed, 56 insertions(+), 45 deletions(-) diff --git a/lib/src/message_actions_modal.dart b/lib/src/message_actions_modal.dart index f0d378cf..9b93695e 100644 --- a/lib/src/message_actions_modal.dart +++ b/lib/src/message_actions_modal.dart @@ -90,6 +90,8 @@ class _MessageActionsModalState extends State { duration: Duration(milliseconds: 300), curve: Curves.easeInOutBack, builder: (context, val, snapshot) { + final hasFileAttachment = + widget.message.attachments?.any((it) => it.type == 'file') == true; return GestureDetector( behavior: HitTestBehavior.translucent, onTap: () => Navigator.maybePop(context), @@ -111,7 +113,7 @@ class _MessageActionsModalState extends State { child: Center( child: SingleChildScrollView( child: Padding( - padding: const EdgeInsets.symmetric(vertical: 8.0), + padding: const EdgeInsets.all(8.0), child: Column( crossAxisAlignment: widget.reverse ? CrossAxisAlignment.end @@ -136,6 +138,7 @@ class _MessageActionsModalState extends State { messageTheme: widget.messageTheme, ), ), + SizedBox(height: 8), IgnorePointer( child: MessageWidget( key: Key('MessageWidget'), @@ -151,8 +154,12 @@ class _MessageActionsModalState extends State { showThreadReplyIndicator: false, showReplyMessage: false, showUserAvatar: widget.showUserAvatar, + attachmentPadding: EdgeInsets.all( + hasFileAttachment ? 4 : 2, + ), showTimestamp: false, translateUserAvatar: false, + padding: const EdgeInsets.all(0), textPadding: EdgeInsets.symmetric( vertical: 8.0, horizontal: @@ -168,10 +175,10 @@ class _MessageActionsModalState extends State { shape: widget.messageShape, ), ), + SizedBox(height: 8), Padding( padding: EdgeInsets.only( - right: widget.reverse ? 8 : 0, - left: widget.reverse ? 0 : 48, + left: widget.reverse ? 0 : 40, ), child: SizedBox( width: MediaQuery.of(context).size.width * 0.75, diff --git a/lib/src/message_list_view.dart b/lib/src/message_list_view.dart index b659845e..0e764bca 100644 --- a/lib/src/message_list_view.dart +++ b/lib/src/message_list_view.dart @@ -783,7 +783,7 @@ class _MessageListViewState extends State { final allRead = readList.length >= (channel.memberCount ?? 0) - 1; final hasFileAttachment = - message.attachments.any((it) => it.type == 'file'); + message.attachments?.any((it) => it.type == 'file') == true; final isThreadMessage = message?.parentId != null && message?.showInChannel == true; diff --git a/lib/src/message_reactions_modal.dart b/lib/src/message_reactions_modal.dart index 8520e8ec..bf72daf8 100644 --- a/lib/src/message_reactions_modal.dart +++ b/lib/src/message_reactions_modal.dart @@ -62,6 +62,8 @@ class MessageReactionsModal extends StatelessWidget { duration: Duration(milliseconds: 300), curve: Curves.easeInOutBack, builder: (context, val, snapshot) { + final hasFileAttachment = + message.attachments?.any((it) => it.type == 'file') == true; return GestureDetector( behavior: HitTestBehavior.translucent, onTap: () => Navigator.maybePop(context), @@ -83,7 +85,7 @@ class MessageReactionsModal extends StatelessWidget { child: Center( child: SingleChildScrollView( child: Padding( - padding: const EdgeInsets.symmetric(vertical: 8.0), + padding: const EdgeInsets.all(8.0), child: Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.stretch, @@ -106,6 +108,7 @@ class MessageReactionsModal extends StatelessWidget { messageTheme: messageTheme, ), ), + const SizedBox(height: 8), IgnorePointer( child: MessageWidget( key: Key('MessageWidget'), @@ -124,6 +127,10 @@ class MessageReactionsModal extends StatelessWidget { translateUserAvatar: false, showSendingIndicator: false, shape: messageShape, + padding: const EdgeInsets.all(0), + attachmentPadding: EdgeInsets.all( + hasFileAttachment ? 4 : 2, + ), showInChannelIndicator: false, textPadding: EdgeInsets.symmetric( vertical: 8.0, @@ -135,8 +142,10 @@ class MessageReactionsModal extends StatelessWidget { message.status == null), ), ), - if (message.latestReactions?.isNotEmpty == true) + if (message.latestReactions?.isNotEmpty == true) ...[ + const SizedBox(height: 8), _buildReactionCard(context), + ] ], ), ), @@ -150,47 +159,42 @@ class MessageReactionsModal extends StatelessWidget { ); } - Padding _buildReactionCard(BuildContext context) { + Widget _buildReactionCard(BuildContext context) { final currentUser = StreamChat.of(context).user; - return Padding( - padding: const EdgeInsets.symmetric( - horizontal: 8.0, + return Card( + color: StreamChatTheme.of(context).colorTheme.white, + clipBehavior: Clip.hardEdge, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(16), ), - child: Card( - color: StreamChatTheme.of(context).colorTheme.white, - clipBehavior: Clip.hardEdge, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(16), - ), - margin: EdgeInsets.zero, - child: Padding( - padding: const EdgeInsets.all(16), - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - Text( - 'Message Reactions', - style: StreamChatTheme.of(context).textTheme.headlineBold, - ), - const SizedBox(height: 16), - Flexible( - child: SingleChildScrollView( - child: Wrap( - spacing: 16, - runSpacing: 16, - alignment: WrapAlignment.start, - children: message.latestReactions - .map((e) => _buildReaction( - e, - currentUser, - context, - )) - .toList(), - ), + margin: EdgeInsets.zero, + child: Padding( + padding: const EdgeInsets.all(16), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + 'Message Reactions', + style: StreamChatTheme.of(context).textTheme.headlineBold, + ), + const SizedBox(height: 16), + Flexible( + child: SingleChildScrollView( + child: Wrap( + spacing: 16, + runSpacing: 16, + alignment: WrapAlignment.start, + children: message.latestReactions + .map((e) => _buildReaction( + e, + currentUser, + context, + )) + .toList(), ), ), - ], - ), + ), + ], ), ), ); diff --git a/lib/src/message_widget.dart b/lib/src/message_widget.dart index 95753d09..29749c14 100644 --- a/lib/src/message_widget.dart +++ b/lib/src/message_widget.dart @@ -434,8 +434,8 @@ class _MessageWidgetState extends State { ), if (widget.showReactionPickerIndicator) Positioned( - right: 0, - top: -8, + right: widget.reverse ? -6 : 6, + top: -6, child: Transform( transform: Matrix4.rotationY( widget.reverse ? pi : 0), From 150e51ac62ccfb260b37786a1dcdd9d0c019b5cf Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Wed, 13 Jan 2021 18:37:54 +0530 Subject: [PATCH 0904/1140] [UserAvatar] Fix online status indicator size Signed-off-by: Sahil Kumar --- lib/src/channel_bottom_sheet.dart | 4 +++- lib/src/user_avatar.dart | 8 ++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/lib/src/channel_bottom_sheet.dart b/lib/src/channel_bottom_sheet.dart index d03f233c..6b3e4658 100644 --- a/lib/src/channel_bottom_sheet.dart +++ b/lib/src/channel_bottom_sheet.dart @@ -74,7 +74,7 @@ class _ChannelBottomSheetState extends State { ), borderRadius: BorderRadius.circular(32.0), onlineIndicatorConstraints: - BoxConstraints.tight(Size(16.0, 16.0)), + BoxConstraints.tight(Size(12.0, 12.0)), ), SizedBox( height: 6.0, @@ -110,6 +110,8 @@ class _ChannelBottomSheetState extends State { maxWidth: 64.0, ), borderRadius: BorderRadius.circular(32.0), + onlineIndicatorConstraints: + BoxConstraints.tight(Size(12.0, 12.0)), ), SizedBox( height: 6.0, diff --git a/lib/src/user_avatar.dart b/lib/src/user_avatar.dart index 688eff77..706c4d7e 100644 --- a/lib/src/user_avatar.dart +++ b/lib/src/user_avatar.dart @@ -92,18 +92,18 @@ class UserAvatar extends StatelessWidget { child: Material( type: MaterialType.circle, child: Container( - padding: const EdgeInsets.all(2.0), + margin: const EdgeInsets.all(2.0), constraints: onlineIndicatorConstraints ?? BoxConstraints.tightFor( - width: 12, - height: 12, + width: 8, + height: 8, ), child: Material( shape: CircleBorder(), color: streamChatTheme.colorTheme.accentGreen, ), ), - color: StreamChatTheme.of(context).colorTheme.white, + color: streamChatTheme.colorTheme.white, ), ), ), From ed767ec65b6198a36ac061dc6b8c7f9e2573b676 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Wed, 13 Jan 2021 18:41:26 +0530 Subject: [PATCH 0905/1140] Fix tests Signed-off-by: Sahil Kumar --- test/src/reaction_bubble_test.dart | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/src/reaction_bubble_test.dart b/test/src/reaction_bubble_test.dart index c0bc8cd1..0b6c90ef 100644 --- a/test/src/reaction_bubble_test.dart +++ b/test/src/reaction_bubble_test.dart @@ -19,6 +19,7 @@ void main() { reactions: [], borderColor: Colors.black, backgroundColor: Colors.white, + maskColor: Colors.white, ), ), ), @@ -56,6 +57,7 @@ void main() { ], borderColor: Colors.black, backgroundColor: Colors.white, + maskColor: Colors.white, ), ), ), @@ -96,6 +98,7 @@ void main() { ], borderColor: Colors.black, backgroundColor: Colors.white, + maskColor: Colors.white, ), ), ), From a8889ba693664714eaec3a53b28eeffbde5bbea4 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Wed, 13 Jan 2021 18:50:48 +0530 Subject: [PATCH 0906/1140] feat: Added images for photos modal --- lib/src/image_footer.dart | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/lib/src/image_footer.dart b/lib/src/image_footer.dart index e43eb3fb..9daf9a5c 100644 --- a/lib/src/image_footer.dart +++ b/lib/src/image_footer.dart @@ -218,12 +218,14 @@ class _ImageFooterState extends State { shrinkWrap: true, physics: NeverScrollableScrollPhysics(), itemBuilder: (context, position) { + Widget media; + if (widget.mediaAttachments[position].type == 'video') { var controllerPackage = widget.videoPackages[ videoAttachments .indexOf(widget.mediaAttachments[position])]; - return InkWell( + media = InkWell( onTap: () { widget.mediaSelectedCallBack(position); }, @@ -235,7 +237,7 @@ class _ImageFooterState extends State { ), ); } else { - return InkWell( + media = InkWell( onTap: () { widget.mediaSelectedCallBack(position); }, @@ -254,6 +256,28 @@ class _ImageFooterState extends State { ), ); } + + return Stack( + children: [ + media, + Padding( + padding: EdgeInsets.all(8.0), + child: Align( + alignment: Alignment.topLeft, + child: UserAvatar( + user: widget.message.user, + constraints: BoxConstraints.tight( + Size( + 24, + 24, + ), + ), + showOnlineStatus: false, + ), + ), + ), + ], + ); }, itemCount: widget.mediaAttachments.length, gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( From 60c3118cd88bcaf2be5462b423004cf506f531b2 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Wed, 13 Jan 2021 19:02:59 +0530 Subject: [PATCH 0907/1140] [MessageReactionsModal] Fix user online indicator size, reaction bubble alignment Signed-off-by: Sahil Kumar --- lib/src/message_reactions_modal.dart | 12 +++++++++--- lib/src/reaction_bubble.dart | 8 ++++---- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/lib/src/message_reactions_modal.dart b/lib/src/message_reactions_modal.dart index bf72daf8..c96b3afa 100644 --- a/lib/src/message_reactions_modal.dart +++ b/lib/src/message_reactions_modal.dart @@ -217,6 +217,7 @@ class MessageReactionsModal extends StatelessWidget { crossAxisAlignment: CrossAxisAlignment.center, children: [ Stack( + overflow: Overflow.visible, children: [ UserAvatar( onTap: onUserAvatarTap, @@ -225,6 +226,10 @@ class MessageReactionsModal extends StatelessWidget { height: 64, width: 64, ), + onlineIndicatorConstraints: BoxConstraints.tightFor( + height: 12, + width: 12, + ), borderRadius: BorderRadius.circular(32), ), Positioned( @@ -236,13 +241,14 @@ class MessageReactionsModal extends StatelessWidget { flipTail: !reverse, borderColor: messageTheme.reactionsBorderColor, backgroundColor: messageTheme.reactionsBackgroundColor, - maskColor: messageTheme.reactionsMaskColor, + maskColor: StreamChatTheme.of(context).colorTheme.white, + tailCirclesSpacing: 1, highlightOwnReactions: false, ), ), bottom: 6, - left: isCurrentUser ? 0 : null, - right: isCurrentUser ? 0 : null, + left: isCurrentUser ? -3 : null, + right: isCurrentUser ? -3 : null, ), ], ), diff --git a/lib/src/reaction_bubble.dart b/lib/src/reaction_bubble.dart index 3811bace..74a2ae99 100644 --- a/lib/src/reaction_bubble.dart +++ b/lib/src/reaction_bubble.dart @@ -16,7 +16,7 @@ class ReactionBubble extends StatelessWidget { this.reverse = false, this.flipTail = false, this.highlightOwnReactions = true, - this.tailCirclesSpace = 0, + this.tailCirclesSpacing = 0, }) : super(key: key); final List reactions; @@ -26,7 +26,7 @@ class ReactionBubble extends StatelessWidget { final bool reverse; final bool flipTail; final bool highlightOwnReactions; - final double tailCirclesSpace; + final double tailCirclesSpacing; @override Widget build(BuildContext context) { @@ -45,7 +45,7 @@ class ReactionBubble extends StatelessWidget { padding: const EdgeInsets.all(2), decoration: BoxDecoration( color: maskColor, - borderRadius: BorderRadius.all(Radius.circular(14)), + borderRadius: BorderRadius.all(Radius.circular(16)), ), child: Container( padding: EdgeInsets.symmetric( @@ -148,7 +148,7 @@ class ReactionBubble extends StatelessWidget { backgroundColor, borderColor, maskColor, - tailCirclesSpace: tailCirclesSpace, + tailCirclesSpace: tailCirclesSpacing, ), ); return Transform( From 8cd33852a6fa2b154c8c5f0dc917625224c3bd92 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Wed, 13 Jan 2021 20:03:58 +0530 Subject: [PATCH 0908/1140] fix: removed extra listview --- lib/src/message_list_view.dart | 309 ++++++++++++++++----------------- 1 file changed, 152 insertions(+), 157 deletions(-) diff --git a/lib/src/message_list_view.dart b/lib/src/message_list_view.dart index f60b9f5e..8dee39ed 100644 --- a/lib/src/message_list_view.dart +++ b/lib/src/message_list_view.dart @@ -333,172 +333,167 @@ class _MessageListViewState extends State { childAnchor: Alignment.topCenter, message: statusString, child: LazyLoadScrollView( - child: LazyLoadScrollView( - onStartOfPage: () async { - _inBetweenList = false; - if (!_upToDate) { - _topPaginationActive = false; - _bottomPaginationActive = true; - return _paginateData( + onStartOfPage: () async { + _inBetweenList = false; + if (!_upToDate) { + _topPaginationActive = false; + _bottomPaginationActive = true; + return _paginateData( + streamChannel, + QueryDirection.bottom, + ); + } + }, + onEndOfPage: () async { + _inBetweenList = false; + _topPaginationActive = true; + _bottomPaginationActive = false; + return _paginateData( + streamChannel, + QueryDirection.top, + ); + }, + onInBetweenOfPage: () { + _inBetweenList = true; + }, + child: ScrollablePositionedList.separated( + key: ValueKey(initialIndex + initialAlignment), + itemPositionsListener: _itemPositionListener, + addAutomaticKeepAlives: true, + initialScrollIndex: initialIndex ?? 0, + initialAlignment: initialAlignment ?? 0, + physics: widget.scrollPhysics, + itemScrollController: _scrollController, + reverse: true, + itemCount: messages.length + + 2 + + (_isThreadConversation ? 1 : 0), + separatorBuilder: (context, i) { + if (i == messages.length) return Offstage(); + if (i == 0) return SizedBox(height: 30); + if (i == messages.length + 1) { + final replyCount = + widget.parentMessage.replyCount; + return Container( + decoration: BoxDecoration( + gradient: StreamChatTheme.of(context) + .colorTheme + .bgGradient, + ), + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Text( + '$replyCount ${replyCount == 1 ? 'Reply' : 'Replies'}', + textAlign: TextAlign.center, + style: StreamChatTheme.of(context) + .channelTheme + .channelHeaderTheme + .lastMessageAt, + ), + ), + ); + } + + final message = messages[i]; + 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(), + ) + : DateDivider( + dateTime: nextMessage.createdAt.toLocal(), + ); + return Padding( + padding: + const EdgeInsets.symmetric(vertical: 12.0), + child: divider, + ); + } + 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; + final isDeleted = message.isDeleted; + if (timeDiff >= 1 || + !isNextUserSame || + isThread || + isDeleted) { + return SizedBox(height: 8); + } + return SizedBox(height: 2); + }, + itemBuilder: (context, i) { + if (i == messages.length + 2) { + if (widget.parentMessageBuilder != null) { + return widget.parentMessageBuilder( + context, + widget.parentMessage, + ); + } else { + return buildParentMessage(widget.parentMessage); + } + } + if (i == messages.length + 1) { + return _buildLoadingIndicator( + streamChannel, + QueryDirection.top, + ); + } + if (i == 0) { + return _buildLoadingIndicator( streamChannel, QueryDirection.bottom, ); } - }, - onEndOfPage: () async { - _inBetweenList = false; - _topPaginationActive = true; - _bottomPaginationActive = false; - return _paginateData( - streamChannel, - QueryDirection.top, - ); - }, - onInBetweenOfPage: () { - _inBetweenList = true; - }, - child: ScrollablePositionedList.separated( - key: ValueKey(initialIndex + initialAlignment), - itemPositionsListener: _itemPositionListener, - addAutomaticKeepAlives: true, - initialScrollIndex: initialIndex ?? 0, - initialAlignment: initialAlignment ?? 0, - physics: widget.scrollPhysics, - itemScrollController: _scrollController, - reverse: true, - itemCount: messages.length + - 2 + - (_isThreadConversation ? 1 : 0), - separatorBuilder: (context, i) { - if (i == messages.length) return Offstage(); - if (i == 0) return SizedBox(height: 30); - if (i == messages.length + 1) { - final replyCount = - widget.parentMessage.replyCount; - return Container( - decoration: BoxDecoration( - gradient: StreamChatTheme.of(context) - .colorTheme - .bgGradient, - ), - child: Padding( - padding: const EdgeInsets.all(8.0), - child: Text( - '$replyCount ${replyCount == 1 ? 'Reply' : 'Replies'}', - textAlign: TextAlign.center, - style: StreamChatTheme.of(context) - .channelTheme - .channelHeaderTheme - .lastMessageAt, - ), - ), - ); - } + final message = messages[i - 1]; - final message = messages[i]; - 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(), - ) - : DateDivider( - dateTime: - nextMessage.createdAt.toLocal(), - ); - return Padding( - padding: const EdgeInsets.symmetric( - vertical: 12.0), - child: divider, - ); - } - final timeDiff = - Jiffy(nextMessage.createdAt.toLocal()).diff( - message.createdAt.toLocal(), - Units.MINUTE, + Widget messageWidget; + + if (i == 1) { + messageWidget = _buildBottomMessage( + context, + message, + messages, + streamChannel, ); - - final isNextUserSame = - message.user.id == nextMessage.user?.id; - final isThread = message.replyCount > 0; - final isDeleted = message.isDeleted; - if (timeDiff >= 1 || - !isNextUserSame || - isThread || - isDeleted) { - return SizedBox(height: 8); - } - return SizedBox(height: 2); - }, - itemBuilder: (context, i) { - if (i == messages.length + 2) { - if (widget.parentMessageBuilder != null) { - return widget.parentMessageBuilder( - context, - widget.parentMessage, - ); - } else { - return buildParentMessage( - widget.parentMessage); - } - } - if (i == messages.length + 1) { - return _buildLoadingIndicator( - streamChannel, - QueryDirection.top, - ); - } - if (i == 0) { - return _buildLoadingIndicator( - streamChannel, - QueryDirection.bottom, - ); - } - final message = messages[i - 1]; - - Widget messageWidget; - - if (i == 1) { - messageWidget = _buildBottomMessage( - context, - message, - messages, - streamChannel, - ); - } else if (i == messages.length - 1) { - messageWidget = _buildTopMessage( - context, - message, - messages, - streamChannel, + } else if (i == messages.length - 1) { + messageWidget = _buildTopMessage( + context, + message, + messages, + streamChannel, + ); + } else { + if (widget.messageBuilder != null) { + messageWidget = Builder( + key: + ValueKey('MESSAGE-${message.id}'), + builder: (context) => widget.messageBuilder( + context, + MessageDetails( + context, + message, + messages, + i, + ), + messages), ); } else { - if (widget.messageBuilder != null) { - messageWidget = Builder( - key: ValueKey( - 'MESSAGE-${message.id}'), - builder: (context) => widget.messageBuilder( - context, - MessageDetails( - context, - message, - messages, - i, - ), - messages), - ); - } else { - messageWidget = - buildMessage(message, messages, i); - } + messageWidget = + buildMessage(message, messages, i); } - return messageWidget; - }, - ), + } + return messageWidget; + }, ), ), ); From a1b6fa75c9750de9b2d76627fdcf7fdb9a0f7220 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Wed, 13 Jan 2021 16:10:13 +0100 Subject: [PATCH 0909/1140] fix pickerindicator --- 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 ccefce6e..dd0c49cd 100644 --- a/lib/src/message_widget.dart +++ b/lib/src/message_widget.dart @@ -431,7 +431,7 @@ class _MessageWidgetState extends State { ), if (widget.showReactionPickerIndicator) Positioned( - right: 0, + right: 4, top: -8, child: Transform( transform: Matrix4.rotationY( From 6535e44313ea53d15ddb72604cfb9b0f777cb3b5 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Wed, 13 Jan 2021 16:22:46 +0100 Subject: [PATCH 0910/1140] fix reaction picker --- lib/src/message_widget.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/src/message_widget.dart b/lib/src/message_widget.dart index 29749c14..070bdad5 100644 --- a/lib/src/message_widget.dart +++ b/lib/src/message_widget.dart @@ -434,8 +434,8 @@ class _MessageWidgetState extends State { ), if (widget.showReactionPickerIndicator) Positioned( - right: widget.reverse ? -6 : 6, - top: -6, + right: 4, + top: -8, child: Transform( transform: Matrix4.rotationY( widget.reverse ? pi : 0), From 5e18b7f006970b58f915d1517855c43adc3d4350 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Thu, 14 Jan 2021 13:03:50 +0530 Subject: [PATCH 0911/1140] Hide/Show searchBar on channel list scroll Signed-off-by: Sahil Kumar --- example/lib/main.dart | 247 +++++++++++++++++++++--------------------- 1 file changed, 123 insertions(+), 124 deletions(-) diff --git a/example/lib/main.dart b/example/lib/main.dart index 7b2f578a..2c2c5bab 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -457,133 +457,132 @@ class _ChannelListPageState extends State { }, child: ChannelsBloc( child: MessageSearchBloc( - child: Column( - children: [ - SearchTextField( - controller: _controller, - showCloseButton: _isSearchActive, - ), - Expanded( - child: AnimatedSwitcher( - duration: const Duration(milliseconds: 350), - child: GestureDetector( - behavior: HitTestBehavior.opaque, - onPanDown: (_) => FocusScope.of(context).unfocus(), - child: _isSearchActive - ? MessageSearchListView( - messageQuery: _channelQuery, - filters: { - 'members': { - r'$in': [user.id] - } - }, - sortOptions: [ - SortOption( - 'created_at', - direction: SortOption.ASC, - ), - ], - pullToRefresh: false, - paginationParams: PaginationParams(limit: 20), - emptyBuilder: (_, query) { - return LayoutBuilder( - builder: (context, viewportConstraints) { - return SingleChildScrollView( - physics: AlwaysScrollableScrollPhysics(), - child: ConstrainedBox( - constraints: BoxConstraints( - minHeight: - viewportConstraints.maxHeight, - ), - child: Center( - child: Column( - children: [ - Padding( - padding: const EdgeInsets.all(24), - child: StreamSvgIcon.search( - size: 96, - color: Colors.grey, - ), - ), - Text( - 'No results for \"$query\"...', - ), - ], - ), - ), - ), - ); - }, - ); - }, - onItemTap: (messageResponse) async { - final client = StreamChat.of(context).client; - final message = messageResponse.message; - final channel = client.channel( - messageResponse.channel.type, - id: messageResponse.channel.id, - ); - if (channel.state == null) { - await channel.watch(); - } - Navigator.pushNamed( - context, - Routes.CHANNEL_PAGE, - arguments: ChannelPageArgs( - channel: channel, - initialMessage: message, - ), - ); - }, - ) - : ChannelListView( - onStartChatPressed: () { - Navigator.pushNamed(context, Routes.NEW_CHAT); - }, - swipeToAction: true, - filter: { - 'members': { - r'$in': [user.id], - }, - }, - options: { - 'presence': true, - }, - pagination: PaginationParams( - limit: 20, - ), - channelWidget: ChannelPage(), - onViewInfoTap: (channel) { - if (channel.memberCount == 2 && - channel.isDistinct) { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => StreamChannel( - channel: channel, - child: ChatInfoScreen( - user: channel.state.members.first.user, - ), - ), - ), - ); - } else { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => StreamChannel( - channel: channel, - child: GroupInfoScreen(), - ), - ), - ); - } - }, - ), - ), + child: NestedScrollView( + floatHeaderSlivers: true, + headerSliverBuilder: (_, __) => [ + SliverToBoxAdapter( + child: SearchTextField( + controller: _controller, + showCloseButton: _isSearchActive, ), ), ], + body: AnimatedSwitcher( + duration: const Duration(milliseconds: 350), + child: GestureDetector( + behavior: HitTestBehavior.opaque, + onPanDown: (_) => FocusScope.of(context).unfocus(), + child: _isSearchActive + ? MessageSearchListView( + messageQuery: _channelQuery, + filters: { + 'members': { + r'$in': [user.id] + } + }, + sortOptions: [ + SortOption( + 'created_at', + direction: SortOption.ASC, + ), + ], + pullToRefresh: false, + paginationParams: PaginationParams(limit: 20), + emptyBuilder: (_, query) { + return LayoutBuilder( + builder: (context, viewportConstraints) { + return SingleChildScrollView( + physics: AlwaysScrollableScrollPhysics(), + child: ConstrainedBox( + constraints: BoxConstraints( + minHeight: viewportConstraints.maxHeight, + ), + child: Center( + child: Column( + children: [ + Padding( + padding: const EdgeInsets.all(24), + child: StreamSvgIcon.search( + size: 96, + color: Colors.grey, + ), + ), + Text( + 'No results for \"$query\"...', + ), + ], + ), + ), + ), + ); + }, + ); + }, + onItemTap: (messageResponse) async { + final client = StreamChat.of(context).client; + final message = messageResponse.message; + final channel = client.channel( + messageResponse.channel.type, + id: messageResponse.channel.id, + ); + if (channel.state == null) { + await channel.watch(); + } + Navigator.pushNamed( + context, + Routes.CHANNEL_PAGE, + arguments: ChannelPageArgs( + channel: channel, + initialMessage: message, + ), + ); + }, + ) + : ChannelListView( + onStartChatPressed: () { + Navigator.pushNamed(context, Routes.NEW_CHAT); + }, + swipeToAction: true, + filter: { + 'members': { + r'$in': [user.id], + }, + }, + options: { + 'presence': true, + }, + pagination: PaginationParams( + limit: 20, + ), + channelWidget: ChannelPage(), + onViewInfoTap: (channel) { + if (channel.memberCount == 2 && channel.isDistinct) { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => StreamChannel( + channel: channel, + child: ChatInfoScreen( + user: channel.state.members.first.user, + ), + ), + ), + ); + } else { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => StreamChannel( + channel: channel, + child: GroupInfoScreen(), + ), + ), + ); + } + }, + ), + ), + ), ), ), ), From 5b5b0e56a8b6886c2b624897ad7ced15092c23a6 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Thu, 14 Jan 2021 13:40:02 +0530 Subject: [PATCH 0912/1140] fix: fixed media loading bug --- lib/src/channel_media_display_screen.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/channel_media_display_screen.dart b/lib/src/channel_media_display_screen.dart index ebc95516..8b69fac8 100644 --- a/lib/src/channel_media_display_screen.dart +++ b/lib/src/channel_media_display_screen.dart @@ -156,7 +156,7 @@ class _ChannelMediaDisplayScreenState extends State { } return LazyLoadScrollView( - onEndOfPage: () => messageSearchBloc.search( + onEndOfPage: () => messageSearchBloc.loadMore( filter: { 'cid': { r'$in': ['messaging:${StreamChannel.of(context).channel.id}'] From 7874b91f2aec55b4a3c6db4c83fa1fd98993d9f2 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Thu, 14 Jan 2021 15:11:51 +0530 Subject: [PATCH 0913/1140] fix: fixed media loading --- lib/src/channel_file_display_screen.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/channel_file_display_screen.dart b/lib/src/channel_file_display_screen.dart index 6feac224..c6132609 100644 --- a/lib/src/channel_file_display_screen.dart +++ b/lib/src/channel_file_display_screen.dart @@ -142,7 +142,7 @@ class _ChannelFileDisplayScreenState extends State { } return LazyLoadScrollView( - onEndOfPage: () => messageSearchBloc.search( + onEndOfPage: () => messageSearchBloc.loadMore( filter: { 'cid': { r'$in': ['messaging:${StreamChannel.of(context).channel.id}'] From 188cd17468bd7e2fb68411216347801570695740 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Thu, 14 Jan 2021 15:13:40 +0530 Subject: [PATCH 0914/1140] [ImageFooter] Add border and boxshadow to media user avatar Signed-off-by: Sahil Kumar --- lib/src/image_footer.dart | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/lib/src/image_footer.dart b/lib/src/image_footer.dart index 9daf9a5c..6ff3e8c8 100644 --- a/lib/src/image_footer.dart +++ b/lib/src/image_footer.dart @@ -262,16 +262,28 @@ class _ImageFooterState extends State { media, Padding( padding: EdgeInsets.all(8.0), - child: Align( - alignment: Alignment.topLeft, + child: Container( + clipBehavior: Clip.antiAlias, + decoration: BoxDecoration( + shape: BoxShape.circle, + color: StreamChatTheme.of(context) + .colorTheme + .white + .withOpacity(0.6), + boxShadow: [ + BoxShadow( + blurRadius: 8.0, + color: StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(0.3), + ), + ], + ), + padding: const EdgeInsets.all(1), child: UserAvatar( user: widget.message.user, - constraints: BoxConstraints.tight( - Size( - 24, - 24, - ), - ), + constraints: BoxConstraints.tight(Size(24, 24)), showOnlineStatus: false, ), ), From 21dd08bcc536902cc85de1fbe3ba03290dda71ed Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Thu, 14 Jan 2021 10:43:41 +0100 Subject: [PATCH 0915/1140] fix colorscheme --- lib/src/stream_chat_theme.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/src/stream_chat_theme.dart b/lib/src/stream_chat_theme.dart index 70845ba9..f9c81be7 100644 --- a/lib/src/stream_chat_theme.dart +++ b/lib/src/stream_chat_theme.dart @@ -491,9 +491,9 @@ class ColorTheme { stops: [0, 1], ), this.borderTop = const Effect( - sigmaX: 0, sigmaY: -1, color: Color(0xff141924), blur: 0.0), + sigmaX: 0, sigmaY: -1, color: Color(0xff000000), blur: 0.0), this.borderBottom = - const Effect(sigmaX: 0, sigmaY: 1, color: Color(0xff141924), blur: 0.0), + const Effect(sigmaX: 0, sigmaY: 1, color: Color(0xff000000), blur: 0.0), this.shadowIconButton = const Effect( sigmaX: 0, sigmaY: 2, color: Color(0xff000000), alpha: 0.5, blur: 4.0), this.modalShadow = const Effect( From d4201a09b8b43855bce8d1f6ed5518a4c73d6ff5 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Thu, 14 Jan 2021 11:02:00 +0100 Subject: [PATCH 0916/1140] update te dependencies --- example/pubspec.yaml | 2 +- pubspec.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 941d8bcd..a1975f82 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -1,6 +1,6 @@ name: example description: A new Flutter project. -version: 1.1.1+2 +version: 1.1.1+3 environment: sdk: ">=2.2.2 <3.0.0" diff --git a/pubspec.yaml b/pubspec.yaml index 9ef7a80a..09ddc61c 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -28,7 +28,7 @@ dependencies: file_picker: ^2.0.12 image_picker: ^0.6.7+2 flutter_keyboard_visibility: ^4.0.2 - stream_chat: ^0.2.23+2 + stream_chat: ^0.2.23+3 mime: ^0.9.6+3 video_compress: ^2.1.1 visibility_detector: ^0.1.5 From be282bfc57eb3ae9072d8e5c37fab4939be9c180 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Thu, 14 Jan 2021 11:08:04 +0100 Subject: [PATCH 0917/1140] fix android build --- example/android/app/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/example/android/app/build.gradle b/example/android/app/build.gradle index c5ff1b9e..c90beca2 100644 --- a/example/android/app/build.gradle +++ b/example/android/app/build.gradle @@ -27,7 +27,7 @@ apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" android { compileSdkVersion 29 - ndkVersion '21.3.6528147' + ndkVersion '22.0.7026061' sourceSets { main.java.srcDirs += 'src/main/kotlin' From be75bf3fb3ca6726fea379e9906ee9a82e12d249 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Thu, 14 Jan 2021 12:24:16 +0100 Subject: [PATCH 0918/1140] update llc repo --- packages/dart_client/CHANGELOG.md | 9 +++++++ packages/dart_client/example/pubspec.yaml | 18 ++++++------- packages/dart_client/lib/src/api/channel.dart | 2 ++ packages/dart_client/lib/src/client.dart | 19 +++++++++++--- packages/dart_client/lib/version.dart | 2 +- packages/dart_client/pubspec.yaml | 26 +++++++++---------- 6 files changed, 50 insertions(+), 26 deletions(-) diff --git a/packages/dart_client/CHANGELOG.md b/packages/dart_client/CHANGELOG.md index a570a254..dbab1dcb 100644 --- a/packages/dart_client/CHANGELOG.md +++ b/packages/dart_client/CHANGELOG.md @@ -1,3 +1,12 @@ +## 0.2.23+3 + +- Remove + notation from userAgent +- Fix optimistic update for totalUnreadCount + +## 0.2.23+2 + +- Do not throw an error when calling queryChannels without an active connection if the offline storage is enabled + ## 0.2.23+1 - Throw an error when calling queryChannels without an active connection diff --git a/packages/dart_client/example/pubspec.yaml b/packages/dart_client/example/pubspec.yaml index f8733ee5..59a8bb96 100644 --- a/packages/dart_client/example/pubspec.yaml +++ b/packages/dart_client/example/pubspec.yaml @@ -9,16 +9,16 @@ environment: dependencies: flutter: sdk: flutter - flutter_widgets: ^0.1.12 - timeago: ^2.0.29 + flutter_widgets: ^0.1.11 + timeago: ^2.0.26 jiffy: ^3.0.1 - date_format: ^1.0.9 - cached_network_image: ^2.5.0 - flutter_markdown: ^0.5.2 - url_launcher: ^5.7.10 - video_player: ^1.0.1 - chewie: ^0.12.1+1 - animations: ^1.1.2 + date_format: ^1.0.8 + cached_network_image: ^2.0.0 + flutter_markdown: ^0.3.4 + url_launcher: ^5.4.2 + video_player: ^0.10.8+1 + chewie: ^0.9.10 + animations: ^1.0.0+5 stream_chat: path: ../ diff --git a/packages/dart_client/lib/src/api/channel.dart b/packages/dart_client/lib/src/api/channel.dart index 5a0dcbfa..abe31984 100644 --- a/packages/dart_client/lib/src/api/channel.dart +++ b/packages/dart_client/lib/src/api/channel.dart @@ -428,6 +428,8 @@ class Channel { /// Mark all channel messages as read Future markRead() async { _checkInitialized(); + client.state.totalUnreadCount = + max(0, (client.state.totalUnreadCount ?? 0) - (state.unreadCount ?? 0)); state._unreadCountController.add(0); final response = await _client.post('$_channelURL/read', data: {}); return _client.decode(response.data, EmptyResponse.fromJson); diff --git a/packages/dart_client/lib/src/client.dart b/packages/dart_client/lib/src/client.dart index 0952447a..4e0743ff 100644 --- a/packages/dart_client/lib/src/client.dart +++ b/packages/dart_client/lib/src/client.dart @@ -565,8 +565,15 @@ class Client { await _connectCompleter.future; } if (wsConnectionStatus.value != ConnectionStatus.connected) { - throw Exception( - 'You cannot use queryChannels without an active connection. Call setUser to connect the client.'); + final errorMessage = + 'You cannot use queryChannels without an active connection. Please call setUser to connect the client.'; + if (persistenceEnabled) { + logger.warning( + '$errorMessage\nTrying to retrieve channels from the offline storage.'); + onlyOffline = true; + } else { + throw Exception(errorMessage); + } } } @@ -843,7 +850,8 @@ class Client { String get _authType => _anonymous ? 'anonymous' : 'jwt'; // TODO: get the right version of the lib from the build toolchain - String get _userAgent => 'stream-chat-dart-client-$PACKAGE_VERSION'; + String get _userAgent => + 'stream-chat-dart-client-${PACKAGE_VERSION.split('+')[0]}'; Map get _commonQueryParams => { 'user_id': state.user?.id, @@ -1281,6 +1289,11 @@ class ClientState { _listenUserUpdated(); } + /// Used internally for optimistic update of unread count + set totalUnreadCount(int unreadCount) { + _totalUnreadCountController?.add(unreadCount ?? 0); + } + void _listenChannelHidden() { _subscriptions.add(_client.on(EventType.channelHidden).listen((event) { _client._offlineStorage?.deleteChannels([event.cid]); diff --git a/packages/dart_client/lib/version.dart b/packages/dart_client/lib/version.dart index 75bf93d6..4650f5b2 100644 --- a/packages/dart_client/lib/version.dart +++ b/packages/dart_client/lib/version.dart @@ -2,4 +2,4 @@ import 'package:stream_chat/src/client.dart'; /// Current package version /// Used in [Client] to build the `x-stream-client` header -const PACKAGE_VERSION = '0.2.23+1'; +const PACKAGE_VERSION = '0.2.23+3'; diff --git a/packages/dart_client/pubspec.yaml b/packages/dart_client/pubspec.yaml index 31c4d555..924c1ed4 100644 --- a/packages/dart_client/pubspec.yaml +++ b/packages/dart_client/pubspec.yaml @@ -1,7 +1,7 @@ name: stream_chat homepage: https://getstream.io/ description: The official Dart client for Stream Chat, a service for building chat applications. -version: 0.2.23+1 +version: 0.2.23+3 repository: https://github.com/GetStream/stream-chat-dart issue_tracker: https://github.com/GetStream/stream-chat-dart/issues @@ -11,26 +11,26 @@ environment: dependencies: flutter: sdk: flutter - json_annotation: ^3.1.1 - shared_preferences: ^0.5.12+4 + json_annotation: ^3.0.1 + shared_preferences: ^0.5.7+3 logging: ^0.11.4 dio: ^3.0.10 web_socket_channel: ^1.1.0 uuid: ^2.2.2 - async: ^2.4.2 + async: ^2.4.1 stream_channel: ^2.0.0 - moor: ^3.4.0 - path_provider: ^1.6.24 - path: ^1.7.0 + moor: ^3.3.1 + path_provider: ^1.6.10 + path: ^1.6.4 rxdart: ^0.24.1 - collection: ^1.14.13 + collection: ^1.14.12 sqlite3_flutter_libs: ^0.3.0 dev_dependencies: - build_runner: ^1.10.11 - json_serializable: ^3.5.1 - moor_generator: ^3.4.0 + build_runner: ^1.10.0 + json_serializable: ^3.3.0 + moor_generator: ^3.1.0 flutter_test: sdk: flutter - pedantic: ^1.9.2 - mockito: ^4.1.3 + pedantic: ^1.8.0+1 + mockito: ^4.1.1 From d5062ee8aacd3eedc2cb90c0c7dd970544b61ef2 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Thu, 14 Jan 2021 17:00:15 +0530 Subject: [PATCH 0919/1140] fix: fixed channel separator --- lib/src/channel_list_view.dart | 14 ++++---------- lib/src/stream_chat_theme.dart | 8 ++++---- 2 files changed, 8 insertions(+), 14 deletions(-) diff --git a/lib/src/channel_list_view.dart b/lib/src/channel_list_view.dart index 1ab10934..2de00c0e 100644 --- a/lib/src/channel_list_view.dart +++ b/lib/src/channel_list_view.dart @@ -729,17 +729,11 @@ class _ChannelListViewState extends State } Widget _separatorBuilder(context, i) { - var effect = StreamChatTheme.of(context).colorTheme.borderTop; + var effect = StreamChatTheme.of(context).colorTheme.borderBottom; - return BackdropFilter( - filter: ui.ImageFilter.blur( - sigmaX: effect.sigmaX, - sigmaY: effect.sigmaY, - ), - child: Container( - height: 1, - color: effect.color.withOpacity(0.08), - ), + return Container( + height: 1, + color: effect.color.withOpacity(effect.alpha ?? 1.0), ); } diff --git a/lib/src/stream_chat_theme.dart b/lib/src/stream_chat_theme.dart index f9c81be7..8230ba5c 100644 --- a/lib/src/stream_chat_theme.dart +++ b/lib/src/stream_chat_theme.dart @@ -492,8 +492,8 @@ class ColorTheme { ), this.borderTop = const Effect( sigmaX: 0, sigmaY: -1, color: Color(0xff000000), blur: 0.0), - this.borderBottom = - const Effect(sigmaX: 0, sigmaY: 1, color: Color(0xff000000), blur: 0.0), + this.borderBottom = const Effect( + sigmaX: 0, sigmaY: 1, color: Color(0xff000000), blur: 0.0, alpha: 0.08), this.shadowIconButton = const Effect( sigmaX: 0, sigmaY: 2, color: Color(0xff000000), alpha: 0.5, blur: 4.0), this.modalShadow = const Effect( @@ -514,8 +514,8 @@ class ColorTheme { this.accentGreen = const Color(0xff20E070), this.borderTop = const Effect( sigmaX: 0, sigmaY: -1, color: Color(0xff141924), blur: 0.0), - this.borderBottom = - const Effect(sigmaX: 0, sigmaY: 1, color: Color(0xff141924), blur: 0.0), + this.borderBottom = const Effect( + sigmaX: 0, sigmaY: 1, color: Color(0xff141924), blur: 0.0, alpha: 1.0), this.shadowIconButton = const Effect( sigmaX: 0, sigmaY: 2, color: Color(0xff000000), alpha: 0.5, blur: 4.0), this.modalShadow = const Effect( From 2e31ed077b406e1e7b75df38f6e421f5afbca1e2 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Thu, 14 Jan 2021 17:15:10 +0530 Subject: [PATCH 0920/1140] [ImageFooter] Fix photosModalBottomSheet Signed-off-by: Sahil Kumar --- lib/src/image_footer.dart | 235 ++++++++++++++++++++------------------ 1 file changed, 122 insertions(+), 113 deletions(-) diff --git a/lib/src/image_footer.dart b/lib/src/image_footer.dart index 6ff3e8c8..7778ede8 100644 --- a/lib/src/image_footer.dart +++ b/lib/src/image_footer.dart @@ -174,129 +174,138 @@ class _ImageFooterState extends State { showModalBottomSheet( context: context, barrierColor: StreamChatTheme.of(context).colorTheme.overlay, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(16.0), + backgroundColor: StreamChatTheme.of(context).colorTheme.white, + isScrollControlled: true, + shape: const RoundedRectangleBorder( + borderRadius: const BorderRadius.only( + topLeft: const Radius.circular(16.0), + topRight: const Radius.circular(16.0), + ), ), builder: (context) { - return Column( - mainAxisSize: MainAxisSize.min, - children: [ - Container( - decoration: BoxDecoration( - color: StreamChatTheme.of(context).colorTheme.white, - borderRadius: BorderRadius.only( - topRight: Radius.circular(16.0), - topLeft: Radius.circular(16.0), - )), - child: Stack( + final crossAxisCount = 3; + final noOfRowToShowInitially = + widget.mediaAttachments.length > 3 ? 2 : 1; + final size = MediaQuery.of(context).size; + final initialChildSize = + 48 + (size.width * noOfRowToShowInitially) / crossAxisCount; + return DraggableScrollableSheet( + expand: false, + initialChildSize: initialChildSize / size.height, + builder: (context, scrollController) { + return SingleChildScrollView( + controller: scrollController, + child: Column( + mainAxisSize: MainAxisSize.min, children: [ - Center( - child: Padding( - padding: const EdgeInsets.all(16.0), - child: Text( - 'Photos', - style: - StreamChatTheme.of(context).textTheme.headlineBold, + Stack( + children: [ + Center( + child: Padding( + padding: const EdgeInsets.all(16.0), + child: Text( + 'Photos', + style: StreamChatTheme.of(context) + .textTheme + .headlineBold, + ), + ), ), - ), + Align( + alignment: Alignment.centerRight, + child: IconButton( + icon: StreamSvgIcon.close( + color: StreamChatTheme.of(context).colorTheme.black, + ), + onPressed: () => Navigator.maybePop(context), + ), + ), + ], ), - Align( - alignment: Alignment.centerRight, - child: IconButton( - icon: StreamSvgIcon.close( - color: StreamChatTheme.of(context).colorTheme.black, + Flexible( + child: GridView.builder( + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), + itemCount: widget.mediaAttachments.length, + padding: const EdgeInsets.all(1), + gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: crossAxisCount, + mainAxisSpacing: 2.0, + crossAxisSpacing: 2.0, ), - onPressed: () => Navigator.maybePop(context), + itemBuilder: (context, index) { + Widget media; + final attachment = widget.mediaAttachments[index]; + + if (attachment.type == 'video') { + var controllerPackage = widget.videoPackages[ + videoAttachments.indexOf(attachment)]; + + media = InkWell( + onTap: () => widget.mediaSelectedCallBack(index), + child: FittedBox( + fit: BoxFit.cover, + child: Chewie( + controller: controllerPackage.chewieController, + ), + ), + ); + } else { + media = InkWell( + onTap: () => widget.mediaSelectedCallBack(index), + child: AspectRatio( + child: CachedNetworkImage( + imageUrl: attachment.imageUrl ?? + attachment.assetUrl ?? + attachment.thumbUrl, + fit: BoxFit.cover, + ), + aspectRatio: 1.0, + ), + ); + } + + return Stack( + children: [ + media, + Padding( + padding: EdgeInsets.all(8.0), + child: Container( + clipBehavior: Clip.antiAlias, + decoration: BoxDecoration( + shape: BoxShape.circle, + color: StreamChatTheme.of(context) + .colorTheme + .white + .withOpacity(0.6), + boxShadow: [ + BoxShadow( + blurRadius: 8.0, + color: StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(0.3), + ), + ], + ), + padding: const EdgeInsets.all(1), + child: UserAvatar( + user: widget.message.user, + constraints: + BoxConstraints.tight(Size(24, 24)), + showOnlineStatus: false, + ), + ), + ), + ], + ); + }, ), ), ], ), - ), - Container( - color: StreamChatTheme.of(context).colorTheme.white, - child: GridView.builder( - shrinkWrap: true, - physics: NeverScrollableScrollPhysics(), - itemBuilder: (context, position) { - Widget media; - - if (widget.mediaAttachments[position].type == 'video') { - var controllerPackage = widget.videoPackages[ - videoAttachments - .indexOf(widget.mediaAttachments[position])]; - - media = InkWell( - onTap: () { - widget.mediaSelectedCallBack(position); - }, - child: FittedBox( - fit: BoxFit.cover, - child: Chewie( - controller: controllerPackage.chewieController, - ), - ), - ); - } else { - media = InkWell( - onTap: () { - widget.mediaSelectedCallBack(position); - }, - child: Padding( - padding: const EdgeInsets.all(1.0), - child: AspectRatio( - child: CachedNetworkImage( - imageUrl: widget - .mediaAttachments[position].imageUrl ?? - widget.mediaAttachments[position].assetUrl ?? - widget.mediaAttachments[position].thumbUrl, - fit: BoxFit.cover, - ), - aspectRatio: 1.0, - ), - ), - ); - } - - return Stack( - children: [ - media, - Padding( - padding: EdgeInsets.all(8.0), - child: Container( - clipBehavior: Clip.antiAlias, - decoration: BoxDecoration( - shape: BoxShape.circle, - color: StreamChatTheme.of(context) - .colorTheme - .white - .withOpacity(0.6), - boxShadow: [ - BoxShadow( - blurRadius: 8.0, - color: StreamChatTheme.of(context) - .colorTheme - .black - .withOpacity(0.3), - ), - ], - ), - padding: const EdgeInsets.all(1), - child: UserAvatar( - user: widget.message.user, - constraints: BoxConstraints.tight(Size(24, 24)), - showOnlineStatus: false, - ), - ), - ), - ], - ); - }, - itemCount: widget.mediaAttachments.length, - gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( - crossAxisCount: 3), - ), - ), - ], + ); + }, ); }, ); From 1f0ac3efbfda14027c014527e1dcdcbe2e28e11b Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Thu, 14 Jan 2021 12:51:27 +0100 Subject: [PATCH 0921/1140] update sample app version --- example/pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/example/pubspec.yaml b/example/pubspec.yaml index a1975f82..665c015c 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -1,6 +1,6 @@ name: example description: A new Flutter project. -version: 1.1.1+3 +version: 1.1.1+4 environment: sdk: ">=2.2.2 <3.0.0" From 4e6fbc8d2ee0daed973d0ba71c6aa48f776b8b68 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Fri, 15 Jan 2021 13:29:28 +0530 Subject: [PATCH 0922/1140] [MessageWidget] Separate our default messageShape and attachmentShape Signed-off-by: Sahil Kumar --- lib/src/message_actions_modal.dart | 3 ++ lib/src/message_reactions_modal.dart | 3 ++ lib/src/message_widget.dart | 80 ++++++++++++++-------------- 3 files changed, 47 insertions(+), 39 deletions(-) diff --git a/lib/src/message_actions_modal.dart b/lib/src/message_actions_modal.dart index 9b93695e..2f4e0f8b 100644 --- a/lib/src/message_actions_modal.dart +++ b/lib/src/message_actions_modal.dart @@ -32,6 +32,7 @@ class MessageActionsModal extends StatefulWidget { final bool showFlagButton; final bool reverse; final ShapeBorder messageShape; + final ShapeBorder attachmentShape; final DisplayWidget showUserAvatar; const MessageActionsModal({ @@ -51,6 +52,7 @@ class MessageActionsModal extends StatefulWidget { this.showUserAvatar = DisplayWidget.show, this.editMessageInputBuilder, this.messageShape, + this.attachmentShape, this.reverse = false, }) : super(key: key); @@ -173,6 +175,7 @@ class _MessageActionsModalState extends State { showInChannelIndicator: false, showSendingIndicator: false, shape: widget.messageShape, + attachmentShape: widget.attachmentShape, ), ), SizedBox(height: 8), diff --git a/lib/src/message_reactions_modal.dart b/lib/src/message_reactions_modal.dart index c96b3afa..e09e21db 100644 --- a/lib/src/message_reactions_modal.dart +++ b/lib/src/message_reactions_modal.dart @@ -20,6 +20,7 @@ class MessageReactionsModal extends StatelessWidget { final bool showReactions; final DisplayWidget showUserAvatar; final ShapeBorder messageShape; + final ShapeBorder attachmentShape; final void Function(User) onUserAvatarTap; const MessageReactionsModal({ @@ -30,6 +31,7 @@ class MessageReactionsModal extends StatelessWidget { this.onThreadTap, this.editMessageInputBuilder, this.messageShape, + this.attachmentShape, this.reverse = false, this.showUserAvatar = DisplayWidget.show, this.onUserAvatarTap, @@ -127,6 +129,7 @@ class MessageReactionsModal extends StatelessWidget { translateUserAvatar: false, showSendingIndicator: false, shape: messageShape, + attachmentShape: attachmentShape, padding: const EdgeInsets.all(0), attachmentPadding: EdgeInsets.all( hasFileAttachment ? 4 : 2, diff --git a/lib/src/message_widget.dart b/lib/src/message_widget.dart index 070bdad5..bec93cc1 100644 --- a/lib/src/message_widget.dart +++ b/lib/src/message_widget.dart @@ -295,10 +295,6 @@ class _MessageWidgetState extends State { var leftPadding = widget.showUserAvatar != DisplayWidget.gone ? avatarWidth + 8.5 : 0.5; - final hasFiles = - widget.message.attachments?.any((element) => element.type == 'file') == - true; - return Material( type: MaterialType.transparency, child: Portal( @@ -406,29 +402,19 @@ class _MessageWidgetState extends State { BorderRadius.zero, ), color: _getBackgroundColor(), - child: Padding( - padding: EdgeInsets.all( - hasFiles ? 2.0 : 0.0), - child: Column( - crossAxisAlignment: - CrossAxisAlignment - .end, - mainAxisSize: - MainAxisSize.min, - children: [ - if (hasQuotedMessage) - _buildQuotedMessage(), - if (hasNonUrlAttachments) - _parseAttachments( - context), - if (widget.message.text - .trim() - .isNotEmpty && - !isGiphy) - _buildTextBubble( - context), - ], - ), + child: Column( + crossAxisAlignment: + CrossAxisAlignment.end, + mainAxisSize: + MainAxisSize.min, + children: [ + if (hasQuotedMessage) + _buildQuotedMessage(), + if (hasNonUrlAttachments) + _parseAttachments(), + if (!isGiphy) + _buildTextBubble(), + ], ), ), ), @@ -718,6 +704,8 @@ class _MessageWidgetState extends State { : DisplayWidget.show, messageTheme: widget.messageTheme, messageShape: widget.shape ?? _getDefaultShape(context), + attachmentShape: + widget.attachmentShape ?? _getDefaultAttachmentShape(context), reverse: widget.reverse, showDeleteMessage: widget.showDeleteMessage || isDeleteFailed, message: widget.message, @@ -763,6 +751,8 @@ class _MessageWidgetState extends State { onUserAvatarTap: widget.onUserAvatarTap, messageTheme: widget.messageTheme, messageShape: widget.shape ?? _getDefaultShape(context), + attachmentShape: + widget.attachmentShape ?? _getDefaultAttachmentShape(context), reverse: widget.reverse, message: widget.message, editMessageInputBuilder: widget.editMessageInputBuilder, @@ -773,20 +763,31 @@ class _MessageWidgetState extends State { }); } - ShapeBorder _getDefaultShape(BuildContext context) { + ShapeBorder _getDefaultAttachmentShape(BuildContext context) { + final hasFiles = + widget.message.attachments?.any((it) => it.type == 'file') == true; return RoundedRectangleBorder( - side: widget.attachmentBorderSide ?? - widget.borderSide ?? - BorderSide( - color: StreamChatTheme.of(context).colorTheme.greyWhisper, - ), - borderRadius: widget.attachmentBorderRadiusGeometry ?? - widget.borderRadiusGeometry ?? - BorderRadius.zero, + side: hasFiles + ? widget.attachmentBorderSide ?? + BorderSide( + color: StreamChatTheme.of(context).colorTheme.greyWhisper, + ) + : BorderSide.none, + borderRadius: widget.attachmentBorderRadiusGeometry ?? BorderRadius.zero, ); } - Widget _parseAttachments(BuildContext context) { + ShapeBorder _getDefaultShape(BuildContext context) { + return RoundedRectangleBorder( + side: widget.borderSide ?? + BorderSide( + color: StreamChatTheme.of(context).colorTheme.greyWhisper, + ), + borderRadius: widget.borderRadiusGeometry ?? BorderRadius.zero, + ); + } + + Widget _parseAttachments() { final images = widget.message.attachments ?.where((element) => element.type == 'image' && element.ogScrapeUrl == null) @@ -849,7 +850,7 @@ class _MessageWidgetState extends State { Attachment attachment, }) { final attachmentShape = - widget.attachmentShape ?? widget.shape ?? _getDefaultShape(context); + widget.attachmentShape ?? _getDefaultAttachmentShape(context); return Material( clipBehavior: Clip.antiAlias, shape: attachmentShape, @@ -920,7 +921,8 @@ class _MessageWidgetState extends State { ), ); - Widget _buildTextBubble(BuildContext context) { + Widget _buildTextBubble() { + if (widget.message.text.trim().isNotEmpty) return Offstage(); return Transform( transform: Matrix4.rotationY(widget.reverse ? pi : 0), alignment: Alignment.center, From fdb56992c11836d2c4bbfcb9914e639353ce62e2 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Fri, 15 Jan 2021 13:35:08 +0530 Subject: [PATCH 0923/1140] [MessageWidget] Minor condition fix 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 bec93cc1..fb436e5b 100644 --- a/lib/src/message_widget.dart +++ b/lib/src/message_widget.dart @@ -922,7 +922,7 @@ class _MessageWidgetState extends State { ); Widget _buildTextBubble() { - if (widget.message.text.trim().isNotEmpty) return Offstage(); + if (widget.message.text.trim().isEmpty) return Offstage(); return Transform( transform: Matrix4.rotationY(widget.reverse ? pi : 0), alignment: Alignment.center, From 6fac5c9dd1cc6b4343ec8f0346baf8ee313c6f34 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Fri, 15 Jan 2021 13:49:09 +0530 Subject: [PATCH 0924/1140] [UserListView] Fix indicatorConstraints for grid user item Signed-off-by: Sahil Kumar --- lib/src/user_list_view.dart | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/src/user_list_view.dart b/lib/src/user_list_view.dart index ef51ad92..6197a06e 100644 --- a/lib/src/user_list_view.dart +++ b/lib/src/user_list_view.dart @@ -416,6 +416,10 @@ class _UserListViewState extends State height: 64, width: 64, ), + onlineIndicatorConstraints: BoxConstraints.tightFor( + height: 12, + width: 12, + ), onTap: (user) => widget.onUserTap(user, widget.userWidget), onLongPress: widget.onUserLongPress, From 89e17eb2968c454e42dbfd6f9718c56b045f01b9 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Fri, 15 Jan 2021 14:14:42 +0530 Subject: [PATCH 0925/1140] [GroupInfoScreen] Fix search textfield design Signed-off-by: Sahil Kumar --- example/lib/group_info_screen.dart | 88 ++++++++++++++---------------- 1 file changed, 41 insertions(+), 47 deletions(-) diff --git a/example/lib/group_info_screen.dart b/example/lib/group_info_screen.dart index bde4c0df..cac6fc9c 100644 --- a/example/lib/group_info_screen.dart +++ b/example/lib/group_info_screen.dart @@ -612,7 +612,10 @@ class _GroupInfoScreenState extends State { body: UsersBloc( child: Column( children: [ - _buildTextInputSection(modalSetState), + Padding( + padding: const EdgeInsets.all(16), + child: _buildTextInputSection(modalSetState), + ), Expanded( child: UserListView( selectedUsers: {}, @@ -690,66 +693,57 @@ class _GroupInfoScreenState extends State { } Widget _buildTextInputSection(modalSetState) { + final theme = StreamChatTheme.of(context); return Column( children: [ - SizedBox( - height: 16.0, - ), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - SizedBox( - width: 16.0, - ), Expanded( - child: TextField( - controller: _searchController, - cursorColor: StreamChatTheme.of(context).colorTheme.black, - autofocus: true, - decoration: InputDecoration( - isDense: true, - prefixIconConstraints: BoxConstraints.tight(Size(36.0, 44.0)), - prefixIcon: Padding( - padding: const EdgeInsets.symmetric( - vertical: 2.0, horizontal: 6.0), - child: StreamSvgIcon.search( - color: StreamChatTheme.of(context).colorTheme.black, + child: Container( + height: 36, + child: TextField( + controller: _searchController, + cursorColor: theme.colorTheme.black, + autofocus: true, + decoration: InputDecoration( + hintText: 'Search', + hintStyle: theme.textTheme.body.copyWith( + color: theme.colorTheme.grey, ), + prefixIconConstraints: BoxConstraints.tight(Size(40, 24)), + prefixIcon: StreamSvgIcon.search( + color: theme.colorTheme.black, + size: 24, + ), + enabledBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(24.0), + borderSide: BorderSide( + color: theme.colorTheme.greyWhisper, + ), + ), + focusedBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(24.0), + borderSide: BorderSide( + color: theme.colorTheme.greyWhisper, + )), + contentPadding: const EdgeInsets.all(0), ), - hintText: 'Search', - border: OutlineInputBorder( - borderRadius: BorderRadius.circular(32.0), - borderSide: BorderSide( - color: StreamChatTheme.of(context) - .colorTheme - .black - .withOpacity(0.08)), - ), - focusedBorder: OutlineInputBorder( - borderRadius: BorderRadius.circular(32.0), - borderSide: BorderSide( - color: StreamChatTheme.of(context) - .colorTheme - .black - .withOpacity(0.08)), - ), - contentPadding: EdgeInsets.zero, ), ), ), - SizedBox( - width: 8.0, - ), + SizedBox(width: 16.0), IconButton( icon: StreamSvgIcon.close_small( - color: StreamChatTheme.of(context) - .colorTheme - .black - .withOpacity(0.5), + color: theme.colorTheme.grey, ), - onPressed: () { - Navigator.pop(context); - }, + constraints: BoxConstraints.tightFor( + height: 24, + width: 24, + ), + padding: EdgeInsets.zero, + splashRadius: 24, + onPressed: () => Navigator.pop(context), ) ], ), From b9d86b3a2707fb210ae02f4abae93e9f7577b4f3 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Fri, 15 Jan 2021 14:20:55 +0530 Subject: [PATCH 0926/1140] :| Signed-off-by: Sahil Kumar --- lib/src/image_footer.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/image_footer.dart b/lib/src/image_footer.dart index 7778ede8..8d4ca8b5 100644 --- a/lib/src/image_footer.dart +++ b/lib/src/image_footer.dart @@ -185,7 +185,7 @@ class _ImageFooterState extends State { builder: (context) { final crossAxisCount = 3; final noOfRowToShowInitially = - widget.mediaAttachments.length > 3 ? 2 : 1; + widget.mediaAttachments.length > crossAxisCount ? 2 : 1; final size = MediaQuery.of(context).size; final initialChildSize = 48 + (size.width * noOfRowToShowInitially) / crossAxisCount; From a83e8680efe86b99ff3fbb66c7f75f779fde3947 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Fri, 15 Jan 2021 11:27:34 +0100 Subject: [PATCH 0927/1140] fix emoji parser --- lib/src/extension.dart | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/lib/src/extension.dart b/lib/src/extension.dart index 3ffd0e24..7e572db5 100644 --- a/lib/src/extension.dart +++ b/lib/src/extension.dart @@ -15,12 +15,14 @@ extension StringExtension on String { final characters = this.trim().characters; if (characters.isEmpty) return false; if (characters.length > 3) return false; + final regExp = RegExp('[0-9]'); return characters.every((c) { - return _emojis.firstWhere( - (Emoji emoji) => emoji.char.contains(c), - orElse: () => null, - ) != - null; + return !regExp.hasMatch(c) && + _emojis.firstWhere( + (Emoji emoji) => emoji.char.contains(c), + orElse: () => null, + ) != + null; }); } } From 006b3e21c3d8188801bf9e680f848cfb6d2302ec Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Fri, 15 Jan 2021 16:06:36 +0530 Subject: [PATCH 0928/1140] [Extension] Improve isOnlyEmoji digitRecognizer function Signed-off-by: Sahil Kumar --- lib/src/extension.dart | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/lib/src/extension.dart b/lib/src/extension.dart index 7e572db5..5a26d515 100644 --- a/lib/src/extension.dart +++ b/lib/src/extension.dart @@ -3,6 +3,9 @@ import 'package:characters/characters.dart'; final _emojis = Emoji.all(); +//https://pub.dev/documentation/quiver/latest/quiver.strings/isDigit.html +bool isDigit(int rune) => rune ^ 0x30 <= 9; + extension StringExtension on String { String capitalize() { return "${this[0].toUpperCase()}${this.substring(1)}"; @@ -15,14 +18,14 @@ extension StringExtension on String { final characters = this.trim().characters; if (characters.isEmpty) return false; if (characters.length > 3) return false; - final regExp = RegExp('[0-9]'); + final containsDigits = characters.any((c) => isDigit(c.runes.first)); + if (containsDigits) return false; return characters.every((c) { - return !regExp.hasMatch(c) && - _emojis.firstWhere( - (Emoji emoji) => emoji.char.contains(c), - orElse: () => null, - ) != - null; + return _emojis.firstWhere( + (Emoji emoji) => emoji.char.contains(c), + orElse: () => null, + ) != + null; }); } } From 67753a06c527caee4048d6d3410975bc4d07712b Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Fri, 15 Jan 2021 16:08:38 +0530 Subject: [PATCH 0929/1140] [MessageWidget] Show only max 2 thread participants Signed-off-by: Sahil Kumar --- lib/src/message_widget.dart | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/src/message_widget.dart b/lib/src/message_widget.dart index fb436e5b..65817823 100644 --- a/lib/src/message_widget.dart +++ b/lib/src/message_widget.dart @@ -522,7 +522,7 @@ class _MessageWidgetState extends State { var children = []; - final threadParticipants = widget.message.threadParticipants; + final threadParticipants = widget.message?.threadParticipants?.take(2); final showThreadParticipants = threadParticipants?.isNotEmpty == true; final replyCount = widget.message.replyCount; @@ -551,7 +551,7 @@ class _MessageWidgetState extends State { if (showThreadParticipants) SizedBox.fromSize( size: Size((threadParticipants.length * 8.0) + 8, 16), - child: _buildThreadParticipantsIndicator(), + child: _buildThreadParticipantsIndicator(threadParticipants), ), InkWell( onTap: widget.onThreadTap != null ? onThreadTap : null, @@ -628,10 +628,10 @@ class _MessageWidgetState extends State { ); } - Widget _buildThreadParticipantsIndicator() { + Widget _buildThreadParticipantsIndicator(Iterable threadParticipants) { var padding = 0.0; return Stack( - children: widget.message.threadParticipants.map((user) { + children: threadParticipants.map((user) { padding += 8.0; return Positioned( right: padding - 8, From e8e55c007389458178f957d3a6a234bccf821f6f Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Fri, 15 Jan 2021 16:12:19 +0530 Subject: [PATCH 0930/1140] [MessageActionsModal] Fix flag action button title Signed-off-by: Sahil Kumar --- lib/src/message_actions_modal.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/message_actions_modal.dart b/lib/src/message_actions_modal.dart index 2f4e0f8b..c45c351d 100644 --- a/lib/src/message_actions_modal.dart +++ b/lib/src/message_actions_modal.dart @@ -464,7 +464,7 @@ class _MessageActionsModalState extends State { ), const SizedBox(width: 16), Text( - 'Flag', + 'Flag Message', style: StreamChatTheme.of(context).textTheme.body, ), ], From 6da45c17017b45ed5ae42343534508924c511349 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Fri, 15 Jan 2021 16:18:47 +0530 Subject: [PATCH 0931/1140] [Extension] Remove unnecessary isDigit check from `isOnlyEmoji` Signed-off-by: Sahil Kumar --- lib/src/extension.dart | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/lib/src/extension.dart b/lib/src/extension.dart index 5a26d515..ad26735a 100644 --- a/lib/src/extension.dart +++ b/lib/src/extension.dart @@ -3,9 +3,6 @@ import 'package:characters/characters.dart'; final _emojis = Emoji.all(); -//https://pub.dev/documentation/quiver/latest/quiver.strings/isDigit.html -bool isDigit(int rune) => rune ^ 0x30 <= 9; - extension StringExtension on String { String capitalize() { return "${this[0].toUpperCase()}${this.substring(1)}"; @@ -18,15 +15,7 @@ extension StringExtension on String { final characters = this.trim().characters; if (characters.isEmpty) return false; if (characters.length > 3) return false; - final containsDigits = characters.any((c) => isDigit(c.runes.first)); - if (containsDigits) return false; - return characters.every((c) { - return _emojis.firstWhere( - (Emoji emoji) => emoji.char.contains(c), - orElse: () => null, - ) != - null; - }); + return characters.every((c) => _emojis.map((e) => e.char).contains(c)); } } From 83e149dab3e1c644ea8d64d5138bdc71779a06ca Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Fri, 15 Jan 2021 11:55:18 +0100 Subject: [PATCH 0932/1140] bump version --- example/pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 665c015c..f508c3a0 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -1,6 +1,6 @@ name: example description: A new Flutter project. -version: 1.1.1+4 +version: 1.1.2 environment: sdk: ">=2.2.2 <3.0.0" From 03038169222574e0ada14cc97e7dd0ac75534ab8 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Fri, 15 Jan 2021 14:54:35 +0100 Subject: [PATCH 0933/1140] update build.yml --- .github/workflows/build.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 48f6df96..10a36b64 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -44,6 +44,10 @@ jobs: build_and_deploy_android: runs-on: ubuntu-latest steps: + - name: Decode google-services.json + env: + FIREBASE_SECRET: ${{ secrets.FIREBASE_SECRET }} + run: echo $FIREBASE_SECRET > example/android/app/google-services.json - uses: actions/checkout@v2 - uses: actions/setup-java@v1 with: From cd99cc6db35fbc634e94d7ef84976a5be819bf76 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Fri, 15 Jan 2021 14:56:20 +0100 Subject: [PATCH 0934/1140] update build.yml --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 10a36b64..ae82e297 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -46,7 +46,7 @@ jobs: steps: - name: Decode google-services.json env: - FIREBASE_SECRET: ${{ secrets.FIREBASE_SECRET }} + FIREBASE_SECRET: ${{ secrets.FIREBASE_SECRET }} run: echo $FIREBASE_SECRET > example/android/app/google-services.json - uses: actions/checkout@v2 - uses: actions/setup-java@v1 From b6122667c83e75becdd86d6818f598365d41d9a5 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Fri, 15 Jan 2021 14:59:58 +0100 Subject: [PATCH 0935/1140] update build.yml --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index ae82e297..ccf112ab 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -47,7 +47,7 @@ jobs: - name: Decode google-services.json env: FIREBASE_SECRET: ${{ secrets.FIREBASE_SECRET }} - run: echo $FIREBASE_SECRET > example/android/app/google-services.json + run: echo $FIREBASE_SECRET > ./example/android/app/google-services.json - uses: actions/checkout@v2 - uses: actions/setup-java@v1 with: From bc42ab078f91c9bc7bdb68f6a3b8f329644e7943 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Fri, 15 Jan 2021 15:12:15 +0100 Subject: [PATCH 0936/1140] update build.yml --- .github/workflows/build.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index ccf112ab..d5d554b7 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -47,7 +47,9 @@ jobs: - name: Decode google-services.json env: FIREBASE_SECRET: ${{ secrets.FIREBASE_SECRET }} - run: echo $FIREBASE_SECRET > ./example/android/app/google-services.json + run: | + pwd + echo $FIREBASE_SECRET > ./example/android/app/google-services.json - uses: actions/checkout@v2 - uses: actions/setup-java@v1 with: From 18531837eb10f08f0b2911d92e0ba1015f68911a Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Fri, 15 Jan 2021 15:21:04 +0100 Subject: [PATCH 0937/1140] update build.yml --- .github/workflows/build.yml | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index d5d554b7..e8e5cfa1 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -44,12 +44,6 @@ jobs: build_and_deploy_android: runs-on: ubuntu-latest steps: - - name: Decode google-services.json - env: - FIREBASE_SECRET: ${{ secrets.FIREBASE_SECRET }} - run: | - pwd - echo $FIREBASE_SECRET > ./example/android/app/google-services.json - uses: actions/checkout@v2 - uses: actions/setup-java@v1 with: @@ -60,6 +54,10 @@ jobs: - run: | cd example flutter pub get + - name: Decode google-services.json + env: + FIREBASE_SECRET: ${{ secrets.FIREBASE_SECRET }} + run: echo $FIREBASE_SECRET > ./example/android/app/google-services.json - name: Build run: | cd example From 96c321eb8cebb1bc6cd19434d10537b078de45ac Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Fri, 15 Jan 2021 15:41:50 +0100 Subject: [PATCH 0938/1140] update build.yml --- .github/workflows/build.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index e8e5cfa1..93a4d7a6 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -56,8 +56,8 @@ jobs: flutter pub get - name: Decode google-services.json env: - FIREBASE_SECRET: ${{ secrets.FIREBASE_SECRET }} - run: echo $FIREBASE_SECRET > ./example/android/app/google-services.json + ANDROID_GOOGLE_SERVICES: ${{ secrets.ANDROID_GOOGLE_SERVICES }} + run: echo $ANDROID_GOOGLE_SERVICES > ./example/android/app/google-services.json - name: Build run: | cd example From befdbccaa032da93110dc6327cbe72ff6a267501 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Fri, 15 Jan 2021 15:58:54 +0100 Subject: [PATCH 0939/1140] update build.yml --- .github/workflows/build.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 93a4d7a6..388d0e05 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -63,9 +63,10 @@ jobs: cd example flutter build apk - name: Deploy - uses: wzieba/Firebase-Distribution-Github-Action@v1.2.1 + uses: wzieba/Firebase-Distribution-Github-Action@v1.3.2 with: appId: ${{secrets.FIREBASE_ANDROID_APPID}} token: ${{secrets.FIREBASE_TOKEN}} groups: stream-testers - file: example/build/app/outputs/apk/release/app-release.apk \ No newline at end of file + debug: true + file: ./example/build/app/outputs/apk/release/app-release.apk \ No newline at end of file From 676dc3afb38c1e761f3f111d7420774727e0a402 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Fri, 15 Jan 2021 16:11:42 +0100 Subject: [PATCH 0940/1140] update build.yml --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 388d0e05..2d288fa3 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -69,4 +69,4 @@ jobs: token: ${{secrets.FIREBASE_TOKEN}} groups: stream-testers debug: true - file: ./example/build/app/outputs/apk/release/app-release.apk \ No newline at end of file + file: packages/flutter_widgets/example/build/app/outputs/apk/release/app-release.apk \ No newline at end of file From 228233d89e2869de68855b2828a2fb1041ac3b89 Mon Sep 17 00:00:00 2001 From: Neevash Ramdial Date: Fri, 15 Jan 2021 11:11:57 -0400 Subject: [PATCH 0941/1140] fix dependency conflicts --- packages/dart_client/example/pubspec.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/dart_client/example/pubspec.yaml b/packages/dart_client/example/pubspec.yaml index 59a8bb96..53bde0f4 100644 --- a/packages/dart_client/example/pubspec.yaml +++ b/packages/dart_client/example/pubspec.yaml @@ -14,10 +14,10 @@ dependencies: jiffy: ^3.0.1 date_format: ^1.0.8 cached_network_image: ^2.0.0 - flutter_markdown: ^0.3.4 + flutter_markdown: ^0.5.2 url_launcher: ^5.4.2 - video_player: ^0.10.8+1 - chewie: ^0.9.10 + video_player: ^1.0.1 + chewie: 0.12.1+1 animations: ^1.0.0+5 stream_chat: From d1ecf21163b3e492b61a5b0c539d6beee771730f Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Fri, 15 Jan 2021 16:43:14 +0100 Subject: [PATCH 0942/1140] update build.yml --- .github/workflows/build.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 2d288fa3..994582df 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -5,7 +5,6 @@ on: branches: - master - feature/new-ui - - feature/mono-repo release: types: - created From 4589dd86452beda0cb6e6cc8e22c796a58b2ee55 Mon Sep 17 00:00:00 2001 From: Neevash Ramdial Date: Fri, 15 Jan 2021 12:17:48 -0400 Subject: [PATCH 0943/1140] resolve melos analyze warnings --- .../dart_client/lib/src/api/websocket.dart | 8 +- packages/dart_client/lib/src/client.dart | 14 ++- .../lib/src/db/shared/native_db.dart | 3 +- .../lib/src/db/shared/unsupported_db.dart | 2 + .../dart_client/lib/src/db/shared/web_db.dart | 2 + .../example/lib/chat_info_screen.dart | 1 - .../example/lib/group_info_screen.dart | 2 - .../flutter_widgets/example/lib/main.dart | 4 +- .../example/lib/routes/app_routes.dart | 3 + packages/flutter_widgets/example/pubspec.yaml | 3 +- .../lib/src/channel_file_display_screen.dart | 2 - .../lib/src/channel_list_view.dart | 1 - .../flutter_widgets/lib/src/image_footer.dart | 115 +----------------- .../lib/src/message_input.dart | 8 ++ .../lib/src/message_reactions_modal.dart | 2 +- .../lib/src/option_list_tile.dart | 1 - .../lib/src/user_list_view.dart | 2 + packages/flutter_widgets/lib/src/utils.dart | 2 +- 18 files changed, 44 insertions(+), 131 deletions(-) diff --git a/packages/dart_client/lib/src/api/websocket.dart b/packages/dart_client/lib/src/api/websocket.dart index 7d904a12..a8288573 100644 --- a/packages/dart_client/lib/src/api/websocket.dart +++ b/packages/dart_client/lib/src/api/websocket.dart @@ -14,7 +14,11 @@ import 'web_socket_channel_stub.dart' if (dart.library.html) 'web_socket_channel_html.dart' if (dart.library.io) 'web_socket_channel_io.dart'; +/// Typedef which exposes an [Event] as the only parameter. typedef EventHandler = void Function(Event); + +/// Typedef used for connecting to a websocket. Method returns a [WebSocketChannel] +/// and accepts a connection [url] and an optional [Iterable] of `protocols`. typedef ConnectWebSocket = WebSocketChannel Function(String url, {Iterable protocols}); @@ -236,7 +240,9 @@ class WebSocket { try { await connect(); - } catch (e) {} + } catch (e) { + logger.log(Level.SEVERE, e.toString()); + } await Future.delayed( Duration(seconds: min(_retryAttempt * 5, 25)), () { diff --git a/packages/dart_client/lib/src/client.dart b/packages/dart_client/lib/src/client.dart index 4e0743ff..7e024c69 100644 --- a/packages/dart_client/lib/src/client.dart +++ b/packages/dart_client/lib/src/client.dart @@ -13,6 +13,7 @@ import 'package:stream_chat/src/models/channel_model.dart'; import 'package:stream_chat/src/models/own_user.dart'; import 'package:stream_chat/version.dart'; import 'package:uuid/uuid.dart'; +import 'package:pedantic/pedantic.dart' show unawaited; import 'api/channel.dart'; import 'api/connection_status.dart'; @@ -25,8 +26,15 @@ import 'models/event.dart'; import 'models/message.dart'; import 'models/user.dart'; +/// Handler function used for logging records. Function requires a single [LogRecord] +/// as the only parameter. typedef LogHandlerFunction = void Function(LogRecord record); + +/// Used for decoding [Map] data to a generic type `T`. typedef DecoderFunction = T Function(Map); + +/// A function which can be used to request a Stream Chat API token from your +/// own backend server. Function requires a single [userId]. typedef TokenProvider = Future Function(String userId); /// The key used to save the userId to sharedPreferences @@ -462,7 +470,7 @@ class Client { if (value == ConnectionStatus.connected && state.channels?.isNotEmpty == true) { - queryChannels(filter: { + unawaited (queryChannels(filter: { 'cid': { '\$in': state.channels.keys.toList(), }, @@ -474,7 +482,7 @@ class Client { online: true, )); }, - ); + )); } else { _synced = false; } @@ -712,7 +720,7 @@ class Client { } } - _parseError(DioError error) { + dynamic _parseError(DioError error) { if (error.type == DioErrorType.RESPONSE) { final apiError = ApiError(error.response?.data, error.response?.statusCode); diff --git a/packages/dart_client/lib/src/db/shared/native_db.dart b/packages/dart_client/lib/src/db/shared/native_db.dart index 38a1923e..deee5b08 100644 --- a/packages/dart_client/lib/src/db/shared/native_db.dart +++ b/packages/dart_client/lib/src/db/shared/native_db.dart @@ -1,3 +1,4 @@ +//ignore_for_file: public_member_api_docs import 'dart:io'; import 'dart:isolate'; import 'package:flutter/material.dart'; @@ -9,7 +10,7 @@ import 'package:path_provider/path_provider.dart'; import 'package:stream_chat/src/db/offline_storage.dart'; class SharedDB { - static constructDatabase(dbName) async { + static Future constructDatabase(dbName) async { final dir = await getApplicationDocumentsDirectory(); final path = join(dir.path, dbName); final file = File(path); diff --git a/packages/dart_client/lib/src/db/shared/unsupported_db.dart b/packages/dart_client/lib/src/db/shared/unsupported_db.dart index 9d4ef84f..bbb4ccb7 100644 --- a/packages/dart_client/lib/src/db/shared/unsupported_db.dart +++ b/packages/dart_client/lib/src/db/shared/unsupported_db.dart @@ -1,3 +1,5 @@ +//ignore_for_file: public_member_api_docs +//ignore_for_file: always_declare_return_types class SharedDB { static constructDatabase(dbName) async { print('Unsupported Platform'); diff --git a/packages/dart_client/lib/src/db/shared/web_db.dart b/packages/dart_client/lib/src/db/shared/web_db.dart index bd579280..f79c224a 100644 --- a/packages/dart_client/lib/src/db/shared/web_db.dart +++ b/packages/dart_client/lib/src/db/shared/web_db.dart @@ -1,3 +1,5 @@ +//ignore_for_file: public_member_api_docs +//ignore_for_file: always_declare_return_types import 'package:moor/moor_web.dart'; import 'package:stream_chat/src/db/offline_storage.dart'; diff --git a/packages/flutter_widgets/example/lib/chat_info_screen.dart b/packages/flutter_widgets/example/lib/chat_info_screen.dart index 5eb0df7d..4106b96e 100644 --- a/packages/flutter_widgets/example/lib/chat_info_screen.dart +++ b/packages/flutter_widgets/example/lib/chat_info_screen.dart @@ -1,4 +1,3 @@ -import 'package:emojis/emojis.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:jiffy/jiffy.dart'; diff --git a/packages/flutter_widgets/example/lib/group_info_screen.dart b/packages/flutter_widgets/example/lib/group_info_screen.dart index cac6fc9c..253901c9 100644 --- a/packages/flutter_widgets/example/lib/group_info_screen.dart +++ b/packages/flutter_widgets/example/lib/group_info_screen.dart @@ -907,8 +907,6 @@ class _GroupInfoScreenState extends State { ); } - void _showRemoveUserModal(User user) {} - Widget _buildConnectedTitleState(User user) { var alternativeWidget; diff --git a/packages/flutter_widgets/example/lib/main.dart b/packages/flutter_widgets/example/lib/main.dart index 2c2c5bab..460a80a3 100644 --- a/packages/flutter_widgets/example/lib/main.dart +++ b/packages/flutter_widgets/example/lib/main.dart @@ -115,7 +115,7 @@ class _HomePageState extends State { return [ BottomNavigationBarItem( icon: Stack( - overflow: Overflow.visible, + clipBehavior: Clip.none, children: [ StreamSvgIcon.message( color: _isSelected(0) @@ -133,7 +133,7 @@ class _HomePageState extends State { ), BottomNavigationBarItem( icon: Stack( - overflow: Overflow.visible, + clipBehavior: Clip.none, children: [ StreamSvgIcon.mentions( color: _isSelected(1) diff --git a/packages/flutter_widgets/example/lib/routes/app_routes.dart b/packages/flutter_widgets/example/lib/routes/app_routes.dart index 20725b26..0c8a899f 100644 --- a/packages/flutter_widgets/example/lib/routes/app_routes.dart +++ b/packages/flutter_widgets/example/lib/routes/app_routes.dart @@ -79,6 +79,9 @@ class AppRoutes { builder: (_) { return GroupInfoScreen(); }); + // Default case, should not reach here. + default: + return null; } } } diff --git a/packages/flutter_widgets/example/pubspec.yaml b/packages/flutter_widgets/example/pubspec.yaml index 38c25b65..b4d32fa0 100644 --- a/packages/flutter_widgets/example/pubspec.yaml +++ b/packages/flutter_widgets/example/pubspec.yaml @@ -8,8 +8,7 @@ environment: dependencies: flutter: sdk: flutter - stream_chat_flutter: - path: ../ + stream_chat_flutter: 0.2.13+1 flutter_apns: ^1.4.1 flutter_local_notifications: ^2.0.2 flutter_svg: ^0.19.1 diff --git a/packages/flutter_widgets/lib/src/channel_file_display_screen.dart b/packages/flutter_widgets/lib/src/channel_file_display_screen.dart index c6132609..d5aef38c 100644 --- a/packages/flutter_widgets/lib/src/channel_file_display_screen.dart +++ b/packages/flutter_widgets/lib/src/channel_file_display_screen.dart @@ -160,8 +160,6 @@ class _ChannelFileDisplayScreenState extends State { ), child: ListView.builder( itemBuilder: (context, position) { - var channel = StreamChannel.of(context).channel; - return Padding( padding: const EdgeInsets.all(1.0), child: Padding( diff --git a/packages/flutter_widgets/lib/src/channel_list_view.dart b/packages/flutter_widgets/lib/src/channel_list_view.dart index 2de00c0e..61a0aabb 100644 --- a/packages/flutter_widgets/lib/src/channel_list_view.dart +++ b/packages/flutter_widgets/lib/src/channel_list_view.dart @@ -1,6 +1,5 @@ import 'dart:async'; import 'dart:convert'; -import 'dart:ui' as ui; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; diff --git a/packages/flutter_widgets/lib/src/image_footer.dart b/packages/flutter_widgets/lib/src/image_footer.dart index 8d4ca8b5..75e6bb73 100644 --- a/packages/flutter_widgets/lib/src/image_footer.dart +++ b/packages/flutter_widgets/lib/src/image_footer.dart @@ -1,7 +1,5 @@ import 'dart:async'; import 'dart:io'; -import 'dart:math'; -import 'dart:typed_data'; import 'package:cached_network_image/cached_network_image.dart'; import 'package:chewie/chewie.dart'; @@ -9,8 +7,6 @@ import 'package:dio/dio.dart'; import 'package:esys_flutter_share/esys_flutter_share.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; -import 'package:image_gallery_saver/image_gallery_saver.dart'; -import 'package:path_provider/path_provider.dart'; import 'package:stream_chat/stream_chat.dart'; import 'package:stream_chat_flutter/src/stream_chat_theme.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; @@ -58,15 +54,16 @@ class ImageFooter extends StatefulWidget implements PreferredSizeWidget { } class _ImageFooterState extends State { + //ignore:unused_field bool _userSearchMode = false; TextEditingController _searchController; final TextEditingController _messageController = TextEditingController(); final FocusNode _messageFocusNode = FocusNode(); + //ignore:unused_field String _channelNameQuery; final List _selectedChannels = []; - bool _loading = false; Timer _debounce; @@ -311,95 +308,6 @@ class _ImageFooterState extends State { ); } - Widget _buildShareTextInputSection(modalSetState) { - return Align( - alignment: Alignment.bottomCenter, - child: BottomAppBar( - child: Container( - height: 40.0, - margin: const EdgeInsets.symmetric( - vertical: 8, - horizontal: 8, - ), - child: _loading - ? Center( - child: Padding( - padding: const EdgeInsets.all(8.0), - child: CircularProgressIndicator(), - ), - ) - : Row( - children: [ - Expanded( - child: TextField( - controller: _messageController, - focusNode: _messageFocusNode, - onChanged: (val) { - modalSetState(() {}); - }, - onTap: () { - modalSetState(() {}); - setState(() {}); - }, - decoration: InputDecoration( - prefixText: ' ', - hintText: 'Add a comment', - enabledBorder: OutlineInputBorder( - borderRadius: BorderRadius.circular(24.0), - borderSide: BorderSide( - color: StreamChatTheme.of(context) - .colorTheme - .black - .withOpacity(0.16), - ), - ), - focusedBorder: OutlineInputBorder( - borderRadius: BorderRadius.circular(24.0), - borderSide: BorderSide( - color: StreamChatTheme.of(context) - .colorTheme - .black - .withOpacity(0.16), - )), - contentPadding: const EdgeInsets.all(0), - ), - ), - ), - SizedBox(width: 8), - IconTheme( - data: StreamChatTheme.of(context) - .channelTheme - .messageInputButtonIconTheme, - child: IconButton( - onPressed: () async { - modalSetState(() => _loading = true); - await sendMessage(); - modalSetState(() => _loading = false); - }, - splashRadius: 24, - visualDensity: VisualDensity.compact, - constraints: BoxConstraints.tightFor( - height: 24, - width: 24, - ), - padding: EdgeInsets.zero, - icon: Transform.rotate( - angle: -pi / 2, - child: StreamSvgIcon.Icon_send_message( - color: StreamChatTheme.of(context) - .colorTheme - .accentBlue, - ), - ), - ), - ), - ], - ), - ), - ), - ); - } - /// Sends the current message Future sendMessage() async { var text = _messageController.text.trim(); @@ -420,25 +328,6 @@ class _ImageFooterState extends State { _selectedChannels.clear(); Navigator.pop(context); } - - Future _saveImage(String url) async { - var response = await Dio() - .get(url, options: Options(responseType: ResponseType.bytes)); - final result = await ImageGallerySaver.saveImage( - Uint8List.fromList(response.data), - quality: 60, - name: "${DateTime.now().millisecondsSinceEpoch}"); - return result; - } - - Future _saveVideo(String url) async { - var appDocDir = await getTemporaryDirectory(); - var savePath = - appDocDir.path + "/${DateTime.now().millisecondsSinceEpoch}.mp4"; - await Dio().download(url, savePath); - final result = await ImageGallerySaver.saveFile(savePath); - print(result); - } } /// Used for clipping textfield prefix icon diff --git a/packages/flutter_widgets/lib/src/message_input.dart b/packages/flutter_widgets/lib/src/message_input.dart index 22a36882..6fafb5d8 100644 --- a/packages/flutter_widgets/lib/src/message_input.dart +++ b/packages/flutter_widgets/lib/src/message_input.dart @@ -798,6 +798,8 @@ class MessageInputState extends State { ? StreamChatTheme.of(context).colorTheme.black.withOpacity(0.2) : StreamChatTheme.of(context).colorTheme.black.withOpacity(0.5); break; + default: + return Colors.black; } } @@ -1014,6 +1016,8 @@ class MessageInputState extends State { ); }); break; + default: + return SizedBox(); } } @@ -1038,6 +1042,7 @@ class MessageInputState extends State { final mediaInfo = await CompressVideoService.compressVideo(file.path); if (mediaInfo.filesize / (1024 * 1024) > _kMaxAttachmentSize) { + // ignore: deprecated_member_use Scaffold.of(context).showSnackBar( SnackBar( content: Text( @@ -1058,6 +1063,7 @@ class MessageInputState extends State { path: mediaInfo.path, ); } else { + // ignore: deprecated_member_use Scaffold.of(context).showSnackBar( SnackBar( content: Text( @@ -1110,6 +1116,7 @@ class MessageInputState extends State { }); print(e); print(s); + // ignore: deprecated_member_use Scaffold.of(context).showSnackBar( SnackBar( content: Text('Error adding the attachment: $e'), @@ -2013,6 +2020,7 @@ class MessageInputState extends State { attachment.file = file; }); } else { + // ignore: deprecated_member_use Scaffold.of(context).showSnackBar( SnackBar( content: Text( diff --git a/packages/flutter_widgets/lib/src/message_reactions_modal.dart b/packages/flutter_widgets/lib/src/message_reactions_modal.dart index e09e21db..1ee3486d 100644 --- a/packages/flutter_widgets/lib/src/message_reactions_modal.dart +++ b/packages/flutter_widgets/lib/src/message_reactions_modal.dart @@ -220,7 +220,7 @@ class MessageReactionsModal extends StatelessWidget { crossAxisAlignment: CrossAxisAlignment.center, children: [ Stack( - overflow: Overflow.visible, + clipBehavior: Clip.none, children: [ UserAvatar( onTap: onUserAvatarTap, diff --git a/packages/flutter_widgets/lib/src/option_list_tile.dart b/packages/flutter_widgets/lib/src/option_list_tile.dart index 1b87c9d7..61ce939e 100644 --- a/packages/flutter_widgets/lib/src/option_list_tile.dart +++ b/packages/flutter_widgets/lib/src/option_list_tile.dart @@ -1,6 +1,5 @@ import 'package:flutter/material.dart'; import 'package:stream_chat_flutter/src/stream_chat_theme.dart'; -import 'package:stream_chat_flutter/src/stream_svg_icon.dart'; class OptionListTile extends StatelessWidget { final String title; diff --git a/packages/flutter_widgets/lib/src/user_list_view.dart b/packages/flutter_widgets/lib/src/user_list_view.dart index 6197a06e..c5bac576 100644 --- a/packages/flutter_widgets/lib/src/user_list_view.dart +++ b/packages/flutter_widgets/lib/src/user_list_view.dart @@ -524,6 +524,7 @@ abstract class ListItem { final user = (this as ListUserItem).user; return 'USER-${user.id}'; } + return null; } Widget when({ @@ -536,6 +537,7 @@ abstract class ListItem { if (this is ListUserItem) { return userItem((this as ListUserItem).user); } + return SizedBox(); } } diff --git a/packages/flutter_widgets/lib/src/utils.dart b/packages/flutter_widgets/lib/src/utils.dart index d1dec9c8..20e78a24 100644 --- a/packages/flutter_widgets/lib/src/utils.dart +++ b/packages/flutter_widgets/lib/src/utils.dart @@ -9,7 +9,7 @@ Future launchURL(BuildContext context, String url) async { if (await canLaunch(url)) { await launch(url); } else { - Scaffold.of(context).showSnackBar( + ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text('Cannot launch the url'), ), From f4f6285cdb4fc5de60ce528e963525a488a890eb Mon Sep 17 00:00:00 2001 From: Neevash Ramdial Date: Fri, 15 Jan 2021 12:19:41 -0400 Subject: [PATCH 0944/1140] remove dart client example --- packages/dart_client/example/README.md | 1 - .../dart_client/example/android/.gitignore | 7 - .../example/android/app/build.gradle | 67 ---- .../android/app/src/debug/AndroidManifest.xml | 7 - .../android/app/src/main/AndroidManifest.xml | 31 -- .../example/stream_chat_dart/MainActivity.kt | 12 - .../main/res/drawable/launch_background.xml | 12 - .../src/main/res/mipmap-hdpi/ic_launcher.png | Bin 544 -> 0 bytes .../src/main/res/mipmap-mdpi/ic_launcher.png | Bin 442 -> 0 bytes .../src/main/res/mipmap-xhdpi/ic_launcher.png | Bin 721 -> 0 bytes .../main/res/mipmap-xxhdpi/ic_launcher.png | Bin 1031 -> 0 bytes .../main/res/mipmap-xxxhdpi/ic_launcher.png | Bin 1443 -> 0 bytes .../app/src/main/res/values/styles.xml | 8 - .../app/src/profile/AndroidManifest.xml | 7 - .../dart_client/example/android/build.gradle | 31 -- .../example/android/gradle.properties | 4 - .../gradle/wrapper/gradle-wrapper.properties | 6 - .../example/android/settings.gradle | 15 - packages/dart_client/example/ios/.gitignore | 32 -- .../ios/Flutter/AppFrameworkInfo.plist | 26 -- .../example/ios/Flutter/Debug.xcconfig | 2 - .../example/ios/Flutter/Release.xcconfig | 2 - .../contents.xcworkspacedata | 7 - .../xcshareddata/xcschemes/Runner.xcscheme | 91 ----- .../contents.xcworkspacedata | 10 - .../example/ios/Runner/AppDelegate.swift | 13 - .../AppIcon.appiconset/Contents.json | 122 ------ .../Icon-App-1024x1024@1x.png | Bin 10932 -> 0 bytes .../AppIcon.appiconset/Icon-App-20x20@1x.png | Bin 564 -> 0 bytes .../AppIcon.appiconset/Icon-App-20x20@2x.png | Bin 1283 -> 0 bytes .../AppIcon.appiconset/Icon-App-20x20@3x.png | Bin 1588 -> 0 bytes .../AppIcon.appiconset/Icon-App-29x29@1x.png | Bin 1025 -> 0 bytes .../AppIcon.appiconset/Icon-App-29x29@2x.png | Bin 1716 -> 0 bytes .../AppIcon.appiconset/Icon-App-29x29@3x.png | Bin 1920 -> 0 bytes .../AppIcon.appiconset/Icon-App-40x40@1x.png | Bin 1283 -> 0 bytes .../AppIcon.appiconset/Icon-App-40x40@2x.png | Bin 1895 -> 0 bytes .../AppIcon.appiconset/Icon-App-40x40@3x.png | Bin 2665 -> 0 bytes .../AppIcon.appiconset/Icon-App-60x60@2x.png | Bin 2665 -> 0 bytes .../AppIcon.appiconset/Icon-App-60x60@3x.png | Bin 3831 -> 0 bytes .../AppIcon.appiconset/Icon-App-76x76@1x.png | Bin 1888 -> 0 bytes .../AppIcon.appiconset/Icon-App-76x76@2x.png | Bin 3294 -> 0 bytes .../Icon-App-83.5x83.5@2x.png | Bin 3612 -> 0 bytes .../LaunchImage.imageset/Contents.json | 23 -- .../LaunchImage.imageset/LaunchImage.png | Bin 68 -> 0 bytes .../LaunchImage.imageset/LaunchImage@2x.png | Bin 68 -> 0 bytes .../LaunchImage.imageset/LaunchImage@3x.png | Bin 68 -> 0 bytes .../LaunchImage.imageset/README.md | 5 - .../Runner/Base.lproj/LaunchScreen.storyboard | 37 -- .../ios/Runner/Base.lproj/Main.storyboard | 26 -- .../dart_client/example/ios/Runner/Info.plist | 50 --- .../ios/Runner/Runner-Bridging-Header.h | 1 - .../example/lib/channel_header.dart | 83 ---- .../example/lib/channel_image.dart | 25 -- .../example/lib/channel_list_page.dart | 138 ------- .../example/lib/channel_list_view.dart | 208 ----------- .../example/lib/channel_name_text.dart | 19 - .../example/lib/channel_page_app_bar.dart | 41 -- .../example/lib/channel_preview.dart | 139 ------- .../example/lib/connection_indicator.dart | 100 ----- packages/dart_client/example/lib/main.dart | 94 ----- .../example/lib/message_input.dart | 137 ------- .../example/lib/message_list_view.dart | 280 -------------- .../dart_client/example/lib/message_page.dart | 110 ------ .../example/lib/message_widget.dart | 353 ------------------ .../example/lib/stream_channel.dart | 128 ------- .../dart_client/example/lib/stream_chat.dart | 95 ----- .../dart_client/example/lib/user_avatar.dart | 29 -- packages/dart_client/example/pubspec.yaml | 33 -- .../dart_client/example/test/widget_test.dart | 29 -- .../example/web/icons/Icon-192.png | Bin 5292 -> 0 bytes .../example/web/icons/Icon-512.png | Bin 8252 -> 0 bytes packages/dart_client/example/web/index.html | 20 - .../dart_client/example/web/manifest.json | 23 -- 73 files changed, 2739 deletions(-) delete mode 100644 packages/dart_client/example/README.md delete mode 100644 packages/dart_client/example/android/.gitignore delete mode 100644 packages/dart_client/example/android/app/build.gradle delete mode 100644 packages/dart_client/example/android/app/src/debug/AndroidManifest.xml delete mode 100644 packages/dart_client/example/android/app/src/main/AndroidManifest.xml delete mode 100644 packages/dart_client/example/android/app/src/main/kotlin/com/example/stream_chat_dart/MainActivity.kt delete mode 100644 packages/dart_client/example/android/app/src/main/res/drawable/launch_background.xml delete mode 100644 packages/dart_client/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png delete mode 100644 packages/dart_client/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png delete mode 100644 packages/dart_client/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png delete mode 100644 packages/dart_client/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png delete mode 100644 packages/dart_client/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png delete mode 100644 packages/dart_client/example/android/app/src/main/res/values/styles.xml delete mode 100644 packages/dart_client/example/android/app/src/profile/AndroidManifest.xml delete mode 100644 packages/dart_client/example/android/build.gradle delete mode 100644 packages/dart_client/example/android/gradle.properties delete mode 100644 packages/dart_client/example/android/gradle/wrapper/gradle-wrapper.properties delete mode 100644 packages/dart_client/example/android/settings.gradle delete mode 100644 packages/dart_client/example/ios/.gitignore delete mode 100644 packages/dart_client/example/ios/Flutter/AppFrameworkInfo.plist delete mode 100644 packages/dart_client/example/ios/Flutter/Debug.xcconfig delete mode 100644 packages/dart_client/example/ios/Flutter/Release.xcconfig delete mode 100644 packages/dart_client/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata delete mode 100644 packages/dart_client/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme delete mode 100644 packages/dart_client/example/ios/Runner.xcworkspace/contents.xcworkspacedata delete mode 100644 packages/dart_client/example/ios/Runner/AppDelegate.swift delete mode 100644 packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json delete mode 100644 packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png delete mode 100644 packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png delete mode 100644 packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png delete mode 100644 packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png delete mode 100644 packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png delete mode 100644 packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png delete mode 100644 packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png delete mode 100644 packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png delete mode 100644 packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png delete mode 100644 packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png delete mode 100644 packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png delete mode 100644 packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png delete mode 100644 packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png delete mode 100644 packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png delete mode 100644 packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png delete mode 100644 packages/dart_client/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json delete mode 100644 packages/dart_client/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png delete mode 100644 packages/dart_client/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png delete mode 100644 packages/dart_client/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png delete mode 100644 packages/dart_client/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md delete mode 100644 packages/dart_client/example/ios/Runner/Base.lproj/LaunchScreen.storyboard delete mode 100644 packages/dart_client/example/ios/Runner/Base.lproj/Main.storyboard delete mode 100644 packages/dart_client/example/ios/Runner/Info.plist delete mode 100644 packages/dart_client/example/ios/Runner/Runner-Bridging-Header.h delete mode 100644 packages/dart_client/example/lib/channel_header.dart delete mode 100644 packages/dart_client/example/lib/channel_image.dart delete mode 100644 packages/dart_client/example/lib/channel_list_page.dart delete mode 100644 packages/dart_client/example/lib/channel_list_view.dart delete mode 100644 packages/dart_client/example/lib/channel_name_text.dart delete mode 100644 packages/dart_client/example/lib/channel_page_app_bar.dart delete mode 100644 packages/dart_client/example/lib/channel_preview.dart delete mode 100644 packages/dart_client/example/lib/connection_indicator.dart delete mode 100644 packages/dart_client/example/lib/main.dart delete mode 100644 packages/dart_client/example/lib/message_input.dart delete mode 100644 packages/dart_client/example/lib/message_list_view.dart delete mode 100644 packages/dart_client/example/lib/message_page.dart delete mode 100644 packages/dart_client/example/lib/message_widget.dart delete mode 100644 packages/dart_client/example/lib/stream_channel.dart delete mode 100644 packages/dart_client/example/lib/stream_chat.dart delete mode 100644 packages/dart_client/example/lib/user_avatar.dart delete mode 100644 packages/dart_client/example/pubspec.yaml delete mode 100644 packages/dart_client/example/test/widget_test.dart delete mode 100644 packages/dart_client/example/web/icons/Icon-192.png delete mode 100644 packages/dart_client/example/web/icons/Icon-512.png delete mode 100644 packages/dart_client/example/web/index.html delete mode 100644 packages/dart_client/example/web/manifest.json diff --git a/packages/dart_client/example/README.md b/packages/dart_client/example/README.md deleted file mode 100644 index 5bbae90f..00000000 --- a/packages/dart_client/example/README.md +++ /dev/null @@ -1 +0,0 @@ -# Stream Chat Example App diff --git a/packages/dart_client/example/android/.gitignore b/packages/dart_client/example/android/.gitignore deleted file mode 100644 index bc2100d8..00000000 --- a/packages/dart_client/example/android/.gitignore +++ /dev/null @@ -1,7 +0,0 @@ -gradle-wrapper.jar -/.gradle -/captures/ -/gradlew -/gradlew.bat -/local.properties -GeneratedPluginRegistrant.java diff --git a/packages/dart_client/example/android/app/build.gradle b/packages/dart_client/example/android/app/build.gradle deleted file mode 100644 index 0aa3ddb0..00000000 --- a/packages/dart_client/example/android/app/build.gradle +++ /dev/null @@ -1,67 +0,0 @@ -def localProperties = new Properties() -def localPropertiesFile = rootProject.file('local.properties') -if (localPropertiesFile.exists()) { - localPropertiesFile.withReader('UTF-8') { reader -> - localProperties.load(reader) - } -} - -def flutterRoot = localProperties.getProperty('flutter.sdk') -if (flutterRoot == null) { - throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") -} - -def flutterVersionCode = localProperties.getProperty('flutter.versionCode') -if (flutterVersionCode == null) { - flutterVersionCode = '1' -} - -def flutterVersionName = localProperties.getProperty('flutter.versionName') -if (flutterVersionName == null) { - flutterVersionName = '1.0' -} - -apply plugin: 'com.android.application' -apply plugin: 'kotlin-android' -apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" - -android { - compileSdkVersion 28 - - sourceSets { - main.java.srcDirs += 'src/main/kotlin' - } - - lintOptions { - disable 'InvalidPackage' - } - - defaultConfig { - // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). - applicationId "com.example.stream_chat" - minSdkVersion 16 - targetSdkVersion 28 - versionCode flutterVersionCode.toInteger() - versionName flutterVersionName - testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" - } - - buildTypes { - release { - // TODO: Add your own signing config for the release build. - // Signing with the debug keys for now, so `flutter run --release` works. - signingConfig signingConfigs.debug - } - } -} - -flutter { - source '../..' -} - -dependencies { - implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" - testImplementation 'junit:junit:4.12' - androidTestImplementation 'androidx.test:runner:1.1.1' - androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1' -} diff --git a/packages/dart_client/example/android/app/src/debug/AndroidManifest.xml b/packages/dart_client/example/android/app/src/debug/AndroidManifest.xml deleted file mode 100644 index f3e724c3..00000000 --- a/packages/dart_client/example/android/app/src/debug/AndroidManifest.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - diff --git a/packages/dart_client/example/android/app/src/main/AndroidManifest.xml b/packages/dart_client/example/android/app/src/main/AndroidManifest.xml deleted file mode 100644 index 03a0d883..00000000 --- a/packages/dart_client/example/android/app/src/main/AndroidManifest.xml +++ /dev/null @@ -1,31 +0,0 @@ - - - - - - - - - - - - - - diff --git a/packages/dart_client/example/android/app/src/main/kotlin/com/example/stream_chat_dart/MainActivity.kt b/packages/dart_client/example/android/app/src/main/kotlin/com/example/stream_chat_dart/MainActivity.kt deleted file mode 100644 index ad61bdd4..00000000 --- a/packages/dart_client/example/android/app/src/main/kotlin/com/example/stream_chat_dart/MainActivity.kt +++ /dev/null @@ -1,12 +0,0 @@ -package com.example.stream_chat - -import androidx.annotation.NonNull; -import io.flutter.embedding.android.FlutterActivity -import io.flutter.embedding.engine.FlutterEngine -import io.flutter.plugins.GeneratedPluginRegistrant - -class MainActivity: FlutterActivity() { - override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) { - GeneratedPluginRegistrant.registerWith(flutterEngine); - } -} diff --git a/packages/dart_client/example/android/app/src/main/res/drawable/launch_background.xml b/packages/dart_client/example/android/app/src/main/res/drawable/launch_background.xml deleted file mode 100644 index 304732f8..00000000 --- a/packages/dart_client/example/android/app/src/main/res/drawable/launch_background.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - diff --git a/packages/dart_client/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/packages/dart_client/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png deleted file mode 100644 index db77bb4b7b0906d62b1847e87f15cdcacf6a4f29..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 544 zcmeAS@N?(olHy`uVBq!ia0vp^9w5xY3?!3`olAj~WQl7;NpOBzNqJ&XDuZK6ep0G} zXKrG8YEWuoN@d~6R2!h8bpbvhu0Wd6uZuB!w&u2PAxD2eNXD>P5D~Wn-+_Wa#27Xc zC?Zj|6r#X(-D3u$NCt}(Ms06KgJ4FxJVv{GM)!I~&n8Bnc94O7-Hd)cjDZswgC;Qs zO=b+9!WcT8F?0rF7!Uys2bs@gozCP?z~o%U|N3vA*22NaGQG zlg@K`O_XuxvZ&Ks^m&R!`&1=spLvfx7oGDKDwpwW`#iqdw@AL`7MR}m`rwr|mZgU`8P7SBkL78fFf!WnuYWm$5Z0 zNXhDbCv&49sM544K|?c)WrFfiZvCi9h0O)B3Pgg&ebxsLQ05GG~ AQ2+n{ diff --git a/packages/dart_client/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/packages/dart_client/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png deleted file mode 100644 index 17987b79bb8a35cc66c3c1fd44f5a5526c1b78be..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 442 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA3?vioaBc-sk|nMYCBgY=CFO}lsSJ)O`AMk? zp1FzXsX?iUDV2pMQ*D5Xx&nMcT!A!W`0S9QKQy;}1Cl^CgaH=;G9cpY;r$Q>i*pfB zP2drbID<_#qf;rPZx^FqH)F_D#*k@@q03KywUtLX8Ua?`H+NMzkczFPK3lFz@i_kW%1NOn0|D2I9n9wzH8m|-tHjsw|9>@K=iMBhxvkv6m8Y-l zytQ?X=U+MF$@3 zt`~i=@j|6y)RWMK--}M|=T`o&^Ni>IoWKHEbBXz7?A@mgWoL>!*SXo`SZH-*HSdS+ yn*9;$7;m`l>wYBC5bq;=U}IMqLzqbYCidGC!)_gkIk_C@Uy!y&wkt5C($~2D>~)O*cj@FGjOCM)M>_ixfudOh)?xMu#Fs z#}Y=@YDTwOM)x{K_j*Q;dPdJ?Mz0n|pLRx{4n|)f>SXlmV)XB04CrSJn#dS5nK2lM zrZ9#~WelCp7&e13Y$jvaEXHskn$2V!!DN-nWS__6T*l;H&Fopn?A6HZ-6WRLFP=R` zqG+CE#d4|IbyAI+rJJ`&x9*T`+a=p|0O(+s{UBcyZdkhj=yS1>AirP+0R;mf2uMgM zC}@~JfByORAh4SyRgi&!(cja>F(l*O+nd+@4m$|6K6KDn_&uvCpV23&>G9HJp{xgg zoq1^2_p9@|WEo z*X_Uko@K)qYYv~>43eQGMdbiGbo>E~Q& zrYBH{QP^@Sti!`2)uG{irBBq@y*$B zi#&(U-*=fp74j)RyIw49+0MRPMRU)+a2r*PJ$L5roHt2$UjExCTZSbq%V!HeS7J$N zdG@vOZB4v_lF7Plrx+hxo7(fCV&}fHq)$ diff --git a/packages/dart_client/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/packages/dart_client/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png deleted file mode 100644 index d5f1c8d34e7a88e3f88bea192c3a370d44689c3c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1031 zcmeAS@N?(olHy`uVBq!ia0vp^6F``Q8Ax83A=Cw=BuiW)N`mv#O3D+9QW+dm@{>{( zJaZG%Q-e|yQz{EjrrIztFa`(sgt!6~Yi|1%a`XoT0ojZ}lNrNjb9xjc(B0U1_% zz5^97Xt*%oq$rQy4?0GKNfJ44uvxI)gC`h-NZ|&0-7(qS@?b!5r36oQ}zyZrNO3 zMO=Or+<~>+A&uN&E!^Sl+>xE!QC-|oJv`ApDhqC^EWD|@=#J`=d#Xzxs4ah}w&Jnc z$|q_opQ^2TrnVZ0o~wh<3t%W&flvYGe#$xqda2bR_R zvPYgMcHgjZ5nSA^lJr%;<&0do;O^tDDh~=pIxA#coaCY>&N%M2^tq^U%3DB@ynvKo}b?yu-bFc-u0JHzced$sg7S3zqI(2 z#Km{dPr7I=pQ5>FuK#)QwK?Y`E`B?nP+}U)I#c1+FM*1kNvWG|a(TpksZQ3B@sD~b zpQ2)*V*TdwjFOtHvV|;OsiDqHi=6%)o4b!)x$)%9pGTsE z-JL={-Ffv+T87W(Xpooq<`r*VzWQcgBN$$`u}f>-ZQI1BB8ykN*=e4rIsJx9>z}*o zo~|9I;xof diff --git a/packages/dart_client/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/packages/dart_client/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png deleted file mode 100644 index 4d6372eebdb28e45604e46eeda8dd24651419bc0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1443 zcmb`G{WsKk6vsdJTdFg%tJav9_E4vzrOaqkWF|A724Nly!y+?N9`YV6wZ}5(X(D_N(?!*n3`|_r0Hc?=PQw&*vnU?QTFY zB_MsH|!j$PP;I}?dppoE_gA(4uc!jV&0!l7_;&p2^pxNo>PEcNJv za5_RT$o2Mf!<+r?&EbHH6nMoTsDOa;mN(wv8RNsHpG)`^ymG-S5By8=l9iVXzN_eG%Xg2@Xeq76tTZ*dGh~Lo9vl;Zfs+W#BydUw zCkZ$o1LqWQO$FC9aKlLl*7x9^0q%0}$OMlp@Kk_jHXOjofdePND+j!A{q!8~Jn+s3 z?~~w@4?egS02}8NuulUA=L~QQfm;MzCGd)XhiftT;+zFO&JVyp2mBww?;QByS_1w! zrQlx%{^cMj0|Bo1FjwY@Q8?Hx0cIPF*@-ZRFpPc#bBw{5@tD(5%sClzIfl8WU~V#u zm5Q;_F!wa$BSpqhN>W@2De?TKWR*!ujY;Yylk_X5#~V!L*Gw~;$%4Q8~Mad z@`-kG?yb$a9cHIApZDVZ^U6Xkp<*4rU82O7%}0jjHlK{id@?-wpN*fCHXyXh(bLt* zPc}H-x0e4E&nQ>y%B-(EL=9}RyC%MyX=upHuFhAk&MLbsF0LP-q`XnH78@fT+pKPW zu72MW`|?8ht^tz$iC}ZwLp4tB;Q49K!QCF3@!iB1qOI=?w z7In!}F~ij(18UYUjnbmC!qKhPo%24?8U1x{7o(+?^Zu0Hx81|FuS?bJ0jgBhEMzf< zCgUq7r2OCB(`XkKcN-TL>u5y#dD6D!)5W?`O5)V^>jb)P)GBdy%t$uUMpf$SNV31$ zb||OojAbvMP?T@$h_ZiFLFVHDmbyMhJF|-_)HX3%m=CDI+ID$0^C>kzxprBW)hw(v zr!Gmda);ICoQyhV_oP5+C%?jcG8v+D@9f?Dk*!BxY}dazmrT@64UrP3hlslANK)bq z$67n83eh}OeW&SV@HG95P|bjfqJ7gw$e+`Hxo!4cx`jdK1bJ>YDSpGKLPZ^1cv$ek zIB?0S<#tX?SJCLWdMd{-ME?$hc7A$zBOdIJ)4!KcAwb=VMov)nK;9z>x~rfT1>dS+ zZ6#`2v@`jgbqq)P22H)Tx2CpmM^o1$B+xT6`(v%5xJ(?j#>Q$+rx_R|7TzDZe{J6q zG1*EcU%tE?!kO%^M;3aM6JN*LAKUVb^xz8-Pxo#jR5(-KBeLJvA@-gxNHx0M-ZJLl z;#JwQoh~9V?`UVo#}{6ka@II>++D@%KqGpMdlQ}?9E*wFcf5(#XQnP$Dk5~%iX^>f z%$y;?M0BLp{O3a(-4A?ewryHrrD%cx#Q^%KY1H zNre$ve+vceSLZcNY4U(RBX&)oZn*Py()h)XkE?PL$!bNb{N5FVI2Y%LKEm%yvpyTP z(1P?z~7YxD~Rf<(a@_y` diff --git a/packages/dart_client/example/android/app/src/main/res/values/styles.xml b/packages/dart_client/example/android/app/src/main/res/values/styles.xml deleted file mode 100644 index 00fa4417..00000000 --- a/packages/dart_client/example/android/app/src/main/res/values/styles.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - diff --git a/packages/dart_client/example/android/app/src/profile/AndroidManifest.xml b/packages/dart_client/example/android/app/src/profile/AndroidManifest.xml deleted file mode 100644 index f3e724c3..00000000 --- a/packages/dart_client/example/android/app/src/profile/AndroidManifest.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - diff --git a/packages/dart_client/example/android/build.gradle b/packages/dart_client/example/android/build.gradle deleted file mode 100644 index 3100ad2d..00000000 --- a/packages/dart_client/example/android/build.gradle +++ /dev/null @@ -1,31 +0,0 @@ -buildscript { - ext.kotlin_version = '1.3.50' - repositories { - google() - jcenter() - } - - dependencies { - classpath 'com.android.tools.build:gradle:3.5.0' - classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" - } -} - -allprojects { - repositories { - google() - jcenter() - } -} - -rootProject.buildDir = '../build' -subprojects { - project.buildDir = "${rootProject.buildDir}/${project.name}" -} -subprojects { - project.evaluationDependsOn(':app') -} - -task clean(type: Delete) { - delete rootProject.buildDir -} diff --git a/packages/dart_client/example/android/gradle.properties b/packages/dart_client/example/android/gradle.properties deleted file mode 100644 index 38c8d454..00000000 --- a/packages/dart_client/example/android/gradle.properties +++ /dev/null @@ -1,4 +0,0 @@ -org.gradle.jvmargs=-Xmx1536M -android.enableR8=true -android.useAndroidX=true -android.enableJetifier=true diff --git a/packages/dart_client/example/android/gradle/wrapper/gradle-wrapper.properties b/packages/dart_client/example/android/gradle/wrapper/gradle-wrapper.properties deleted file mode 100644 index 296b146b..00000000 --- a/packages/dart_client/example/android/gradle/wrapper/gradle-wrapper.properties +++ /dev/null @@ -1,6 +0,0 @@ -#Fri Jun 23 08:50:38 CEST 2017 -distributionBase=GRADLE_USER_HOME -distributionPath=wrapper/dists -zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/packages/dart_client/example/android/settings.gradle b/packages/dart_client/example/android/settings.gradle deleted file mode 100644 index 5a2f14fb..00000000 --- a/packages/dart_client/example/android/settings.gradle +++ /dev/null @@ -1,15 +0,0 @@ -include ':app' - -def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() - -def plugins = new Properties() -def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') -if (pluginsFile.exists()) { - pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } -} - -plugins.each { name, path -> - def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() - include ":$name" - project(":$name").projectDir = pluginDirectory -} diff --git a/packages/dart_client/example/ios/.gitignore b/packages/dart_client/example/ios/.gitignore deleted file mode 100644 index e96ef602..00000000 --- a/packages/dart_client/example/ios/.gitignore +++ /dev/null @@ -1,32 +0,0 @@ -*.mode1v3 -*.mode2v3 -*.moved-aside -*.pbxuser -*.perspectivev3 -**/*sync/ -.sconsign.dblite -.tags* -**/.vagrant/ -**/DerivedData/ -Icon? -**/Pods/ -**/.symlinks/ -profile -xcuserdata -**/.generated/ -Flutter/App.framework -Flutter/Flutter.framework -Flutter/Flutter.podspec -Flutter/Generated.xcconfig -Flutter/app.flx -Flutter/app.zip -Flutter/flutter_assets/ -Flutter/flutter_export_environment.sh -ServiceDefinitions.json -Runner/GeneratedPluginRegistrant.* - -# Exceptions to above rules. -!default.mode1v3 -!default.mode2v3 -!default.pbxuser -!default.perspectivev3 diff --git a/packages/dart_client/example/ios/Flutter/AppFrameworkInfo.plist b/packages/dart_client/example/ios/Flutter/AppFrameworkInfo.plist deleted file mode 100644 index 6b4c0f78..00000000 --- a/packages/dart_client/example/ios/Flutter/AppFrameworkInfo.plist +++ /dev/null @@ -1,26 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - App - CFBundleIdentifier - io.flutter.flutter.app - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - App - CFBundlePackageType - FMWK - CFBundleShortVersionString - 1.0 - CFBundleSignature - ???? - CFBundleVersion - 1.0 - MinimumOSVersion - 8.0 - - diff --git a/packages/dart_client/example/ios/Flutter/Debug.xcconfig b/packages/dart_client/example/ios/Flutter/Debug.xcconfig deleted file mode 100644 index e8efba11..00000000 --- a/packages/dart_client/example/ios/Flutter/Debug.xcconfig +++ /dev/null @@ -1,2 +0,0 @@ -#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" -#include "Generated.xcconfig" diff --git a/packages/dart_client/example/ios/Flutter/Release.xcconfig b/packages/dart_client/example/ios/Flutter/Release.xcconfig deleted file mode 100644 index 399e9340..00000000 --- a/packages/dart_client/example/ios/Flutter/Release.xcconfig +++ /dev/null @@ -1,2 +0,0 @@ -#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" -#include "Generated.xcconfig" diff --git a/packages/dart_client/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/packages/dart_client/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata deleted file mode 100644 index 1d526a16..00000000 --- a/packages/dart_client/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata +++ /dev/null @@ -1,7 +0,0 @@ - - - - - diff --git a/packages/dart_client/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/packages/dart_client/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme deleted file mode 100644 index a28140cf..00000000 --- a/packages/dart_client/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ /dev/null @@ -1,91 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/packages/dart_client/example/ios/Runner.xcworkspace/contents.xcworkspacedata b/packages/dart_client/example/ios/Runner.xcworkspace/contents.xcworkspacedata deleted file mode 100644 index 21a3cc14..00000000 --- a/packages/dart_client/example/ios/Runner.xcworkspace/contents.xcworkspacedata +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - diff --git a/packages/dart_client/example/ios/Runner/AppDelegate.swift b/packages/dart_client/example/ios/Runner/AppDelegate.swift deleted file mode 100644 index 70693e4a..00000000 --- a/packages/dart_client/example/ios/Runner/AppDelegate.swift +++ /dev/null @@ -1,13 +0,0 @@ -import UIKit -import Flutter - -@UIApplicationMain -@objc class AppDelegate: FlutterAppDelegate { - override func application( - _ application: UIApplication, - didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? - ) -> Bool { - GeneratedPluginRegistrant.register(with: self) - return super.application(application, didFinishLaunchingWithOptions: launchOptions) - } -} diff --git a/packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json deleted file mode 100644 index d36b1fab..00000000 --- a/packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json +++ /dev/null @@ -1,122 +0,0 @@ -{ - "images" : [ - { - "size" : "20x20", - "idiom" : "iphone", - "filename" : "Icon-App-20x20@2x.png", - "scale" : "2x" - }, - { - "size" : "20x20", - "idiom" : "iphone", - "filename" : "Icon-App-20x20@3x.png", - "scale" : "3x" - }, - { - "size" : "29x29", - "idiom" : "iphone", - "filename" : "Icon-App-29x29@1x.png", - "scale" : "1x" - }, - { - "size" : "29x29", - "idiom" : "iphone", - "filename" : "Icon-App-29x29@2x.png", - "scale" : "2x" - }, - { - "size" : "29x29", - "idiom" : "iphone", - "filename" : "Icon-App-29x29@3x.png", - "scale" : "3x" - }, - { - "size" : "40x40", - "idiom" : "iphone", - "filename" : "Icon-App-40x40@2x.png", - "scale" : "2x" - }, - { - "size" : "40x40", - "idiom" : "iphone", - "filename" : "Icon-App-40x40@3x.png", - "scale" : "3x" - }, - { - "size" : "60x60", - "idiom" : "iphone", - "filename" : "Icon-App-60x60@2x.png", - "scale" : "2x" - }, - { - "size" : "60x60", - "idiom" : "iphone", - "filename" : "Icon-App-60x60@3x.png", - "scale" : "3x" - }, - { - "size" : "20x20", - "idiom" : "ipad", - "filename" : "Icon-App-20x20@1x.png", - "scale" : "1x" - }, - { - "size" : "20x20", - "idiom" : "ipad", - "filename" : "Icon-App-20x20@2x.png", - "scale" : "2x" - }, - { - "size" : "29x29", - "idiom" : "ipad", - "filename" : "Icon-App-29x29@1x.png", - "scale" : "1x" - }, - { - "size" : "29x29", - "idiom" : "ipad", - "filename" : "Icon-App-29x29@2x.png", - "scale" : "2x" - }, - { - "size" : "40x40", - "idiom" : "ipad", - "filename" : "Icon-App-40x40@1x.png", - "scale" : "1x" - }, - { - "size" : "40x40", - "idiom" : "ipad", - "filename" : "Icon-App-40x40@2x.png", - "scale" : "2x" - }, - { - "size" : "76x76", - "idiom" : "ipad", - "filename" : "Icon-App-76x76@1x.png", - "scale" : "1x" - }, - { - "size" : "76x76", - "idiom" : "ipad", - "filename" : "Icon-App-76x76@2x.png", - "scale" : "2x" - }, - { - "size" : "83.5x83.5", - "idiom" : "ipad", - "filename" : "Icon-App-83.5x83.5@2x.png", - "scale" : "2x" - }, - { - "size" : "1024x1024", - "idiom" : "ios-marketing", - "filename" : "Icon-App-1024x1024@1x.png", - "scale" : "1x" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} diff --git a/packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png b/packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png deleted file mode 100644 index dc9ada4725e9b0ddb1deab583e5b5102493aa332..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10932 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 diff --git a/packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png deleted file mode 100644 index f091b6b0bca859a3f474b03065bef75ba58a9e4c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1588 zcmV-42Fv-0P)C1SqPt}wig>|5Crh^=oyX$BK<}M8eLU3e2hGT;=G|!_SP)7zNI6fqUMB=)y zRAZ>eDe#*r`yDAVgB_R*LB*MAc)8(b{g{9McCXW!lq7r(btRoB9!8B-#AI6JMb~YFBEvdsV)`mEQO^&#eRKx@b&x- z5lZm*!WfD8oCLzfHGz#u7sT0^VLMI1MqGxF^v+`4YYnVYgk*=kU?HsSz{v({E3lb9 z>+xILjBN)t6`=g~IBOelGQ(O990@BfXf(DRI5I$qN$0Gkz-FSc$3a+2fX$AedL4u{ z4V+5Ong(9LiGcIKW?_352sR;LtDPmPJXI{YtT=O8=76o9;*n%_m|xo!i>7$IrZ-{l z-x3`7M}qzHsPV@$v#>H-TpjDh2UE$9g6sysUREDy_R(a)>=eHw-WAyfIN z*qb!_hW>G)Tu8nSw9yn#3wFMiLcfc4pY0ek1}8(NqkBR@t4{~oC>ryc-h_ByH(Cg5 z>ao-}771+xE3um9lWAY1FeQFxowa1(!J(;Jg*wrg!=6FdRX+t_<%z&d&?|Bn){>zm zZQj(aA_HeBY&OC^jj*)N`8fa^ePOU72VpInJoI1?`ty#lvlNzs(&MZX+R%2xS~5Kh zX*|AU4QE#~SgPzOXe9>tRj>hjU@c1k5Y_mW*Jp3fI;)1&g3j|zDgC+}2Q_v%YfDax z!?umcN^n}KYQ|a$Lr+51Nf9dkkYFSjZZjkma$0KOj+;aQ&721~t7QUKx61J3(P4P1 zstI~7-wOACnWP4=8oGOwz%vNDqD8w&Q`qcNGGrbbf&0s9L0De{4{mRS?o0MU+nR_! zrvshUau0G^DeMhM_v{5BuLjb#Hh@r23lDAk8oF(C+P0rsBpv85EP>4CVMx#04MOfG z;P%vktHcXwTj~+IE(~px)3*MY77e}p#|c>TD?sMatC0Tu4iKKJ0(X8jxQY*gYtxsC z(zYC$g|@+I+kY;dg_dE>scBf&bP1Nc@Hz<3R)V`=AGkc;8CXqdi=B4l2k|g;2%#m& z*jfX^%b!A8#bI!j9-0Fi0bOXl(-c^AB9|nQaE`*)Hw+o&jS9@7&Gov#HbD~#d{twV zXd^Tr^mWLfFh$@Dr$e;PBEz4(-2q1FF0}c;~B5sA}+Q>TOoP+t>wf)V9Iy=5ruQa;z)y zI9C9*oUga6=hxw6QasLPnee@3^Rr*M{CdaL5=R41nLs(AHk_=Y+A9$2&H(B7!_pURs&8aNw7?`&Z&xY_Ye z)~D5Bog^td-^QbUtkTirdyK^mTHAOuptDflut!#^lnKqU md>ggs(5nOWAqO?umG&QVYK#ibz}*4>0000U6E9hRK9^#O7(mu>ETqrXGsduA8$)?`v2seloOCza43C{NQ$$gAOH**MCn0Q?+L7dl7qnbRdqZ8LSVp1ItDxhxD?t@5_yHg6A8yI zC*%Wgg22K|8E#!~cTNYR~@Y9KepMPrrB8cABapAFa=`H+UGhkXUZV1GnwR1*lPyZ;*K(i~2gp|@bzp8}og7e*#% zEnr|^CWdVV!-4*Y_7rFvlww2Ze+>j*!Z!pQ?2l->4q#nqRu9`ELo6RMS5=br47g_X zRw}P9a7RRYQ%2Vsd0Me{_(EggTnuN6j=-?uFS6j^u69elMypu?t>op*wBx<=Wx8?( ztpe^(fwM6jJX7M-l*k3kEpWOl_Vk3@(_w4oc}4YF4|Rt=2V^XU?#Yz`8(e?aZ@#li0n*=g^qOcVpd-Wbok=@b#Yw zqn8u9a)z>l(1kEaPYZ6hwubN6i<8QHgsu0oE) ziJ(p;Wxm>sf!K+cw>R-(^Y2_bahB+&KI9y^);#0qt}t-$C|Bo71lHi{_+lg#f%RFy z0um=e3$K3i6K{U_4K!EX?F&rExl^W|G8Z8;`5z-k}OGNZ0#WVb$WCpQu-_YsiqKP?BB# vzVHS-CTUF4Ozn5G+mq_~Qqto~ahA+K`|lyv3(-e}00000NkvXXu0mjfd`9t{ diff --git a/packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png deleted file mode 100644 index d0ef06e7edb86cdfe0d15b4b0d98334a86163658..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1716 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 diff --git a/packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png deleted file mode 100644 index c8f9ed8f5cee1c98386d13b17e89f719e83555b2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1895 zcmV-t2blPYP)FQtfgmafE#=YDCq`qUBt#QpG%*H6QHY765~R=q zZ6iudfM}q!Pz#~9JgOi8QJ|DSu?1-*(kSi1K4#~5?#|rh?sS)(-JQqX*}ciXJ56_H zdw=^s_srbAdqxlvGyrgGet#6T7_|j;95sL%MtM;q86vOxKM$f#puR)Bjv9Zvz9-di zXOTSsZkM83)E9PYBXC<$6(|>lNLVBb&&6y{NByFCp%6+^ALR@NCTse_wqvNmSWI-m z!$%KlHFH2omF!>#%1l3LTZg(s7eof$7*xB)ZQ0h?ejh?Ta9fDv59+u#MokW+1t8Zb zgHv%K(u9G^Lv`lh#f3<6!JVTL3(dCpxHbnbA;kKqQyd1~^Xe0VIaYBSWm6nsr;dFj z4;G-RyL?cYgsN1{L4ZFFNa;8)Rv0fM0C(~Tkit94 zz#~A)59?QjD&pAPSEQ)p8gP|DS{ng)j=2ux)_EzzJ773GmQ_Cic%3JJhC0t2cx>|v zJcVusIB!%F90{+}8hG3QU4KNeKmK%T>mN57NnCZ^56=0?&3@!j>a>B43pi{!u z7JyDj7`6d)qVp^R=%j>UIY6f+3`+qzIc!Y_=+uN^3BYV|o+$vGo-j-Wm<10%A=(Yk^beI{t%ld@yhKjq0iNjqN4XMGgQtbKubPM$JWBz}YA65k%dm*awtC^+f;a-x4+ddbH^7iDWGg&N0n#MW{kA|=8iMUiFYvMoDY@sPC#t$55gn6ykUTPAr`a@!(;np824>2xJthS z*ZdmT`g5-`BuJs`0LVhz+D9NNa3<=6m;cQLaF?tCv8)zcRSh66*Z|vXhG@$I%U~2l z?`Q zykI#*+rQ=z6Jm=Bui-SfpDYLA=|vzGE(dYm=OC8XM&MDo7ux4UF1~0J1+i%aCUpRe zt3L_uNyQ*cE(38Uy03H%I*)*Bh=Lb^Xj3?I^Hnbeq72(EOK^Y93CNp*uAA{5Lc=ky zx=~RKa4{iTm{_>_vSCm?$Ej=i6@=m%@VvAITnigVg{&@!7CDgs908761meDK5azA} z4?=NOH|PdvabgJ&fW2{Mo$Q0CcD8Qc84%{JPYt5EiG{MdLIAeX%T=D7NIP4%Hw}p9 zg)==!2Lbp#j{u_}hMiao9=!VSyx0gHbeCS`;q&vzeq|fs`y&^X-lso(Ls@-706qmA z7u*T5PMo_w3{se1t2`zWeO^hOvTsohG_;>J0wVqVe+n)AbQCx)yh9;w+J6?NF5Lmo zecS@ieAKL8%bVd@+-KT{yI|S}O>pYckUFs;ry9Ow$CD@ztz5K-*D$^{i(_1llhSh^ zEkL$}tsQt5>QA^;QgjgIfBDmcOgi5YDyu?t6vSnbp=1+@6D& z5MJ}B8q;bRlVoxasyhcUF1+)o`&3r0colr}QJ3hcSdLu;9;td>kf@Tcn<@9sIx&=m z;AD;SCh95=&p;$r{Xz3iWCO^MX83AGJ(yH&eTXgv|0=34#-&WAmw{)U7OU9!Wz^!7 zZ%jZFi@JR;>Mhi7S>V7wQ176|FdW2m?&`qa(ScO^CFPR80HucLHOTy%5s*HR0^8)i h0WYBP*#0Ks^FNSabJA*5${_#%002ovPDHLkV1oKhTl@e3 diff --git a/packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png deleted file mode 100644 index a6d6b8609df07bf62e5100a53a01510388bd2b22..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2665 zcmV-v3YPVWP)oFh3q0MFesq&64WThn3$;G69TfjsAv=f2G9}p zgSx99+!YV6qME!>9MD13x)k(+XE7W?_O4LoLb5ND8 zaV{9+P@>42xDfRiYBMSgD$0!vssptcb;&?u9u(LLBKmkZ>RMD=kvD3h`sk6!QYtBa ztlZI#nu$8lJ^q2Z79UTgZe>BU73(Aospiq+?SdMt8lDZ;*?@tyWVZVS_Q7S&*tJaiRlJ z+aSMOmbg3@h5}v;A*c8SbqM3icg-`Cnwl;7Ts%A1RkNIp+Txl-Ckkvg4oxrqGA5ewEgYqwtECD<_3Egu)xGllKt&J8g&+=ac@Jq4-?w6M3b*>w5 z69N3O%=I^6&UL5gZ!}trC7bUj*12xLdkNs~Bz4QdJJ*UDZox2UGR}SNg@lmOvhCc~ z*f_UeXv(=#I#*7>VZx2ObEN~UoGUTl=-@)E;YtCRZ>SVp$p9yG5hEFZ!`wI!spd)n zSk+vK0Vin7FL{7f&6OB%f;SH22dtbcF<|9fi2Fp%q4kxL!b1#l^)8dUwJ zwEf{(wJj@8iYDVnKB`eSU+;ml-t2`@%_)0jDM`+a46xhDbBj2+&Ih>1A>6aky#(-SYyE{R3f#y57wfLs z6w1p~$bp;6!9DX$M+J~S@D6vJAaElETnsX4h9a5tvPhC3L@qB~bOzkL@^z0k_hS{T4PF*TDrgdXp+dzsE? z>V|VR035Pl9n5&-RePFdS{7KAr2vPOqR9=M$vXA1Yy5>w;EsF`;OK{2pkn-kpp9Pw z)r;5JfJKKaT$4qCb{TaXHjb$QA{y0EYy*+b1XI;6Ah- zw13P)xT`>~eFoJC!>{2XL(a_#upp3gaR1#5+L(Jmzp4TBnx{~WHedpJ1ch8JFk~Sw z>F+gN+i+VD?gMXwcIhn8rz`>e>J^TI3E-MW>f}6R-pL}>WMOa0k#jN+`RyUVUC;#D zg|~oS^$6%wpF{^Qr+}X>0PKcr3Fc&>Z>uv@C);pwDs@2bZWhYP!rvGx?_|q{d`t<*XEb#=aOb=N+L@CVBGqImZf&+a zCQEa3$~@#kC);pasdG=f6tuIi0PO-y&tvX%>Mv=oY3U$nD zJ#gMegnQ46pq+3r=;zmgcG+zRc9D~c>z+jo9&D+`E6$LmyFqlmCYw;-Zooma{sR@~ z)_^|YL1&&@|GXo*pivH7k!msl+$Sew3%XJnxajt0K%3M6Bd&YFNy9}tWG^aovK2eX z1aL1%7;KRDrA@eG-Wr6w+;*H_VD~qLiVI`{_;>o)k`{8xa3EJT1O_>#iy_?va0eR? zDV=N%;Zjb%Z2s$@O>w@iqt!I}tLjGk!=p`D23I}N4Be@$(|iSA zf3Ih7b<{zqpDB4WF_5X1(peKe+rASze%u8eKLn#KKXt;UZ+Adf$_TO+vTqshLLJ5c z52HucO=lrNVae5XWOLm!V@n-ObU11!b+DN<$RuU+YsrBq*lYT;?AwJpmNKniF0Q1< zJCo>Q$=v$@&y=sj6{r!Y&y&`0$-I}S!H_~pI&2H8Z1C|BX4VgZ^-! zje3-;x0PBD!M`v*J_)rL^+$<1VJhH*2Fi~aA7s&@_rUHYJ9zD=M%4AFQ`}k8OC$9s XsPq=LnkwKG00000NkvXXu0mjfhAk5^ diff --git a/packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png deleted file mode 100644 index a6d6b8609df07bf62e5100a53a01510388bd2b22..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2665 zcmV-v3YPVWP)oFh3q0MFesq&64WThn3$;G69TfjsAv=f2G9}p zgSx99+!YV6qME!>9MD13x)k(+XE7W?_O4LoLb5ND8 zaV{9+P@>42xDfRiYBMSgD$0!vssptcb;&?u9u(LLBKmkZ>RMD=kvD3h`sk6!QYtBa ztlZI#nu$8lJ^q2Z79UTgZe>BU73(Aospiq+?SdMt8lDZ;*?@tyWVZVS_Q7S&*tJaiRlJ z+aSMOmbg3@h5}v;A*c8SbqM3icg-`Cnwl;7Ts%A1RkNIp+Txl-Ckkvg4oxrqGA5ewEgYqwtECD<_3Egu)xGllKt&J8g&+=ac@Jq4-?w6M3b*>w5 z69N3O%=I^6&UL5gZ!}trC7bUj*12xLdkNs~Bz4QdJJ*UDZox2UGR}SNg@lmOvhCc~ z*f_UeXv(=#I#*7>VZx2ObEN~UoGUTl=-@)E;YtCRZ>SVp$p9yG5hEFZ!`wI!spd)n zSk+vK0Vin7FL{7f&6OB%f;SH22dtbcF<|9fi2Fp%q4kxL!b1#l^)8dUwJ zwEf{(wJj@8iYDVnKB`eSU+;ml-t2`@%_)0jDM`+a46xhDbBj2+&Ih>1A>6aky#(-SYyE{R3f#y57wfLs z6w1p~$bp;6!9DX$M+J~S@D6vJAaElETnsX4h9a5tvPhC3L@qB~bOzkL@^z0k_hS{T4PF*TDrgdXp+dzsE? z>V|VR035Pl9n5&-RePFdS{7KAr2vPOqR9=M$vXA1Yy5>w;EsF`;OK{2pkn-kpp9Pw z)r;5JfJKKaT$4qCb{TaXHjb$QA{y0EYy*+b1XI;6Ah- zw13P)xT`>~eFoJC!>{2XL(a_#upp3gaR1#5+L(Jmzp4TBnx{~WHedpJ1ch8JFk~Sw z>F+gN+i+VD?gMXwcIhn8rz`>e>J^TI3E-MW>f}6R-pL}>WMOa0k#jN+`RyUVUC;#D zg|~oS^$6%wpF{^Qr+}X>0PKcr3Fc&>Z>uv@C);pwDs@2bZWhYP!rvGx?_|q{d`t<*XEb#=aOb=N+L@CVBGqImZf&+a zCQEa3$~@#kC);pasdG=f6tuIi0PO-y&tvX%>Mv=oY3U$nD zJ#gMegnQ46pq+3r=;zmgcG+zRc9D~c>z+jo9&D+`E6$LmyFqlmCYw;-Zooma{sR@~ z)_^|YL1&&@|GXo*pivH7k!msl+$Sew3%XJnxajt0K%3M6Bd&YFNy9}tWG^aovK2eX z1aL1%7;KRDrA@eG-Wr6w+;*H_VD~qLiVI`{_;>o)k`{8xa3EJT1O_>#iy_?va0eR? zDV=N%;Zjb%Z2s$@O>w@iqt!I}tLjGk!=p`D23I}N4Be@$(|iSA zf3Ih7b<{zqpDB4WF_5X1(peKe+rASze%u8eKLn#KKXt;UZ+Adf$_TO+vTqshLLJ5c z52HucO=lrNVae5XWOLm!V@n-ObU11!b+DN<$RuU+YsrBq*lYT;?AwJpmNKniF0Q1< zJCo>Q$=v$@&y=sj6{r!Y&y&`0$-I}S!H_~pI&2H8Z1C|BX4VgZ^-! zje3-;x0PBD!M`v*J_)rL^+$<1VJhH*2Fi~aA7s&@_rUHYJ9zD=M%4AFQ`}k8OC$9s XsPq=LnkwKG00000NkvXXu0mjfhAk5^ diff --git a/packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png deleted file mode 100644 index 75b2d164a5a98e212cca15ea7bf2ab5de5108680..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3831 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 diff --git a/packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png deleted file mode 100644 index c4df70d39da7941ef3f6dcb7f06a192d8dcb308d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1888 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 iW8Zci7-kcv6Uzs@r-FtIZ-&5|)J Q1PU{Fy85}Sb4q9e0B4a5jsO4v diff --git a/packages/dart_client/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png b/packages/dart_client/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png deleted file mode 100644 index 9da19eacad3b03bb08bbddbbf4ac48dd78b3d838..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 68 zcmeAS@N?(olHy`uVBq!ia0vp^j3CUx0wlM}@Gt=>Zci7-kcv6Uzs@r-FtIZ-&5|)J Q1PU{Fy85}Sb4q9e0B4a5jsO4v diff --git a/packages/dart_client/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png b/packages/dart_client/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png deleted file mode 100644 index 9da19eacad3b03bb08bbddbbf4ac48dd78b3d838..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 68 zcmeAS@N?(olHy`uVBq!ia0vp^j3CUx0wlM}@Gt=>Zci7-kcv6Uzs@r-FtIZ-&5|)J Q1PU{Fy85}Sb4q9e0B4a5jsO4v diff --git a/packages/dart_client/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md b/packages/dart_client/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md deleted file mode 100644 index 89c2725b..00000000 --- a/packages/dart_client/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md +++ /dev/null @@ -1,5 +0,0 @@ -# Launch Screen Assets - -You can customize the launch screen with your own desired assets by replacing the image files in this directory. - -You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images. \ No newline at end of file diff --git a/packages/dart_client/example/ios/Runner/Base.lproj/LaunchScreen.storyboard b/packages/dart_client/example/ios/Runner/Base.lproj/LaunchScreen.storyboard deleted file mode 100644 index f2e259c7..00000000 --- a/packages/dart_client/example/ios/Runner/Base.lproj/LaunchScreen.storyboard +++ /dev/null @@ -1,37 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/packages/dart_client/example/ios/Runner/Base.lproj/Main.storyboard b/packages/dart_client/example/ios/Runner/Base.lproj/Main.storyboard deleted file mode 100644 index f3c28516..00000000 --- a/packages/dart_client/example/ios/Runner/Base.lproj/Main.storyboard +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/packages/dart_client/example/ios/Runner/Info.plist b/packages/dart_client/example/ios/Runner/Info.plist deleted file mode 100644 index d89e1ca3..00000000 --- a/packages/dart_client/example/ios/Runner/Info.plist +++ /dev/null @@ -1,50 +0,0 @@ - - - - - NSAppTransportSecurity - - NSAllowsArbitraryLoads - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - stream_chat - CFBundlePackageType - APPL - CFBundleShortVersionString - $(FLUTTER_BUILD_NAME) - CFBundleSignature - ???? - CFBundleVersion - $(FLUTTER_BUILD_NUMBER) - LSRequiresIPhoneOS - - UILaunchStoryboardName - LaunchScreen - UIMainStoryboardFile - Main - UISupportedInterfaceOrientations - - UIInterfaceOrientationPortrait - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - UISupportedInterfaceOrientations~ipad - - UIInterfaceOrientationPortrait - UIInterfaceOrientationPortraitUpsideDown - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - UIViewControllerBasedStatusBarAppearance - - - diff --git a/packages/dart_client/example/ios/Runner/Runner-Bridging-Header.h b/packages/dart_client/example/ios/Runner/Runner-Bridging-Header.h deleted file mode 100644 index 308a2a56..00000000 --- a/packages/dart_client/example/ios/Runner/Runner-Bridging-Header.h +++ /dev/null @@ -1 +0,0 @@ -#import "GeneratedPluginRegistrant.h" diff --git a/packages/dart_client/example/lib/channel_header.dart b/packages/dart_client/example/lib/channel_header.dart deleted file mode 100644 index c452a2f5..00000000 --- a/packages/dart_client/example/lib/channel_header.dart +++ /dev/null @@ -1,83 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:stream_chat/stream_chat.dart'; -import 'package:timeago/timeago.dart' as timeago; - -import './channel_name_text.dart'; -import 'channel_image.dart'; -import 'stream_channel.dart'; - -class ChannelHeader extends StatelessWidget implements PreferredSizeWidget { - final bool showBackButton; - final VoidCallback onBackPressed; - - ChannelHeader({ - Key key, - this.showBackButton = true, - this.onBackPressed, - }) : preferredSize = Size.fromHeight(kToolbarHeight), - super(key: key); - - @override - Widget build(BuildContext context) { - final streamChat = StreamChannel.of(context); - return AppBar( - leading: showBackButton ? _buildBackButton(context) : Container(), - actions: [ - Padding( - padding: const EdgeInsets.only(right: 10.0), - child: ChannelImage(channel: streamChat.channel), - ), - ], - centerTitle: true, - title: Column( - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - ChannelNameText( - channel: streamChat.channel, - ), - _buildLastActive(context, streamChat.channel), - ], - ), - ); - } - - StatelessWidget _buildLastActive(BuildContext context, Channel channel) { - return (channel.lastMessageAt != null) - ? Text( - 'Active ${timeago.format(channel.lastMessageAt)}', - style: Theme.of(context).textTheme.caption, - ) - : Container(); - } - - Padding _buildBackButton(BuildContext context) { - return Padding( - padding: const EdgeInsets.all(14.0), - child: RawMaterialButton( - shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(4)), - elevation: 0, - highlightElevation: 0, - focusElevation: 0, - disabledElevation: 0, - hoverElevation: 0, - onPressed: () { - if (onBackPressed != null) { - onBackPressed(); - } else { - Navigator.of(context).pop(); - } - }, - fillColor: Colors.black.withOpacity(.1), - padding: EdgeInsets.all(4), - child: Icon( - Icons.arrow_back_ios, - size: 15, - color: Colors.black, - ), - ), - ); - } - - @override - final Size preferredSize; -} diff --git a/packages/dart_client/example/lib/channel_image.dart b/packages/dart_client/example/lib/channel_image.dart deleted file mode 100644 index f28db180..00000000 --- a/packages/dart_client/example/lib/channel_image.dart +++ /dev/null @@ -1,25 +0,0 @@ -import 'package:cached_network_image/cached_network_image.dart'; -import 'package:flutter/material.dart'; -import 'package:stream_chat/stream_chat.dart'; - -class ChannelImage extends StatelessWidget { - const ChannelImage({ - Key key, - @required this.channel, - }) : super(key: key); - - final Channel channel; - - @override - Widget build(BuildContext context) { - return CircleAvatar( - radius: 20, - backgroundImage: channel.extraData.containsKey('image') - ? CachedNetworkImageProvider(channel.extraData['image'] as String) - : null, - child: channel.extraData.containsKey('image') - ? null - : Text(channel.config.name[0]), - ); - } -} diff --git a/packages/dart_client/example/lib/channel_list_page.dart b/packages/dart_client/example/lib/channel_list_page.dart deleted file mode 100644 index 7c3864b5..00000000 --- a/packages/dart_client/example/lib/channel_list_page.dart +++ /dev/null @@ -1,138 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter/widgets.dart'; -import 'package:stream_chat/stream_chat.dart'; - -import './connection_indicator.dart'; -import './message_page.dart'; -import './stream_channel.dart'; -import 'channel_list_view.dart'; -import 'channel_page_app_bar.dart'; -import 'stream_chat.dart'; - -class ChannelListPage extends StatefulWidget { - ChannelListPage({ - this.filter, - this.options, - this.sort, - this.pagination, - }); - - final Map filter; - final Map options; - final List sort; - final PaginationParams pagination; - - @override - ChannelListPageState createState() => ChannelListPageState(); -} - -class ChannelListPageState extends State { - String _selectedChannelId; - bool showSplit; - IndicatorController _indicatorController = IndicatorController(); - - @override - Widget build(BuildContext context) { - showSplit = MediaQuery.of(context).size.width > 1000; - return Flex( - direction: Axis.horizontal, - children: [ - Flexible( - flex: 1, - child: Scaffold( - bottomNavigationBar: ConnectionIndicator( - indicatorController: _indicatorController, - ), - appBar: ChannelPageAppBar(), - body: ChannelListView( - channelWidget: MessagePage(), - options: widget.options, - filter: widget.filter, - pagination: widget.pagination, - sort: widget.sort, - onChannelTap: showSplit - ? (channelClient, _) { - _navigateToChannel(context, channelClient); - } - : null, - ), - floatingActionButton: FloatingActionButton( - onPressed: () {}, - backgroundColor: Colors.white, - child: Icon( - Icons.send, - ), - ), - ), - ), - showSplit ? _buildMessageView(context) : Container(), - ], - ); - } - - Flexible _buildMessageView(BuildContext context) { - return Flexible( - flex: 2, - child: _selectedChannelId == null - ? Scaffold( - body: Center( - child: Text( - 'Pick a channel to show the messages 💬', - style: Theme.of(context).textTheme.headline, - ), - ), - ) - : StreamChannel( - channelClient: StreamChat.of(context) - .client - .state - .channels - .firstWhere((c) => c.id == _selectedChannelId), - child: MessagePage(), - ), - ); - } - - void _navigateToChannel( - BuildContext context, - Channel channel, - ) { - setState(() { - _selectedChannelId = channel.id; - }); - } - - @override - void initState() { - super.initState(); - - final streamChat = StreamChat.of(context); - streamChat.client.wsConnectionStatus.addListener(() { - if (streamChat.client.wsConnectionStatus.value == - ConnectionStatus.disconnected) { - _indicatorController.showIndicator( - duration: Duration(minutes: 1), - color: Colors.red, - text: 'Disconnected', - ); - } else if (streamChat.client.wsConnectionStatus.value == - ConnectionStatus.connecting) { - _indicatorController.showIndicator( - duration: Duration(minutes: 1), - color: Colors.yellow, - text: 'Reconnecting', - ); - } else if (streamChat.client.wsConnectionStatus.value == - ConnectionStatus.connected) { - _indicatorController.showIndicator( - duration: Duration(seconds: 5), - color: Colors.green, - text: 'Connected', - ); - streamChat.clearChannels(); - - streamChat.queryChannels(); - } - }); - } -} diff --git a/packages/dart_client/example/lib/channel_list_view.dart b/packages/dart_client/example/lib/channel_list_view.dart deleted file mode 100644 index 9c89d4d6..00000000 --- a/packages/dart_client/example/lib/channel_list_view.dart +++ /dev/null @@ -1,208 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:stream_chat/stream_chat.dart'; - -import 'channel_preview.dart'; -import 'stream_channel.dart'; -import 'stream_chat.dart'; - -typedef ChannelTapCallback = void Function(Channel, Widget); - -class ChannelListView extends StatefulWidget { - ChannelListView({ - Key key, - this.filter, - this.options, - this.sort, - this.pagination, - this.onChannelTap, - this.channelWidget, - this.channelPreview, - }) : assert(channelWidget != null || onChannelTap != null), - super(key: key); - - final Map filter; - final Map options; - final List sort; - final PaginationParams pagination; - final ScrollController _scrollController = ScrollController(); - final ChannelTapCallback onChannelTap; - final Widget channelWidget; - final Widget channelPreview; - - @override - _ChannelListViewState createState() => _ChannelListViewState(); -} - -class _ChannelListViewState extends State { - @override - Widget build(BuildContext context) { - final streamChat = StreamChat.of(context); - return RefreshIndicator( - onRefresh: () async { - streamChat.clearChannels(); - return streamChat.queryChannels( - filter: widget.filter, - sortOptions: widget.sort, - paginationParams: widget.pagination, - options: widget.options, - ); - }, - child: StreamBuilder>( - stream: streamChat.client.state.channelsStream, - builder: (context, snapshot) { - if (!snapshot.hasData) { - return Center( - child: CircularProgressIndicator(), - ); - } - - if (snapshot.hasError) { - print((snapshot.error as Error).stackTrace); - return Center( - child: Text(snapshot.error.toString()), - ); - } - - final channelsStates = snapshot.data; - return ListView.custom( - physics: AlwaysScrollableScrollPhysics(), - controller: widget._scrollController, - childrenDelegate: SliverChildBuilderDelegate( - (context, i) { - return _itemBuilder(context, i, channelsStates); - }, - childCount: (channelsStates.length * 2) + 1, - findChildIndexCallback: (key) { - final ValueKey valueKey = key; - final index = channelsStates - .indexWhere((cs) => 'CHANNEL-${cs.id}' == valueKey.value); - return index != -1 ? (index * 2) : null; - }, - ), - ); - }), - ); - } - - Widget _itemBuilder(context, int i, List channelsStates) { - if (i % 2 != 0) { - return _separatorBuilder(context, i); - } - - i = i ~/ 2; - - final streamChat = StreamChat.of(context); - if (i < channelsStates.length) { - final channelState = channelsStates[i]; - - final channelClient = streamChat.client.state.channels - .firstWhere((c) => c.cid == channelState.cid); - - ChannelTapCallback onTap; - if (widget.onChannelTap != null) { - onTap = widget.onChannelTap; - } else { - onTap = (client, _) { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) { - return StreamChannel( - child: widget.channelWidget, - channelClient: client, - ); - }, - ), - ); - }; - } - - Widget child; - if (widget.channelPreview != null) { - child = Stack( - children: [ - widget.channelPreview, - Positioned.fill( - child: Material( - color: Colors.transparent, - child: InkWell( - onTap: () { - onTap(channelClient, widget.channelWidget); - }, - ), - ), - ), - ], - ); - } else { - child = ChannelPreview( - onTap: (channelClient) { - onTap(channelClient, widget.channelWidget); - }, - ); - } - - return StreamChannel( - key: ValueKey('CHANNEL-${channelClient?.id}'), - child: child, - channelClient: channelClient, - ); - } else { - return _buildQueryProgressIndicator(context, streamChat); - } - } - - Widget _buildQueryProgressIndicator(context, StreamChat streamChat) { - return StreamBuilder( - stream: streamChat.queryChannelsLoading, - initialData: false, - builder: (context, snapshot) { - return Container( - height: 100, - padding: EdgeInsets.all(32), - child: Center( - child: snapshot.data ? CircularProgressIndicator() : Container(), - ), - ); - }); - } - - Widget _separatorBuilder(context, i) { - return Container( - height: 1, - color: Colors.black.withOpacity(0.1), - margin: EdgeInsets.symmetric(horizontal: 16), - ); - } - - void _listenChannelPagination(StreamChat streamChat) { - if (widget._scrollController.position.maxScrollExtent == - widget._scrollController.position.pixels) { - streamChat.queryChannels( - filter: widget.filter, - sortOptions: widget.sort, - paginationParams: widget.pagination.copyWith( - offset: streamChat.channels.length, - ), - options: widget.options, - ); - } - } - - @override - void initState() { - super.initState(); - - final streamChat = StreamChat.of(context); - streamChat.queryChannels( - filter: widget.filter, - sortOptions: widget.sort, - paginationParams: widget.pagination, - options: widget.options, - ); - - widget._scrollController.addListener(() { - _listenChannelPagination(streamChat); - }); - } -} diff --git a/packages/dart_client/example/lib/channel_name_text.dart b/packages/dart_client/example/lib/channel_name_text.dart deleted file mode 100644 index f31f38c5..00000000 --- a/packages/dart_client/example/lib/channel_name_text.dart +++ /dev/null @@ -1,19 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:stream_chat/stream_chat.dart'; - -class ChannelNameText extends StatelessWidget { - const ChannelNameText({ - Key key, - this.channel, - }) : super(key: key); - - final Channel channel; - - @override - Widget build(BuildContext context) { - return Text( - channel.extraData['name'] as String ?? channel.config.name, - style: Theme.of(context).textTheme.body2, - ); - } -} diff --git a/packages/dart_client/example/lib/channel_page_app_bar.dart b/packages/dart_client/example/lib/channel_page_app_bar.dart deleted file mode 100644 index 8ee1e754..00000000 --- a/packages/dart_client/example/lib/channel_page_app_bar.dart +++ /dev/null @@ -1,41 +0,0 @@ -import 'package:flutter/material.dart'; - -class ChannelPageAppBar extends StatelessWidget implements PreferredSizeWidget { - ChannelPageAppBar({ - Key key, - }) : preferredSize = Size.fromHeight(kToolbarHeight), - super(key: key); - - @override - Widget build(BuildContext context) { - return SafeArea( - child: Material( - elevation: 4, - child: Padding( - padding: EdgeInsets.symmetric(vertical: 5, horizontal: 30), - child: Container( - decoration: BoxDecoration( - color: Colors.black.withAlpha(5), - borderRadius: BorderRadius.circular(32.0), - border: Border.all(color: Colors.black.withOpacity(.2))), - child: Padding( - padding: const EdgeInsets.only(left: 8.0), - child: TextField( - style: Theme.of(context).textTheme.body1, - autofocus: false, - decoration: InputDecoration( - hintText: 'Search', - prefixText: ' ', - border: InputBorder.none, - ), - ), - ), - ), - ), - ), - ); - } - - @override - final Size preferredSize; -} diff --git a/packages/dart_client/example/lib/channel_preview.dart b/packages/dart_client/example/lib/channel_preview.dart deleted file mode 100644 index 8926e107..00000000 --- a/packages/dart_client/example/lib/channel_preview.dart +++ /dev/null @@ -1,139 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter/widgets.dart'; -import 'package:jiffy/jiffy.dart'; -import 'package:stream_chat/stream_chat.dart'; - -import 'channel_image.dart'; -import 'channel_name_text.dart'; -import 'stream_channel.dart'; -import 'stream_chat.dart'; - -class ChannelPreview extends StatelessWidget { - final void Function(Channel) onTap; - - const ChannelPreview({ - Key key, - this.onTap, - }) : super(key: key); - - @override - Widget build(BuildContext context) { - final streamChannel = StreamChannel.of(context); - return _buildChannelPreview( - context, - streamChannel, - ); - } - - StreamChannel _buildChannelPreview( - BuildContext context, - StreamChannelState streamChannel, - ) { - final channelClient = StreamChat.of(context) - .client - .state - .channels - .firstWhere((c) => c.cid == streamChannel.channel.cid); - return StreamChannel( - channelClient: channelClient, - child: ListTile( - onTap: () { - onTap(channelClient); - }, - leading: ChannelImage( - channel: streamChannel.channel, - ), - title: ChannelNameText( - channel: streamChannel.channel, - ), - subtitle: _buildSubtitle( - streamChannel, - ), - trailing: Column( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.end, - children: [ - _buildDate(context, streamChannel.channel.lastMessageAt), - ], - ), - ), - ); - } - - Text _buildDate(BuildContext context, DateTime lastMessageAt) { - String stringDate; - final now = DateTime.now(); - - if (now.year != lastMessageAt.year || - now.month != lastMessageAt.month || - now.day != lastMessageAt.day) { - stringDate = Jiffy(lastMessageAt.toLocal()).format('dd/MM/yyyy'); - } else { - stringDate = Jiffy(lastMessageAt.toLocal()).format('HH:mm'); - } - - return Text( - stringDate, - style: Theme.of(context).textTheme.caption, - ); - } - - Widget _buildSubtitle( - StreamChannelState streamChannel, - ) { - return StreamBuilder>( - stream: streamChannel.channelClient.state.typingEventsStream, - initialData: [], - builder: (context, snapshot) { - final typings = snapshot.data; - final opacity = - streamChannel.channelClient.state.unreadCount > .0 ? 1.0 : 0.5; - return typings.isNotEmpty - ? _buildTypings(typings, context, opacity) - : _buildLastMessage(context, streamChannel, opacity); - }); - } - - Widget _buildLastMessage( - BuildContext context, StreamChannelState streamChannel, double opacity) { - final lastMessage = streamChannel.channel.state.messages.isNotEmpty - ? streamChannel.channel.state.messages.last - : null; - if (lastMessage == null) { - return SizedBox.fromSize( - size: Size.zero, - ); - } - - final prefix = lastMessage.attachments - .map((e) { - if (e.type == 'image') { - return '📷'; - } else if (e.type == 'video') { - return '🎬'; - } - return null; - }) - .where((e) => e != null) - .join(' '); - - return Text( - '$prefix ${lastMessage.text ?? ''}', - maxLines: 1, - overflow: TextOverflow.ellipsis, - style: Theme.of(context).textTheme.caption.copyWith( - color: Colors.black.withOpacity(opacity), - ), - ); - } - - Text _buildTypings(List typings, BuildContext context, double opacity) { - return Text( - '${typings.map((u) => u.extraData.containsKey('name') ? u.extraData['name'] : u.id).join(',')} ${typings.length == 1 ? 'is' : 'are'} typing...', - maxLines: 1, - style: Theme.of(context).textTheme.caption.copyWith( - color: Colors.black.withOpacity(opacity), - ), - ); - } -} diff --git a/packages/dart_client/example/lib/connection_indicator.dart b/packages/dart_client/example/lib/connection_indicator.dart deleted file mode 100644 index 4fb81861..00000000 --- a/packages/dart_client/example/lib/connection_indicator.dart +++ /dev/null @@ -1,100 +0,0 @@ -import 'package:flutter/material.dart'; - -class ConnectionIndicator extends StatefulWidget { - final IndicatorController indicatorController; - - const ConnectionIndicator({ - Key key, - this.indicatorController, - }) : super(key: key); - - @override - _ConnectionIndicatorState createState() => _ConnectionIndicatorState(); -} - -class _ConnectionIndicatorState extends State { - double _height = 0; - String _text; - Color _color; - VoidCallback _listener; - - @override - Widget build(BuildContext context) { - return AnimatedContainer( - duration: Duration(milliseconds: 300), - height: _height, - child: Container( - width: double.infinity, - child: Material( - color: _color ?? Theme.of(context).snackBarTheme.backgroundColor, - child: Center( - child: Text(_text ?? ''), - ), - ), - ), - ); - } - - @override - void initState() { - super.initState(); - - _listener = () { - final values = widget.indicatorController.indicatorValues.value; - if (mounted) { - setState(() { - _height = 30; - _text = values.text; - _color = values.color; - }); - } - - if (values.duration != null) { - Future.delayed(values.duration, () { - if (mounted) { - setState(() { - _height = 0; - _text = ''; - }); - } - }); - } - }; - - widget.indicatorController.indicatorValues.addListener(_listener); - } - - @override - void dispose() { - widget.indicatorController.indicatorValues.removeListener(_listener); - super.dispose(); - } -} - -class IndicatorValues { - final String text; - final Color color; - final Duration duration; - - IndicatorValues({ - this.duration, - this.text, - this.color, - }); -} - -class IndicatorController { - ValueNotifier indicatorValues = ValueNotifier(null); - - void showIndicator({ - Duration duration, - Color color, - String text, - }) { - indicatorValues.value = IndicatorValues( - text: text, - color: color, - duration: duration, - ); - } -} diff --git a/packages/dart_client/example/lib/main.dart b/packages/dart_client/example/lib/main.dart deleted file mode 100644 index de87783b..00000000 --- a/packages/dart_client/example/lib/main.dart +++ /dev/null @@ -1,94 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:stream_chat/stream_chat.dart'; - -import 'channel_list_page.dart'; -import 'stream_chat.dart'; - -void main() async { - final client = Client( - "qk4nn7rpcn75", - logLevel: Level.INFO, - ); - - await client.setUser( - User(id: "wild-breeze-7"), - 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoid2lsZC1icmVlemUtNyJ9.VM2EX1EXOfgqa-bTH_3JzeY0T99ngWzWahSauP3dBMo', - ); - - runApp(StreamChat( - child: MyApp(), - client: client, - )); -} - -class MyApp extends StatefulWidget { - @override - _MyAppState createState() => _MyAppState(); -} - -class _MyAppState extends State { - @override - Widget build(BuildContext context) { - return MaterialApp( - debugShowCheckedModeBanner: false, - title: 'Stream Chat Example', - home: ChatLoader(), - theme: ThemeData( - scaffoldBackgroundColor: Color(0xfff1f1f3), - primaryColor: Color(0xfff1f1f3), - accentColor: Color(0xff006bff), - iconTheme: IconThemeData( - color: Color(0xff006bff), - ), - floatingActionButtonTheme: FloatingActionButtonThemeData( - foregroundColor: Color(0xff006bff), - ), - backgroundColor: Color(0xfff1f1f3), - canvasColor: Color(0xfff1f1f3), - ), - ); - } - - @override - void dispose() { - StreamChat.of(context).dispose(); - super.dispose(); - } -} - -class ChatLoader extends StatelessWidget { - @override - Widget build(BuildContext context) { - final streamChat = StreamChat.of(context); - return StreamBuilder( - stream: streamChat.userStream, - builder: (context, snapshot) { - if (snapshot.hasError) { - return Scaffold( - body: Center( - child: Text('${snapshot.error}'), - ), - ); - } else if (!snapshot.hasData) { - return Scaffold( - body: Center( - child: CircularProgressIndicator(), - ), - ); - } else { - return ChannelListPage( - filter: { - 'members': { - '\$in': [StreamChat.of(context).user.id], - } - }, - sort: [SortOption("last_message_at")], - pagination: PaginationParams( - limit: 20, - ), - ); - } - }, - ); - } -} diff --git a/packages/dart_client/example/lib/message_input.dart b/packages/dart_client/example/lib/message_input.dart deleted file mode 100644 index 243f1d31..00000000 --- a/packages/dart_client/example/lib/message_input.dart +++ /dev/null @@ -1,137 +0,0 @@ -import 'dart:ui'; - -import 'package:flutter/material.dart'; -import 'package:stream_chat/stream_chat.dart'; - -import 'stream_channel.dart'; - -class MessageInput extends StatefulWidget { - MessageInput({ - Key key, - this.onMessageSent, - this.parent, - }) : super(key: key); - - final void Function(Message) onMessageSent; - final Message parent; - - @override - _MessageInputState createState() => _MessageInputState(); -} - -class _MessageInputState extends State { - final _textController = TextEditingController(); - bool _messageIsPresent = false; - bool _typingStarted = false; - - @override - Widget build(BuildContext context) { - return Padding( - padding: const EdgeInsets.all(8.0), - child: Container( - width: MediaQuery.of(context).size.width, - padding: EdgeInsets.all(2), - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(10.0), - gradient: _typingStarted - ? LinearGradient(colors: [Color(0xFF00AEFF), Color(0xFF0076FF)]) - : null, - ), - child: Container( - decoration: BoxDecoration( - color: Theme.of(context).canvasColor, - borderRadius: BorderRadius.circular(10.0), - ), - child: Container( - decoration: BoxDecoration( - color: Colors.black.withAlpha(5), - borderRadius: BorderRadius.circular(10.0), - border: Border.all(color: Colors.black.withOpacity(.2)), - ), - child: Flex( - direction: Axis.horizontal, - children: [ - Expanded( - child: TextField( - minLines: null, - maxLines: null, - onSubmitted: (_) { - _sendMessage(context); - }, - controller: _textController, - onChanged: (s) { - StreamChannel.of(context).channelClient.keyStroke(); - setState(() { - _messageIsPresent = s.trim().isNotEmpty; - }); - }, - onTap: () { - setState(() { - _typingStarted = true; - }); - }, - style: Theme.of(context).textTheme.body1, - autofocus: false, - decoration: InputDecoration( - hintText: 'Write a message', - prefixText: ' ', - border: InputBorder.none, - ), - ), - ), - AnimatedCrossFade( - crossFadeState: _messageIsPresent - ? CrossFadeState.showFirst - : CrossFadeState.showSecond, - firstChild: _buildSendButton(context), - secondChild: Container(), - duration: Duration(milliseconds: 300), - alignment: Alignment.center, - ), - ], - ), - ), - ), - ), - ); - } - - IconButton _buildSendButton(BuildContext context) { - return IconButton( - onPressed: () { - _sendMessage(context); - }, - icon: Icon( - Icons.send, - ), - ); - } - - void _sendMessage(BuildContext context) { - final text = _textController.text.trim(); - if (text.isEmpty) { - return; - } - - _textController.clear(); - setState(() { - _messageIsPresent = false; - _typingStarted = false; - }); - FocusScope.of(context).unfocus(); - - StreamChannel.of(context) - .channelClient - .sendMessage( - Message( - parentId: widget.parent?.id, - text: text, - ), - ) - .then((_) { - if (widget.onMessageSent != null) { - widget.onMessageSent(Message(text: text)); - } - }); - } -} diff --git a/packages/dart_client/example/lib/message_list_view.dart b/packages/dart_client/example/lib/message_list_view.dart deleted file mode 100644 index af8608d6..00000000 --- a/packages/dart_client/example/lib/message_list_view.dart +++ /dev/null @@ -1,280 +0,0 @@ -import 'dart:async'; - -import 'package:flutter/material.dart'; -import 'package:flutter_widgets/flutter_widgets.dart'; -import 'package:stream_chat/stream_chat.dart'; - -import 'message_widget.dart'; -import 'stream_channel.dart'; - -typedef MessageBuilder = Widget Function(BuildContext, Message, int index); -typedef ParentMessageBuilder = Widget Function(BuildContext, Message); -typedef OnThreadSelectCallback = void Function(Message parent); - -class MessageListView extends StatefulWidget { - MessageListView({ - Key key, - MessageBuilder messageBuilder, - this.parentMessageBuilder, - this.parentMessage, - this.onThreadSelect, - }) : _messageBuilder = messageBuilder, - super(key: key); - - final MessageBuilder _messageBuilder; - final ParentMessageBuilder parentMessageBuilder; - final OnThreadSelectCallback onThreadSelect; - final Message parentMessage; - - @override - _MessageListViewState createState() => _MessageListViewState(); -} - -class _MessageListViewState extends State { - static const _newMessageLoadingOffset = 100; - final ScrollController _scrollController = ScrollController(); - bool _isBottom = true; - bool _topWasVisible = false; - List _messages = []; - List _newMessageList = []; - - @override - Widget build(BuildContext context) { - final streamChannel = StreamChannel.of(context); - - /// TODO: find a better solution when (https://github.com/flutter/flutter/issues/21023) is fixed - return NotificationListener( - onNotification: (_) { - if (_scrollController.offset < 150 && _newMessageList.isNotEmpty) { - setState(() { - _messages.insertAll(0, _newMessageList); - _newMessageList.clear(); - }); - } - return true; - }, - child: ListView.custom( - physics: AlwaysScrollableScrollPhysics(), - controller: _scrollController, - reverse: true, - childrenDelegate: SliverChildBuilderDelegate( - (context, i) { - if (i == _messages.length + 1) { - if (widget.parentMessage != null) { - if (widget.parentMessageBuilder != null) { - return widget.parentMessageBuilder( - context, widget.parentMessage); - } else { - return Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - MessageWidget( - key: ValueKey( - 'PARENT-MESSAGE-${widget.parentMessage.id}'), - previousMessage: null, - message: widget.parentMessage.copyWith(replyCount: 0), - nextMessage: null, - onThreadSelect: widget.onThreadSelect, - ), - Padding( - padding: const EdgeInsets.symmetric(horizontal: 32), - child: Container( - padding: const EdgeInsets.all(8), - child: Text( - 'Start of a new thread', - textAlign: TextAlign.center, - ), - color: Theme.of(context).primaryColorLight, - ), - ), - ], - ); - } - } else { - return SizedBox(); - } - } - - if (i == _messages.length) { - return _buildLoadingIndicator(streamChannel); - } - final message = _messages[i]; - - if (widget._messageBuilder != null) { - return widget._messageBuilder(context, message, i); - } - - final previousMessage = - i < _messages.length - 1 ? _messages[i + 1] : null; - final nextMessage = i > 0 ? _messages[i - 1] : null; - - if (i == 0) { - return _buildBottomMessage( - streamChannel, - previousMessage, - message, - context, - ); - } - - if (i == _messages.length - 1) { - return _buildTopMessage( - message, - nextMessage, - streamChannel, - context, - ); - } - - return MessageWidget( - key: ValueKey('MESSAGE-${message.id}'), - previousMessage: previousMessage, - message: message, - nextMessage: nextMessage, - onThreadSelect: widget.onThreadSelect, - ); - }, - childCount: _messages.length + 2, - findChildIndexCallback: (key) { - final ValueKey valueKey = key; - final index = _messages - .indexWhere((m) => 'MESSAGE-${m.id}' == valueKey.value); - return index != -1 ? index : null; - }, - ), - ), - ); - } - - Container _buildLoadingIndicator(StreamChannelState streamChannel) { - return Container( - height: 50, - child: StreamBuilder( - stream: streamChannel.queryMessage, - initialData: false, - builder: (context, snapshot) { - if (snapshot.hasError) { - print((snapshot.error as Error).stackTrace.toString()); - return Center( - child: Text(snapshot.error.toString()), - ); - } - if (!snapshot.data) { - return Container(); - } - return Center( - child: Padding( - padding: const EdgeInsets.all(8.0), - child: CircularProgressIndicator(), - ), - ); - }), - ); - } - - Widget _buildTopMessage( - Message message, - Message nextMessage, - StreamChannelState streamChannelState, - BuildContext context, - ) { - return VisibilityDetector( - key: ValueKey('TOP-MESSAGE'), - child: MessageWidget( - key: ValueKey('MESSAGE-${message.id}'), - previousMessage: null, - message: message, - nextMessage: nextMessage, - onThreadSelect: widget.onThreadSelect, - ), - onVisibilityChanged: (visibility) { - final topIsVisible = visibility.visibleBounds != Rect.zero; - if (topIsVisible && !_topWasVisible) { - streamChannelState.queryMessages(); - } - _topWasVisible = topIsVisible; - }, - ); - } - - Widget _buildBottomMessage( - StreamChannelState channelBloc, - Message previousMessage, - Message message, - BuildContext context, - ) { - return VisibilityDetector( - key: ValueKey('BOTTOM-MESSAGE'), - onVisibilityChanged: (visibility) { - _isBottom = visibility.visibleBounds != Rect.zero; - if (_isBottom) { - if (channelBloc.channelClient.state.unreadCount > 0) { - channelBloc.channelClient.markRead(); - } - } - }, - child: MessageWidget( - key: ValueKey('MESSAGE-${message.id}'), - previousMessage: previousMessage, - message: message, - nextMessage: null, - onThreadSelect: widget.onThreadSelect, - ), - ); - } - - StreamSubscription _streamListener; - - @override - void initState() { - super.initState(); - - final streamChannel = StreamChannel.of(context); - if (streamChannel.channelClient.state.unreadCount > 0) { - streamChannel.channelClient.markRead(); - } - - Stream> stream; - - if (widget.parentMessage == null) { - stream = streamChannel.channelStateStream.map((c) => c.messages); - } else { - streamChannel.getReplies(widget.parentMessage.id); - stream = streamChannel.channelClient.state.threadsStream - .where((threads) => threads.containsKey(widget.parentMessage.id)) - .map((threads) => threads[widget.parentMessage.id]); - } - - _streamListener = stream.listen((newMessages) { - newMessages = newMessages.reversed.toList(); - if (_messages.isEmpty || newMessages.first.id != _messages.first.id) { - if (!_scrollController.hasClients || - _scrollController.offset < _newMessageLoadingOffset) { - setState(() { - _messages = newMessages; - }); - } else if (newMessages.first.user.id == - streamChannel.channelClient.client.state.user.id) { - _scrollController.jumpTo(0); - WidgetsBinding.instance.addPostFrameCallback((_) { - setState(() { - _messages = newMessages; - }); - }); - } else { - _newMessageList = newMessages; - } - } else { - setState(() { - _messages = newMessages; - }); - } - }); - } - - @override - void dispose() { - _streamListener.cancel(); - super.dispose(); - } -} diff --git a/packages/dart_client/example/lib/message_page.dart b/packages/dart_client/example/lib/message_page.dart deleted file mode 100644 index 3d3c8073..00000000 --- a/packages/dart_client/example/lib/message_page.dart +++ /dev/null @@ -1,110 +0,0 @@ -import 'package:animations/animations.dart'; -import 'package:flutter/material.dart'; -import 'package:stream_chat/stream_chat.dart'; - -import './channel_header.dart'; -import 'connection_indicator.dart'; -import 'message_input.dart'; -import 'message_list_view.dart'; -import 'stream_channel.dart'; -import 'stream_chat.dart'; - -class MessagePage extends StatefulWidget { - final PreferredSizeWidget _channelHeader; - - const MessagePage({ - Key key, - PreferredSizeWidget channelHeader, - this.parentMessage, - }) : _channelHeader = channelHeader, - super(key: key); - - final Message parentMessage; - - @override - _MessagePageState createState() => _MessagePageState(); -} - -class _MessagePageState extends State { - IndicatorController _indicatorController = IndicatorController(); - - @override - Widget build(BuildContext context) { - return Scaffold( - resizeToAvoidBottomInset: true, - appBar: widget._channelHeader ?? ChannelHeader(), - body: Column( - children: [ - ConnectionIndicator( - indicatorController: _indicatorController, - ), - Expanded( - child: MessageListView( - parentMessage: widget.parentMessage, - onThreadSelect: (message) { - Navigator.of(context).push( - PageRouteBuilder( - pageBuilder: (_, __, ___) => StreamChannel( - channelClient: StreamChannel.of(context).channelClient, - child: MessagePage( - parentMessage: message, - channelHeader: widget._channelHeader, - ), - ), - transitionsBuilder: ( - _, - animation, - secondaryAnimation, - child, - ) => - SharedAxisTransition( - child: child, - animation: animation, - secondaryAnimation: secondaryAnimation, - transitionType: SharedAxisTransitionType.horizontal, - ), - ), - ); - }, - ), - ), - MessageInput(), - ], - ), - ); - } - - @override - void initState() { - super.initState(); - - final streamChat = StreamChat.of(context); - streamChat.client.wsConnectionStatus.addListener(() { - if (streamChat.client.wsConnectionStatus.value == - ConnectionStatus.disconnected) { - _indicatorController.showIndicator( - duration: Duration(minutes: 1), - color: Colors.red, - text: 'Disconnected', - ); - } else if (streamChat.client.wsConnectionStatus.value == - ConnectionStatus.connecting) { - _indicatorController.showIndicator( - duration: Duration(minutes: 1), - color: Colors.yellow, - text: 'Reconnecting', - ); - } else if (streamChat.client.wsConnectionStatus.value == - ConnectionStatus.connected) { - _indicatorController.showIndicator( - duration: Duration(seconds: 5), - color: Colors.green, - text: 'Connected', - ); - - final streamChat = StreamChannel.of(context); - streamChat.queryMessages(); - } - }); - } -} diff --git a/packages/dart_client/example/lib/message_widget.dart b/packages/dart_client/example/lib/message_widget.dart deleted file mode 100644 index aba9ced1..00000000 --- a/packages/dart_client/example/lib/message_widget.dart +++ /dev/null @@ -1,353 +0,0 @@ -import 'package:cached_network_image/cached_network_image.dart'; -import 'package:chewie/chewie.dart'; -import 'package:date_format/date_format.dart'; -import 'package:flutter/foundation.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_markdown/flutter_markdown.dart'; -import 'package:stream_chat/stream_chat.dart'; -import 'package:url_launcher/url_launcher.dart'; -import 'package:video_player/video_player.dart'; - -import 'message_list_view.dart'; -import 'stream_chat.dart'; -import 'user_avatar.dart'; - -class MessageWidget extends StatefulWidget { - const MessageWidget({ - Key key, - @required this.previousMessage, - @required this.message, - @required this.nextMessage, - this.onThreadSelect, - }) : super(key: key); - - final Message previousMessage; - final Message message; - final Message nextMessage; - final OnThreadSelectCallback onThreadSelect; - - @override - _MessageWidgetState createState() => _MessageWidgetState(); -} - -class _MessageWidgetState extends State - with AutomaticKeepAliveClientMixin { - final Map _videoControllers = {}; - final Map _chuwieControllers = {}; - - @override - Widget build(BuildContext context) { - super.build(context); - - final streamChat = StreamChat.of(context); - final currentUserId = streamChat.user.id; - final messageUserId = widget.message.user.id; - final previousUserId = widget.previousMessage?.user?.id; - final nextUserId = widget.nextMessage?.user?.id; - final isMyMessage = messageUserId == currentUserId; - final isLastUser = previousUserId == messageUserId; - final isNextUser = nextUserId == messageUserId; - final alignment = - isMyMessage ? Alignment.centerRight : Alignment.centerLeft; - - var row = [ - Column( - crossAxisAlignment: - isMyMessage ? CrossAxisAlignment.end : CrossAxisAlignment.start, - children: [ - _buildBubble(context, isMyMessage, isLastUser), - widget.message.replyCount > 0 - ? GestureDetector( - onTap: () { - if (widget.onThreadSelect != null) { - widget.onThreadSelect(widget.message); - } - }, - child: Padding( - padding: const EdgeInsets.symmetric(vertical: 2.0), - child: Row( - children: [ - Text( - 'Replies: ${widget.message.replyCount}', - style: Theme.of(context) - .textTheme - .subtitle - .copyWith(color: Colors.blue), - ), - Icon( - Icons.subdirectory_arrow_left, - color: Colors.black12, - ), - ], - ), - ), - ) - : Container(), - isNextUser ? Container() : _buildTimestamp(isMyMessage, alignment), - ], - ), - isNextUser - ? Container( - width: 40, - ) - : Padding( - padding: EdgeInsets.only( - left: isMyMessage ? 8.0 : 0, - right: isMyMessage ? 0 : 8.0, - ), - child: UserAvatar(user: widget.message.user), - ), - ]; - - if (!isMyMessage) { - row = row.reversed.toList(); - } - - return Container( - padding: const EdgeInsets.symmetric(horizontal: 10.0), - margin: EdgeInsets.only( - top: isLastUser ? 5 : 24, - bottom: widget.nextMessage == null ? 30 : 0, - ), - child: Row( - crossAxisAlignment: CrossAxisAlignment.end, - mainAxisAlignment: - isMyMessage ? MainAxisAlignment.end : MainAxisAlignment.start, - mainAxisSize: MainAxisSize.max, - children: row, - ), - ); - } - - Widget _buildBubble( - BuildContext context, - bool isMyMessage, - bool isLastUser, - ) { - var nOfAttachmentWidgets = 0; - - final column = Column( - crossAxisAlignment: - isMyMessage ? CrossAxisAlignment.end : CrossAxisAlignment.start, - children: widget.message.attachments.map((attachment) { - nOfAttachmentWidgets++; - - Widget attachmentWidget; - if (attachment.type == 'video') { - attachmentWidget = _buildVideo(attachment, isMyMessage, isLastUser); - } else if (attachment.type == 'image' || attachment.type == 'giphy') { - attachmentWidget = _buildImage(isMyMessage, isLastUser, attachment); - } - - if (attachmentWidget != null) { - final boxDecoration = _buildBoxDecoration(isMyMessage, isLastUser) - .copyWith(color: Color(0xffebebeb)); - return ClipRRect( - borderRadius: boxDecoration.borderRadius, - child: Container( - decoration: boxDecoration, - constraints: BoxConstraints.loose(Size.fromWidth(300)), - child: Stack( - children: [ - Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - attachmentWidget, - attachment.title != null - ? Container( - constraints: - BoxConstraints.loose(Size.fromHeight(70)), - child: Padding( - padding: const EdgeInsets.all(8.0), - child: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - attachment.title, - overflow: TextOverflow.ellipsis, - style: Theme.of(context) - .textTheme - .subtitle - .copyWith(color: Colors.blue), - ), - Text( - Uri.parse(attachment.thumbUrl) - .authority - .split('.') - .reversed - .take(2) - .toList() - .reversed - .join('.'), - overflow: TextOverflow.ellipsis, - style: - Theme.of(context).textTheme.caption, - ), - ], - ), - ), - color: Color(0xffebebeb), - ) - : Container(), - ], - ), - attachment.type == 'image' && attachment.titleLink != null - ? Positioned.fill( - child: Material( - color: Colors.transparent, - child: InkWell( - onTap: () => _launchURL(attachment.titleLink), - ), - ), - ) - : SizedBox.fromSize( - size: Size.zero, - ), - ], - ), - margin: EdgeInsets.only( - top: nOfAttachmentWidgets > 1 ? 5 : 0, - ), - ), - ); - } - - nOfAttachmentWidgets--; - return Container(); - }).toList(), - ); - - if (widget.message.text.trim().isNotEmpty) { - column.children.add(Container( - margin: EdgeInsets.only( - top: nOfAttachmentWidgets > 0 ? 5 : 0, - ), - decoration: _buildBoxDecoration( - isMyMessage, isLastUser || nOfAttachmentWidgets > 0), - padding: EdgeInsets.all(10), - constraints: BoxConstraints.loose(Size.fromWidth(300)), - child: MarkdownBody( - data: '${widget.message.text}', - onTapLink: (link) { - _launchURL(link); - }, - styleSheet: MarkdownStyleSheet.fromTheme(Theme.of(context)), - ), - )); - } - - return column; - } - - Widget _buildImage( - bool isMyMessage, - bool isLastUser, - Attachment attachment, - ) { - return CachedNetworkImage( - imageUrl: attachment.thumbUrl ?? attachment.imageUrl, - fit: BoxFit.cover, - ); - } - - Widget _buildVideo( - Attachment attachment, - bool isMyMessage, - bool isLastUser, - ) { - VideoPlayerController videoController; - if (_videoControllers.containsKey(attachment.assetUrl)) { - videoController = _videoControllers[attachment.assetUrl]; - } else { - videoController = VideoPlayerController.network(attachment.assetUrl); - _videoControllers[attachment.assetUrl] = videoController; - } - - ChewieController chewieController; - if (_chuwieControllers.containsKey(attachment.assetUrl)) { - chewieController = _chuwieControllers[attachment.assetUrl]; - } else { - chewieController = ChewieController( - videoPlayerController: videoController, - autoInitialize: true, - errorBuilder: (_, e) { - return Stack( - children: [ - Container( - decoration: BoxDecoration( - image: DecorationImage( - fit: BoxFit.cover, - image: CachedNetworkImageProvider( - attachment.thumbUrl, - ), - ), - ), - ), - Material( - color: Colors.transparent, - child: InkWell( - onTap: () => _launchURL(attachment.titleLink), - ), - ), - ], - ); - }); - _chuwieControllers[attachment.assetUrl] = chewieController; - } - - return Chewie( - key: ValueKey( - 'ATTACHMENT-${attachment.title}-${widget.message.id}'), - controller: chewieController, - ); - } - - Future _launchURL(String url) async { - if (await canLaunch(url)) { - await launch(url); - } else { - Scaffold.of(context).showSnackBar( - SnackBar( - content: Text('Cannot launch the url'), - ), - ); - } - } - - @override - void dispose() { - _videoControllers.values.forEach((element) { - element.dispose(); - }); - super.dispose(); - } - - Widget _buildTimestamp(bool isMyMessage, Alignment alignment) { - return Padding( - padding: const EdgeInsets.only(top: 5.0), - child: Text( - formatDate(widget.message.createdAt.toLocal(), [HH, ':', nn]), - ), - ); - } - - BoxDecoration _buildBoxDecoration(bool isMyMessage, bool isLastUser) { - return BoxDecoration( - border: isMyMessage ? null : Border.all(color: Colors.black.withAlpha(8)), - borderRadius: BorderRadius.only( - topLeft: Radius.circular((isMyMessage || !isLastUser) ? 16 : 2), - bottomLeft: Radius.circular(isMyMessage ? 16 : 2), - topRight: Radius.circular((isMyMessage && isLastUser) ? 2 : 16), - bottomRight: Radius.circular(isMyMessage ? 2 : 16), - ), - color: isMyMessage ? Color(0xffebebeb) : Colors.white, - ); - } - - @override - bool get wantKeepAlive { - return widget.message.attachments.isNotEmpty; - } -} diff --git a/packages/dart_client/example/lib/stream_channel.dart b/packages/dart_client/example/lib/stream_channel.dart deleted file mode 100644 index 40c082c1..00000000 --- a/packages/dart_client/example/lib/stream_channel.dart +++ /dev/null @@ -1,128 +0,0 @@ -import 'dart:async'; - -import 'package:flutter/material.dart'; -import 'package:rxdart/rxdart.dart'; -import 'package:stream_chat/stream_chat.dart'; - -class StreamChannel extends StatefulWidget { - StreamChannel({ - Key key, - @required this.child, - @required this.channelClient, - }) : super( - key: key, - ); - - final Widget child; - final Channel channelClient; - - static StreamChannelState of(BuildContext context) { - StreamChannelState streamChannelState; - - streamChannelState = context.findAncestorStateOfType(); - - if (streamChannelState == null) { - throw Exception( - 'You must have a StreamChannel widget at the top of your widget tree'); - } - - return streamChannelState; - } - - @override - StreamChannelState createState() => StreamChannelState(); -} - -class StreamChannelState extends State { - StreamChannelState(); - - Channel get channelClient => widget.channelClient; - - Channel get channel => widget.channelClient; - - Stream get channelStateStream => - widget.channelClient.state.channelStateStream; - - final BehaviorSubject _queryMessageController = BehaviorSubject(); - - Stream get queryMessage => _queryMessageController.stream; - - void queryMessages() { - _queryMessageController.add(true); - - String firstId; - if (channel.state.messages.isNotEmpty) { - firstId = channel.state.messages.first.id; - } - - widget.channelClient - .query( - messagesPagination: PaginationParams( - lessThan: firstId, - limit: 100, - ), - ) - .then((res) { - _queryMessageController.add(false); - }).catchError((e, stack) { - _queryMessageController.addError(e, stack); - }); - } - - Future getReplies(String parentId) async { - _queryMessageController.add(true); - - String firstId; - if (widget.channelClient.state.threads.containsKey(parentId)) { - firstId = widget.channelClient.state.threads[parentId].first.id; - } - - return widget.channelClient - .getReplies( - parentId, - PaginationParams( - lessThan: firstId, - limit: 100, - ), - ) - .then((res) { - _queryMessageController.add(false); - }).catchError((e, stack) { - _queryMessageController.addError(e, stack); - }); - } - - @override - void dispose() { - _queryMessageController.close(); - super.dispose(); - } - - @override - Widget build(BuildContext context) { - if (widget.channelClient == null) { - return Center( - child: CircularProgressIndicator(), - ); - } - return FutureBuilder( - future: widget.channelClient.initialized, - initialData: widget.channelClient.state != null, - builder: (context, snapshot) { - if (!snapshot.hasData) { - return Scaffold( - body: Center( - child: CircularProgressIndicator(), - ), - ); - } else if (snapshot.hasError) { - return Center( - child: Text(snapshot.error), - ); - } else { - return widget.child; - } - }, - ); - } -} diff --git a/packages/dart_client/example/lib/stream_chat.dart b/packages/dart_client/example/lib/stream_chat.dart deleted file mode 100644 index f6b1db38..00000000 --- a/packages/dart_client/example/lib/stream_chat.dart +++ /dev/null @@ -1,95 +0,0 @@ -import 'dart:async'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter/material.dart'; -import 'package:rxdart/rxdart.dart'; -import 'package:stream_chat/stream_chat.dart'; - -class StreamChat extends InheritedWidget { - final Client client; - final List _subscriptions = []; - - StreamChat({ - Key key, - @required this.client, - @required Widget child, - }) : super( - key: key, - child: child, - ) { - _subscriptions.add(client.on(EventType.messageNew).listen((Event e) { - final index = channels.indexWhere((c) => c.cid == e.cid); - if (index > 0) { - final channel = channels.removeAt(index); - channels.insert(0, channel); - } - })); - } - - User get user => client.state.user; - - Stream get userStream => client.state.userStream; - - final List channels = []; - - final BehaviorSubject _queryChannelsLoadingController = - BehaviorSubject.seeded(false); - - Stream get queryChannelsLoading => - _queryChannelsLoadingController.stream; - - Future queryChannels({ - Map filter, - List sortOptions, - PaginationParams paginationParams, - Map options, - }) async { - if (_queryChannelsLoadingController.value) { - return; - } - _queryChannelsLoadingController.sink.add(true); - - try { - client.queryChannels( - filter: filter, - sort: sortOptions, - options: options, - paginationParams: paginationParams, - ); - } finally { - _queryChannelsLoadingController.sink.add(false); - } - } - - void clearChannels() { - channels.clear(); - } - - void dispose() { - client.dispose(); - _subscriptions.forEach((s) => s.cancel()); - _queryChannelsLoadingController.close(); - } - - @override - bool updateShouldNotify(InheritedWidget oldWidget) { - return true; - } - - static StreamChat of(BuildContext context, [bool listen = false]) { - StreamChat streamChat; - - if (listen) { - streamChat = context.dependOnInheritedWidgetOfExactType(); - } else { - streamChat = context.findAncestorWidgetOfExactType(); - } - - if (streamChat == null) { - throw Exception( - 'You must have a StreamChat widget at the top of your widget tree'); - } - - return streamChat; - } -} diff --git a/packages/dart_client/example/lib/user_avatar.dart b/packages/dart_client/example/lib/user_avatar.dart deleted file mode 100644 index c815f363..00000000 --- a/packages/dart_client/example/lib/user_avatar.dart +++ /dev/null @@ -1,29 +0,0 @@ -import 'package:cached_network_image/cached_network_image.dart'; -import 'package:flutter/material.dart'; -import 'package:stream_chat/stream_chat.dart'; - -class UserAvatar extends StatelessWidget { - const UserAvatar({ - Key key, - @required this.user, - this.radius = 16, - }) : super(key: key); - - final User user; - final double radius; - - @override - Widget build(BuildContext context) { - return CircleAvatar( - radius: this.radius, - backgroundImage: user.extraData.containsKey('image') - ? CachedNetworkImageProvider(user.extraData['image'] as String) - : null, - child: user.extraData.containsKey('image') - ? null - : Text(user?.extraData?.containsKey('name') ?? false - ? user.extraData['name'][0] - : ''), - ); - } -} diff --git a/packages/dart_client/example/pubspec.yaml b/packages/dart_client/example/pubspec.yaml deleted file mode 100644 index 53bde0f4..00000000 --- a/packages/dart_client/example/pubspec.yaml +++ /dev/null @@ -1,33 +0,0 @@ -name: stream_chat_example -description: example Flutter project using Stream Chat service - -version: 1.0.0+1 - -environment: - sdk: ">=2.1.0 <3.0.0" - -dependencies: - flutter: - sdk: flutter - flutter_widgets: ^0.1.11 - timeago: ^2.0.26 - jiffy: ^3.0.1 - date_format: ^1.0.8 - cached_network_image: ^2.0.0 - flutter_markdown: ^0.5.2 - url_launcher: ^5.4.2 - video_player: ^1.0.1 - chewie: 0.12.1+1 - animations: ^1.0.0+5 - - stream_chat: - path: ../ - -dev_dependencies: - flutter_test: - sdk: flutter - build_runner: any - build_web_compilers: any - -flutter: - uses-material-design: true diff --git a/packages/dart_client/example/test/widget_test.dart b/packages/dart_client/example/test/widget_test.dart deleted file mode 100644 index 8d7438e9..00000000 --- a/packages/dart_client/example/test/widget_test.dart +++ /dev/null @@ -1,29 +0,0 @@ -// This is a basic Flutter widget test. -// -// To perform an interaction with a widget in your test, use the WidgetTester -// utility that Flutter provides. For example, you can send tap and scroll -// gestures. You can also use WidgetTester to find child widgets in the widget -// tree, read text, and verify that the values of widget properties are correct. - -import 'package:flutter/material.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:stream_chat_example/main.dart'; - -void main() { - testWidgets('Counter increments smoke test', (WidgetTester tester) async { - // Build our app and trigger a frame. - await tester.pumpWidget(MyApp()); - - // Verify that our counter starts at 0. - expect(find.text('0'), findsOneWidget); - expect(find.text('1'), findsNothing); - - // Tap the '+' icon and trigger a frame. - await tester.tap(find.byIcon(Icons.add)); - await tester.pump(); - - // Verify that our counter has incremented. - expect(find.text('0'), findsNothing); - expect(find.text('1'), findsOneWidget); - }); -} diff --git a/packages/dart_client/example/web/icons/Icon-192.png b/packages/dart_client/example/web/icons/Icon-192.png deleted file mode 100644 index b749bfef07473333cf1dd31e9eed89862a5d52aa..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5292 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 diff --git a/packages/dart_client/example/web/icons/Icon-512.png b/packages/dart_client/example/web/icons/Icon-512.png deleted file mode 100644 index 88cfd48dff1169879ba46840804b412fe02fefd6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8252 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 diff --git a/packages/dart_client/example/web/index.html b/packages/dart_client/example/web/index.html deleted file mode 100644 index 97221146..00000000 --- a/packages/dart_client/example/web/index.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - - - stream_chat - - - - - - diff --git a/packages/dart_client/example/web/manifest.json b/packages/dart_client/example/web/manifest.json deleted file mode 100644 index bad373ca..00000000 --- a/packages/dart_client/example/web/manifest.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "name": "stream_chat", - "short_name": "stream_chat", - "start_url": ".", - "display": "minimal-ui", - "background_color": "#0175C2", - "theme_color": "#0175C2", - "description": "A new Flutter project.", - "orientation": "portrait-primary", - "prefer_related_applications": false, - "icons": [ - { - "src": "icons/Icon-192.png", - "sizes": "192x192", - "type": "image/png" - }, - { - "src": "icons/Icon-512.png", - "sizes": "512x512", - "type": "image/png" - } - ] -} From 022386d45763eba371fd6aa6dbdeb1e0a0c1584d Mon Sep 17 00:00:00 2001 From: Neevash Ramdial Date: Fri, 15 Jan 2021 12:30:50 -0400 Subject: [PATCH 0945/1140] Resolve lint:pub warnings --- packages/dart_client/lib/src/client.dart | 2 +- packages/dart_client/pubspec.yaml | 2 +- packages/flutter_widgets/pubspec.yaml | 6 +++++- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/packages/dart_client/lib/src/client.dart b/packages/dart_client/lib/src/client.dart index 7e024c69..c5a77d11 100644 --- a/packages/dart_client/lib/src/client.dart +++ b/packages/dart_client/lib/src/client.dart @@ -470,7 +470,7 @@ class Client { if (value == ConnectionStatus.connected && state.channels?.isNotEmpty == true) { - unawaited (queryChannels(filter: { + unawaited(queryChannels(filter: { 'cid': { '\$in': state.channels.keys.toList(), }, diff --git a/packages/dart_client/pubspec.yaml b/packages/dart_client/pubspec.yaml index 924c1ed4..d045fe22 100644 --- a/packages/dart_client/pubspec.yaml +++ b/packages/dart_client/pubspec.yaml @@ -25,6 +25,7 @@ dependencies: rxdart: ^0.24.1 collection: ^1.14.12 sqlite3_flutter_libs: ^0.3.0 + pedantic: ^1.9.2 dev_dependencies: build_runner: ^1.10.0 @@ -32,5 +33,4 @@ dev_dependencies: moor_generator: ^3.1.0 flutter_test: sdk: flutter - pedantic: ^1.8.0+1 mockito: ^4.1.1 diff --git a/packages/flutter_widgets/pubspec.yaml b/packages/flutter_widgets/pubspec.yaml index c0d16cb0..a68082a1 100644 --- a/packages/flutter_widgets/pubspec.yaml +++ b/packages/flutter_widgets/pubspec.yaml @@ -44,6 +44,9 @@ dependencies: transparent_image: ^1.0.0 ezanimation: ^0.4.1 synchronized: ^2.2.0+2 + characters: ^1.0.0 + dio: ^3.0.10 + path_provider: ^1.6.27 flutter: assets: @@ -53,7 +56,8 @@ flutter: - animations/ dev_dependencies: - pedantic: ^1.9.2 + flutter_test: sdk: flutter mockito: ^4.1.3 + pedantic: ^1.9.2 From d4b0ab87e109f8a14b68ff9aa879dc167475986a Mon Sep 17 00:00:00 2001 From: Neevash Ramdial Date: Fri, 15 Jan 2021 12:37:01 -0400 Subject: [PATCH 0946/1140] ignore deprecated api --- packages/flutter_widgets/lib/src/utils.dart | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/flutter_widgets/lib/src/utils.dart b/packages/flutter_widgets/lib/src/utils.dart index 20e78a24..cf747284 100644 --- a/packages/flutter_widgets/lib/src/utils.dart +++ b/packages/flutter_widgets/lib/src/utils.dart @@ -9,7 +9,8 @@ Future launchURL(BuildContext context, String url) async { if (await canLaunch(url)) { await launch(url); } else { - ScaffoldMessenger.of(context).showSnackBar( + // ignore: deprecated_member_use + Scaffold.of(context).showSnackBar( SnackBar( content: Text('Cannot launch the url'), ), From 109505adca64ced37c4f3c8e6b9418c2f238410a Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Mon, 18 Jan 2021 09:41:08 +0100 Subject: [PATCH 0947/1140] fix modal divider --- packages/flutter_widgets/lib/src/stream_chat_theme.dart | 6 +++++- packages/flutter_widgets/lib/src/utils.dart | 5 +++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/packages/flutter_widgets/lib/src/stream_chat_theme.dart b/packages/flutter_widgets/lib/src/stream_chat_theme.dart index 8230ba5c..5b5927c8 100644 --- a/packages/flutter_widgets/lib/src/stream_chat_theme.dart +++ b/packages/flutter_widgets/lib/src/stream_chat_theme.dart @@ -491,7 +491,11 @@ class ColorTheme { stops: [0, 1], ), this.borderTop = const Effect( - sigmaX: 0, sigmaY: -1, color: Color(0xff000000), blur: 0.0), + sigmaX: 0, + sigmaY: -1, + color: Color(0xff000000), + blur: 0.0, + alpha: 0.08), this.borderBottom = const Effect( sigmaX: 0, sigmaY: 1, color: Color(0xff000000), blur: 0.0, alpha: 0.08), this.shadowIconButton = const Effect( diff --git a/packages/flutter_widgets/lib/src/utils.dart b/packages/flutter_widgets/lib/src/utils.dart index cf747284..060d2416 100644 --- a/packages/flutter_widgets/lib/src/utils.dart +++ b/packages/flutter_widgets/lib/src/utils.dart @@ -35,6 +35,7 @@ Future showConfirmationDialog( topRight: Radius.circular(16.0), )), builder: (context) { + final effect = StreamChatTheme.of(context).colorTheme.borderTop; return Column( mainAxisSize: MainAxisSize.min, children: [ @@ -52,8 +53,8 @@ Future showConfirmationDialog( ), SizedBox(height: 36.0), Container( - color: StreamChatTheme.of(context).colorTheme.greyGainsboro, - height: 1.0, + color: effect.color.withOpacity(effect.alpha ?? 1), + height: 1, ), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, From 3aa8b5999dd81e2f02e7cda204e3797928472439 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Mon, 18 Jan 2021 10:30:08 +0100 Subject: [PATCH 0948/1140] fix sample app dependency path --- packages/flutter_widgets/example/pubspec.yaml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/flutter_widgets/example/pubspec.yaml b/packages/flutter_widgets/example/pubspec.yaml index b4d32fa0..181e6453 100644 --- a/packages/flutter_widgets/example/pubspec.yaml +++ b/packages/flutter_widgets/example/pubspec.yaml @@ -1,6 +1,6 @@ name: example description: A new Flutter project. -version: 1.1.2 +version: 1.1.2+1 environment: sdk: ">=2.2.2 <3.0.0" @@ -8,7 +8,8 @@ environment: dependencies: flutter: sdk: flutter - stream_chat_flutter: 0.2.13+1 + stream_chat_flutter: + path: ../ flutter_apns: ^1.4.1 flutter_local_notifications: ^2.0.2 flutter_svg: ^0.19.1 From ca1101ac8a6e855cb3696facf76f3b13a4750d0c Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Mon, 18 Jan 2021 10:31:06 +0100 Subject: [PATCH 0949/1140] trigger workflow action on feature/new-ui --- .github/workflows/stream_flutter_workflow.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/stream_flutter_workflow.yml b/.github/workflows/stream_flutter_workflow.yml index 282b2a8f..8ced7815 100644 --- a/.github/workflows/stream_flutter_workflow.yml +++ b/.github/workflows/stream_flutter_workflow.yml @@ -9,6 +9,7 @@ on: push: branches: - main + - feature/new-ui paths-ignore: - 'docs/**' From 4044e1bcdc9ce94283054eb1a952dca994d3f379 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Mon, 18 Jan 2021 12:26:48 +0100 Subject: [PATCH 0950/1140] hide overlay on delete message --- .../lib/src/message_actions_modal.dart | 296 +++++++++--------- 1 file changed, 154 insertions(+), 142 deletions(-) diff --git a/packages/flutter_widgets/lib/src/message_actions_modal.dart b/packages/flutter_widgets/lib/src/message_actions_modal.dart index c45c351d..923378de 100644 --- a/packages/flutter_widgets/lib/src/message_actions_modal.dart +++ b/packages/flutter_widgets/lib/src/message_actions_modal.dart @@ -61,6 +61,8 @@ class MessageActionsModal extends StatefulWidget { } class _MessageActionsModalState extends State { + bool _showActions = true; + @override Widget build(BuildContext context) { return _showMessageOptionsModal(); @@ -87,160 +89,163 @@ class _MessageActionsModalState extends State { ? 1 : (roughSentenceSize == 0 ? 1 : (roughSentenceSize / roughMaxSize)); - return TweenAnimationBuilder( - tween: Tween(begin: 0.0, end: 1.0), - duration: Duration(milliseconds: 300), - curve: Curves.easeInOutBack, - builder: (context, val, snapshot) { - final hasFileAttachment = - widget.message.attachments?.any((it) => it.type == 'file') == true; - return GestureDetector( - behavior: HitTestBehavior.translucent, - onTap: () => Navigator.maybePop(context), - child: Stack( - children: [ - Positioned.fill( - child: BackdropFilter( - filter: ImageFilter.blur( - sigmaX: 10, - sigmaY: 10, - ), - child: Container( - color: StreamChatTheme.of(context).colorTheme.overlay, - ), - ), + final hasFileAttachment = + widget.message.attachments?.any((it) => it.type == 'file') == true; + + return GestureDetector( + behavior: HitTestBehavior.translucent, + onTap: () => Navigator.maybePop(context), + child: Stack( + children: [ + Positioned.fill( + child: BackdropFilter( + filter: ImageFilter.blur( + sigmaX: 10, + sigmaY: 10, ), - Transform.scale( - scale: val, - child: Center( - child: SingleChildScrollView( - child: Padding( - padding: const EdgeInsets.all(8.0), - child: Column( - crossAxisAlignment: widget.reverse - ? CrossAxisAlignment.end - : CrossAxisAlignment.start, - children: [ - if (widget.showReactions && - (widget.message.status == - MessageSendingStatus.SENT || - widget.message.status == null)) - Align( - alignment: Alignment( - user.id == widget.message.user.id - ? (divFactor > 1.0 - ? 0.0 - : (1.0 - divFactor)) - : (divFactor > 1.0 - ? 0.0 - : -(1.0 - divFactor)), - 0.0), - child: ReactionPicker( - message: widget.message, - messageTheme: widget.messageTheme, - ), - ), - SizedBox(height: 8), - IgnorePointer( - child: MessageWidget( - key: Key('MessageWidget'), - reverse: widget.reverse, - message: widget.message.copyWith( - text: widget.message.text.length > 200 - ? '${widget.message.text.substring(0, 200)}...' - : widget.message.text, - ), - messageTheme: widget.messageTheme, - showReactions: false, - showUsername: false, - showThreadReplyIndicator: false, - showReplyMessage: false, - showUserAvatar: widget.showUserAvatar, - attachmentPadding: EdgeInsets.all( - hasFileAttachment ? 4 : 2, - ), - showTimestamp: false, - translateUserAvatar: false, - padding: const EdgeInsets.all(0), - textPadding: EdgeInsets.symmetric( - vertical: 8.0, - horizontal: - widget.message.text.isOnlyEmoji ? 0 : 16.0, - ), - showReactionPickerIndicator: - widget.showReactions && - (widget.message.status == - MessageSendingStatus.SENT || - widget.message.status == null), - showInChannelIndicator: false, - showSendingIndicator: false, - shape: widget.messageShape, - attachmentShape: widget.attachmentShape, - ), - ), - SizedBox(height: 8), - Padding( - padding: EdgeInsets.only( - left: widget.reverse ? 0 : 40, - ), - 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: Container( + color: StreamChatTheme.of(context).colorTheme.overlay, + ), + ), + ), + if (_showActions) + TweenAnimationBuilder( + tween: Tween(begin: 0.0, end: 1.0), + duration: Duration(milliseconds: 300), + curve: Curves.easeInOutBack, + builder: (context, val, snapshot) { + return Transform.scale( + scale: val, + child: Center( + child: SingleChildScrollView( + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Column( + crossAxisAlignment: widget.reverse + ? CrossAxisAlignment.end + : CrossAxisAlignment.start, + children: [ + if (widget.showReactions && + (widget.message.status == + MessageSendingStatus.SENT || + widget.message.status == null)) + Align( + alignment: Alignment( + user.id == widget.message.user.id + ? (divFactor > 1.0 + ? 0.0 + : (1.0 - divFactor)) + : (divFactor > 1.0 + ? 0.0 + : -(1.0 - divFactor)), + 0.0), + child: ReactionPicker( + message: widget.message, + messageTheme: widget.messageTheme, ), - child: Column( - crossAxisAlignment: - CrossAxisAlignment.stretch, - children: [ - if (widget.showReplyMessage && + ), + SizedBox(height: 8), + IgnorePointer( + child: MessageWidget( + key: Key('MessageWidget'), + reverse: widget.reverse, + message: widget.message.copyWith( + text: widget.message.text.length > 200 + ? '${widget.message.text.substring(0, 200)}...' + : widget.message.text, + ), + messageTheme: widget.messageTheme, + showReactions: false, + showUsername: false, + showThreadReplyIndicator: false, + showReplyMessage: false, + showUserAvatar: widget.showUserAvatar, + attachmentPadding: EdgeInsets.all( + hasFileAttachment ? 4 : 2, + ), + showTimestamp: false, + translateUserAvatar: false, + padding: const EdgeInsets.all(0), + textPadding: EdgeInsets.symmetric( + vertical: 8.0, + horizontal: widget.message.text.isOnlyEmoji + ? 0 + : 16.0, + ), + showReactionPickerIndicator: + widget.showReactions && (widget.message.status == MessageSendingStatus.SENT || - widget.message.status == null) && - widget.message.parentId == null) - _buildReplyButton(context), - if (widget.showThreadReplyMessage && - (widget.message.status == - MessageSendingStatus.SENT || - widget.message.status == null) && - widget.message.parentId == null) - _buildThreadReplyButton(context), - if (widget.showResendMessage) - _buildResendMessage(context), - if (widget.showEditMessage) - _buildEditMessage(context), - if (widget.showCopyMessage) - _buildCopyButton(context), - if (widget.showFlagButton) - _buildFlagButton(context), - if (widget.showDeleteMessage) - _buildDeleteButton(context), - ].insertBetween( - Container( - height: 1, - color: StreamChatTheme.of(context) - .colorTheme - .greyWhisper, + widget.message.status == null), + showInChannelIndicator: false, + showSendingIndicator: false, + shape: widget.messageShape, + attachmentShape: widget.attachmentShape, + ), + ), + SizedBox(height: 8), + Padding( + padding: EdgeInsets.only( + left: widget.reverse ? 0 : 40, + ), + 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: [ + if (widget.showReplyMessage && + (widget.message.status == + MessageSendingStatus.SENT || + widget.message.status == null) && + widget.message.parentId == null) + _buildReplyButton(context), + if (widget.showThreadReplyMessage && + (widget.message.status == + MessageSendingStatus.SENT || + widget.message.status == null) && + widget.message.parentId == null) + _buildThreadReplyButton(context), + if (widget.showResendMessage) + _buildResendMessage(context), + if (widget.showEditMessage) + _buildEditMessage(context), + if (widget.showCopyMessage) + _buildCopyButton(context), + if (widget.showFlagButton) + _buildFlagButton(context), + if (widget.showDeleteMessage) + _buildDeleteButton(context), + ].insertBetween( + Container( + height: 1, + color: StreamChatTheme.of(context) + .colorTheme + .greyWhisper, + ), ), ), ), ), ), - ), - ], + ], + ), ), ), ), - ), - ), - ], - ), - ); - }, + ); + }, + ), + ], + ), ); } @@ -273,6 +278,9 @@ class _MessageActionsModalState extends State { } void _showDeleteDialog() async { + setState(() { + _showActions = false; + }); var answer = await showConfirmationDialog(context, title: 'Delete message', icon: StreamSvgIcon.flag( @@ -293,6 +301,10 @@ class _MessageActionsModalState extends State { } catch (err) { _showErrorAlert(); } + } else { + setState(() { + _showActions = true; + }); } } From afec7122fb5930574f1896864b2d173a7e9bb745 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Mon, 18 Jan 2021 12:47:30 +0100 Subject: [PATCH 0951/1140] workaround for a weird error while uploading the image for the first time --- packages/flutter_widgets/lib/src/message_input.dart | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/flutter_widgets/lib/src/message_input.dart b/packages/flutter_widgets/lib/src/message_input.dart index 6fafb5d8..80ccbf71 100644 --- a/packages/flutter_widgets/lib/src/message_input.dart +++ b/packages/flutter_widgets/lib/src/message_input.dart @@ -1029,7 +1029,11 @@ class MessageInputState extends State { setState(() { _attachments.add(attachment); }); - final mediaFile = await medium.originFile; + + final mediaFile = await medium.originFile.timeout( + Duration(seconds: 5), + onTimeout: () => medium.originFile, + ); var file = PlatformFile( path: mediaFile.path, From d3206253eab61e3ec11708814a00191dcf0d1c44 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Mon, 18 Jan 2021 12:52:03 +0100 Subject: [PATCH 0952/1140] fix textfield options --- packages/flutter_widgets/lib/src/stream_chat.dart | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/flutter_widgets/lib/src/stream_chat.dart b/packages/flutter_widgets/lib/src/stream_chat.dart index 3ebdf6e9..5d1b7484 100644 --- a/packages/flutter_widgets/lib/src/stream_chat.dart +++ b/packages/flutter_widgets/lib/src/stream_chat.dart @@ -80,7 +80,6 @@ class StreamChatState extends State with WidgetsBindingObserver { primaryIconTheme: streamTheme.primaryIconTheme, accentColor: streamTheme.colorTheme.accentBlue, scaffoldBackgroundColor: streamTheme.colorTheme.white, - buttonTheme: streamTheme.buttonTheme, ), child: widget.child, ); From 024ed66154fbc5c0edc9c185a08e6d1782234555 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Mon, 18 Jan 2021 12:55:13 +0100 Subject: [PATCH 0953/1140] fix error status --- packages/flutter_widgets/lib/src/message_widget.dart | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/packages/flutter_widgets/lib/src/message_widget.dart b/packages/flutter_widgets/lib/src/message_widget.dart index 65817823..070aa271 100644 --- a/packages/flutter_widgets/lib/src/message_widget.dart +++ b/packages/flutter_widgets/lib/src/message_widget.dart @@ -453,16 +453,10 @@ class _MessageWidgetState extends State { ), if (isFailedState) Positioned( - left: widget.reverse ? -3 : null, + left: widget.reverse ? -9 : null, right: widget.reverse ? null : -9, - bottom: showBottomRow ? 20 : 0, - child: Container( - decoration: BoxDecoration( - color: Colors.white, - shape: BoxShape.circle, - ), - child: StreamSvgIcon.error(size: 20), - ), + bottom: showBottomRow ? 18 : -2, + child: StreamSvgIcon.error(size: 20), ), ], ), From 0380e90121b0881bd7e7adebfcdbeb29e02e8a5c Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Mon, 18 Jan 2021 18:35:03 +0530 Subject: [PATCH 0954/1140] fix: Fixed textfield not expanding --- .../lib/src/message_input.dart | 147 +++++++++--------- 1 file changed, 72 insertions(+), 75 deletions(-) diff --git a/packages/flutter_widgets/lib/src/message_input.dart b/packages/flutter_widgets/lib/src/message_input.dart index 6fafb5d8..ef0461ec 100644 --- a/packages/flutter_widgets/lib/src/message_input.dart +++ b/packages/flutter_widgets/lib/src/message_input.dart @@ -433,83 +433,80 @@ class MessageInputState extends State { _buildAttachments(), LimitedBox( maxHeight: widget.maxHeight, - child: SizedBox( - height: 40, - child: TextField( - key: Key('messageInputText'), - enabled: _inputEnabled, - minLines: null, - maxLines: null, - onSubmitted: (_) => sendMessage(), - keyboardType: widget.keyboardType, - controller: textEditingController, - focusNode: _focusNode, - style: theme.textTheme.body, - autofocus: false, - textAlignVertical: TextAlignVertical.center, - decoration: InputDecoration( - isDense: true, - hintText: _getHint(), - hintStyle: theme.textTheme.body.copyWith( - color: theme.colorTheme.grey, - ), - border: OutlineInputBorder( - borderSide: BorderSide(color: Colors.transparent)), - focusedBorder: OutlineInputBorder( - borderSide: BorderSide(color: Colors.transparent)), - enabledBorder: OutlineInputBorder( - borderSide: BorderSide(color: Colors.transparent)), - errorBorder: OutlineInputBorder( - borderSide: BorderSide(color: Colors.transparent)), - disabledBorder: OutlineInputBorder( - borderSide: BorderSide(color: Colors.transparent)), - contentPadding: const EdgeInsets.fromLTRB(16, 12, 13, 11), - prefixIcon: _commandEnabled - ? Container( - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(12), - color: theme.colorTheme.accentBlue, - ), - height: 24, - margin: const EdgeInsets.all(8.0), - padding: const EdgeInsets.only(right: 8, left: 4), - child: Row( - mainAxisSize: MainAxisSize.min, - children: [ - StreamSvgIcon.lightning( - color: Colors.white, - size: 16.0, - ), - Text( - _chosenCommand?.name?.toUpperCase() ?? '', - style: StreamChatTheme.of(context) - .textTheme - .footnoteBold - .copyWith( - color: Colors.white, - ), - ), - ], - ), - ) - : null, - suffixIcon: _commandEnabled - ? IconButton( - icon: StreamSvgIcon.close_small(), - splashRadius: 24, - padding: const EdgeInsets.all(0), - constraints: BoxConstraints.tightFor( - height: 24, - width: 24, - ), - onPressed: () { - setState(() => _commandEnabled = false); - }, - ) - : null, + child: TextField( + key: Key('messageInputText'), + enabled: _inputEnabled, + minLines: null, + maxLines: null, + onSubmitted: (_) => sendMessage(), + keyboardType: widget.keyboardType, + controller: textEditingController, + focusNode: _focusNode, + style: theme.textTheme.body, + autofocus: false, + textAlignVertical: TextAlignVertical.center, + decoration: InputDecoration( + isDense: true, + hintText: _getHint(), + hintStyle: theme.textTheme.body.copyWith( + color: theme.colorTheme.grey, ), - textCapitalization: TextCapitalization.sentences, + border: OutlineInputBorder( + borderSide: BorderSide(color: Colors.transparent)), + focusedBorder: OutlineInputBorder( + borderSide: BorderSide(color: Colors.transparent)), + enabledBorder: OutlineInputBorder( + borderSide: BorderSide(color: Colors.transparent)), + errorBorder: OutlineInputBorder( + borderSide: BorderSide(color: Colors.transparent)), + disabledBorder: OutlineInputBorder( + borderSide: BorderSide(color: Colors.transparent)), + contentPadding: const EdgeInsets.fromLTRB(16, 12, 13, 11), + prefixIcon: _commandEnabled + ? Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(12), + color: theme.colorTheme.accentBlue, + ), + height: 24, + margin: const EdgeInsets.all(8.0), + padding: const EdgeInsets.only(right: 8, left: 4), + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + StreamSvgIcon.lightning( + color: Colors.white, + size: 16.0, + ), + Text( + _chosenCommand?.name?.toUpperCase() ?? '', + style: StreamChatTheme.of(context) + .textTheme + .footnoteBold + .copyWith( + color: Colors.white, + ), + ), + ], + ), + ) + : null, + suffixIcon: _commandEnabled + ? IconButton( + icon: StreamSvgIcon.close_small(), + splashRadius: 24, + padding: const EdgeInsets.all(0), + constraints: BoxConstraints.tightFor( + height: 24, + width: 24, + ), + onPressed: () { + setState(() => _commandEnabled = false); + }, + ) + : null, ), + textCapitalization: TextCapitalization.sentences, ), ) ], From 57375a4df8c64d3f00b539e752179b10834968c3 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Mon, 18 Jan 2021 19:01:26 +0530 Subject: [PATCH 0955/1140] fix: Fixed thread brightness --- packages/flutter_widgets/lib/src/thread_header.dart | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/flutter_widgets/lib/src/thread_header.dart b/packages/flutter_widgets/lib/src/thread_header.dart index eb748272..35d554a6 100644 --- a/packages/flutter_widgets/lib/src/thread_header.dart +++ b/packages/flutter_widgets/lib/src/thread_header.dart @@ -79,6 +79,7 @@ class ThreadHeader extends StatelessWidget implements PreferredSizeWidget { Widget build(BuildContext context) { return AppBar( automaticallyImplyLeading: false, + brightness: Theme.of(context).brightness, elevation: 1, leading: showBackButton ? StreamBackButton( From 623b6f0c76e5968e662e6474b0cdfd98ccb0b131 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Mon, 18 Jan 2021 20:04:48 +0530 Subject: [PATCH 0956/1140] fix: Fixed focus issue --- packages/flutter_widgets/example/lib/main.dart | 4 ++++ .../flutter_widgets/lib/src/channel_list_header.dart | 12 ++++++++++-- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/packages/flutter_widgets/example/lib/main.dart b/packages/flutter_widgets/example/lib/main.dart index 460a80a3..86cfa52d 100644 --- a/packages/flutter_widgets/example/lib/main.dart +++ b/packages/flutter_widgets/example/lib/main.dart @@ -156,6 +156,9 @@ class _HomePageState extends State { onNewChatButtonTap: () { Navigator.pushNamed(context, Routes.NEW_CHAT); }, + preNavigationCallback: () { + FocusScope.of(context).requestFocus(FocusNode()); + }, ), drawer: _buildDrawer(context, user), drawerEdgeDragWidth: 50, @@ -519,6 +522,7 @@ class _ChannelListPageState extends State { ); }, onItemTap: (messageResponse) async { + FocusScope.of(context).requestFocus(FocusNode()); final client = StreamChat.of(context).client; final message = messageResponse.message; final channel = client.channel( diff --git a/packages/flutter_widgets/lib/src/channel_list_header.dart b/packages/flutter_widgets/lib/src/channel_list_header.dart index b6bf3ca7..e8583d11 100644 --- a/packages/flutter_widgets/lib/src/channel_list_header.dart +++ b/packages/flutter_widgets/lib/src/channel_list_header.dart @@ -55,6 +55,7 @@ class ChannelListHeader extends StatelessWidget implements PreferredSizeWidget { this.onUserAvatarTap, this.onNewChatButtonTap, this.showConnectionStateTile = false, + this.preNavigationCallback, }) : super(key: key); /// Pass this if you don't have a [Client] in your widget tree. @@ -72,6 +73,8 @@ class ChannelListHeader extends StatelessWidget implements PreferredSizeWidget { final bool showConnectionStateTile; + final VoidCallback preNavigationCallback; + @override Widget build(BuildContext context) { final _client = client ?? StreamChat.of(context).client; @@ -110,8 +113,13 @@ class ChannelListHeader extends StatelessWidget implements PreferredSizeWidget { child: UserAvatar( user: user, showOnlineStatus: false, - onTap: - onUserAvatarTap ?? (_) => Scaffold.of(context).openDrawer(), + onTap: onUserAvatarTap ?? + (_) { + if (preNavigationCallback != null) { + preNavigationCallback(); + } + Scaffold.of(context).openDrawer(); + }, borderRadius: BorderRadius.circular(20), constraints: BoxConstraints.tightFor( height: 40, From 7412a507e2b47a8a695211687fe3b2fc12de083c Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Mon, 18 Jan 2021 20:07:21 +0530 Subject: [PATCH 0957/1140] fix: Added top padding to highlight --- packages/flutter_widgets/lib/src/message_list_view.dart | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/flutter_widgets/lib/src/message_list_view.dart b/packages/flutter_widgets/lib/src/message_list_view.dart index a0b5a60d..c990d2c7 100644 --- a/packages/flutter_widgets/lib/src/message_list_view.dart +++ b/packages/flutter_widgets/lib/src/message_list_view.dart @@ -956,7 +956,10 @@ class _MessageListViewState extends State { end: colorTheme.white.withOpacity(0), ), duration: const Duration(seconds: 3), - child: child, + child: Padding( + padding: const EdgeInsets.only(top: 4.0), + child: child, + ), onEnd: () => initialMessageHighlightComplete = true, builder: (_, color, child) { return Container( From efc2dc97732a168bb205a042abeb277694f9fde2 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Mon, 18 Jan 2021 21:00:09 +0530 Subject: [PATCH 0958/1140] fix: Added error bottom sheet instead of snackbar --- .../lib/src/message_input.dart | 98 +++++++++++++++---- 1 file changed, 77 insertions(+), 21 deletions(-) diff --git a/packages/flutter_widgets/lib/src/message_input.dart b/packages/flutter_widgets/lib/src/message_input.dart index ef0461ec..d3623f01 100644 --- a/packages/flutter_widgets/lib/src/message_input.dart +++ b/packages/flutter_widgets/lib/src/message_input.dart @@ -1039,15 +1039,9 @@ class MessageInputState extends State { final mediaInfo = await CompressVideoService.compressVideo(file.path); if (mediaInfo.filesize / (1024 * 1024) > _kMaxAttachmentSize) { - // ignore: deprecated_member_use - Scaffold.of(context).showSnackBar( - SnackBar( - content: Text( - 'The file is too large to upload. The file size limit is 20MB. We tried compressing it, but it was not enough.', - ), - ), + _showErrorAlert( + 'The file is too large to upload. The file size limit is 20MB. We tried compressing it, but it was not enough.', ); - setState(() { _attachments.remove(attachment); }); @@ -1060,13 +1054,8 @@ class MessageInputState extends State { path: mediaInfo.path, ); } else { - // ignore: deprecated_member_use - Scaffold.of(context).showSnackBar( - SnackBar( - content: Text( - 'The file is too large to upload. The file size limit is 20MB', - ), - ), + _showErrorAlert( + 'The file is too large to upload. The file size limit is 20MB.', ); } } @@ -2018,12 +2007,8 @@ class MessageInputState extends State { }); } else { // ignore: deprecated_member_use - Scaffold.of(context).showSnackBar( - SnackBar( - content: Text( - 'The file is too large to upload. The file size limit is 20MB', - ), - ), + _showErrorAlert( + 'The file is too large to upload. The file size limit is 20MB.', ); setState(() { _attachments.remove(attachment); @@ -2276,6 +2261,77 @@ class MessageInputState extends State { }); } + void _showErrorAlert(String description) { + showModalBottomSheet( + backgroundColor: StreamChatTheme.of(context).colorTheme.white, + context: context, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.only( + topLeft: Radius.circular(16.0), + topRight: Radius.circular(16.0), + )), + builder: (context) { + return Column( + mainAxisSize: MainAxisSize.min, + children: [ + SizedBox( + height: 26.0, + ), + StreamSvgIcon.error( + color: StreamChatTheme.of(context).colorTheme.accentRed, + size: 24.0, + ), + SizedBox( + height: 26.0, + ), + Text( + 'Something went wrong', + style: StreamChatTheme.of(context).textTheme.headlineBold, + ), + SizedBox( + height: 7.0, + ), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 16.0), + child: Text( + description, + textAlign: TextAlign.center, + ), + ), + SizedBox( + height: 36.0, + ), + Container( + color: + StreamChatTheme.of(context).colorTheme.black.withOpacity(.08), + height: 1.0, + ), + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + FlatButton( + child: Text( + 'OK', + style: StreamChatTheme.of(context) + .textTheme + .bodyBold + .copyWith( + color: StreamChatTheme.of(context) + .colorTheme + .accentBlue), + ), + onPressed: () { + Navigator.of(context).pop(); + }, + ), + ], + ), + ], + ); + }, + ); + } + void _parseExistingMessage(Message message) { textEditingController.text = message.text; From 53d5bb95c90e3fff64193b24dd0953c2f1daf261 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Mon, 18 Jan 2021 21:11:12 +0530 Subject: [PATCH 0959/1140] fix: Remove name when user isn't owner --- packages/flutter_widgets/example/lib/group_info_screen.dart | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/flutter_widgets/example/lib/group_info_screen.dart b/packages/flutter_widgets/example/lib/group_info_screen.dart index 253901c9..2207c282 100644 --- a/packages/flutter_widgets/example/lib/group_info_screen.dart +++ b/packages/flutter_widgets/example/lib/group_info_screen.dart @@ -70,6 +70,10 @@ class _GroupInfoScreenState extends State { ); } + var userMember = snapshot.data + .firstWhere((e) => e.user.id == StreamChat.of(context).user.id); + var isOwner = userMember.role == 'owner'; + return Scaffold( backgroundColor: StreamChatTheme.of(context).colorTheme.whiteSnow, appBar: AppBar( @@ -161,7 +165,7 @@ class _GroupInfoScreenState extends State { height: 8.0, color: StreamChatTheme.of(context).colorTheme.greyGainsboro, ), - _buildNameTile(), + if (isOwner) _buildNameTile(), _buildOptionListTiles(), ], ), From feac47d4e063682dcb89e6062ac16cca11a557d8 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Tue, 19 Jan 2021 09:58:02 +0100 Subject: [PATCH 0960/1140] hide chat info modal on delete --- .../lib/src/channel_bottom_sheet.dart | 308 ++++++++++-------- 1 file changed, 165 insertions(+), 143 deletions(-) diff --git a/packages/flutter_widgets/lib/src/channel_bottom_sheet.dart b/packages/flutter_widgets/lib/src/channel_bottom_sheet.dart index 6b3e4658..3ae7e948 100644 --- a/packages/flutter_widgets/lib/src/channel_bottom_sheet.dart +++ b/packages/flutter_widgets/lib/src/channel_bottom_sheet.dart @@ -14,6 +14,8 @@ class ChannelBottomSheet extends StatefulWidget { } class _ChannelBottomSheetState extends State { + bool _showActions = true; + @override Widget build(BuildContext context) { var channel = StreamChannel.of(context).channel; @@ -33,157 +35,177 @@ class _ChannelBottomSheetState extends State { topRight: Radius.circular(16.0), ), ), - child: ListView( - shrinkWrap: true, - children: [ - SizedBox( - height: 24.0, - ), - Center( - child: Padding( - padding: const EdgeInsets.symmetric(horizontal: 16.0), - child: ChannelName( - textStyle: StreamChatTheme.of(context).textTheme.headlineBold, - ), - ), - ), - SizedBox( - height: 5.0, - ), - Center( - child: ChannelInfo( - showTypingIndicator: false, - channel: StreamChannel.of(context).channel, - textStyle: - StreamChatTheme.of(context).channelPreviewTheme.subtitle, - ), - ), - SizedBox( - height: 17.0, - ), - if (channel.isDistinct && channel.memberCount == 2) - Column( + child: !_showActions + ? SizedBox() + : ListView( + shrinkWrap: true, children: [ - UserAvatar( - user: members - .firstWhere((e) => e.user.id != userAsMember.user.id) - .user, - constraints: BoxConstraints( - maxHeight: 64.0, - maxWidth: 64.0, + SizedBox( + height: 24.0, + ), + Center( + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 16.0), + child: ChannelName( + textStyle: + StreamChatTheme.of(context).textTheme.headlineBold, + ), ), - borderRadius: BorderRadius.circular(32.0), - onlineIndicatorConstraints: - BoxConstraints.tight(Size(12.0, 12.0)), ), SizedBox( - height: 6.0, + height: 5.0, ), - Text( - members - .firstWhere((e) => e.user.id != userAsMember.user.id) - .user - .name, - style: StreamChatTheme.of(context).textTheme.footnoteBold, - maxLines: 1, - overflow: TextOverflow.ellipsis, + Center( + child: ChannelInfo( + showTypingIndicator: false, + channel: StreamChannel.of(context).channel, + textStyle: StreamChatTheme.of(context) + .channelPreviewTheme + .subtitle, + ), + ), + SizedBox( + height: 17.0, + ), + if (channel.isDistinct && channel.memberCount == 2) + Column( + children: [ + UserAvatar( + user: members + .firstWhere( + (e) => e.user.id != userAsMember.user.id) + .user, + constraints: BoxConstraints( + maxHeight: 64.0, + maxWidth: 64.0, + ), + borderRadius: BorderRadius.circular(32.0), + onlineIndicatorConstraints: + BoxConstraints.tight(Size(12.0, 12.0)), + ), + SizedBox( + height: 6.0, + ), + Text( + members + .firstWhere( + (e) => e.user.id != userAsMember.user.id) + .user + .name, + style: + StreamChatTheme.of(context).textTheme.footnoteBold, + maxLines: 1, + overflow: TextOverflow.ellipsis, + ), + ], + ), + if (!(channel.isDistinct && channel.memberCount == 2)) + Container( + height: 94.0, + alignment: Alignment.center, + child: ListView.builder( + scrollDirection: Axis.horizontal, + itemCount: members.length, + shrinkWrap: true, + itemBuilder: (context, index) { + return Padding( + padding: const EdgeInsets.symmetric(horizontal: 8.0), + child: Column( + children: [ + UserAvatar( + user: members[index].user, + constraints: BoxConstraints( + maxHeight: 64.0, + maxWidth: 64.0, + ), + borderRadius: BorderRadius.circular(32.0), + onlineIndicatorConstraints: + BoxConstraints.tight(Size(12.0, 12.0)), + ), + SizedBox( + height: 6.0, + ), + Text( + members[index].user.name, + style: StreamChatTheme.of(context) + .textTheme + .footnoteBold, + maxLines: 1, + overflow: TextOverflow.ellipsis, + ), + ], + ), + ); + }, + ), + ), + SizedBox( + height: 24.0, + ), + OptionListTile( + leading: Padding( + padding: const EdgeInsets.symmetric(horizontal: 16.0), + child: StreamSvgIcon.user( + color: StreamChatTheme.of(context).colorTheme.grey, + ), + ), + title: 'View Info', + onTap: widget.onViewInfoTap, + ), + if (!channel.isDistinct) + OptionListTile( + leading: Padding( + padding: const EdgeInsets.symmetric(horizontal: 16.0), + child: StreamSvgIcon.userRemove( + color: StreamChatTheme.of(context).colorTheme.grey, + ), + ), + title: 'Leave Group', + onTap: () async { + setState(() { + _showActions = false; + }); + await _showLeaveDialog(); + setState(() { + _showActions = true; + }); + }, + ), + if (isOwner) + OptionListTile( + leading: Padding( + padding: const EdgeInsets.symmetric(horizontal: 16.0), + child: StreamSvgIcon.delete( + color: StreamChatTheme.of(context).colorTheme.accentRed, + ), + ), + title: 'Delete Conversation', + titleColor: + StreamChatTheme.of(context).colorTheme.accentRed, + onTap: () async { + setState(() { + _showActions = false; + }); + await _showDeleteDialog(); + setState(() { + _showActions = true; + }); + }, + ), + OptionListTile( + leading: Padding( + padding: const EdgeInsets.symmetric(horizontal: 16.0), + child: StreamSvgIcon.close_small( + color: StreamChatTheme.of(context).colorTheme.grey, + ), + ), + title: 'Cancel', + onTap: () { + Navigator.pop(context); + }, ), ], ), - if (!(channel.isDistinct && channel.memberCount == 2)) - Container( - height: 94.0, - alignment: Alignment.center, - child: ListView.builder( - scrollDirection: Axis.horizontal, - itemCount: members.length, - shrinkWrap: true, - itemBuilder: (context, index) { - return Padding( - padding: const EdgeInsets.symmetric(horizontal: 8.0), - child: Column( - children: [ - UserAvatar( - user: members[index].user, - constraints: BoxConstraints( - maxHeight: 64.0, - maxWidth: 64.0, - ), - borderRadius: BorderRadius.circular(32.0), - onlineIndicatorConstraints: - BoxConstraints.tight(Size(12.0, 12.0)), - ), - SizedBox( - height: 6.0, - ), - Text( - members[index].user.name, - style: StreamChatTheme.of(context) - .textTheme - .footnoteBold, - maxLines: 1, - overflow: TextOverflow.ellipsis, - ), - ], - ), - ); - }, - ), - ), - SizedBox( - height: 24.0, - ), - OptionListTile( - leading: Padding( - padding: const EdgeInsets.symmetric(horizontal: 16.0), - child: StreamSvgIcon.user( - color: StreamChatTheme.of(context).colorTheme.grey, - ), - ), - title: 'View Info', - onTap: widget.onViewInfoTap, - ), - if (!channel.isDistinct) - OptionListTile( - leading: Padding( - padding: const EdgeInsets.symmetric(horizontal: 16.0), - child: StreamSvgIcon.userRemove( - color: StreamChatTheme.of(context).colorTheme.grey, - ), - ), - title: 'Leave Group', - onTap: () async { - _showLeaveDialog(); - }, - ), - if (isOwner) - OptionListTile( - leading: Padding( - padding: const EdgeInsets.symmetric(horizontal: 16.0), - child: StreamSvgIcon.delete( - color: StreamChatTheme.of(context).colorTheme.accentRed, - ), - ), - title: 'Delete Conversation', - titleColor: StreamChatTheme.of(context).colorTheme.accentRed, - onTap: () async { - _showDeleteDialog(); - }, - ), - OptionListTile( - leading: Padding( - padding: const EdgeInsets.symmetric(horizontal: 16.0), - child: StreamSvgIcon.close_small( - color: StreamChatTheme.of(context).colorTheme.grey, - ), - ), - title: 'Cancel', - onTap: () { - Navigator.pop(context); - }, - ), - ], - ), ); } From 48f9897c6337525779b4d306dbfccf596a434b59 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Tue, 19 Jan 2021 10:10:57 +0100 Subject: [PATCH 0961/1140] fix readlist filter --- packages/flutter_widgets/lib/src/message_list_view.dart | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/flutter_widgets/lib/src/message_list_view.dart b/packages/flutter_widgets/lib/src/message_list_view.dart index a0b5a60d..97434934 100644 --- a/packages/flutter_widgets/lib/src/message_list_view.dart +++ b/packages/flutter_widgets/lib/src/message_list_view.dart @@ -813,9 +813,7 @@ class _MessageListViewState extends State { final readList = channel.state?.read?.where((read) { if (read.user.id == userId) return false; return (read.lastRead.isAfter(message.createdAt) || - read.lastRead.isAtSameMomentAs(message.createdAt)) && - (index == 0 || - read.lastRead.isBefore(messages[index - 1].createdAt)); + read.lastRead.isAtSameMomentAs(message.createdAt)); })?.toList() ?? []; From 230f6d048f81c8e2002fe7162919f150b06bd6df Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Tue, 19 Jan 2021 10:41:44 +0100 Subject: [PATCH 0962/1140] bump sample app version --- packages/flutter_widgets/example/pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/flutter_widgets/example/pubspec.yaml b/packages/flutter_widgets/example/pubspec.yaml index 181e6453..f7f941b8 100644 --- a/packages/flutter_widgets/example/pubspec.yaml +++ b/packages/flutter_widgets/example/pubspec.yaml @@ -1,6 +1,6 @@ name: example description: A new Flutter project. -version: 1.1.2+1 +version: 1.1.2+2 environment: sdk: ">=2.2.2 <3.0.0" From 25e3e492101c2a03191b0d8b6da42dae1d8255d1 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Tue, 19 Jan 2021 10:49:29 +0100 Subject: [PATCH 0963/1140] fix consecutive message mentions --- packages/flutter_widgets/lib/src/message_input.dart | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/flutter_widgets/lib/src/message_input.dart b/packages/flutter_widgets/lib/src/message_input.dart index d3623f01..bf480167 100644 --- a/packages/flutter_widgets/lib/src/message_input.dart +++ b/packages/flutter_widgets/lib/src/message_input.dart @@ -2203,6 +2203,8 @@ class MessageInputState extends State { await streamChannel.reloadChannel(); } + _mentionedUsers.clear(); + if (widget.editMessage == null || widget.editMessage.status == MessageSendingStatus.FAILED) { sendingFuture = channel.sendMessage(message); From 55e2e75a0fbe5d2ee308b85b350ac6fe3f4d47e2 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Tue, 19 Jan 2021 11:01:59 +0100 Subject: [PATCH 0964/1140] fix mentions in the same message --- packages/flutter_widgets/lib/src/message_text.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/flutter_widgets/lib/src/message_text.dart b/packages/flutter_widgets/lib/src/message_text.dart index 64fc855d..c64d9520 100644 --- a/packages/flutter_widgets/lib/src/message_text.dart +++ b/packages/flutter_widgets/lib/src/message_text.dart @@ -66,9 +66,9 @@ class MessageText extends StatelessWidget { } String _replaceMentions(String text) { - message.mentionedUsers?.forEach((u) { + message.mentionedUsers?.map((u) => u.name)?.toSet()?.forEach((userName) { text = text.replaceAll( - '@${u.name}', '[@${u.name}](@${u.name.replaceAll(' ', '')})'); + '@${userName}', '[@${userName}](@${userName.replaceAll(' ', '')})'); }); return text; } From 1785ade1b071a0e8e174e3e6b3a7e2b31082828d Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Tue, 19 Jan 2021 15:46:23 +0530 Subject: [PATCH 0965/1140] fix: Added correct paddings for error --- packages/flutter_widgets/lib/src/message_widget.dart | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/packages/flutter_widgets/lib/src/message_widget.dart b/packages/flutter_widgets/lib/src/message_widget.dart index 070aa271..226f6f56 100644 --- a/packages/flutter_widgets/lib/src/message_widget.dart +++ b/packages/flutter_widgets/lib/src/message_widget.dart @@ -381,12 +381,14 @@ class _MessageWidgetState extends State { clipBehavior: Clip.antiAlias, elevation: 0.0, margin: EdgeInsets.symmetric( - horizontal: - widget.showUserAvatar == + horizontal: (isFailedState + ? 15.0 + : 0.0) + + (widget.showUserAvatar == DisplayWidget .gone ? 0 - : 4.0, + : 4.0), ), shape: widget.shape ?? RoundedRectangleBorder( @@ -453,8 +455,8 @@ class _MessageWidgetState extends State { ), if (isFailedState) Positioned( - left: widget.reverse ? -9 : null, - right: widget.reverse ? null : -9, + left: widget.reverse ? 0 : null, + right: widget.reverse ? null : 0, bottom: showBottomRow ? 18 : -2, child: StreamSvgIcon.error(size: 20), ), From e2ae51275464c0f2b85eb610718b4d58fbd112e8 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Tue, 19 Jan 2021 17:19:32 +0530 Subject: [PATCH 0966/1140] fix: Fixed emoticon padding, svg image --- packages/flutter_widgets/lib/src/file_attachment.dart | 4 ++++ packages/flutter_widgets/lib/src/message_widget.dart | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/flutter_widgets/lib/src/file_attachment.dart b/packages/flutter_widgets/lib/src/file_attachment.dart index 96061cab..2629b1a7 100644 --- a/packages/flutter_widgets/lib/src/file_attachment.dart +++ b/packages/flutter_widgets/lib/src/file_attachment.dart @@ -131,6 +131,10 @@ class _FileAttachmentState extends State { ); break; case FileAttachmentType.online: + if (widget.attachment.extraData['mime_type'] == 'svg') { + return getFileTypeImage(widget.attachment.extraData['other']); + } + return CachedNetworkImage( imageUrl: widget.attachment.imageUrl ?? widget.attachment.assetUrl ?? diff --git a/packages/flutter_widgets/lib/src/message_widget.dart b/packages/flutter_widgets/lib/src/message_widget.dart index 226f6f56..94e2164f 100644 --- a/packages/flutter_widgets/lib/src/message_widget.dart +++ b/packages/flutter_widgets/lib/src/message_widget.dart @@ -926,7 +926,7 @@ class _MessageWidgetState extends State { crossAxisAlignment: CrossAxisAlignment.start, children: [ Padding( - padding: widget.textPadding, + padding: isOnlyEmoji ? EdgeInsets.zero : widget.textPadding, child: widget.textBuilder != null ? widget.textBuilder(context, widget.message) : MessageText( From 8e008d0aadbde490a33d78d040f3f90d2f3d8d5c Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Tue, 19 Jan 2021 17:34:41 +0530 Subject: [PATCH 0967/1140] fix: fixed message_input.dart --- packages/flutter_widgets/lib/src/message_input.dart | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/flutter_widgets/lib/src/message_input.dart b/packages/flutter_widgets/lib/src/message_input.dart index cc4fe07d..856fac1c 100644 --- a/packages/flutter_widgets/lib/src/message_input.dart +++ b/packages/flutter_widgets/lib/src/message_input.dart @@ -462,15 +462,16 @@ class MessageInputState extends State { disabledBorder: OutlineInputBorder( borderSide: BorderSide(color: Colors.transparent)), contentPadding: const EdgeInsets.fromLTRB(16, 12, 13, 11), + prefixIconConstraints: BoxConstraints.tight(Size(78, 24)), + suffixIconConstraints: BoxConstraints.tight(Size(40, 40)), prefixIcon: _commandEnabled ? Container( decoration: BoxDecoration( borderRadius: BorderRadius.circular(12), color: theme.colorTheme.accentBlue, ), - height: 24, - margin: const EdgeInsets.all(8.0), - padding: const EdgeInsets.only(right: 8, left: 4), + margin: const EdgeInsets.only(right: 4, left: 8), + alignment: Alignment.center, child: Row( mainAxisSize: MainAxisSize.min, children: [ From 54380797548396a7c55373bb78e1c93dca927131 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Tue, 19 Jan 2021 17:47:24 +0530 Subject: [PATCH 0968/1140] fix: Fixed svg images --- packages/flutter_widgets/lib/src/file_attachment.dart | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/packages/flutter_widgets/lib/src/file_attachment.dart b/packages/flutter_widgets/lib/src/file_attachment.dart index 2629b1a7..3fa8c469 100644 --- a/packages/flutter_widgets/lib/src/file_attachment.dart +++ b/packages/flutter_widgets/lib/src/file_attachment.dart @@ -128,18 +128,20 @@ class _FileAttachmentState extends State { return Image.memory( widget.file.bytes, fit: BoxFit.cover, + errorBuilder: (_, obj, trace) { + return getFileTypeImage(widget.attachment.extraData['other']); + }, ); break; case FileAttachmentType.online: - if (widget.attachment.extraData['mime_type'] == 'svg') { - return getFileTypeImage(widget.attachment.extraData['other']); - } - return CachedNetworkImage( imageUrl: widget.attachment.imageUrl ?? widget.attachment.assetUrl ?? widget.attachment.thumbUrl, fit: BoxFit.cover, + errorWidget: (_, obj, trace) { + return getFileTypeImage(widget.attachment.extraData['other']); + }, progressIndicatorBuilder: (context, _, progress) { return Center( child: Container( From f040231541d37ac095a3d70eb0247d0823f280bf Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Tue, 19 Jan 2021 17:52:03 +0530 Subject: [PATCH 0969/1140] fix: Fixed on swipe bug --- packages/flutter_widgets/lib/src/message_list_view.dart | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/flutter_widgets/lib/src/message_list_view.dart b/packages/flutter_widgets/lib/src/message_list_view.dart index da8dfb06..666321d1 100644 --- a/packages/flutter_widgets/lib/src/message_list_view.dart +++ b/packages/flutter_widgets/lib/src/message_list_view.dart @@ -934,7 +934,10 @@ class _MessageListViewState extends State { if (!message.isDeleted && !message.isSystem && !message.isEphemeral) { child = Swipeable( - onSwipeEnd: () => widget.onMessageSwiped(message), + onSwipeEnd: () { + FocusScope.of(context).unfocus(); + widget.onMessageSwiped(message); + }, backgroundIcon: StreamSvgIcon.reply( color: StreamChatTheme.of(context).colorTheme.accentBlue, ), From 93897bcf2724463494325f458ac77f3d3be708ca Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Tue, 19 Jan 2021 16:25:20 +0100 Subject: [PATCH 0970/1140] fix button padding --- .../lib/src/message_actions_modal.dart | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/flutter_widgets/lib/src/message_actions_modal.dart b/packages/flutter_widgets/lib/src/message_actions_modal.dart index 923378de..0cda4e9d 100644 --- a/packages/flutter_widgets/lib/src/message_actions_modal.dart +++ b/packages/flutter_widgets/lib/src/message_actions_modal.dart @@ -447,7 +447,7 @@ class _MessageActionsModalState extends State { } }, child: Padding( - padding: const EdgeInsets.symmetric(vertical: 8.0, horizontal: 16.0), + padding: const EdgeInsets.symmetric(vertical: 11.0, horizontal: 16.0), child: Row( children: [ StreamSvgIcon.reply( @@ -468,7 +468,7 @@ class _MessageActionsModalState extends State { return InkWell( onTap: () => _showFlagDialog(), child: Padding( - padding: const EdgeInsets.symmetric(vertical: 8.0, horizontal: 16.0), + padding: const EdgeInsets.symmetric(vertical: 11.0, horizontal: 16.0), child: Row( children: [ StreamSvgIcon.icon_flag( @@ -491,7 +491,7 @@ class _MessageActionsModalState extends State { return InkWell( onTap: () => _showDeleteDialog(), child: Padding( - padding: const EdgeInsets.symmetric(vertical: 8.0, horizontal: 16.0), + padding: const EdgeInsets.symmetric(vertical: 11.0, horizontal: 16.0), child: Row( children: [ StreamSvgIcon.delete( @@ -518,7 +518,7 @@ class _MessageActionsModalState extends State { Navigator.pop(context); }, child: Padding( - padding: const EdgeInsets.symmetric(vertical: 8.0, horizontal: 16.0), + padding: const EdgeInsets.symmetric(vertical: 11.0, horizontal: 16.0), child: Row( children: [ StreamSvgIcon.copy( @@ -543,7 +543,7 @@ class _MessageActionsModalState extends State { _showEditBottomSheet(context); }, child: Padding( - padding: const EdgeInsets.symmetric(vertical: 8.0, horizontal: 16.0), + padding: const EdgeInsets.symmetric(vertical: 11.0, horizontal: 16.0), child: Row( children: [ StreamSvgIcon.edit( @@ -575,7 +575,7 @@ class _MessageActionsModalState extends State { } }, child: Padding( - padding: const EdgeInsets.symmetric(vertical: 8.0, horizontal: 16.0), + padding: const EdgeInsets.symmetric(vertical: 11.0, horizontal: 16.0), child: Row( children: [ StreamSvgIcon.circle_up( @@ -670,7 +670,7 @@ class _MessageActionsModalState extends State { } }, child: Padding( - padding: const EdgeInsets.symmetric(vertical: 8.0, horizontal: 16.0), + padding: const EdgeInsets.symmetric(vertical: 11.0, horizontal: 16.0), child: Row( children: [ StreamSvgIcon.thread( From 581185657e65077b0124cf36652975e51c0ad9d8 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Tue, 19 Jan 2021 16:27:45 +0100 Subject: [PATCH 0971/1140] fix appbar brightness in groupinfo --- packages/flutter_widgets/example/lib/group_info_screen.dart | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/flutter_widgets/example/lib/group_info_screen.dart b/packages/flutter_widgets/example/lib/group_info_screen.dart index 2207c282..3d54b59b 100644 --- a/packages/flutter_widgets/example/lib/group_info_screen.dart +++ b/packages/flutter_widgets/example/lib/group_info_screen.dart @@ -77,6 +77,7 @@ class _GroupInfoScreenState extends State { return Scaffold( backgroundColor: StreamChatTheme.of(context).colorTheme.whiteSnow, appBar: AppBar( + brightness: Theme.of(context).brightness, elevation: 1.0, toolbarHeight: 56.0, backgroundColor: StreamChatTheme.of(context).colorTheme.white, From 183aefb0e7dddb737131d66f6fa0b6e134d78d06 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Wed, 20 Jan 2021 13:03:23 +0530 Subject: [PATCH 0972/1140] fix: Fixed modal crash --- packages/flutter_widgets/lib/src/image_footer.dart | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/flutter_widgets/lib/src/image_footer.dart b/packages/flutter_widgets/lib/src/image_footer.dart index 75e6bb73..0c7a463a 100644 --- a/packages/flutter_widgets/lib/src/image_footer.dart +++ b/packages/flutter_widgets/lib/src/image_footer.dart @@ -189,6 +189,7 @@ class _ImageFooterState extends State { return DraggableScrollableSheet( expand: false, initialChildSize: initialChildSize / size.height, + minChildSize: initialChildSize / size.height, builder: (context, scrollController) { return SingleChildScrollView( controller: scrollController, From 9d82134f44a3ac97ecc9e62ab363c9f8fdf229d5 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Wed, 20 Jan 2021 13:23:56 +0530 Subject: [PATCH 0973/1140] fix: removed online indicator on group info screen modal --- .../example/lib/group_info_screen.dart | 23 +------------------ 1 file changed, 1 insertion(+), 22 deletions(-) diff --git a/packages/flutter_widgets/example/lib/group_info_screen.dart b/packages/flutter_widgets/example/lib/group_info_screen.dart index 2207c282..eee83c00 100644 --- a/packages/flutter_widgets/example/lib/group_info_screen.dart +++ b/packages/flutter_widgets/example/lib/group_info_screen.dart @@ -938,28 +938,7 @@ class _GroupInfoScreenState extends State { } } - return Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - if (user.online) - Material( - type: MaterialType.circle, - child: Container( - padding: const EdgeInsets.symmetric(horizontal: 8.0), - constraints: BoxConstraints.tightFor( - width: 28, - height: 12, - ), - child: Material( - shape: CircleBorder(), - color: Color(0xff20E070), - ), - ), - color: StreamChatTheme.of(context).colorTheme.white, - ), - alternativeWidget, - ], - ); + return alternativeWidget; } Widget _buildModalListTile( From 2e12742165396ce30c7afdedfc7d85ee7a20c0d9 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Wed, 20 Jan 2021 13:31:04 +0530 Subject: [PATCH 0974/1140] fix: centered and made online indicator in chat_info_screen.dart smaller --- packages/flutter_widgets/example/lib/chat_info_screen.dart | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/flutter_widgets/example/lib/chat_info_screen.dart b/packages/flutter_widgets/example/lib/chat_info_screen.dart index 4106b96e..a6b14dec 100644 --- a/packages/flutter_widgets/example/lib/chat_info_screen.dart +++ b/packages/flutter_widgets/example/lib/chat_info_screen.dart @@ -382,7 +382,7 @@ class _ChatInfoScreenState extends State { child: Container( padding: const EdgeInsets.symmetric(horizontal: 8.0), constraints: BoxConstraints.tightFor( - width: 28, + width: 24, height: 12, ), child: Material( @@ -393,6 +393,10 @@ class _ChatInfoScreenState extends State { color: StreamChatTheme.of(context).colorTheme.white, ), alternativeWidget, + if (widget.user.online) + SizedBox( + width: 24.0, + ), ], ); } From 38dd71891462ecfabc6a977dad27d33888934f63 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Wed, 20 Jan 2021 15:46:45 +0530 Subject: [PATCH 0975/1140] fix: Fix modal user avatar border --- packages/flutter_widgets/lib/src/image_footer.dart | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/packages/flutter_widgets/lib/src/image_footer.dart b/packages/flutter_widgets/lib/src/image_footer.dart index 0c7a463a..0131561e 100644 --- a/packages/flutter_widgets/lib/src/image_footer.dart +++ b/packages/flutter_widgets/lib/src/image_footer.dart @@ -272,10 +272,7 @@ class _ImageFooterState extends State { clipBehavior: Clip.antiAlias, decoration: BoxDecoration( shape: BoxShape.circle, - color: StreamChatTheme.of(context) - .colorTheme - .white - .withOpacity(0.6), + color: Colors.white.withOpacity(0.6), boxShadow: [ BoxShadow( blurRadius: 8.0, @@ -286,7 +283,7 @@ class _ImageFooterState extends State { ), ], ), - padding: const EdgeInsets.all(1), + padding: const EdgeInsets.all(2), child: UserAvatar( user: widget.message.user, constraints: From ded8b37e6104403b747f2d71c5993e8a3d11ec36 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Wed, 20 Jan 2021 16:04:06 +0530 Subject: [PATCH 0976/1140] fix: Menu closes on download --- packages/flutter_widgets/lib/src/image_actions_modal.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/flutter_widgets/lib/src/image_actions_modal.dart b/packages/flutter_widgets/lib/src/image_actions_modal.dart index 97729ca1..85ab5090 100644 --- a/packages/flutter_widgets/lib/src/image_actions_modal.dart +++ b/packages/flutter_widgets/lib/src/image_actions_modal.dart @@ -83,12 +83,12 @@ class ImageActionsModal extends StatelessWidget { urls[currentIndex].assetUrl ?? urls[currentIndex].thumbUrl; + Navigator.pop(context); + if (urls[currentIndex].type == 'video') { await _saveVideo(url); - Navigator.pop(context); } else { await _saveImage(url); - Navigator.pop(context); } }, ), From d48ccf15dfcb80f40e0b198c54f7e3de3fd9b1c3 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Wed, 20 Jan 2021 16:21:03 +0530 Subject: [PATCH 0977/1140] feat: Added message reply --- .../lib/src/full_screen_media.dart | 2 + .../lib/src/giphy_attachment.dart | 20 ++++++++-- .../lib/src/image_actions_modal.dart | 4 +- .../lib/src/image_attachment.dart | 10 ++++- .../flutter_widgets/lib/src/image_header.dart | 39 +++++++++++-------- .../lib/src/message_list_view.dart | 20 ++++++++++ .../lib/src/message_widget.dart | 5 +++ .../lib/src/video_attachment.dart | 10 ++++- 8 files changed, 84 insertions(+), 26 deletions(-) diff --git a/packages/flutter_widgets/lib/src/full_screen_media.dart b/packages/flutter_widgets/lib/src/full_screen_media.dart index e164eec8..473c9a05 100644 --- a/packages/flutter_widgets/lib/src/full_screen_media.dart +++ b/packages/flutter_widgets/lib/src/full_screen_media.dart @@ -10,6 +10,8 @@ import 'stream_channel.dart'; import '../stream_chat_flutter.dart'; +enum ReturnActionType { none, reply } + typedef ShowMessageCallback = void Function(Message message, Channel channel); /// A full screen image widget diff --git a/packages/flutter_widgets/lib/src/giphy_attachment.dart b/packages/flutter_widgets/lib/src/giphy_attachment.dart index df5a5705..6abe3df9 100644 --- a/packages/flutter_widgets/lib/src/giphy_attachment.dart +++ b/packages/flutter_widgets/lib/src/giphy_attachment.dart @@ -13,6 +13,7 @@ class GiphyAttachment extends StatelessWidget { final Message message; final Size size; final ShowMessageCallback onShowMessage; + final ValueChanged onReturnAction; const GiphyAttachment({ Key key, @@ -21,6 +22,7 @@ class GiphyAttachment extends StatelessWidget { this.message, this.size, this.onShowMessage, + this.onReturnAction, }) : super(key: key); @override @@ -65,8 +67,9 @@ class GiphyAttachment extends StatelessWidget { Padding( padding: const EdgeInsets.all(8.0), child: GestureDetector( - onTap: () { - Navigator.push(context, MaterialPageRoute(builder: (_) { + onTap: () async { + var res = await Navigator.push(context, + MaterialPageRoute(builder: (_) { final channel = StreamChannel.of(context).channel; return StreamChannel( @@ -82,6 +85,10 @@ class GiphyAttachment extends StatelessWidget { ), ); })); + + if (res != null) { + onReturnAction(res); + } }, child: ClipRRect( borderRadius: BorderRadius.only( @@ -320,8 +327,9 @@ class GiphyAttachment extends StatelessWidget { Widget _buildSentAttachment(context) { return Container( child: GestureDetector( - onTap: () { - Navigator.push(context, MaterialPageRoute(builder: (_) { + onTap: () async { + var res = + await Navigator.push(context, MaterialPageRoute(builder: (_) { var channel = StreamChannel.of(context).channel; return StreamChannel( @@ -337,6 +345,10 @@ class GiphyAttachment extends StatelessWidget { ), ); })); + + if (res != null) { + onReturnAction(res); + } }, child: Stack( children: [ diff --git a/packages/flutter_widgets/lib/src/image_actions_modal.dart b/packages/flutter_widgets/lib/src/image_actions_modal.dart index 85ab5090..2a251c61 100644 --- a/packages/flutter_widgets/lib/src/image_actions_modal.dart +++ b/packages/flutter_widgets/lib/src/image_actions_modal.dart @@ -60,7 +60,9 @@ class ImageActionsModal extends StatelessWidget { size: 24.0, color: StreamChatTheme.of(context).colorTheme.grey, ), - () {}, + () { + Navigator.pop(context, ReturnActionType.reply); + }, ), _buildButton( context, diff --git a/packages/flutter_widgets/lib/src/image_attachment.dart b/packages/flutter_widgets/lib/src/image_attachment.dart index f9e3290b..4be47262 100644 --- a/packages/flutter_widgets/lib/src/image_attachment.dart +++ b/packages/flutter_widgets/lib/src/image_attachment.dart @@ -14,6 +14,7 @@ class ImageAttachment extends StatelessWidget { final Size size; final bool showTitle; final ShowMessageCallback onShowMessage; + final ValueChanged onReturnAction; const ImageAttachment({ Key key, @@ -23,6 +24,7 @@ class ImageAttachment extends StatelessWidget { this.messageTheme, this.showTitle = true, this.onShowMessage, + this.onReturnAction, }) : super(key: key); @override @@ -42,8 +44,8 @@ class ImageAttachment extends StatelessWidget { children: [ Expanded( child: GestureDetector( - onTap: () { - Navigator.push( + onTap: () async { + var result = await Navigator.push( context, MaterialPageRoute( builder: (_) { @@ -64,6 +66,10 @@ class ImageAttachment extends StatelessWidget { }, ), ); + + if (result != null) { + onReturnAction(result); + } }, child: CachedNetworkImage( height: size?.height, diff --git a/packages/flutter_widgets/lib/src/image_header.dart b/packages/flutter_widgets/lib/src/image_header.dart index 1f6237ab..1694f0b7 100644 --- a/packages/flutter_widgets/lib/src/image_header.dart +++ b/packages/flutter_widgets/lib/src/image_header.dart @@ -101,24 +101,29 @@ class ImageHeader extends StatelessWidget implements PreferredSizeWidget { @override final Size preferredSize; - void _showMessageActionModalBottomSheet(BuildContext context) { + void _showMessageActionModalBottomSheet(BuildContext context) async { final channel = StreamChannel.of(context).channel; - showDialog( - context: context, - barrierColor: StreamChatTheme.of(context).colorTheme.overlay, - builder: (context) { - return StreamChannel( - channel: channel, - child: ImageActionsModal( - userName: userName, - sentAt: sentAt, - message: message, - urls: urls, - currentIndex: currentIndex, - onShowMessage: onShowMessage, - ), - ); - }); + var result = await showDialog( + context: context, + barrierColor: StreamChatTheme.of(context).colorTheme.overlay, + builder: (context) { + return StreamChannel( + channel: channel, + child: ImageActionsModal( + userName: userName, + sentAt: sentAt, + message: message, + urls: urls, + currentIndex: currentIndex, + onShowMessage: onShowMessage, + ), + ); + }, + ); + + if (result != null) { + Navigator.pop(context, result); + } } } diff --git a/packages/flutter_widgets/lib/src/message_list_view.dart b/packages/flutter_widgets/lib/src/message_list_view.dart index 666321d1..9a0fe955 100644 --- a/packages/flutter_widgets/lib/src/message_list_view.dart +++ b/packages/flutter_widgets/lib/src/message_list_view.dart @@ -780,6 +780,16 @@ class _MessageListViewState extends State { ? StreamChatTheme.of(context).ownMessageTheme : StreamChatTheme.of(context).otherMessageTheme, onShowMessage: widget.onShowMessage, + onReturnAction: (action) { + switch (action) { + case ReturnActionType.none: + break; + case ReturnActionType.reply: + FocusScope.of(context).unfocus(); + widget.onMessageSwiped(message); + break; + } + }, ); } @@ -930,6 +940,16 @@ class _MessageListViewState extends State { readList: readList, allRead: allRead, onShowMessage: widget.onShowMessage, + onReturnAction: (action) { + switch (action) { + case ReturnActionType.none: + break; + case ReturnActionType.reply: + FocusScope.of(context).unfocus(); + widget.onMessageSwiped(message); + break; + } + }, ); if (!message.isDeleted && !message.isSystem && !message.isEphemeral) { diff --git a/packages/flutter_widgets/lib/src/message_widget.dart b/packages/flutter_widgets/lib/src/message_widget.dart index 94e2164f..eeabaa13 100644 --- a/packages/flutter_widgets/lib/src/message_widget.dart +++ b/packages/flutter_widgets/lib/src/message_widget.dart @@ -120,6 +120,7 @@ class MessageWidget extends StatefulWidget { final List readList; final ShowMessageCallback onShowMessage; + final ValueChanged onReturnAction; /// If true show the users username next to the timestamp of the message final bool showUsername; @@ -178,6 +179,7 @@ class MessageWidget extends StatefulWidget { this.onShowMessage, this.editMessageInputBuilder, this.textBuilder, + this.onReturnAction, Map customAttachmentBuilders, this.readList, this.padding, @@ -199,6 +201,7 @@ class MessageWidget extends StatefulWidget { MediaQuery.of(context).size.height * 0.3, ), onShowMessage: onShowMessage, + onReturnAction: onReturnAction, ); }, 'video': (context, message, attachment) { @@ -211,6 +214,7 @@ class MessageWidget extends StatefulWidget { ), message: message, onShowMessage: onShowMessage, + onReturnAction: onReturnAction, ); }, 'giphy': (context, message, attachment) { @@ -223,6 +227,7 @@ class MessageWidget extends StatefulWidget { MediaQuery.of(context).size.height * 0.3, ), onShowMessage: onShowMessage, + onReturnAction: onReturnAction, ); }, 'file': (context, message, attachment) { diff --git a/packages/flutter_widgets/lib/src/video_attachment.dart b/packages/flutter_widgets/lib/src/video_attachment.dart index 83763aee..b775109f 100644 --- a/packages/flutter_widgets/lib/src/video_attachment.dart +++ b/packages/flutter_widgets/lib/src/video_attachment.dart @@ -15,6 +15,7 @@ class VideoAttachment extends StatefulWidget { final Size size; final Message message; final ShowMessageCallback onShowMessage; + final ValueChanged onReturnAction; VideoAttachment({ Key key, @@ -23,6 +24,7 @@ class VideoAttachment extends StatefulWidget { this.message, this.size, this.onShowMessage, + this.onReturnAction, }) : super(key: key); @override @@ -84,10 +86,10 @@ class _VideoAttachmentState extends State { }); return GestureDetector( - onTap: () { + onTap: () async { final channel = StreamChannel.of(context).channel; - Navigator.push( + var res = await Navigator.push( context, MaterialPageRoute( builder: (_) => StreamChannel( @@ -102,6 +104,10 @@ class _VideoAttachmentState extends State { ), ), ); + + if (res != null) { + widget.onReturnAction(res); + } }, child: Container( height: widget.size?.height, From a2343e8693dc118400440a7caabd4f820bdaa8a0 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Wed, 20 Jan 2021 12:40:19 +0100 Subject: [PATCH 0978/1140] extract on tap --- .../lib/src/giphy_attachment.dart | 47 ++++++++++--------- 1 file changed, 26 insertions(+), 21 deletions(-) diff --git a/packages/flutter_widgets/lib/src/giphy_attachment.dart b/packages/flutter_widgets/lib/src/giphy_attachment.dart index 6abe3df9..0f89bc75 100644 --- a/packages/flutter_widgets/lib/src/giphy_attachment.dart +++ b/packages/flutter_widgets/lib/src/giphy_attachment.dart @@ -68,27 +68,7 @@ class GiphyAttachment extends StatelessWidget { padding: const EdgeInsets.all(8.0), child: GestureDetector( onTap: () async { - var res = await Navigator.push(context, - MaterialPageRoute(builder: (_) { - final channel = StreamChannel.of(context).channel; - - return StreamChannel( - channel: channel, - child: FullScreenMedia( - mediaAttachments: [ - attachment, - ], - userName: message.user.name, - sentAt: message.createdAt, - message: message, - onShowMessage: onShowMessage, - ), - ); - })); - - if (res != null) { - onReturnAction(res); - } + _onImageTap(context); }, child: ClipRRect( borderRadius: BorderRadius.only( @@ -324,6 +304,31 @@ class GiphyAttachment extends StatelessWidget { ); } + void _onImageTap(BuildContext context) async { + var res = await Navigator.push(context, MaterialPageRoute( + builder: (_) { + final channel = StreamChannel.of(context).channel; + + return StreamChannel( + channel: channel, + child: FullScreenMedia( + mediaAttachments: [ + attachment, + ], + userName: message.user.name, + sentAt: message.createdAt, + message: message, + onShowMessage: onShowMessage, + ), + ); + }, + )); + + if (res != null) { + onReturnAction(res); + } + } + Widget _buildSentAttachment(context) { return Container( child: GestureDetector( From 8824e348c26d2061544f74f0638bd5b7579f557b Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Wed, 20 Jan 2021 13:01:00 +0100 Subject: [PATCH 0979/1140] bump sample app version --- packages/flutter_widgets/example/pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/flutter_widgets/example/pubspec.yaml b/packages/flutter_widgets/example/pubspec.yaml index f7f941b8..9191f504 100644 --- a/packages/flutter_widgets/example/pubspec.yaml +++ b/packages/flutter_widgets/example/pubspec.yaml @@ -1,6 +1,6 @@ name: example description: A new Flutter project. -version: 1.1.2+2 +version: 1.1.3 environment: sdk: ">=2.2.2 <3.0.0" From 0e857a8938d64a2b485c6b40798b55e0db87b985 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Wed, 20 Jan 2021 17:34:57 +0530 Subject: [PATCH 0980/1140] fix: Added file size fix --- packages/flutter_widgets/lib/src/message_input.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/flutter_widgets/lib/src/message_input.dart b/packages/flutter_widgets/lib/src/message_input.dart index 856fac1c..01ae3d3a 100644 --- a/packages/flutter_widgets/lib/src/message_input.dart +++ b/packages/flutter_widgets/lib/src/message_input.dart @@ -1998,7 +1998,7 @@ class MessageInputState extends State { _attachments.add(attachment); }); - if (file.size > _kMaxAttachmentSize) { + if (file.size / 1024 > _kMaxAttachmentSize) { if (attachmentType == 'video') { final mediaInfo = await CompressVideoService.compressVideo(file.path); file = PlatformFile( From 18cdd2473c67521acd83d61b9739794ff9b9a8c7 Mon Sep 17 00:00:00 2001 From: Neevash Ramdial Date: Wed, 20 Jan 2021 10:26:03 -0400 Subject: [PATCH 0981/1140] update dart sdk version --- packages/dart_client/pubspec.yaml | 2 +- packages/flutter_widgets/pubspec.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/dart_client/pubspec.yaml b/packages/dart_client/pubspec.yaml index d045fe22..71ce5a22 100644 --- a/packages/dart_client/pubspec.yaml +++ b/packages/dart_client/pubspec.yaml @@ -6,7 +6,7 @@ repository: https://github.com/GetStream/stream-chat-dart issue_tracker: https://github.com/GetStream/stream-chat-dart/issues environment: - sdk: ">=2.2.2 <3.0.0" + sdk: ">=2.7.0 <3.0.0" dependencies: flutter: diff --git a/packages/flutter_widgets/pubspec.yaml b/packages/flutter_widgets/pubspec.yaml index a68082a1..277618a6 100644 --- a/packages/flutter_widgets/pubspec.yaml +++ b/packages/flutter_widgets/pubspec.yaml @@ -6,7 +6,7 @@ repository: https://github.com/GetStream/stream-chat-flutter issue_tracker: https://github.com/GetStream/stream-chat-flutter/issues environment: - sdk: ">=2.6.0 <3.0.0" + sdk: ">=2.7.0 <3.0.0" dependencies: flutter: From 53a26d0a59a3275b005396d64d6ac13c4d6e44c0 Mon Sep 17 00:00:00 2001 From: Neevash Ramdial Date: Wed, 20 Jan 2021 10:26:21 -0400 Subject: [PATCH 0982/1140] add publish_to to example pubspec --- packages/flutter_widgets/example/pubspec.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/flutter_widgets/example/pubspec.yaml b/packages/flutter_widgets/example/pubspec.yaml index 9191f504..df738f86 100644 --- a/packages/flutter_widgets/example/pubspec.yaml +++ b/packages/flutter_widgets/example/pubspec.yaml @@ -1,6 +1,7 @@ name: example description: A new Flutter project. version: 1.1.3 +publish_to: 'none' environment: sdk: ">=2.2.2 <3.0.0" From aeaef4babdc461d6c9fc83958f880a94bd9529b1 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Wed, 20 Jan 2021 15:35:43 +0100 Subject: [PATCH 0983/1140] fix file attachment borer --- packages/flutter_widgets/lib/src/file_attachment.dart | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/packages/flutter_widgets/lib/src/file_attachment.dart b/packages/flutter_widgets/lib/src/file_attachment.dart index 3fa8c469..8e3ef4d6 100644 --- a/packages/flutter_widgets/lib/src/file_attachment.dart +++ b/packages/flutter_widgets/lib/src/file_attachment.dart @@ -62,7 +62,13 @@ class _FileAttachmentState extends State { child: Container( width: widget.size?.width ?? 100, height: 56.0, - color: StreamChatTheme.of(context).colorTheme.white, + decoration: BoxDecoration( + color: StreamChatTheme.of(context).colorTheme.white, + borderRadius: BorderRadius.circular(12), + border: Border.all( + color: StreamChatTheme.of(context).colorTheme.greyWhisper, + ), + ), child: Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ From 547e59b9d683e121457628cef7e9c9ebf4c295b4 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Wed, 20 Jan 2021 15:37:21 +0100 Subject: [PATCH 0984/1140] bump sample app version --- packages/flutter_widgets/example/pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/flutter_widgets/example/pubspec.yaml b/packages/flutter_widgets/example/pubspec.yaml index 9191f504..c2070f61 100644 --- a/packages/flutter_widgets/example/pubspec.yaml +++ b/packages/flutter_widgets/example/pubspec.yaml @@ -1,6 +1,6 @@ name: example description: A new Flutter project. -version: 1.1.3 +version: 1.1.3+1 environment: sdk: ">=2.2.2 <3.0.0" From e3f90de28eaaba058a3e24475329962f57e94dc0 Mon Sep 17 00:00:00 2001 From: Neevash Ramdial Date: Wed, 20 Jan 2021 11:09:44 -0400 Subject: [PATCH 0985/1140] Add example to dart client --- packages/dart_client/example/.gitignore | 46 ++++ packages/dart_client/example/.metadata | 10 + packages/dart_client/example/README.md | 16 ++ .../dart_client/example/android/.gitignore | 11 + .../example/android/app/build.gradle | 59 +++++ .../android/app/src/debug/AndroidManifest.xml | 7 + .../android/app/src/main/AndroidManifest.xml | 41 +++ .../stream_chat_dart_example/MainActivity.kt | 6 + .../res/drawable-v21/launch_background.xml | 12 + .../main/res/drawable/launch_background.xml | 12 + .../src/main/res/mipmap-hdpi/ic_launcher.png | Bin 0 -> 544 bytes .../src/main/res/mipmap-mdpi/ic_launcher.png | Bin 0 -> 442 bytes .../src/main/res/mipmap-xhdpi/ic_launcher.png | Bin 0 -> 721 bytes .../main/res/mipmap-xxhdpi/ic_launcher.png | Bin 0 -> 1031 bytes .../main/res/mipmap-xxxhdpi/ic_launcher.png | Bin 0 -> 1443 bytes .../app/src/main/res/values-night/styles.xml | 18 ++ .../app/src/main/res/values/styles.xml | 18 ++ .../app/src/profile/AndroidManifest.xml | 7 + .../dart_client/example/android/build.gradle | 31 +++ .../example/android/gradle.properties | 3 + .../gradle/wrapper/gradle-wrapper.properties | 6 + .../example/android/settings.gradle | 11 + packages/dart_client/example/ios/.gitignore | 32 +++ .../ios/Flutter/AppFrameworkInfo.plist | 26 ++ .../example/ios/Flutter/Debug.xcconfig | 2 + .../example/ios/Flutter/Release.xcconfig | 2 + .../contents.xcworkspacedata | 7 + .../xcshareddata/IDEWorkspaceChecks.plist | 8 + .../xcshareddata/WorkspaceSettings.xcsettings | 8 + .../xcshareddata/xcschemes/Runner.xcscheme | 91 +++++++ .../contents.xcworkspacedata | 10 + .../xcshareddata/IDEWorkspaceChecks.plist | 8 + .../xcshareddata/WorkspaceSettings.xcsettings | 8 + .../example/ios/Runner/AppDelegate.swift | 13 + .../AppIcon.appiconset/Contents.json | 122 +++++++++ .../Icon-App-1024x1024@1x.png | Bin 0 -> 10932 bytes .../AppIcon.appiconset/Icon-App-20x20@1x.png | Bin 0 -> 564 bytes .../AppIcon.appiconset/Icon-App-20x20@2x.png | Bin 0 -> 1283 bytes .../AppIcon.appiconset/Icon-App-20x20@3x.png | Bin 0 -> 1588 bytes .../AppIcon.appiconset/Icon-App-29x29@1x.png | Bin 0 -> 1025 bytes .../AppIcon.appiconset/Icon-App-29x29@2x.png | Bin 0 -> 1716 bytes .../AppIcon.appiconset/Icon-App-29x29@3x.png | Bin 0 -> 1920 bytes .../AppIcon.appiconset/Icon-App-40x40@1x.png | Bin 0 -> 1283 bytes .../AppIcon.appiconset/Icon-App-40x40@2x.png | Bin 0 -> 1895 bytes .../AppIcon.appiconset/Icon-App-40x40@3x.png | Bin 0 -> 2665 bytes .../AppIcon.appiconset/Icon-App-60x60@2x.png | Bin 0 -> 2665 bytes .../AppIcon.appiconset/Icon-App-60x60@3x.png | Bin 0 -> 3831 bytes .../AppIcon.appiconset/Icon-App-76x76@1x.png | Bin 0 -> 1888 bytes .../AppIcon.appiconset/Icon-App-76x76@2x.png | Bin 0 -> 3294 bytes .../Icon-App-83.5x83.5@2x.png | Bin 0 -> 3612 bytes .../LaunchImage.imageset/Contents.json | 23 ++ .../LaunchImage.imageset/LaunchImage.png | Bin 0 -> 68 bytes .../LaunchImage.imageset/LaunchImage@2x.png | Bin 0 -> 68 bytes .../LaunchImage.imageset/LaunchImage@3x.png | Bin 0 -> 68 bytes .../LaunchImage.imageset/README.md | 5 + .../Runner/Base.lproj/LaunchScreen.storyboard | 37 +++ .../ios/Runner/Base.lproj/Main.storyboard | 26 ++ .../dart_client/example/ios/Runner/Info.plist | 45 ++++ .../ios/Runner/Runner-Bridging-Header.h | 1 + packages/dart_client/example/lib/main.dart | 248 ++++++++++++++++++ packages/dart_client/example/pubspec.yaml | 23 ++ packages/dart_client/example/web/favicon.png | Bin 0 -> 917 bytes .../example/web/icons/Icon-192.png | Bin 0 -> 5292 bytes .../example/web/icons/Icon-512.png | Bin 0 -> 8252 bytes packages/dart_client/example/web/index.html | 45 ++++ .../dart_client/example/web/manifest.json | 23 ++ 66 files changed, 1127 insertions(+) create mode 100644 packages/dart_client/example/.gitignore create mode 100644 packages/dart_client/example/.metadata create mode 100644 packages/dart_client/example/README.md create mode 100644 packages/dart_client/example/android/.gitignore create mode 100644 packages/dart_client/example/android/app/build.gradle create mode 100644 packages/dart_client/example/android/app/src/debug/AndroidManifest.xml create mode 100644 packages/dart_client/example/android/app/src/main/AndroidManifest.xml create mode 100644 packages/dart_client/example/android/app/src/main/kotlin/io/getstream/stream_chat_dart_example/stream_chat_dart_example/MainActivity.kt create mode 100644 packages/dart_client/example/android/app/src/main/res/drawable-v21/launch_background.xml create mode 100644 packages/dart_client/example/android/app/src/main/res/drawable/launch_background.xml create mode 100644 packages/dart_client/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png create mode 100644 packages/dart_client/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png create mode 100644 packages/dart_client/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png create mode 100644 packages/dart_client/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png create mode 100644 packages/dart_client/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png create mode 100644 packages/dart_client/example/android/app/src/main/res/values-night/styles.xml create mode 100644 packages/dart_client/example/android/app/src/main/res/values/styles.xml create mode 100644 packages/dart_client/example/android/app/src/profile/AndroidManifest.xml create mode 100644 packages/dart_client/example/android/build.gradle create mode 100644 packages/dart_client/example/android/gradle.properties create mode 100644 packages/dart_client/example/android/gradle/wrapper/gradle-wrapper.properties create mode 100644 packages/dart_client/example/android/settings.gradle create mode 100644 packages/dart_client/example/ios/.gitignore create mode 100644 packages/dart_client/example/ios/Flutter/AppFrameworkInfo.plist create mode 100644 packages/dart_client/example/ios/Flutter/Debug.xcconfig create mode 100644 packages/dart_client/example/ios/Flutter/Release.xcconfig create mode 100644 packages/dart_client/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata create mode 100644 packages/dart_client/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 packages/dart_client/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings create mode 100644 packages/dart_client/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme create mode 100644 packages/dart_client/example/ios/Runner.xcworkspace/contents.xcworkspacedata create mode 100644 packages/dart_client/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 packages/dart_client/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings create mode 100644 packages/dart_client/example/ios/Runner/AppDelegate.swift create mode 100644 packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json create mode 100644 packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png create mode 100644 packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png create mode 100644 packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png create mode 100644 packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png create mode 100644 packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png create mode 100644 packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png create mode 100644 packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png create mode 100644 packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png create mode 100644 packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png create mode 100644 packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png create mode 100644 packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png create mode 100644 packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png create mode 100644 packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png create mode 100644 packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png create mode 100644 packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png create mode 100644 packages/dart_client/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json create mode 100644 packages/dart_client/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png create mode 100644 packages/dart_client/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png create mode 100644 packages/dart_client/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png create mode 100644 packages/dart_client/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md create mode 100644 packages/dart_client/example/ios/Runner/Base.lproj/LaunchScreen.storyboard create mode 100644 packages/dart_client/example/ios/Runner/Base.lproj/Main.storyboard create mode 100644 packages/dart_client/example/ios/Runner/Info.plist create mode 100644 packages/dart_client/example/ios/Runner/Runner-Bridging-Header.h create mode 100644 packages/dart_client/example/lib/main.dart create mode 100644 packages/dart_client/example/pubspec.yaml create mode 100644 packages/dart_client/example/web/favicon.png create mode 100644 packages/dart_client/example/web/icons/Icon-192.png create mode 100644 packages/dart_client/example/web/icons/Icon-512.png create mode 100644 packages/dart_client/example/web/index.html create mode 100644 packages/dart_client/example/web/manifest.json diff --git a/packages/dart_client/example/.gitignore b/packages/dart_client/example/.gitignore new file mode 100644 index 00000000..0fa6b675 --- /dev/null +++ b/packages/dart_client/example/.gitignore @@ -0,0 +1,46 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# IntelliJ related +*.iml +*.ipr +*.iws +.idea/ + +# The .vscode folder contains launch configuration and tasks you configure in +# VS Code which you may wish to be included in version control, so this line +# is commented out by default. +#.vscode/ + +# Flutter/Dart/Pub related +**/doc/api/ +**/ios/Flutter/.last_build_id +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Android Studio will place build artifacts here +/android/app/debug +/android/app/profile +/android/app/release diff --git a/packages/dart_client/example/.metadata b/packages/dart_client/example/.metadata new file mode 100644 index 00000000..48acef37 --- /dev/null +++ b/packages/dart_client/example/.metadata @@ -0,0 +1,10 @@ +# This file tracks properties of this Flutter project. +# Used by Flutter tool to assess capabilities and perform upgrades etc. +# +# This file should be version controlled and should not be manually edited. + +version: + revision: 5d36f2e7f5387b6c751449258ade8e4e6edf99be + channel: beta + +project_type: app diff --git a/packages/dart_client/example/README.md b/packages/dart_client/example/README.md new file mode 100644 index 00000000..ed19a198 --- /dev/null +++ b/packages/dart_client/example/README.md @@ -0,0 +1,16 @@ +# stream_chat_dart_example + +Example using Stream's LLC + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/packages/dart_client/example/android/.gitignore b/packages/dart_client/example/android/.gitignore new file mode 100644 index 00000000..0a741cb4 --- /dev/null +++ b/packages/dart_client/example/android/.gitignore @@ -0,0 +1,11 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java + +# Remember to never publicly share your keystore. +# See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app +key.properties diff --git a/packages/dart_client/example/android/app/build.gradle b/packages/dart_client/example/android/app/build.gradle new file mode 100644 index 00000000..0a93e89f --- /dev/null +++ b/packages/dart_client/example/android/app/build.gradle @@ -0,0 +1,59 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 30 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "io.getstream.stream_chat_dart_example.stream_chat_dart_example" + minSdkVersion 16 + targetSdkVersion 30 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + + buildTypes { + release { + // TODO: Add your own signing config for the release build. + // Signing with the debug keys for now, so `flutter run --release` works. + signingConfig signingConfigs.debug + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/packages/dart_client/example/android/app/src/debug/AndroidManifest.xml b/packages/dart_client/example/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 00000000..f590dd7e --- /dev/null +++ b/packages/dart_client/example/android/app/src/debug/AndroidManifest.xml @@ -0,0 +1,7 @@ + + + + diff --git a/packages/dart_client/example/android/app/src/main/AndroidManifest.xml b/packages/dart_client/example/android/app/src/main/AndroidManifest.xml new file mode 100644 index 00000000..54736655 --- /dev/null +++ b/packages/dart_client/example/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + diff --git a/packages/dart_client/example/android/app/src/main/kotlin/io/getstream/stream_chat_dart_example/stream_chat_dart_example/MainActivity.kt b/packages/dart_client/example/android/app/src/main/kotlin/io/getstream/stream_chat_dart_example/stream_chat_dart_example/MainActivity.kt new file mode 100644 index 00000000..da72a2e2 --- /dev/null +++ b/packages/dart_client/example/android/app/src/main/kotlin/io/getstream/stream_chat_dart_example/stream_chat_dart_example/MainActivity.kt @@ -0,0 +1,6 @@ +package io.getstream.stream_chat_dart_example.stream_chat_dart_example + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} diff --git a/packages/dart_client/example/android/app/src/main/res/drawable-v21/launch_background.xml b/packages/dart_client/example/android/app/src/main/res/drawable-v21/launch_background.xml new file mode 100644 index 00000000..f74085f3 --- /dev/null +++ b/packages/dart_client/example/android/app/src/main/res/drawable-v21/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/packages/dart_client/example/android/app/src/main/res/drawable/launch_background.xml b/packages/dart_client/example/android/app/src/main/res/drawable/launch_background.xml new file mode 100644 index 00000000..304732f8 --- /dev/null +++ b/packages/dart_client/example/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/packages/dart_client/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/packages/dart_client/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..db77bb4b7b0906d62b1847e87f15cdcacf6a4f29 GIT binary patch literal 544 zcmeAS@N?(olHy`uVBq!ia0vp^9w5xY3?!3`olAj~WQl7;NpOBzNqJ&XDuZK6ep0G} zXKrG8YEWuoN@d~6R2!h8bpbvhu0Wd6uZuB!w&u2PAxD2eNXD>P5D~Wn-+_Wa#27Xc zC?Zj|6r#X(-D3u$NCt}(Ms06KgJ4FxJVv{GM)!I~&n8Bnc94O7-Hd)cjDZswgC;Qs zO=b+9!WcT8F?0rF7!Uys2bs@gozCP?z~o%U|N3vA*22NaGQG zlg@K`O_XuxvZ&Ks^m&R!`&1=spLvfx7oGDKDwpwW`#iqdw@AL`7MR}m`rwr|mZgU`8P7SBkL78fFf!WnuYWm$5Z0 zNXhDbCv&49sM544K|?c)WrFfiZvCi9h0O)B3Pgg&ebxsLQ05GG~ AQ2+n{ literal 0 HcmV?d00001 diff --git a/packages/dart_client/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/packages/dart_client/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..17987b79bb8a35cc66c3c1fd44f5a5526c1b78be GIT binary patch literal 442 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA3?vioaBc-sk|nMYCBgY=CFO}lsSJ)O`AMk? zp1FzXsX?iUDV2pMQ*D5Xx&nMcT!A!W`0S9QKQy;}1Cl^CgaH=;G9cpY;r$Q>i*pfB zP2drbID<_#qf;rPZx^FqH)F_D#*k@@q03KywUtLX8Ua?`H+NMzkczFPK3lFz@i_kW%1NOn0|D2I9n9wzH8m|-tHjsw|9>@K=iMBhxvkv6m8Y-l zytQ?X=U+MF$@3 zt`~i=@j|6y)RWMK--}M|=T`o&^Ni>IoWKHEbBXz7?A@mgWoL>!*SXo`SZH-*HSdS+ yn*9;$7;m`l>wYBC5bq;=U}IMqLzqbYCidGC!)_gkIk_C@Uy!y&wkt5C($~2D>~)O*cj@FGjOCM)M>_ixfudOh)?xMu#Fs z#}Y=@YDTwOM)x{K_j*Q;dPdJ?Mz0n|pLRx{4n|)f>SXlmV)XB04CrSJn#dS5nK2lM zrZ9#~WelCp7&e13Y$jvaEXHskn$2V!!DN-nWS__6T*l;H&Fopn?A6HZ-6WRLFP=R` zqG+CE#d4|IbyAI+rJJ`&x9*T`+a=p|0O(+s{UBcyZdkhj=yS1>AirP+0R;mf2uMgM zC}@~JfByORAh4SyRgi&!(cja>F(l*O+nd+@4m$|6K6KDn_&uvCpV23&>G9HJp{xgg zoq1^2_p9@|WEo z*X_Uko@K)qYYv~>43eQGMdbiGbo>E~Q& zrYBH{QP^@Sti!`2)uG{irBBq@y*$B zi#&(U-*=fp74j)RyIw49+0MRPMRU)+a2r*PJ$L5roHt2$UjExCTZSbq%V!HeS7J$N zdG@vOZB4v_lF7Plrx+hxo7(fCV&}fHq)$ literal 0 HcmV?d00001 diff --git a/packages/dart_client/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/packages/dart_client/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..d5f1c8d34e7a88e3f88bea192c3a370d44689c3c GIT binary patch literal 1031 zcmeAS@N?(olHy`uVBq!ia0vp^6F``Q8Ax83A=Cw=BuiW)N`mv#O3D+9QW+dm@{>{( zJaZG%Q-e|yQz{EjrrIztFa`(sgt!6~Yi|1%a`XoT0ojZ}lNrNjb9xjc(B0U1_% zz5^97Xt*%oq$rQy4?0GKNfJ44uvxI)gC`h-NZ|&0-7(qS@?b!5r36oQ}zyZrNO3 zMO=Or+<~>+A&uN&E!^Sl+>xE!QC-|oJv`ApDhqC^EWD|@=#J`=d#Xzxs4ah}w&Jnc z$|q_opQ^2TrnVZ0o~wh<3t%W&flvYGe#$xqda2bR_R zvPYgMcHgjZ5nSA^lJr%;<&0do;O^tDDh~=pIxA#coaCY>&N%M2^tq^U%3DB@ynvKo}b?yu-bFc-u0JHzced$sg7S3zqI(2 z#Km{dPr7I=pQ5>FuK#)QwK?Y`E`B?nP+}U)I#c1+FM*1kNvWG|a(TpksZQ3B@sD~b zpQ2)*V*TdwjFOtHvV|;OsiDqHi=6%)o4b!)x$)%9pGTsE z-JL={-Ffv+T87W(Xpooq<`r*VzWQcgBN$$`u}f>-ZQI1BB8ykN*=e4rIsJx9>z}*o zo~|9I;xof literal 0 HcmV?d00001 diff --git a/packages/dart_client/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/packages/dart_client/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..4d6372eebdb28e45604e46eeda8dd24651419bc0 GIT binary patch literal 1443 zcmb`G{WsKk6vsdJTdFg%tJav9_E4vzrOaqkWF|A724Nly!y+?N9`YV6wZ}5(X(D_N(?!*n3`|_r0Hc?=PQw&*vnU?QTFY zB_MsH|!j$PP;I}?dppoE_gA(4uc!jV&0!l7_;&p2^pxNo>PEcNJv za5_RT$o2Mf!<+r?&EbHH6nMoTsDOa;mN(wv8RNsHpG)`^ymG-S5By8=l9iVXzN_eG%Xg2@Xeq76tTZ*dGh~Lo9vl;Zfs+W#BydUw zCkZ$o1LqWQO$FC9aKlLl*7x9^0q%0}$OMlp@Kk_jHXOjofdePND+j!A{q!8~Jn+s3 z?~~w@4?egS02}8NuulUA=L~QQfm;MzCGd)XhiftT;+zFO&JVyp2mBww?;QByS_1w! zrQlx%{^cMj0|Bo1FjwY@Q8?Hx0cIPF*@-ZRFpPc#bBw{5@tD(5%sClzIfl8WU~V#u zm5Q;_F!wa$BSpqhN>W@2De?TKWR*!ujY;Yylk_X5#~V!L*Gw~;$%4Q8~Mad z@`-kG?yb$a9cHIApZDVZ^U6Xkp<*4rU82O7%}0jjHlK{id@?-wpN*fCHXyXh(bLt* zPc}H-x0e4E&nQ>y%B-(EL=9}RyC%MyX=upHuFhAk&MLbsF0LP-q`XnH78@fT+pKPW zu72MW`|?8ht^tz$iC}ZwLp4tB;Q49K!QCF3@!iB1qOI=?w z7In!}F~ij(18UYUjnbmC!qKhPo%24?8U1x{7o(+?^Zu0Hx81|FuS?bJ0jgBhEMzf< zCgUq7r2OCB(`XkKcN-TL>u5y#dD6D!)5W?`O5)V^>jb)P)GBdy%t$uUMpf$SNV31$ zb||OojAbvMP?T@$h_ZiFLFVHDmbyMhJF|-_)HX3%m=CDI+ID$0^C>kzxprBW)hw(v zr!Gmda);ICoQyhV_oP5+C%?jcG8v+D@9f?Dk*!BxY}dazmrT@64UrP3hlslANK)bq z$67n83eh}OeW&SV@HG95P|bjfqJ7gw$e+`Hxo!4cx`jdK1bJ>YDSpGKLPZ^1cv$ek zIB?0S<#tX?SJCLWdMd{-ME?$hc7A$zBOdIJ)4!KcAwb=VMov)nK;9z>x~rfT1>dS+ zZ6#`2v@`jgbqq)P22H)Tx2CpmM^o1$B+xT6`(v%5xJ(?j#>Q$+rx_R|7TzDZe{J6q zG1*EcU%tE?!kO%^M;3aM6JN*LAKUVb^xz8-Pxo#jR5(-KBeLJvA@-gxNHx0M-ZJLl z;#JwQoh~9V?`UVo#}{6ka@II>++D@%KqGpMdlQ}?9E*wFcf5(#XQnP$Dk5~%iX^>f z%$y;?M0BLp{O3a(-4A?ewryHrrD%cx#Q^%KY1H zNre$ve+vceSLZcNY4U(RBX&)oZn*Py()h)XkE?PL$!bNb{N5FVI2Y%LKEm%yvpyTP z(1P?z~7YxD~Rf<(a@_y` literal 0 HcmV?d00001 diff --git a/packages/dart_client/example/android/app/src/main/res/values-night/styles.xml b/packages/dart_client/example/android/app/src/main/res/values-night/styles.xml new file mode 100644 index 00000000..449a9f93 --- /dev/null +++ b/packages/dart_client/example/android/app/src/main/res/values-night/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/packages/dart_client/example/android/app/src/main/res/values/styles.xml b/packages/dart_client/example/android/app/src/main/res/values/styles.xml new file mode 100644 index 00000000..d74aa35c --- /dev/null +++ b/packages/dart_client/example/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/packages/dart_client/example/android/app/src/profile/AndroidManifest.xml b/packages/dart_client/example/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 00000000..f590dd7e --- /dev/null +++ b/packages/dart_client/example/android/app/src/profile/AndroidManifest.xml @@ -0,0 +1,7 @@ + + + + diff --git a/packages/dart_client/example/android/build.gradle b/packages/dart_client/example/android/build.gradle new file mode 100644 index 00000000..c505a863 --- /dev/null +++ b/packages/dart_client/example/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:4.1.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/packages/dart_client/example/android/gradle.properties b/packages/dart_client/example/android/gradle.properties new file mode 100644 index 00000000..94adc3a3 --- /dev/null +++ b/packages/dart_client/example/android/gradle.properties @@ -0,0 +1,3 @@ +org.gradle.jvmargs=-Xmx1536M +android.useAndroidX=true +android.enableJetifier=true diff --git a/packages/dart_client/example/android/gradle/wrapper/gradle-wrapper.properties b/packages/dart_client/example/android/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 00000000..bc6a58af --- /dev/null +++ b/packages/dart_client/example/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-6.7-all.zip diff --git a/packages/dart_client/example/android/settings.gradle b/packages/dart_client/example/android/settings.gradle new file mode 100644 index 00000000..44e62bcf --- /dev/null +++ b/packages/dart_client/example/android/settings.gradle @@ -0,0 +1,11 @@ +include ':app' + +def localPropertiesFile = new File(rootProject.projectDir, "local.properties") +def properties = new Properties() + +assert localPropertiesFile.exists() +localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) } + +def flutterSdkPath = properties.getProperty("flutter.sdk") +assert flutterSdkPath != null, "flutter.sdk not set in local.properties" +apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle" diff --git a/packages/dart_client/example/ios/.gitignore b/packages/dart_client/example/ios/.gitignore new file mode 100644 index 00000000..e96ef602 --- /dev/null +++ b/packages/dart_client/example/ios/.gitignore @@ -0,0 +1,32 @@ +*.mode1v3 +*.mode2v3 +*.moved-aside +*.pbxuser +*.perspectivev3 +**/*sync/ +.sconsign.dblite +.tags* +**/.vagrant/ +**/DerivedData/ +Icon? +**/Pods/ +**/.symlinks/ +profile +xcuserdata +**/.generated/ +Flutter/App.framework +Flutter/Flutter.framework +Flutter/Flutter.podspec +Flutter/Generated.xcconfig +Flutter/app.flx +Flutter/app.zip +Flutter/flutter_assets/ +Flutter/flutter_export_environment.sh +ServiceDefinitions.json +Runner/GeneratedPluginRegistrant.* + +# Exceptions to above rules. +!default.mode1v3 +!default.mode2v3 +!default.pbxuser +!default.perspectivev3 diff --git a/packages/dart_client/example/ios/Flutter/AppFrameworkInfo.plist b/packages/dart_client/example/ios/Flutter/AppFrameworkInfo.plist new file mode 100644 index 00000000..9367d483 --- /dev/null +++ b/packages/dart_client/example/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 8.0 + + diff --git a/packages/dart_client/example/ios/Flutter/Debug.xcconfig b/packages/dart_client/example/ios/Flutter/Debug.xcconfig new file mode 100644 index 00000000..e8efba11 --- /dev/null +++ b/packages/dart_client/example/ios/Flutter/Debug.xcconfig @@ -0,0 +1,2 @@ +#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" +#include "Generated.xcconfig" diff --git a/packages/dart_client/example/ios/Flutter/Release.xcconfig b/packages/dart_client/example/ios/Flutter/Release.xcconfig new file mode 100644 index 00000000..399e9340 --- /dev/null +++ b/packages/dart_client/example/ios/Flutter/Release.xcconfig @@ -0,0 +1,2 @@ +#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" +#include "Generated.xcconfig" diff --git a/packages/dart_client/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/packages/dart_client/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 00000000..1d526a16 --- /dev/null +++ b/packages/dart_client/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/packages/dart_client/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/packages/dart_client/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 00000000..18d98100 --- /dev/null +++ b/packages/dart_client/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/packages/dart_client/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/packages/dart_client/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 00000000..f9b0d7c5 --- /dev/null +++ b/packages/dart_client/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + PreviewsEnabled + + + diff --git a/packages/dart_client/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/packages/dart_client/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme new file mode 100644 index 00000000..a28140cf --- /dev/null +++ b/packages/dart_client/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/dart_client/example/ios/Runner.xcworkspace/contents.xcworkspacedata b/packages/dart_client/example/ios/Runner.xcworkspace/contents.xcworkspacedata new file mode 100644 index 00000000..21a3cc14 --- /dev/null +++ b/packages/dart_client/example/ios/Runner.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,10 @@ + + + + + + + diff --git a/packages/dart_client/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/packages/dart_client/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 00000000..18d98100 --- /dev/null +++ b/packages/dart_client/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/packages/dart_client/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/packages/dart_client/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 00000000..f9b0d7c5 --- /dev/null +++ b/packages/dart_client/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + PreviewsEnabled + + + diff --git a/packages/dart_client/example/ios/Runner/AppDelegate.swift b/packages/dart_client/example/ios/Runner/AppDelegate.swift new file mode 100644 index 00000000..70693e4a --- /dev/null +++ b/packages/dart_client/example/ios/Runner/AppDelegate.swift @@ -0,0 +1,13 @@ +import UIKit +import Flutter + +@UIApplicationMain +@objc class AppDelegate: FlutterAppDelegate { + override func application( + _ application: UIApplication, + didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? + ) -> Bool { + GeneratedPluginRegistrant.register(with: self) + return super.application(application, didFinishLaunchingWithOptions: launchOptions) + } +} diff --git a/packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 00000000..d36b1fab --- /dev/null +++ b/packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,122 @@ +{ + "images" : [ + { + "size" : "20x20", + "idiom" : "iphone", + "filename" : "Icon-App-20x20@2x.png", + "scale" : "2x" + }, + { + "size" : "20x20", + "idiom" : "iphone", + "filename" : "Icon-App-20x20@3x.png", + "scale" : "3x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@1x.png", + "scale" : "1x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@2x.png", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@3x.png", + "scale" : "3x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "Icon-App-40x40@2x.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "Icon-App-40x40@3x.png", + "scale" : "3x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "Icon-App-60x60@2x.png", + "scale" : "2x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "Icon-App-60x60@3x.png", + "scale" : "3x" + }, + { + "size" : "20x20", + "idiom" : "ipad", + "filename" : "Icon-App-20x20@1x.png", + "scale" : "1x" + }, + { + "size" : "20x20", + "idiom" : "ipad", + "filename" : "Icon-App-20x20@2x.png", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "Icon-App-29x29@1x.png", + "scale" : "1x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "Icon-App-29x29@2x.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "Icon-App-40x40@1x.png", + "scale" : "1x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "Icon-App-40x40@2x.png", + "scale" : "2x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "Icon-App-76x76@1x.png", + "scale" : "1x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "Icon-App-76x76@2x.png", + "scale" : "2x" + }, + { + "size" : "83.5x83.5", + "idiom" : "ipad", + "filename" : "Icon-App-83.5x83.5@2x.png", + "scale" : "2x" + }, + { + "size" : "1024x1024", + "idiom" : "ios-marketing", + "filename" : "Icon-App-1024x1024@1x.png", + "scale" : "1x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png b/packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png new file mode 100644 index 0000000000000000000000000000000000000000..dc9ada4725e9b0ddb1deab583e5b5102493aa332 GIT binary patch literal 10932 zcmeHN2~<R zh`|8`A_PQ1nSu(UMFx?8j8PC!!VDphaL#`F42fd#7Vlc`zIE4n%Y~eiz4y1j|NDpi z?<@|pSJ-HM`qifhf@m%MamgwK83`XpBA<+azdF#2QsT{X@z0A9Bq>~TVErigKH1~P zRX-!h-f0NJ4Mh++{D}J+K>~~rq}d%o%+4dogzXp7RxX4C>Km5XEI|PAFDmo;DFm6G zzjVoB`@qW98Yl0Kvc-9w09^PrsobmG*Eju^=3f?0o-t$U)TL1B3;sZ^!++3&bGZ!o-*6w?;oOhf z=A+Qb$scV5!RbG+&2S}BQ6YH!FKb0``VVX~T$dzzeSZ$&9=X$3)_7Z{SspSYJ!lGE z7yig_41zpQ)%5dr4ff0rh$@ky3-JLRk&DK)NEIHecf9c*?Z1bUB4%pZjQ7hD!A0r-@NF(^WKdr(LXj|=UE7?gBYGgGQV zidf2`ZT@pzXf7}!NH4q(0IMcxsUGDih(0{kRSez&z?CFA0RVXsVFw3^u=^KMtt95q z43q$b*6#uQDLoiCAF_{RFc{!H^moH_cmll#Fc^KXi{9GDl{>%+3qyfOE5;Zq|6#Hb zp^#1G+z^AXfRKaa9HK;%b3Ux~U@q?xg<2DXP%6k!3E)PA<#4$ui8eDy5|9hA5&{?v z(-;*1%(1~-NTQ`Is1_MGdQ{+i*ccd96ab$R$T3=% zw_KuNF@vI!A>>Y_2pl9L{9h1-C6H8<)J4gKI6{WzGBi<@u3P6hNsXG=bRq5c+z;Gc3VUCe;LIIFDmQAGy+=mRyF++u=drBWV8-^>0yE9N&*05XHZpPlE zxu@?8(ZNy7rm?|<+UNe0Vs6&o?l`Pt>P&WaL~M&#Eh%`rg@Mbb)J&@DA-wheQ>hRV z<(XhigZAT z>=M;URcdCaiO3d^?H<^EiEMDV+7HsTiOhoaMX%P65E<(5xMPJKxf!0u>U~uVqnPN7T!X!o@_gs3Ct1 zlZ_$5QXP4{Aj645wG_SNT&6m|O6~Tsl$q?nK*)(`{J4b=(yb^nOATtF1_aS978$x3 zx>Q@s4i3~IT*+l{@dx~Hst21fR*+5}S1@cf>&8*uLw-0^zK(+OpW?cS-YG1QBZ5q! zgTAgivzoF#`cSz&HL>Ti!!v#?36I1*l^mkrx7Y|K6L#n!-~5=d3;K<;Zqi|gpNUn_ z_^GaQDEQ*jfzh;`j&KXb66fWEk1K7vxQIMQ_#Wu_%3 z4Oeb7FJ`8I>Px;^S?)}2+4D_83gHEq>8qSQY0PVP?o)zAv3K~;R$fnwTmI-=ZLK`= zTm+0h*e+Yfr(IlH3i7gUclNH^!MU>id$Jw>O?2i0Cila#v|twub21@e{S2v}8Z13( zNDrTXZVgris|qYm<0NU(tAPouG!QF4ZNpZPkX~{tVf8xY690JqY1NVdiTtW+NqyRP zZ&;T0ikb8V{wxmFhlLTQ&?OP7 z;(z*<+?J2~z*6asSe7h`$8~Se(@t(#%?BGLVs$p``;CyvcT?7Y!{tIPva$LxCQ&4W z6v#F*);|RXvI%qnoOY&i4S*EL&h%hP3O zLsrFZhv&Hu5tF$Lx!8(hs&?!Kx5&L(fdu}UI5d*wn~A`nPUhG&Rv z2#ixiJdhSF-K2tpVL=)5UkXRuPAFrEW}7mW=uAmtVQ&pGE-&az6@#-(Te^n*lrH^m@X-ftVcwO_#7{WI)5v(?>uC9GG{lcGXYJ~Q8q zbMFl7;t+kV;|;KkBW2!P_o%Czhw&Q(nXlxK9ak&6r5t_KH8#1Mr-*0}2h8R9XNkr zto5-b7P_auqTJb(TJlmJ9xreA=6d=d)CVbYP-r4$hDn5|TIhB>SReMfh&OVLkMk-T zYf%$taLF0OqYF?V{+6Xkn>iX@TuqQ?&cN6UjC9YF&%q{Ut3zv{U2)~$>-3;Dp)*(? zg*$mu8^i=-e#acaj*T$pNowo{xiGEk$%DusaQiS!KjJH96XZ-hXv+jk%ard#fu=@Q z$AM)YWvE^{%tDfK%nD49=PI|wYu}lYVbB#a7wtN^Nml@CE@{Gv7+jo{_V?I*jkdLD zJE|jfdrmVbkfS>rN*+`#l%ZUi5_bMS<>=MBDNlpiSb_tAF|Zy`K7kcp@|d?yaTmB^ zo?(vg;B$vxS|SszusORgDg-*Uitzdi{dUV+glA~R8V(?`3GZIl^egW{a919!j#>f` znL1o_^-b`}xnU0+~KIFLQ)$Q6#ym%)(GYC`^XM*{g zv3AM5$+TtDRs%`2TyR^$(hqE7Y1b&`Jd6dS6B#hDVbJlUXcG3y*439D8MrK!2D~6gn>UD4Imctb z+IvAt0iaW73Iq$K?4}H`7wq6YkTMm`tcktXgK0lKPmh=>h+l}Y+pDtvHnG>uqBA)l zAH6BV4F}v$(o$8Gfo*PB>IuaY1*^*`OTx4|hM8jZ?B6HY;F6p4{`OcZZ(us-RVwDx zUzJrCQlp@mz1ZFiSZ*$yX3c_#h9J;yBE$2g%xjmGF4ca z&yL`nGVs!Zxsh^j6i%$a*I3ZD2SoNT`{D%mU=LKaEwbN(_J5%i-6Va?@*>=3(dQy` zOv%$_9lcy9+(t>qohkuU4r_P=R^6ME+wFu&LA9tw9RA?azGhjrVJKy&8=*qZT5Dr8g--d+S8zAyJ$1HlW3Olryt`yE zFIph~Z6oF&o64rw{>lgZISC6p^CBer9C5G6yq%?8tC+)7*d+ib^?fU!JRFxynRLEZ zj;?PwtS}Ao#9whV@KEmwQgM0TVP{hs>dg(1*DiMUOKHdQGIqa0`yZnHk9mtbPfoLx zo;^V6pKUJ!5#n`w2D&381#5#_t}AlTGEgDz$^;u;-vxDN?^#5!zN9ngytY@oTv!nc zp1Xn8uR$1Z;7vY`-<*?DfPHB;x|GUi_fI9@I9SVRv1)qETbNU_8{5U|(>Du84qP#7 z*l9Y$SgA&wGbj>R1YeT9vYjZuC@|{rajTL0f%N@>3$DFU=`lSPl=Iv;EjuGjBa$Gw zHD-;%YOE@<-!7-Mn`0WuO3oWuL6tB2cpPw~Nvuj|KM@))ixuDK`9;jGMe2d)7gHin zS<>k@!x;!TJEc#HdL#RF(`|4W+H88d4V%zlh(7#{q2d0OQX9*FW^`^_<3r$kabWAB z$9BONo5}*(%kx zOXi-yM_cmB3>inPpI~)duvZykJ@^^aWzQ=eQ&STUa}2uT@lV&WoRzkUoE`rR0)`=l zFT%f|LA9fCw>`enm$p7W^E@U7RNBtsh{_-7vVz3DtB*y#*~(L9+x9*wn8VjWw|Q~q zKFsj1Yl>;}%MG3=PY`$g$_mnyhuV&~O~u~)968$0b2!Jkd;2MtAP#ZDYw9hmK_+M$ zb3pxyYC&|CuAbtiG8HZjj?MZJBFbt`ryf+c1dXFuC z0*ZQhBzNBd*}s6K_G}(|Z_9NDV162#y%WSNe|FTDDhx)K!c(mMJh@h87@8(^YdK$&d*^WQe8Z53 z(|@MRJ$Lk-&ii74MPIs80WsOFZ(NX23oR-?As+*aq6b?~62@fSVmM-_*cb1RzZ)`5$agEiL`-E9s7{GM2?(KNPgK1(+c*|-FKoy}X(D_b#etO|YR z(BGZ)0Ntfv-7R4GHoXp?l5g#*={S1{u-QzxCGng*oWr~@X-5f~RA14b8~B+pLKvr4 zfgL|7I>jlak9>D4=(i(cqYf7#318!OSR=^`xxvI!bBlS??`xxWeg?+|>MxaIdH1U~#1tHu zB{QMR?EGRmQ_l4p6YXJ{o(hh-7Tdm>TAX380TZZZyVkqHNzjUn*_|cb?T? zt;d2s-?B#Mc>T-gvBmQZx(y_cfkXZO~{N zT6rP7SD6g~n9QJ)8F*8uHxTLCAZ{l1Y&?6v)BOJZ)=R-pY=Y=&1}jE7fQ>USS}xP#exo57uND0i*rEk@$;nLvRB@u~s^dwRf?G?_enN@$t* zbL%JO=rV(3Ju8#GqUpeE3l_Wu1lN9Y{D4uaUe`g>zlj$1ER$6S6@{m1!~V|bYkhZA z%CvrDRTkHuajMU8;&RZ&itnC~iYLW4DVkP<$}>#&(`UO>!n)Po;Mt(SY8Yb`AS9lt znbX^i?Oe9r_o=?})IHKHoQGKXsps_SE{hwrg?6dMI|^+$CeC&z@*LuF+P`7LfZ*yr+KN8B4{Nzv<`A(wyR@!|gw{zB6Ha ziwPAYh)oJ(nlqSknu(8g9N&1hu0$vFK$W#mp%>X~AU1ay+EKWcFdif{% z#4!4aoVVJ;ULmkQf!ke2}3hqxLK>eq|-d7Ly7-J9zMpT`?dxo6HdfJA|t)?qPEVBDv z{y_b?4^|YA4%WW0VZd8C(ZgQzRI5(I^)=Ub`Y#MHc@nv0w-DaJAqsbEHDWG8Ia6ju zo-iyr*sq((gEwCC&^TYBWt4_@|81?=B-?#P6NMff(*^re zYqvDuO`K@`mjm_Jd;mW_tP`3$cS?R$jR1ZN09$YO%_iBqh5ftzSpMQQtxKFU=FYmP zeY^jph+g<4>YO;U^O>-NFLn~-RqlHvnZl2yd2A{Yc1G@Ga$d+Q&(f^tnPf+Z7serIU};17+2DU_f4Z z@GaPFut27d?!YiD+QP@)T=77cR9~MK@bd~pY%X(h%L={{OIb8IQmf-!xmZkm8A0Ga zQSWONI17_ru5wpHg3jI@i9D+_Y|pCqVuHJNdHUauTD=R$JcD2K_liQisqG$(sm=k9;L* z!L?*4B~ql7uioSX$zWJ?;q-SWXRFhz2Jt4%fOHA=Bwf|RzhwqdXGr78y$J)LR7&3T zE1WWz*>GPWKZ0%|@%6=fyx)5rzUpI;bCj>3RKzNG_1w$fIFCZ&UR0(7S?g}`&Pg$M zf`SLsz8wK82Vyj7;RyKmY{a8G{2BHG%w!^T|Njr!h9TO2LaP^_f22Q1=l$QiU84ao zHe_#{S6;qrC6w~7{y(hs-?-j?lbOfgH^E=XcSgnwW*eEz{_Z<_Px$?ny*JR5%f>l)FnDQ543{x%ZCiu33$Wg!pQFfT_}?5Q|_VSlIbLC`dpoMXL}9 zHfd9&47Mo(7D231gb+kjFxZHS4-m~7WurTH&doVX2KI5sU4v(sJ1@T9eCIKPjsqSr z)C01LsCxk=72-vXmX}CQD#BD;Cthymh&~=f$Q8nn0J<}ZrusBy4PvRNE}+1ceuj8u z0mW5k8fmgeLnTbWHGwfKA3@PdZxhn|PypR&^p?weGftrtCbjF#+zk_5BJh7;0`#Wr zgDpM_;Ax{jO##IrT`Oz;MvfwGfV$zD#c2xckpcXC6oou4ML~ezCc2EtnsQTB4tWNg z?4bkf;hG7IMfhgNI(FV5Gs4|*GyMTIY0$B=_*mso9Ityq$m^S>15>-?0(zQ<8Qy<_TjHE33(?_M8oaM zyc;NxzRVK@DL6RJnX%U^xW0Gpg(lXp(!uK1v0YgHjs^ZXSQ|m#lV7ip7{`C_J2TxPmfw%h$|%acrYHt)Re^PB%O&&=~a zhS(%I#+V>J-vjIib^<+s%ludY7y^C(P8nmqn9fp!i+?vr`bziDE=bx`%2W#Xyrj|i z!XQ4v1%L`m{7KT7q+LZNB^h8Ha2e=`Wp65^0;J00)_^G=au=8Yo;1b`CV&@#=jIBo zjN^JNVfYSs)+kDdGe7`1&8!?MQYKS?DuHZf3iogk_%#9E|5S zWeHrmAo>P;ejX7mwq#*}W25m^ZI+{(Z8fI?4jM_fffY0nok=+88^|*_DwcW>mR#e+ zX$F_KMdb6sRz!~7KkyN0G(3XQ+;z3X%PZ4gh;n-%62U<*VUKNv(D&Q->Na@Xb&u5Q3`3DGf+a8O5x7c#7+R+EAYl@R5us)CIw z7sT@_y~Ao@uL#&^LIh&QceqiT^+lb0YbFZt_SHOtWA%mgPEKVNvVgCsXy{5+zl*X8 zCJe)Q@y>wH^>l4;h1l^Y*9%-23TSmE>q5nI@?mt%n;Sj4Qq`Z+ib)a*a^cJc%E9^J zB;4s+K@rARbcBLT5P=@r;IVnBMKvT*)ew*R;&8vu%?Z&S>s?8?)3*YawM0P4!q$Kv zMmKh3lgE~&w&v%wVzH3Oe=jeNT=n@Y6J6TdHWTjXfX~-=1A1Bw`EW8rn}MqeI34nh zexFeA?&C3B2(E?0{drE@DA2pu(A#ElY&6el60Rn|Qpn-FkfQ8M93AfWIr)drgDFEU zghdWK)^71EWCP(@(=c4kfH1Y(4iugD4fve6;nSUpLT%!)MUHs1!zJYy4y||C+SwQ! z)KM&$7_tyM`sljP2fz6&Z;jxRn{Wup8IOUx8D4uh&(=O zx-7$a;U><*5L^!%xRlw)vAbh;sdlR||& ze}8_8%)c2Fwy=F&H|LM+p{pZB5DKTx>Y?F1N%BlZkXf!}JeGuMZk~LPi7{cidvUGB zAJ4LVeNV%XO>LTrklB#^-;8nb;}6l;1oW&WS=Mz*Az!4cqqQzbOSFq`$Q%PfD7srM zpKgP-D_0XPTRX*hAqeq0TDkJ;5HB1%$3Np)99#16c{ zJImlNL(npL!W|Gr_kxl1GVmF5&^$^YherS7+~q$p zt}{a=*RiD2Ikv6o=IM1kgc7zqpaZ;OB)P!1zz*i3{U()Dq#jG)egvK}@uFLa`oyWZ zf~=MV)|yJn`M^$N%ul5);JuQvaU1r2wt(}J_Qgyy`qWQI`hEeRX0uC@c1(dQ2}=U$ tNIIaX+dr)NRWXcxoR{>fqI{SF_dm1Ylv~=3YHI)h002ovPDHLkV1g(pWS;;4 literal 0 HcmV?d00001 diff --git a/packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..f091b6b0bca859a3f474b03065bef75ba58a9e4c GIT binary patch literal 1588 zcmV-42Fv-0P)C1SqPt}wig>|5Crh^=oyX$BK<}M8eLU3e2hGT;=G|!_SP)7zNI6fqUMB=)y zRAZ>eDe#*r`yDAVgB_R*LB*MAc)8(b{g{9McCXW!lq7r(btRoB9!8B-#AI6JMb~YFBEvdsV)`mEQO^&#eRKx@b&x- z5lZm*!WfD8oCLzfHGz#u7sT0^VLMI1MqGxF^v+`4YYnVYgk*=kU?HsSz{v({E3lb9 z>+xILjBN)t6`=g~IBOelGQ(O990@BfXf(DRI5I$qN$0Gkz-FSc$3a+2fX$AedL4u{ z4V+5Ong(9LiGcIKW?_352sR;LtDPmPJXI{YtT=O8=76o9;*n%_m|xo!i>7$IrZ-{l z-x3`7M}qzHsPV@$v#>H-TpjDh2UE$9g6sysUREDy_R(a)>=eHw-WAyfIN z*qb!_hW>G)Tu8nSw9yn#3wFMiLcfc4pY0ek1}8(NqkBR@t4{~oC>ryc-h_ByH(Cg5 z>ao-}771+xE3um9lWAY1FeQFxowa1(!J(;Jg*wrg!=6FdRX+t_<%z&d&?|Bn){>zm zZQj(aA_HeBY&OC^jj*)N`8fa^ePOU72VpInJoI1?`ty#lvlNzs(&MZX+R%2xS~5Kh zX*|AU4QE#~SgPzOXe9>tRj>hjU@c1k5Y_mW*Jp3fI;)1&g3j|zDgC+}2Q_v%YfDax z!?umcN^n}KYQ|a$Lr+51Nf9dkkYFSjZZjkma$0KOj+;aQ&721~t7QUKx61J3(P4P1 zstI~7-wOACnWP4=8oGOwz%vNDqD8w&Q`qcNGGrbbf&0s9L0De{4{mRS?o0MU+nR_! zrvshUau0G^DeMhM_v{5BuLjb#Hh@r23lDAk8oF(C+P0rsBpv85EP>4CVMx#04MOfG z;P%vktHcXwTj~+IE(~px)3*MY77e}p#|c>TD?sMatC0Tu4iKKJ0(X8jxQY*gYtxsC z(zYC$g|@+I+kY;dg_dE>scBf&bP1Nc@Hz<3R)V`=AGkc;8CXqdi=B4l2k|g;2%#m& z*jfX^%b!A8#bI!j9-0Fi0bOXl(-c^AB9|nQaE`*)Hw+o&jS9@7&Gov#HbD~#d{twV zXd^Tr^mWLfFh$@Dr$e;PBEz4(-2q1FF0}c;~B5sA}+Q>TOoP+t>wf)V9Iy=5ruQa;z)y zI9C9*oUga6=hxw6QasLPnee@3^Rr*M{CdaL5=R41nLs(AHk_=Y+A9$2&H(B7!_pURs&8aNw7?`&Z&xY_Ye z)~D5Bog^td-^QbUtkTirdyK^mTHAOuptDflut!#^lnKqU md>ggs(5nOWAqO?umG&QVYK#ibz}*4>0000U6E9hRK9^#O7(mu>ETqrXGsduA8$)?`v2seloOCza43C{NQ$$gAOH**MCn0Q?+L7dl7qnbRdqZ8LSVp1ItDxhxD?t@5_yHg6A8yI zC*%Wgg22K|8E#!~cTNYR~@Y9KepMPrrB8cABapAFa=`H+UGhkXUZV1GnwR1*lPyZ;*K(i~2gp|@bzp8}og7e*#% zEnr|^CWdVV!-4*Y_7rFvlww2Ze+>j*!Z!pQ?2l->4q#nqRu9`ELo6RMS5=br47g_X zRw}P9a7RRYQ%2Vsd0Me{_(EggTnuN6j=-?uFS6j^u69elMypu?t>op*wBx<=Wx8?( ztpe^(fwM6jJX7M-l*k3kEpWOl_Vk3@(_w4oc}4YF4|Rt=2V^XU?#Yz`8(e?aZ@#li0n*=g^qOcVpd-Wbok=@b#Yw zqn8u9a)z>l(1kEaPYZ6hwubN6i<8QHgsu0oE) ziJ(p;Wxm>sf!K+cw>R-(^Y2_bahB+&KI9y^);#0qt}t-$C|Bo71lHi{_+lg#f%RFy z0um=e3$K3i6K{U_4K!EX?F&rExl^W|G8Z8;`5z-k}OGNZ0#WVb$WCpQu-_YsiqKP?BB# vzVHS-CTUF4Ozn5G+mq_~Qqto~ahA+K`|lyv3(-e}00000NkvXXu0mjfd`9t{ literal 0 HcmV?d00001 diff --git a/packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..d0ef06e7edb86cdfe0d15b4b0d98334a86163658 GIT binary patch literal 1716 zcmds$`#;kQ7{|XelZftyR5~xW7?MLxS4^|Hw3&P7^y)@A9Fj{Xm1~_CIV^XZ%SLBn zA;!r`GqGHg=7>xrB{?psZQs88ZaedDoagm^KF{a*>G|dJWRSe^I$DNW008I^+;Kjt z>9p3GNR^I;v>5_`+91i(*G;u5|L+Bu6M=(afLjtkya#yZ175|z$pU~>2#^Z_pCZ7o z1c6UNcv2B3?; zX%qdxCXQpdKRz=#b*q0P%b&o)5ZrNZt7$fiETSK_VaY=mb4GK`#~0K#~9^ zcY!`#Af+4h?UMR-gMKOmpuYeN5P*RKF!(tb`)oe0j2BH1l?=>y#S5pMqkx6i{*=V9JF%>N8`ewGhRE(|WohnD59R^$_36{4>S zDFlPC5|k?;SPsDo87!B{6*7eqmMdU|QZ84>6)Kd9wNfh90=y=TFQay-0__>=<4pk& zYDjgIhL-jQ9o>z32K)BgAH+HxamL{ZL~ozu)Qqe@a`FpH=oQRA8=L-m-1dam(Ix2V z?du;LdMO+ooBelr^_y4{|44tmgH^2hSzPFd;U^!1p>6d|o)(-01z{i&Kj@)z-yfWQ)V#3Uo!_U}q3u`(fOs`_f^ueFii1xBNUB z6MecwJN$CqV&vhc+)b(p4NzGGEgwWNs z@*lUV6LaduZH)4_g!cE<2G6#+hJrWd5(|p1Z;YJ7ifVHv+n49btR}dq?HHDjl{m$T z!jLZcGkb&XS2OG~u%&R$(X+Z`CWec%QKt>NGYvd5g20)PU(dOn^7%@6kQb}C(%=vr z{?RP(z~C9DPnL{q^@pVw@|Vx~@3v!9dCaBtbh2EdtoNHm4kGxp>i#ct)7p|$QJs+U z-a3qtcPvhihub?wnJqEt>zC@)2suY?%-96cYCm$Q8R%-8$PZYsx3~QOLMDf(piXMm zB=<63yQk1AdOz#-qsEDX>>c)EES%$owHKue;?B3)8aRd}m~_)>SL3h2(9X;|+2#7X z+#2)NpD%qJvCQ0a-uzZLmz*ms+l*N}w)3LRQ*6>|Ub-fyptY(keUxw+)jfwF5K{L9 z|Cl_w=`!l_o><384d&?)$6Nh(GAm=4p_;{qVn#hI8lqewW7~wUlyBM-4Z|)cZr?Rh z=xZ&Ol>4(CU85ea(CZ^aO@2N18K>ftl8>2MqetAR53_JA>Fal`^)1Y--Am~UDa4th zKfCYpcXky$XSFDWBMIl(q=Mxj$iMBX=|j9P)^fDmF(5(5$|?Cx}DKEJa&XZP%OyE`*GvvYQ4PV&!g2|L^Q z?YG}tx;sY@GzMmsY`7r$P+F_YLz)(e}% zyakqFB<6|x9R#TdoP{R$>o7y(-`$$p0NxJ6?2B8tH)4^yF(WhqGZlM3=9Ibs$%U1w zWzcss*_c0=v_+^bfb`kBFsI`d;ElwiU%frgRB%qBjn@!0U2zZehBn|{%uNIKBA7n= zzE`nnwTP85{g;8AkYxA68>#muXa!G>xH22D1I*SiD~7C?7Za+9y7j1SHiuSkKK*^O zsZ==KO(Ua#?YUpXl{ViynyT#Hzk=}5X$e04O@fsMQjb}EMuPWFO0e&8(2N(29$@Vd zn1h8Yd>6z(*p^E{c(L0Lg=wVdupg!z@WG;E0k|4a%s7Up5C0c)55XVK*|x9RQeZ1J@1v9MX;>n34(i>=YE@Iur`0Vah(inE3VUFZNqf~tSz{1fz3Fsn_x4F>o(Yo;kpqvBe-sbwH(*Y zu$JOl0b83zu$JMvy<#oH^Wl>aWL*?aDwnS0iEAwC?DK@aT)GHRLhnz2WCvf3Ba;o=aY7 z2{Asu5MEjGOY4O#Ggz@@J;q*0`kd2n8I3BeNuMmYZf{}pg=jTdTCrIIYuW~luKecn z+E-pHY%ohj@uS0%^ z&(OxwPFPD$+#~`H?fMvi9geVLci(`K?Kj|w{rZ9JgthFHV+=6vMbK~0)Ea<&WY-NC zy-PnZft_k2tfeQ*SuC=nUj4H%SQ&Y$gbH4#2sT0cU0SdFs=*W*4hKGpuR1{)mV;Qf5pw4? zfiQgy0w3fC*w&Bj#{&=7033qFR*<*61B4f9K%CQvxEn&bsWJ{&winp;FP!KBj=(P6 z4Z_n4L7cS;ao2)ax?Tm|I1pH|uLpDSRVghkA_UtFFuZ0b2#>!8;>-_0ELjQSD-DRd z4im;599VHDZYtnWZGAB25W-e(2VrzEh|etsv2YoP#VbIZ{aFkwPrzJ#JvCvA*mXS& z`}Q^v9(W4GiSs}#s7BaN!WA2bniM$0J(#;MR>uIJ^uvgD3GS^%*ikdW6-!VFUU?JV zZc2)4cMsX@j z5HQ^e3BUzOdm}yC-xA%SY``k$rbfk z;CHqifhU*jfGM@DkYCecD9vl*qr58l6x<8URB=&%{!Cu3RO*MrKZ4VO}V6R0a zZw3Eg^0iKWM1dcTYZ0>N899=r6?+adUiBKPciJw}L$=1f4cs^bio&cr9baLF>6#BM z(F}EXe-`F=f_@`A7+Q&|QaZ??Txp_dB#lg!NH=t3$G8&06MFhwR=Iu*Im0s_b2B@| znW>X}sy~m#EW)&6E&!*0%}8UAS)wjt+A(io#wGI@Z2S+Ms1Cxl%YVE800007ip7{`C_J2TxPmfw%h$|%acrYHt)Re^PB%O&&=~a zhS(%I#+V>J-vjIib^<+s%ludY7y^C(P8nmqn9fp!i+?vr`bziDE=bx`%2W#Xyrj|i z!XQ4v1%L`m{7KT7q+LZNB^h8Ha2e=`Wp65^0;J00)_^G=au=8Yo;1b`CV&@#=jIBo zjN^JNVfYSs)+kDdGe7`1&8!?MQYKS?DuHZf3iogk_%#9E|5S zWeHrmAo>P;ejX7mwq#*}W25m^ZI+{(Z8fI?4jM_fffY0nok=+88^|*_DwcW>mR#e+ zX$F_KMdb6sRz!~7KkyN0G(3XQ+;z3X%PZ4gh;n-%62U<*VUKNv(D&Q->Na@Xb&u5Q3`3DGf+a8O5x7c#7+R+EAYl@R5us)CIw z7sT@_y~Ao@uL#&^LIh&QceqiT^+lb0YbFZt_SHOtWA%mgPEKVNvVgCsXy{5+zl*X8 zCJe)Q@y>wH^>l4;h1l^Y*9%-23TSmE>q5nI@?mt%n;Sj4Qq`Z+ib)a*a^cJc%E9^J zB;4s+K@rARbcBLT5P=@r;IVnBMKvT*)ew*R;&8vu%?Z&S>s?8?)3*YawM0P4!q$Kv zMmKh3lgE~&w&v%wVzH3Oe=jeNT=n@Y6J6TdHWTjXfX~-=1A1Bw`EW8rn}MqeI34nh zexFeA?&C3B2(E?0{drE@DA2pu(A#ElY&6el60Rn|Qpn-FkfQ8M93AfWIr)drgDFEU zghdWK)^71EWCP(@(=c4kfH1Y(4iugD4fve6;nSUpLT%!)MUHs1!zJYy4y||C+SwQ! z)KM&$7_tyM`sljP2fz6&Z;jxRn{Wup8IOUx8D4uh&(=O zx-7$a;U><*5L^!%xRlw)vAbh;sdlR||& ze}8_8%)c2Fwy=F&H|LM+p{pZB5DKTx>Y?F1N%BlZkXf!}JeGuMZk~LPi7{cidvUGB zAJ4LVeNV%XO>LTrklB#^-;8nb;}6l;1oW&WS=Mz*Az!4cqqQzbOSFq`$Q%PfD7srM zpKgP-D_0XPTRX*hAqeq0TDkJ;5HB1%$3Np)99#16c{ zJImlNL(npL!W|Gr_kxl1GVmF5&^$^YherS7+~q$p zt}{a=*RiD2Ikv6o=IM1kgc7zqpaZ;OB)P!1zz*i3{U()Dq#jG)egvK}@uFLa`oyWZ zf~=MV)|yJn`M^$N%ul5);JuQvaU1r2wt(}J_Qgyy`qWQI`hEeRX0uC@c1(dQ2}=U$ tNIIaX+dr)NRWXcxoR{>fqI{SF_dm1Ylv~=3YHI)h002ovPDHLkV1g(pWS;;4 literal 0 HcmV?d00001 diff --git a/packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..c8f9ed8f5cee1c98386d13b17e89f719e83555b2 GIT binary patch literal 1895 zcmV-t2blPYP)FQtfgmafE#=YDCq`qUBt#QpG%*H6QHY765~R=q zZ6iudfM}q!Pz#~9JgOi8QJ|DSu?1-*(kSi1K4#~5?#|rh?sS)(-JQqX*}ciXJ56_H zdw=^s_srbAdqxlvGyrgGet#6T7_|j;95sL%MtM;q86vOxKM$f#puR)Bjv9Zvz9-di zXOTSsZkM83)E9PYBXC<$6(|>lNLVBb&&6y{NByFCp%6+^ALR@NCTse_wqvNmSWI-m z!$%KlHFH2omF!>#%1l3LTZg(s7eof$7*xB)ZQ0h?ejh?Ta9fDv59+u#MokW+1t8Zb zgHv%K(u9G^Lv`lh#f3<6!JVTL3(dCpxHbnbA;kKqQyd1~^Xe0VIaYBSWm6nsr;dFj z4;G-RyL?cYgsN1{L4ZFFNa;8)Rv0fM0C(~Tkit94 zz#~A)59?QjD&pAPSEQ)p8gP|DS{ng)j=2ux)_EzzJ773GmQ_Cic%3JJhC0t2cx>|v zJcVusIB!%F90{+}8hG3QU4KNeKmK%T>mN57NnCZ^56=0?&3@!j>a>B43pi{!u z7JyDj7`6d)qVp^R=%j>UIY6f+3`+qzIc!Y_=+uN^3BYV|o+$vGo-j-Wm<10%A=(Yk^beI{t%ld@yhKjq0iNjqN4XMGgQtbKubPM$JWBz}YA65k%dm*awtC^+f;a-x4+ddbH^7iDWGg&N0n#MW{kA|=8iMUiFYvMoDY@sPC#t$55gn6ykUTPAr`a@!(;np824>2xJthS z*ZdmT`g5-`BuJs`0LVhz+D9NNa3<=6m;cQLaF?tCv8)zcRSh66*Z|vXhG@$I%U~2l z?`Q zykI#*+rQ=z6Jm=Bui-SfpDYLA=|vzGE(dYm=OC8XM&MDo7ux4UF1~0J1+i%aCUpRe zt3L_uNyQ*cE(38Uy03H%I*)*Bh=Lb^Xj3?I^Hnbeq72(EOK^Y93CNp*uAA{5Lc=ky zx=~RKa4{iTm{_>_vSCm?$Ej=i6@=m%@VvAITnigVg{&@!7CDgs908761meDK5azA} z4?=NOH|PdvabgJ&fW2{Mo$Q0CcD8Qc84%{JPYt5EiG{MdLIAeX%T=D7NIP4%Hw}p9 zg)==!2Lbp#j{u_}hMiao9=!VSyx0gHbeCS`;q&vzeq|fs`y&^X-lso(Ls@-706qmA z7u*T5PMo_w3{se1t2`zWeO^hOvTsohG_;>J0wVqVe+n)AbQCx)yh9;w+J6?NF5Lmo zecS@ieAKL8%bVd@+-KT{yI|S}O>pYckUFs;ry9Ow$CD@ztz5K-*D$^{i(_1llhSh^ zEkL$}tsQt5>QA^;QgjgIfBDmcOgi5YDyu?t6vSnbp=1+@6D& z5MJ}B8q;bRlVoxasyhcUF1+)o`&3r0colr}QJ3hcSdLu;9;td>kf@Tcn<@9sIx&=m z;AD;SCh95=&p;$r{Xz3iWCO^MX83AGJ(yH&eTXgv|0=34#-&WAmw{)U7OU9!Wz^!7 zZ%jZFi@JR;>Mhi7S>V7wQ176|FdW2m?&`qa(ScO^CFPR80HucLHOTy%5s*HR0^8)i h0WYBP*#0Ks^FNSabJA*5${_#%002ovPDHLkV1oKhTl@e3 literal 0 HcmV?d00001 diff --git a/packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..a6d6b8609df07bf62e5100a53a01510388bd2b22 GIT binary patch literal 2665 zcmV-v3YPVWP)oFh3q0MFesq&64WThn3$;G69TfjsAv=f2G9}p zgSx99+!YV6qME!>9MD13x)k(+XE7W?_O4LoLb5ND8 zaV{9+P@>42xDfRiYBMSgD$0!vssptcb;&?u9u(LLBKmkZ>RMD=kvD3h`sk6!QYtBa ztlZI#nu$8lJ^q2Z79UTgZe>BU73(Aospiq+?SdMt8lDZ;*?@tyWVZVS_Q7S&*tJaiRlJ z+aSMOmbg3@h5}v;A*c8SbqM3icg-`Cnwl;7Ts%A1RkNIp+Txl-Ckkvg4oxrqGA5ewEgYqwtECD<_3Egu)xGllKt&J8g&+=ac@Jq4-?w6M3b*>w5 z69N3O%=I^6&UL5gZ!}trC7bUj*12xLdkNs~Bz4QdJJ*UDZox2UGR}SNg@lmOvhCc~ z*f_UeXv(=#I#*7>VZx2ObEN~UoGUTl=-@)E;YtCRZ>SVp$p9yG5hEFZ!`wI!spd)n zSk+vK0Vin7FL{7f&6OB%f;SH22dtbcF<|9fi2Fp%q4kxL!b1#l^)8dUwJ zwEf{(wJj@8iYDVnKB`eSU+;ml-t2`@%_)0jDM`+a46xhDbBj2+&Ih>1A>6aky#(-SYyE{R3f#y57wfLs z6w1p~$bp;6!9DX$M+J~S@D6vJAaElETnsX4h9a5tvPhC3L@qB~bOzkL@^z0k_hS{T4PF*TDrgdXp+dzsE? z>V|VR035Pl9n5&-RePFdS{7KAr2vPOqR9=M$vXA1Yy5>w;EsF`;OK{2pkn-kpp9Pw z)r;5JfJKKaT$4qCb{TaXHjb$QA{y0EYy*+b1XI;6Ah- zw13P)xT`>~eFoJC!>{2XL(a_#upp3gaR1#5+L(Jmzp4TBnx{~WHedpJ1ch8JFk~Sw z>F+gN+i+VD?gMXwcIhn8rz`>e>J^TI3E-MW>f}6R-pL}>WMOa0k#jN+`RyUVUC;#D zg|~oS^$6%wpF{^Qr+}X>0PKcr3Fc&>Z>uv@C);pwDs@2bZWhYP!rvGx?_|q{d`t<*XEb#=aOb=N+L@CVBGqImZf&+a zCQEa3$~@#kC);pasdG=f6tuIi0PO-y&tvX%>Mv=oY3U$nD zJ#gMegnQ46pq+3r=;zmgcG+zRc9D~c>z+jo9&D+`E6$LmyFqlmCYw;-Zooma{sR@~ z)_^|YL1&&@|GXo*pivH7k!msl+$Sew3%XJnxajt0K%3M6Bd&YFNy9}tWG^aovK2eX z1aL1%7;KRDrA@eG-Wr6w+;*H_VD~qLiVI`{_;>o)k`{8xa3EJT1O_>#iy_?va0eR? zDV=N%;Zjb%Z2s$@O>w@iqt!I}tLjGk!=p`D23I}N4Be@$(|iSA zf3Ih7b<{zqpDB4WF_5X1(peKe+rASze%u8eKLn#KKXt;UZ+Adf$_TO+vTqshLLJ5c z52HucO=lrNVae5XWOLm!V@n-ObU11!b+DN<$RuU+YsrBq*lYT;?AwJpmNKniF0Q1< zJCo>Q$=v$@&y=sj6{r!Y&y&`0$-I}S!H_~pI&2H8Z1C|BX4VgZ^-! zje3-;x0PBD!M`v*J_)rL^+$<1VJhH*2Fi~aA7s&@_rUHYJ9zD=M%4AFQ`}k8OC$9s XsPq=LnkwKG00000NkvXXu0mjfhAk5^ literal 0 HcmV?d00001 diff --git a/packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..a6d6b8609df07bf62e5100a53a01510388bd2b22 GIT binary patch literal 2665 zcmV-v3YPVWP)oFh3q0MFesq&64WThn3$;G69TfjsAv=f2G9}p zgSx99+!YV6qME!>9MD13x)k(+XE7W?_O4LoLb5ND8 zaV{9+P@>42xDfRiYBMSgD$0!vssptcb;&?u9u(LLBKmkZ>RMD=kvD3h`sk6!QYtBa ztlZI#nu$8lJ^q2Z79UTgZe>BU73(Aospiq+?SdMt8lDZ;*?@tyWVZVS_Q7S&*tJaiRlJ z+aSMOmbg3@h5}v;A*c8SbqM3icg-`Cnwl;7Ts%A1RkNIp+Txl-Ckkvg4oxrqGA5ewEgYqwtECD<_3Egu)xGllKt&J8g&+=ac@Jq4-?w6M3b*>w5 z69N3O%=I^6&UL5gZ!}trC7bUj*12xLdkNs~Bz4QdJJ*UDZox2UGR}SNg@lmOvhCc~ z*f_UeXv(=#I#*7>VZx2ObEN~UoGUTl=-@)E;YtCRZ>SVp$p9yG5hEFZ!`wI!spd)n zSk+vK0Vin7FL{7f&6OB%f;SH22dtbcF<|9fi2Fp%q4kxL!b1#l^)8dUwJ zwEf{(wJj@8iYDVnKB`eSU+;ml-t2`@%_)0jDM`+a46xhDbBj2+&Ih>1A>6aky#(-SYyE{R3f#y57wfLs z6w1p~$bp;6!9DX$M+J~S@D6vJAaElETnsX4h9a5tvPhC3L@qB~bOzkL@^z0k_hS{T4PF*TDrgdXp+dzsE? z>V|VR035Pl9n5&-RePFdS{7KAr2vPOqR9=M$vXA1Yy5>w;EsF`;OK{2pkn-kpp9Pw z)r;5JfJKKaT$4qCb{TaXHjb$QA{y0EYy*+b1XI;6Ah- zw13P)xT`>~eFoJC!>{2XL(a_#upp3gaR1#5+L(Jmzp4TBnx{~WHedpJ1ch8JFk~Sw z>F+gN+i+VD?gMXwcIhn8rz`>e>J^TI3E-MW>f}6R-pL}>WMOa0k#jN+`RyUVUC;#D zg|~oS^$6%wpF{^Qr+}X>0PKcr3Fc&>Z>uv@C);pwDs@2bZWhYP!rvGx?_|q{d`t<*XEb#=aOb=N+L@CVBGqImZf&+a zCQEa3$~@#kC);pasdG=f6tuIi0PO-y&tvX%>Mv=oY3U$nD zJ#gMegnQ46pq+3r=;zmgcG+zRc9D~c>z+jo9&D+`E6$LmyFqlmCYw;-Zooma{sR@~ z)_^|YL1&&@|GXo*pivH7k!msl+$Sew3%XJnxajt0K%3M6Bd&YFNy9}tWG^aovK2eX z1aL1%7;KRDrA@eG-Wr6w+;*H_VD~qLiVI`{_;>o)k`{8xa3EJT1O_>#iy_?va0eR? zDV=N%;Zjb%Z2s$@O>w@iqt!I}tLjGk!=p`D23I}N4Be@$(|iSA zf3Ih7b<{zqpDB4WF_5X1(peKe+rASze%u8eKLn#KKXt;UZ+Adf$_TO+vTqshLLJ5c z52HucO=lrNVae5XWOLm!V@n-ObU11!b+DN<$RuU+YsrBq*lYT;?AwJpmNKniF0Q1< zJCo>Q$=v$@&y=sj6{r!Y&y&`0$-I}S!H_~pI&2H8Z1C|BX4VgZ^-! zje3-;x0PBD!M`v*J_)rL^+$<1VJhH*2Fi~aA7s&@_rUHYJ9zD=M%4AFQ`}k8OC$9s XsPq=LnkwKG00000NkvXXu0mjfhAk5^ literal 0 HcmV?d00001 diff --git a/packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..75b2d164a5a98e212cca15ea7bf2ab5de5108680 GIT binary patch literal 3831 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 literal 0 HcmV?d00001 diff --git a/packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png new file mode 100644 index 0000000000000000000000000000000000000000..c4df70d39da7941ef3f6dcb7f06a192d8dcb308d GIT binary patch literal 1888 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 iW8Zci7-kcv6Uzs@r-FtIZ-&5|)J Q1PU{Fy85}Sb4q9e0B4a5jsO4v literal 0 HcmV?d00001 diff --git a/packages/dart_client/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png b/packages/dart_client/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..9da19eacad3b03bb08bbddbbf4ac48dd78b3d838 GIT binary patch literal 68 zcmeAS@N?(olHy`uVBq!ia0vp^j3CUx0wlM}@Gt=>Zci7-kcv6Uzs@r-FtIZ-&5|)J Q1PU{Fy85}Sb4q9e0B4a5jsO4v literal 0 HcmV?d00001 diff --git a/packages/dart_client/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png b/packages/dart_client/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..9da19eacad3b03bb08bbddbbf4ac48dd78b3d838 GIT binary patch literal 68 zcmeAS@N?(olHy`uVBq!ia0vp^j3CUx0wlM}@Gt=>Zci7-kcv6Uzs@r-FtIZ-&5|)J Q1PU{Fy85}Sb4q9e0B4a5jsO4v literal 0 HcmV?d00001 diff --git a/packages/dart_client/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md b/packages/dart_client/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md new file mode 100644 index 00000000..89c2725b --- /dev/null +++ b/packages/dart_client/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md @@ -0,0 +1,5 @@ +# Launch Screen Assets + +You can customize the launch screen with your own desired assets by replacing the image files in this directory. + +You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images. \ No newline at end of file diff --git a/packages/dart_client/example/ios/Runner/Base.lproj/LaunchScreen.storyboard b/packages/dart_client/example/ios/Runner/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 00000000..f2e259c7 --- /dev/null +++ b/packages/dart_client/example/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/dart_client/example/ios/Runner/Base.lproj/Main.storyboard b/packages/dart_client/example/ios/Runner/Base.lproj/Main.storyboard new file mode 100644 index 00000000..f3c28516 --- /dev/null +++ b/packages/dart_client/example/ios/Runner/Base.lproj/Main.storyboard @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/dart_client/example/ios/Runner/Info.plist b/packages/dart_client/example/ios/Runner/Info.plist new file mode 100644 index 00000000..816fd9f3 --- /dev/null +++ b/packages/dart_client/example/ios/Runner/Info.plist @@ -0,0 +1,45 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + stream_chat_dart_example + CFBundlePackageType + APPL + CFBundleShortVersionString + $(FLUTTER_BUILD_NAME) + CFBundleSignature + ???? + CFBundleVersion + $(FLUTTER_BUILD_NUMBER) + LSRequiresIPhoneOS + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UIViewControllerBasedStatusBarAppearance + + + diff --git a/packages/dart_client/example/ios/Runner/Runner-Bridging-Header.h b/packages/dart_client/example/ios/Runner/Runner-Bridging-Header.h new file mode 100644 index 00000000..308a2a56 --- /dev/null +++ b/packages/dart_client/example/ios/Runner/Runner-Bridging-Header.h @@ -0,0 +1 @@ +#import "GeneratedPluginRegistrant.h" diff --git a/packages/dart_client/example/lib/main.dart b/packages/dart_client/example/lib/main.dart new file mode 100644 index 00000000..eb413af6 --- /dev/null +++ b/packages/dart_client/example/lib/main.dart @@ -0,0 +1,248 @@ +import 'package:flutter/material.dart'; +import 'package:stream_chat/stream_chat.dart'; + +Future main() async { + /// Create a new instance of [Client] passing the apikey obtained from your + /// project dashboard. + final client = Client('b67pax5b2wdq'); + + /// Set the current user. In a production scenario, this should be done using + /// a backend to generate a user token using our server SDK. + /// Please see the following for more information: + /// https://getstream.io/chat/docs/ios_user_setup_and_tokens/ + await client.setUser( + User( + id: 'cool-shadow-7', + extraData: { + 'image': + 'https://getstream.io/random_png/?id=cool-shadow-7&name=Cool+shadow', + }, + ), + 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoiY29vbC1zaGFkb3ctNyJ9.gkOlCRb1qgy4joHPaxFwPOdXcGvSPvp6QY0S4mpRkVo', + ); + + /// Creates a channel using the type `messaging` and `godevs`. + /// Channels are containers for holding messages between different members. To + /// learn more about channels and some of our predefined types, checkout our + /// our channel docs: https://getstream.io/chat/docs/initialize_channel/?language=dart + final channel = client.channel('messaging', id: 'godevs'); + + /// `.watch()` is used to create and listen to the channel for updates. If the + /// channel already exists, it will simply listen for new events. + await channel.watch(); + + runApp( + StreamExample( + client: client, + channel: channel, + ), + ); +} + +/// Example using Stream's Low Level Dart client. +class StreamExample extends StatelessWidget { + /// To initialize this example, an instance of [client] and [channel] is required. + const StreamExample({ + Key key, + @required this.client, + @required this.channel, + }) : super(key: key); + + /// Instance of [Client] we created earlier. This contains information about + /// our application and connection state. + final Client client; + + /// The channel we'd like to observe and participate. + final Channel channel; + + @override + Widget build(BuildContext context) { + return MaterialApp( + title: 'Stream Chat Dart Example', + home: HomeScreen(channel: channel), + ); + } +} + +/// Main screen of our application. The layout is comprised of an [AppBar] +/// containing the channel name and a [MessageView] displaying recent messages. +class HomeScreen extends StatelessWidget { + /// [HomeScreen] is constructed using the [Channel] we defined earlier. + const HomeScreen({Key key, @required this.channel}) : super(key: key); + + /// Channel object containing the [Channel.id] we'd like to observe. + final Channel channel; + + @override + Widget build(BuildContext context) { + final messages = channel.state.channelStateStream; + return Scaffold( + appBar: AppBar( + title: Text('Channel: ${channel.id}'), + ), + body: SafeArea( + child: StreamBuilder( + stream: messages, + builder: ( + BuildContext context, + AsyncSnapshot snapshot, + ) { + if (snapshot.hasData && snapshot.data != null) { + return MessageView( + messages: snapshot.data.messages.reversed.toList(), + channel: channel, + ); + } else if (snapshot.hasError) { + return const Center( + child: Text( + 'There was an error loading messages. Please see logs.', + ), + ); + } + return const Center( + child: SizedBox( + width: 100.0, + height: 100.0, + child: CircularProgressIndicator(), + ), + ); + }, + ), + ), + ); + } +} + +/// UI used to display a list of recent messages and a [TextField] for sending +/// new messages. +class MessageView extends StatefulWidget { + /// Message takes the latest list of messages and the current channel. + const MessageView({ + Key key, + @required this.messages, + @required this.channel, + }) : super(key: key); + + /// List of messages sent in the given channel. + final List messages; + + /// Current channel being observed. + final Channel channel; + + @override + _MessageViewState createState() => _MessageViewState(); +} + +class _MessageViewState extends State { + TextEditingController _controller; + ScrollController _scrollController; + + List get _messages => widget.messages; + + @override + void initState() { + super.initState(); + _controller = TextEditingController(); + _scrollController = ScrollController(); + } + + @override + void dispose() { + _controller.dispose(); + _scrollController.dispose(); + super.dispose(); + } + + /// Convenience method for scrolling the list view when a new message is sent. + void _updateList() { + _scrollController.animateTo( + _scrollController.position.maxScrollExtent, + duration: const Duration(milliseconds: 200), + curve: Curves.easeOut, + ); + } + + @override + Widget build(BuildContext context) { + return Column( + children: [ + Expanded( + child: ListView.builder( + controller: _scrollController, + itemCount: _messages.length, + reverse: true, + itemBuilder: (BuildContext context, int index) { + final item = _messages[index]; + if (item.user.id == widget.channel.client.uid) { + return Align( + alignment: Alignment.centerRight, + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Text(item.text), + ), + ); + } else { + return Align( + alignment: Alignment.centerLeft, + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Text(item.text), + ), + ); + } + }, + ), + ), + Padding( + padding: const EdgeInsets.all(8.0), + child: Row( + children: [ + Expanded( + child: TextField( + controller: _controller, + decoration: const InputDecoration( + hintText: 'Enter your message', + ), + ), + ), + Material( + type: MaterialType.circle, + color: Colors.blue, + clipBehavior: Clip.hardEdge, + child: InkWell( + onTap: () async { + // We can send a new message by calling `sendMessage` on + // the current channel. After sending a message, the + // TextField is cleared and the list view is scrolled + // to show the new item. + if (_controller.value.text.isNotEmpty) { + await widget.channel.sendMessage( + Message(text: _controller.value.text), + ); + _controller.clear(); + _updateList(); + } + }, + child: const Padding( + padding: EdgeInsets.all(8.0), + child: Center( + child: Icon( + Icons.send, + color: Colors.white, + ), + ), + ), + ), + ) + ], + ), + ) + ], + ); + } +} + +/// Helper extension for quickly retrieving the current user id from a [Client]. +extension on Client { + String get uid => state.user.id; +} \ No newline at end of file diff --git a/packages/dart_client/example/pubspec.yaml b/packages/dart_client/example/pubspec.yaml new file mode 100644 index 00000000..4d07128c --- /dev/null +++ b/packages/dart_client/example/pubspec.yaml @@ -0,0 +1,23 @@ +name: stream_chat_dart_example +description: Example using Stream's LLC + +publish_to: 'none' +version: 1.0.0+1 + +environment: + sdk: ">=2.7.0 <3.0.0" + +dependencies: + flutter: + sdk: flutter + stream_chat: + path: ../ + +dev_dependencies: + flutter_test: + sdk: flutter + integration_test: + sdk: flutter + +flutter: + uses-material-design: true \ No newline at end of file diff --git a/packages/dart_client/example/web/favicon.png b/packages/dart_client/example/web/favicon.png new file mode 100644 index 0000000000000000000000000000000000000000..8aaa46ac1ae21512746f852a42ba87e4165dfdd1 GIT binary patch literal 917 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|I14-?iy0X7 zltGxWVyS%@P(fs7NJL45ua8x7ey(0(N`6wRUPW#JP&EUCO@$SZnVVXYs8ErclUHn2 zVXFjIVFhG^g!Ppaz)DK8ZIvQ?0~DO|i&7O#^-S~(l1AfjnEK zjFOT9D}DX)@^Za$W4-*MbbUihOG|wNBYh(yU7!lx;>x^|#0uTKVr7USFmqf|i<65o z3raHc^AtelCMM;Vme?vOfh>Xph&xL%(-1c06+^uR^q@XSM&D4+Kp$>4P^%3{)XKjo zGZknv$b36P8?Z_gF{nK@`XI}Z90TzwSQO}0J1!f2c(B=V`5aP@1P1a|PZ!4!3&Gl8 zTYqUsf!gYFyJnXpu0!n&N*SYAX-%d(5gVjrHJWqXQshj@!Zm{!01WsQrH~9=kTxW#6SvuapgMqt>$=j#%eyGrQzr zP{L-3gsMA^$I1&gsBAEL+vxi1*Igl=8#8`5?A-T5=z-sk46WA1IUT)AIZHx1rdUrf zVJrJn<74DDw`j)Ki#gt}mIT-Q`XRa2-jQXQoI%w`nb|XblvzK${ZzlV)m-XcwC(od z71_OEC5Bt9GEXosOXaPTYOia#R4ID2TiU~`zVMl08TV_C%DnU4^+HE>9(CE4D6?Fz oujB08i7adh9xk7*FX66dWH6F5TM;?E2b5PlUHx3vIVCg!0Dx9vYXATM literal 0 HcmV?d00001 diff --git a/packages/dart_client/example/web/icons/Icon-192.png b/packages/dart_client/example/web/icons/Icon-192.png new file mode 100644 index 0000000000000000000000000000000000000000..b749bfef07473333cf1dd31e9eed89862a5d52aa GIT binary patch literal 5292 zcmZ`-2T+sGz6~)*FVZ`aW+(v>MIm&M-g^@e2u-B-DoB?qO+b1Tq<5uCCv>ESfRum& zp%X;f!~1{tzL__3=gjVJ=j=J>+nMj%ncXj1Q(b|Ckbw{Y0FWpt%4y%$uD=Z*c-x~o zE;IoE;xa#7Ll5nj-e4CuXB&G*IM~D21rCP$*xLXAK8rIMCSHuSu%bL&S3)8YI~vyp@KBu9Ph7R_pvKQ@xv>NQ`dZp(u{Z8K3yOB zn7-AR+d2JkW)KiGx0hosml;+eCXp6+w%@STjFY*CJ?udJ64&{BCbuebcuH;}(($@@ znNlgBA@ZXB)mcl9nbX#F!f_5Z=W>0kh|UVWnf!At4V*LQP%*gPdCXd6P@J4Td;!Ur z<2ZLmwr(NG`u#gDEMP19UcSzRTL@HsK+PnIXbVBT@oHm53DZr?~V(0{rsalAfwgo zEh=GviaqkF;}F_5-yA!1u3!gxaR&Mj)hLuj5Q-N-@Lra{%<4ONja8pycD90&>yMB` zchhd>0CsH`^|&TstH-8+R`CfoWqmTTF_0?zDOY`E`b)cVi!$4xA@oO;SyOjJyP^_j zx^@Gdf+w|FW@DMdOi8=4+LJl$#@R&&=UM`)G!y%6ZzQLoSL%*KE8IO0~&5XYR9 z&N)?goEiWA(YoRfT{06&D6Yuu@Qt&XVbuW@COb;>SP9~aRc+z`m`80pB2o%`#{xD@ zI3RAlukL5L>px6b?QW1Ac_0>ew%NM!XB2(H+1Y3AJC?C?O`GGs`331Nd4ZvG~bMo{lh~GeL zSL|tT*fF-HXxXYtfu5z+T5Mx9OdP7J4g%@oeC2FaWO1D{=NvL|DNZ}GO?O3`+H*SI z=grGv=7dL{+oY0eJFGO!Qe(e2F?CHW(i!!XkGo2tUvsQ)I9ev`H&=;`N%Z{L zO?vV%rDv$y(@1Yj@xfr7Kzr<~0{^T8wM80xf7IGQF_S-2c0)0D6b0~yD7BsCy+(zL z#N~%&e4iAwi4F$&dI7x6cE|B{f@lY5epaDh=2-(4N05VO~A zQT3hanGy_&p+7Fb^I#ewGsjyCEUmSCaP6JDB*=_()FgQ(-pZ28-{qx~2foO4%pM9e z*_63RT8XjgiaWY|*xydf;8MKLd{HnfZ2kM%iq}fstImB-K6A79B~YoPVa@tYN@T_$ zea+9)<%?=Fl!kd(Y!G(-o}ko28hg2!MR-o5BEa_72uj7Mrc&{lRh3u2%Y=Xk9^-qa zBPWaD=2qcuJ&@Tf6ue&)4_V*45=zWk@Z}Q?f5)*z)-+E|-yC4fs5CE6L_PH3=zI8p z*Z3!it{1e5_^(sF*v=0{`U9C741&lub89gdhKp|Y8CeC{_{wYK-LSbp{h)b~9^j!s z7e?Y{Z3pZv0J)(VL=g>l;<}xk=T*O5YR|hg0eg4u98f2IrA-MY+StQIuK-(*J6TRR z|IM(%uI~?`wsfyO6Tgmsy1b3a)j6M&-jgUjVg+mP*oTKdHg?5E`!r`7AE_#?Fc)&a z08KCq>Gc=ne{PCbRvs6gVW|tKdcE1#7C4e`M|j$C5EYZ~Y=jUtc zj`+?p4ba3uy7><7wIokM79jPza``{Lx0)zGWg;FW1^NKY+GpEi=rHJ+fVRGfXO zPHV52k?jxei_!YYAw1HIz}y8ZMwdZqU%ESwMn7~t zdI5%B;U7RF=jzRz^NuY9nM)&<%M>x>0(e$GpU9th%rHiZsIT>_qp%V~ILlyt^V`=d z!1+DX@ah?RnB$X!0xpTA0}lN@9V-ePx>wQ?-xrJr^qDlw?#O(RsXeAvM%}rg0NT#t z!CsT;-vB=B87ShG`GwO;OEbeL;a}LIu=&@9cb~Rsx(ZPNQ!NT7H{@j0e(DiLea>QD zPmpe90gEKHEZ8oQ@6%E7k-Ptn#z)b9NbD@_GTxEhbS+}Bb74WUaRy{w;E|MgDAvHw zL)ycgM7mB?XVh^OzbC?LKFMotw3r@i&VdUV%^Efdib)3@soX%vWCbnOyt@Y4swW925@bt45y0HY3YI~BnnzZYrinFy;L?2D3BAL`UQ zEj))+f>H7~g8*VuWQ83EtGcx`hun$QvuurSMg3l4IP8Fe`#C|N6mbYJ=n;+}EQm;< z!!N=5j1aAr_uEnnzrEV%_E|JpTb#1p1*}5!Ce!R@d$EtMR~%9# zd;h8=QGT)KMW2IKu_fA_>p_und#-;Q)p%%l0XZOXQicfX8M~7?8}@U^ihu;mizj)t zgV7wk%n-UOb z#!P5q?Ex+*Kx@*p`o$q8FWL*E^$&1*!gpv?Za$YO~{BHeGY*5%4HXUKa_A~~^d z=E*gf6&+LFF^`j4$T~dR)%{I)T?>@Ma?D!gi9I^HqvjPc3-v~=qpX1Mne@*rzT&Xw zQ9DXsSV@PqpEJO-g4A&L{F&;K6W60D!_vs?Vx!?w27XbEuJJP&);)^+VF1nHqHBWu z^>kI$M9yfOY8~|hZ9WB!q-9u&mKhEcRjlf2nm_@s;0D#c|@ED7NZE% zzR;>P5B{o4fzlfsn3CkBK&`OSb-YNrqx@N#4CK!>bQ(V(D#9|l!e9(%sz~PYk@8zt zPN9oK78&-IL_F zhsk1$6p;GqFbtB^ZHHP+cjMvA0(LqlskbdYE_rda>gvQLTiqOQ1~*7lg%z*&p`Ry& zRcG^DbbPj_jOKHTr8uk^15Boj6>hA2S-QY(W-6!FIq8h$<>MI>PYYRenQDBamO#Fv zAH5&ImqKBDn0v5kb|8i0wFhUBJTpT!rB-`zK)^SNnRmLraZcPYK7b{I@+}wXVdW-{Ps17qdRA3JatEd?rPV z4@}(DAMf5EqXCr4-B+~H1P#;t@O}B)tIJ(W6$LrK&0plTmnPpb1TKn3?f?Kk``?D+ zQ!MFqOX7JbsXfQrz`-M@hq7xlfNz;_B{^wbpG8des56x(Q)H)5eLeDwCrVR}hzr~= zM{yXR6IM?kXxauLza#@#u?Y|o;904HCqF<8yT~~c-xyRc0-vxofnxG^(x%>bj5r}N zyFT+xnn-?B`ohA>{+ZZQem=*Xpqz{=j8i2TAC#x-m;;mo{{sLB_z(UoAqD=A#*juZ zCv=J~i*O8;F}A^Wf#+zx;~3B{57xtoxC&j^ie^?**T`WT2OPRtC`xj~+3Kprn=rVM zVJ|h5ux%S{dO}!mq93}P+h36mZ5aZg1-?vhL$ke1d52qIiXSE(llCr5i=QUS?LIjc zV$4q=-)aaR4wsrQv}^shL5u%6;`uiSEs<1nG^?$kl$^6DL z43CjY`M*p}ew}}3rXc7Xck@k41jx}c;NgEIhKZ*jsBRZUP-x2cm;F1<5$jefl|ppO zmZd%%?gMJ^g9=RZ^#8Mf5aWNVhjAS^|DQO+q$)oeob_&ZLFL(zur$)); zU19yRm)z<4&4-M}7!9+^Wl}Uk?`S$#V2%pQ*SIH5KI-mn%i;Z7-)m$mN9CnI$G7?# zo`zVrUwoSL&_dJ92YhX5TKqaRkfPgC4=Q&=K+;_aDs&OU0&{WFH}kKX6uNQC6%oUH z2DZa1s3%Vtk|bglbxep-w)PbFG!J17`<$g8lVhqD2w;Z0zGsh-r zxZ13G$G<48leNqR!DCVt9)@}(zMI5w6Wo=N zpP1*3DI;~h2WDWgcKn*f!+ORD)f$DZFwgKBafEZmeXQMAsq9sxP9A)7zOYnkHT9JU zRA`umgmP9d6=PHmFIgx=0$(sjb>+0CHG)K@cPG{IxaJ&Ueo8)0RWgV9+gO7+Bl1(F z7!BslJ2MP*PWJ;x)QXbR$6jEr5q3 z(3}F@YO_P1NyTdEXRLU6fp?9V2-S=E+YaeLL{Y)W%6`k7$(EW8EZSA*(+;e5@jgD^I zaJQ2|oCM1n!A&-8`;#RDcZyk*+RPkn_r8?Ak@agHiSp*qFNX)&i21HE?yuZ;-C<3C zwJGd1lx5UzViP7sZJ&|LqH*mryb}y|%AOw+v)yc`qM)03qyyrqhX?ub`Cjwx2PrR! z)_z>5*!*$x1=Qa-0uE7jy0z`>|Ni#X+uV|%_81F7)b+nf%iz=`fF4g5UfHS_?PHbr zB;0$bK@=di?f`dS(j{l3-tSCfp~zUuva+=EWxJcRfp(<$@vd(GigM&~vaYZ0c#BTs z3ijkxMl=vw5AS&DcXQ%eeKt!uKvh2l3W?&3=dBHU=Gz?O!40S&&~ei2vg**c$o;i89~6DVns zG>9a*`k5)NI9|?W!@9>rzJ;9EJ=YlJTx1r1BA?H`LWijk(rTax9(OAu;q4_wTj-yj z1%W4GW&K4T=uEGb+E!>W0SD_C0RR91 literal 0 HcmV?d00001 diff --git a/packages/dart_client/example/web/icons/Icon-512.png b/packages/dart_client/example/web/icons/Icon-512.png new file mode 100644 index 0000000000000000000000000000000000000000..88cfd48dff1169879ba46840804b412fe02fefd6 GIT binary patch literal 8252 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 literal 0 HcmV?d00001 diff --git a/packages/dart_client/example/web/index.html b/packages/dart_client/example/web/index.html new file mode 100644 index 00000000..6f6d6461 --- /dev/null +++ b/packages/dart_client/example/web/index.html @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + + + + + stream_chat_dart_example + + + + + + + + diff --git a/packages/dart_client/example/web/manifest.json b/packages/dart_client/example/web/manifest.json new file mode 100644 index 00000000..5ee3b42d --- /dev/null +++ b/packages/dart_client/example/web/manifest.json @@ -0,0 +1,23 @@ +{ + "name": "stream_chat_dart_example", + "short_name": "stream_chat_dart_example", + "start_url": ".", + "display": "standalone", + "background_color": "#0175C2", + "theme_color": "#0175C2", + "description": "Example using Stream's LLC", + "orientation": "portrait-primary", + "prefer_related_applications": false, + "icons": [ + { + "src": "icons/Icon-192.png", + "sizes": "192x192", + "type": "image/png" + }, + { + "src": "icons/Icon-512.png", + "sizes": "512x512", + "type": "image/png" + } + ] +} From 5da83a3f596d4b6d00f5a4233dc943a8c3debc3a Mon Sep 17 00:00:00 2001 From: Neevash Ramdial Date: Wed, 20 Jan 2021 11:09:55 -0400 Subject: [PATCH 0986/1140] update default readme --- packages/dart_client/example/README.md | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) diff --git a/packages/dart_client/example/README.md b/packages/dart_client/example/README.md index ed19a198..11089159 100644 --- a/packages/dart_client/example/README.md +++ b/packages/dart_client/example/README.md @@ -1,16 +1,2 @@ -# stream_chat_dart_example - -Example using Stream's LLC - -## Getting Started - -This project is a starting point for a Flutter application. - -A few resources to get you started if this is your first Flutter project: - -- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) -- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) - -For help getting started with Flutter, view our -[online documentation](https://flutter.dev/docs), which offers tutorials, -samples, guidance on mobile development, and a full API reference. +# Stream Chat Dart Example +Please see `lib/` for example code. \ No newline at end of file From 993cab00a067605dc7e3529b9b2dd3c90ab49c63 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Wed, 20 Jan 2021 16:54:04 +0100 Subject: [PATCH 0987/1140] bump sample app version --- .../flutter_widgets/example/ios/fastlane/report.xml | 10 +++++----- packages/flutter_widgets/example/pubspec.yaml | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/flutter_widgets/example/ios/fastlane/report.xml b/packages/flutter_widgets/example/ios/fastlane/report.xml index 3a11e14a..0010f637 100644 --- a/packages/flutter_widgets/example/ios/fastlane/report.xml +++ b/packages/flutter_widgets/example/ios/fastlane/report.xml @@ -5,27 +5,27 @@ - + - + - + - + - + diff --git a/packages/flutter_widgets/example/pubspec.yaml b/packages/flutter_widgets/example/pubspec.yaml index f63f6706..69eb72fb 100644 --- a/packages/flutter_widgets/example/pubspec.yaml +++ b/packages/flutter_widgets/example/pubspec.yaml @@ -1,7 +1,7 @@ name: example description: A new Flutter project. -version: 1.1.3+1 publish_to: 'none' +version: 1.1.3+2 environment: sdk: ">=2.2.2 <3.0.0" From ec915a90878b7cad1fe1877e0752b710255812ca Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Wed, 20 Jan 2021 18:00:29 +0100 Subject: [PATCH 0988/1140] fix button style --- packages/dart_client/example/lib/main.dart | 2 +- .../example/lib/advanced_options_page.dart | 17 ++++++++++++++++- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/packages/dart_client/example/lib/main.dart b/packages/dart_client/example/lib/main.dart index eb413af6..8f68c100 100644 --- a/packages/dart_client/example/lib/main.dart +++ b/packages/dart_client/example/lib/main.dart @@ -245,4 +245,4 @@ class _MessageViewState extends State { /// Helper extension for quickly retrieving the current user id from a [Client]. extension on Client { String get uid => state.user.id; -} \ No newline at end of file +} diff --git a/packages/flutter_widgets/example/lib/advanced_options_page.dart b/packages/flutter_widgets/example/lib/advanced_options_page.dart index 2da11406..023ce32c 100644 --- a/packages/flutter_widgets/example/lib/advanced_options_page.dart +++ b/packages/flutter_widgets/example/lib/advanced_options_page.dart @@ -222,8 +222,23 @@ class _AdvancedOptionsPageState extends State { ), Spacer(), RaisedButton( + color: Theme.of(context).brightness == Brightness.light + ? StreamChatTheme.of(context).colorTheme.accentBlue + : Colors.white, elevation: 0, - child: Text('Login', style: TextStyle(fontSize: 16)), + padding: const EdgeInsets.symmetric(vertical: 16), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(26), + ), + child: Text( + 'Login', + style: TextStyle( + fontSize: 16, + color: Theme.of(context).brightness != Brightness.light + ? StreamChatTheme.of(context).colorTheme.accentBlue + : Colors.white, + ), + ), onPressed: () async { if (loading) { return; From 390c1aafcf6293a8754949cb6eff4ee3d6f1cd47 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Wed, 20 Jan 2021 18:01:35 +0100 Subject: [PATCH 0989/1140] version bp --- packages/flutter_widgets/example/pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/flutter_widgets/example/pubspec.yaml b/packages/flutter_widgets/example/pubspec.yaml index 69eb72fb..8c11c0ee 100644 --- a/packages/flutter_widgets/example/pubspec.yaml +++ b/packages/flutter_widgets/example/pubspec.yaml @@ -1,7 +1,7 @@ name: example description: A new Flutter project. publish_to: 'none' -version: 1.1.3+2 +version: 1.1.3+3 environment: sdk: ">=2.2.2 <3.0.0" From 803b42307b7d200a2785c6c2743ef108d3160169 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Thu, 21 Jan 2021 14:02:00 +0530 Subject: [PATCH 0990/1140] feat: Added new ui package --- packages/stream_chat_flutter_core/.gitignore | 74 +++++++++++++++++++ packages/stream_chat_flutter_core/.metadata | 10 +++ .../stream_chat_flutter_core/CHANGELOG.md | 3 + packages/stream_chat_flutter_core/LICENSE | 1 + packages/stream_chat_flutter_core/README.md | 14 ++++ .../lib/stream_chat_flutter_core.dart | 7 ++ .../stream_chat_flutter_core/pubspec.yaml | 54 ++++++++++++++ .../test/stream_chat_flutter_core_test.dart | 13 ++++ 8 files changed, 176 insertions(+) create mode 100644 packages/stream_chat_flutter_core/.gitignore create mode 100644 packages/stream_chat_flutter_core/.metadata create mode 100644 packages/stream_chat_flutter_core/CHANGELOG.md create mode 100644 packages/stream_chat_flutter_core/LICENSE create mode 100644 packages/stream_chat_flutter_core/README.md create mode 100644 packages/stream_chat_flutter_core/lib/stream_chat_flutter_core.dart create mode 100644 packages/stream_chat_flutter_core/pubspec.yaml create mode 100644 packages/stream_chat_flutter_core/test/stream_chat_flutter_core_test.dart diff --git a/packages/stream_chat_flutter_core/.gitignore b/packages/stream_chat_flutter_core/.gitignore new file mode 100644 index 00000000..1985397a --- /dev/null +++ b/packages/stream_chat_flutter_core/.gitignore @@ -0,0 +1,74 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# IntelliJ related +*.iml +*.ipr +*.iws +.idea/ + +# The .vscode folder contains launch configuration and tasks you configure in +# VS Code which you may wish to be included in version control, so this line +# is commented out by default. +#.vscode/ + +# Flutter/Dart/Pub related +**/doc/api/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +build/ + +# Android related +**/android/**/gradle-wrapper.jar +**/android/.gradle +**/android/captures/ +**/android/gradlew +**/android/gradlew.bat +**/android/local.properties +**/android/**/GeneratedPluginRegistrant.java + +# iOS/XCode related +**/ios/**/*.mode1v3 +**/ios/**/*.mode2v3 +**/ios/**/*.moved-aside +**/ios/**/*.pbxuser +**/ios/**/*.perspectivev3 +**/ios/**/*sync/ +**/ios/**/.sconsign.dblite +**/ios/**/.tags* +**/ios/**/.vagrant/ +**/ios/**/DerivedData/ +**/ios/**/Icon? +**/ios/**/Pods/ +**/ios/**/.symlinks/ +**/ios/**/profile +**/ios/**/xcuserdata +**/ios/.generated/ +**/ios/Flutter/App.framework +**/ios/Flutter/Flutter.framework +**/ios/Flutter/Flutter.podspec +**/ios/Flutter/Generated.xcconfig +**/ios/Flutter/app.flx +**/ios/Flutter/app.zip +**/ios/Flutter/flutter_assets/ +**/ios/Flutter/flutter_export_environment.sh +**/ios/ServiceDefinitions.json +**/ios/Runner/GeneratedPluginRegistrant.* + +# Exceptions to above rules. +!**/ios/**/default.mode1v3 +!**/ios/**/default.mode2v3 +!**/ios/**/default.pbxuser +!**/ios/**/default.perspectivev3 diff --git a/packages/stream_chat_flutter_core/.metadata b/packages/stream_chat_flutter_core/.metadata new file mode 100644 index 00000000..5eb50347 --- /dev/null +++ b/packages/stream_chat_flutter_core/.metadata @@ -0,0 +1,10 @@ +# This file tracks properties of this Flutter project. +# Used by Flutter tool to assess capabilities and perform upgrades etc. +# +# This file should be version controlled and should not be manually edited. + +version: + revision: 78910062997c3a836feee883712c241a5fd22983 + channel: stable + +project_type: package diff --git a/packages/stream_chat_flutter_core/CHANGELOG.md b/packages/stream_chat_flutter_core/CHANGELOG.md new file mode 100644 index 00000000..ac071598 --- /dev/null +++ b/packages/stream_chat_flutter_core/CHANGELOG.md @@ -0,0 +1,3 @@ +## [0.0.1] - TODO: Add release date. + +* TODO: Describe initial release. diff --git a/packages/stream_chat_flutter_core/LICENSE b/packages/stream_chat_flutter_core/LICENSE new file mode 100644 index 00000000..ba75c69f --- /dev/null +++ b/packages/stream_chat_flutter_core/LICENSE @@ -0,0 +1 @@ +TODO: Add your license here. diff --git a/packages/stream_chat_flutter_core/README.md b/packages/stream_chat_flutter_core/README.md new file mode 100644 index 00000000..0acef57c --- /dev/null +++ b/packages/stream_chat_flutter_core/README.md @@ -0,0 +1,14 @@ +# stream_chat_flutter_core + +Stream Chat Official Flutter SDK Core. Build and customize your own chat experience using Dart and Flutter. + +## Getting Started + +This project is a starting point for a Dart +[package](https://flutter.dev/developing-packages/), +a library module containing code that can be shared easily across +multiple Flutter or Dart projects. + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/packages/stream_chat_flutter_core/lib/stream_chat_flutter_core.dart b/packages/stream_chat_flutter_core/lib/stream_chat_flutter_core.dart new file mode 100644 index 00000000..1f8e28bb --- /dev/null +++ b/packages/stream_chat_flutter_core/lib/stream_chat_flutter_core.dart @@ -0,0 +1,7 @@ +library stream_chat_flutter_core; + +/// A Calculator. +class Calculator { + /// Returns [value] plus 1. + int addOne(int value) => value + 1; +} diff --git a/packages/stream_chat_flutter_core/pubspec.yaml b/packages/stream_chat_flutter_core/pubspec.yaml new file mode 100644 index 00000000..9590e0c4 --- /dev/null +++ b/packages/stream_chat_flutter_core/pubspec.yaml @@ -0,0 +1,54 @@ +name: stream_chat_flutter_core +description: Stream Chat Official Flutter SDK Core. Build and customize your own chat experience using Dart and Flutter. +version: 0.0.1 +author: +homepage: + +environment: + sdk: ">=2.7.0 <3.0.0" + flutter: ">=1.17.0" + +dependencies: + flutter: + sdk: flutter + +dev_dependencies: + flutter_test: + sdk: flutter + +# For information on the generic Dart part of this file, see the +# following page: https://dart.dev/tools/pub/pubspec + +# The following section is specific to Flutter. +flutter: + + # To add assets to your package, add an assets section, like this: + # assets: + # - images/a_dot_burr.jpeg + # - images/a_dot_ham.jpeg + # + # For details regarding assets in packages, see + # https://flutter.dev/assets-and-images/#from-packages + # + # An image asset can refer to one or more resolution-specific "variants", see + # https://flutter.dev/assets-and-images/#resolution-aware. + + # To add custom fonts to your package, add a fonts section here, + # in this "flutter" section. Each entry in this list should have a + # "family" key with the font family name, and a "fonts" key with a + # list giving the asset and other descriptors for the font. For + # example: + # fonts: + # - family: Schyler + # fonts: + # - asset: fonts/Schyler-Regular.ttf + # - asset: fonts/Schyler-Italic.ttf + # style: italic + # - family: Trajan Pro + # fonts: + # - asset: fonts/TrajanPro.ttf + # - asset: fonts/TrajanPro_Bold.ttf + # weight: 700 + # + # For details regarding fonts in packages, see + # https://flutter.dev/custom-fonts/#from-packages diff --git a/packages/stream_chat_flutter_core/test/stream_chat_flutter_core_test.dart b/packages/stream_chat_flutter_core/test/stream_chat_flutter_core_test.dart new file mode 100644 index 00000000..626831ae --- /dev/null +++ b/packages/stream_chat_flutter_core/test/stream_chat_flutter_core_test.dart @@ -0,0 +1,13 @@ +import 'package:flutter_test/flutter_test.dart'; + +import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; + +void main() { + test('adds one to input values', () { + final calculator = Calculator(); + expect(calculator.addOne(2), 3); + expect(calculator.addOne(-7), -6); + expect(calculator.addOne(0), 1); + expect(() => calculator.addOne(null), throwsNoSuchMethodError); + }); +} From 2982c2d824281e671c7fbbec6f80adcd332d340f Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Thu, 21 Jan 2021 09:43:24 +0100 Subject: [PATCH 0991/1140] fix android ci --- packages/flutter_widgets/example/android/app/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/flutter_widgets/example/android/app/build.gradle b/packages/flutter_widgets/example/android/app/build.gradle index c90beca2..c5ff1b9e 100644 --- a/packages/flutter_widgets/example/android/app/build.gradle +++ b/packages/flutter_widgets/example/android/app/build.gradle @@ -27,7 +27,7 @@ apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" android { compileSdkVersion 29 - ndkVersion '22.0.7026061' + ndkVersion '21.3.6528147' sourceSets { main.java.srcDirs += 'src/main/kotlin' From b5feb31fd0e16318e4ac333e7a433b04aa1e35d7 Mon Sep 17 00:00:00 2001 From: Neevash Ramdial Date: Thu, 21 Jan 2021 06:27:35 -0400 Subject: [PATCH 0992/1140] remove example --- packages/dart_client/example/.gitignore | 46 ---- packages/dart_client/example/.metadata | 10 - packages/dart_client/example/README.md | 2 - .../dart_client/example/android/.gitignore | 11 - .../example/android/app/build.gradle | 59 ----- .../android/app/src/debug/AndroidManifest.xml | 7 - .../android/app/src/main/AndroidManifest.xml | 41 --- .../stream_chat_dart_example/MainActivity.kt | 6 - .../res/drawable-v21/launch_background.xml | 12 - .../main/res/drawable/launch_background.xml | 12 - .../src/main/res/mipmap-hdpi/ic_launcher.png | Bin 544 -> 0 bytes .../src/main/res/mipmap-mdpi/ic_launcher.png | Bin 442 -> 0 bytes .../src/main/res/mipmap-xhdpi/ic_launcher.png | Bin 721 -> 0 bytes .../main/res/mipmap-xxhdpi/ic_launcher.png | Bin 1031 -> 0 bytes .../main/res/mipmap-xxxhdpi/ic_launcher.png | Bin 1443 -> 0 bytes .../app/src/main/res/values-night/styles.xml | 18 -- .../app/src/main/res/values/styles.xml | 18 -- .../app/src/profile/AndroidManifest.xml | 7 - .../dart_client/example/android/build.gradle | 31 --- .../example/android/gradle.properties | 3 - .../gradle/wrapper/gradle-wrapper.properties | 6 - .../example/android/settings.gradle | 11 - packages/dart_client/example/ios/.gitignore | 32 --- .../ios/Flutter/AppFrameworkInfo.plist | 26 -- .../example/ios/Flutter/Debug.xcconfig | 2 - .../example/ios/Flutter/Release.xcconfig | 2 - .../contents.xcworkspacedata | 7 - .../xcshareddata/IDEWorkspaceChecks.plist | 8 - .../xcshareddata/WorkspaceSettings.xcsettings | 8 - .../xcshareddata/xcschemes/Runner.xcscheme | 91 ------- .../contents.xcworkspacedata | 10 - .../xcshareddata/IDEWorkspaceChecks.plist | 8 - .../xcshareddata/WorkspaceSettings.xcsettings | 8 - .../example/ios/Runner/AppDelegate.swift | 13 - .../AppIcon.appiconset/Contents.json | 122 --------- .../Icon-App-1024x1024@1x.png | Bin 10932 -> 0 bytes .../AppIcon.appiconset/Icon-App-20x20@1x.png | Bin 564 -> 0 bytes .../AppIcon.appiconset/Icon-App-20x20@2x.png | Bin 1283 -> 0 bytes .../AppIcon.appiconset/Icon-App-20x20@3x.png | Bin 1588 -> 0 bytes .../AppIcon.appiconset/Icon-App-29x29@1x.png | Bin 1025 -> 0 bytes .../AppIcon.appiconset/Icon-App-29x29@2x.png | Bin 1716 -> 0 bytes .../AppIcon.appiconset/Icon-App-29x29@3x.png | Bin 1920 -> 0 bytes .../AppIcon.appiconset/Icon-App-40x40@1x.png | Bin 1283 -> 0 bytes .../AppIcon.appiconset/Icon-App-40x40@2x.png | Bin 1895 -> 0 bytes .../AppIcon.appiconset/Icon-App-40x40@3x.png | Bin 2665 -> 0 bytes .../AppIcon.appiconset/Icon-App-60x60@2x.png | Bin 2665 -> 0 bytes .../AppIcon.appiconset/Icon-App-60x60@3x.png | Bin 3831 -> 0 bytes .../AppIcon.appiconset/Icon-App-76x76@1x.png | Bin 1888 -> 0 bytes .../AppIcon.appiconset/Icon-App-76x76@2x.png | Bin 3294 -> 0 bytes .../Icon-App-83.5x83.5@2x.png | Bin 3612 -> 0 bytes .../LaunchImage.imageset/Contents.json | 23 -- .../LaunchImage.imageset/LaunchImage.png | Bin 68 -> 0 bytes .../LaunchImage.imageset/LaunchImage@2x.png | Bin 68 -> 0 bytes .../LaunchImage.imageset/LaunchImage@3x.png | Bin 68 -> 0 bytes .../LaunchImage.imageset/README.md | 5 - .../Runner/Base.lproj/LaunchScreen.storyboard | 37 --- .../ios/Runner/Base.lproj/Main.storyboard | 26 -- .../dart_client/example/ios/Runner/Info.plist | 45 ---- .../ios/Runner/Runner-Bridging-Header.h | 1 - packages/dart_client/example/lib/main.dart | 248 ------------------ packages/dart_client/example/pubspec.yaml | 23 -- packages/dart_client/example/web/favicon.png | Bin 917 -> 0 bytes .../example/web/icons/Icon-192.png | Bin 5292 -> 0 bytes .../example/web/icons/Icon-512.png | Bin 8252 -> 0 bytes packages/dart_client/example/web/index.html | 45 ---- .../dart_client/example/web/manifest.json | 23 -- 66 files changed, 1113 deletions(-) delete mode 100644 packages/dart_client/example/.gitignore delete mode 100644 packages/dart_client/example/.metadata delete mode 100644 packages/dart_client/example/README.md delete mode 100644 packages/dart_client/example/android/.gitignore delete mode 100644 packages/dart_client/example/android/app/build.gradle delete mode 100644 packages/dart_client/example/android/app/src/debug/AndroidManifest.xml delete mode 100644 packages/dart_client/example/android/app/src/main/AndroidManifest.xml delete mode 100644 packages/dart_client/example/android/app/src/main/kotlin/io/getstream/stream_chat_dart_example/stream_chat_dart_example/MainActivity.kt delete mode 100644 packages/dart_client/example/android/app/src/main/res/drawable-v21/launch_background.xml delete mode 100644 packages/dart_client/example/android/app/src/main/res/drawable/launch_background.xml delete mode 100644 packages/dart_client/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png delete mode 100644 packages/dart_client/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png delete mode 100644 packages/dart_client/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png delete mode 100644 packages/dart_client/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png delete mode 100644 packages/dart_client/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png delete mode 100644 packages/dart_client/example/android/app/src/main/res/values-night/styles.xml delete mode 100644 packages/dart_client/example/android/app/src/main/res/values/styles.xml delete mode 100644 packages/dart_client/example/android/app/src/profile/AndroidManifest.xml delete mode 100644 packages/dart_client/example/android/build.gradle delete mode 100644 packages/dart_client/example/android/gradle.properties delete mode 100644 packages/dart_client/example/android/gradle/wrapper/gradle-wrapper.properties delete mode 100644 packages/dart_client/example/android/settings.gradle delete mode 100644 packages/dart_client/example/ios/.gitignore delete mode 100644 packages/dart_client/example/ios/Flutter/AppFrameworkInfo.plist delete mode 100644 packages/dart_client/example/ios/Flutter/Debug.xcconfig delete mode 100644 packages/dart_client/example/ios/Flutter/Release.xcconfig delete mode 100644 packages/dart_client/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata delete mode 100644 packages/dart_client/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist delete mode 100644 packages/dart_client/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings delete mode 100644 packages/dart_client/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme delete mode 100644 packages/dart_client/example/ios/Runner.xcworkspace/contents.xcworkspacedata delete mode 100644 packages/dart_client/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist delete mode 100644 packages/dart_client/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings delete mode 100644 packages/dart_client/example/ios/Runner/AppDelegate.swift delete mode 100644 packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json delete mode 100644 packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png delete mode 100644 packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png delete mode 100644 packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png delete mode 100644 packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png delete mode 100644 packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png delete mode 100644 packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png delete mode 100644 packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png delete mode 100644 packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png delete mode 100644 packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png delete mode 100644 packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png delete mode 100644 packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png delete mode 100644 packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png delete mode 100644 packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png delete mode 100644 packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png delete mode 100644 packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png delete mode 100644 packages/dart_client/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json delete mode 100644 packages/dart_client/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png delete mode 100644 packages/dart_client/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png delete mode 100644 packages/dart_client/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png delete mode 100644 packages/dart_client/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md delete mode 100644 packages/dart_client/example/ios/Runner/Base.lproj/LaunchScreen.storyboard delete mode 100644 packages/dart_client/example/ios/Runner/Base.lproj/Main.storyboard delete mode 100644 packages/dart_client/example/ios/Runner/Info.plist delete mode 100644 packages/dart_client/example/ios/Runner/Runner-Bridging-Header.h delete mode 100644 packages/dart_client/example/lib/main.dart delete mode 100644 packages/dart_client/example/pubspec.yaml delete mode 100644 packages/dart_client/example/web/favicon.png delete mode 100644 packages/dart_client/example/web/icons/Icon-192.png delete mode 100644 packages/dart_client/example/web/icons/Icon-512.png delete mode 100644 packages/dart_client/example/web/index.html delete mode 100644 packages/dart_client/example/web/manifest.json diff --git a/packages/dart_client/example/.gitignore b/packages/dart_client/example/.gitignore deleted file mode 100644 index 0fa6b675..00000000 --- a/packages/dart_client/example/.gitignore +++ /dev/null @@ -1,46 +0,0 @@ -# Miscellaneous -*.class -*.log -*.pyc -*.swp -.DS_Store -.atom/ -.buildlog/ -.history -.svn/ - -# IntelliJ related -*.iml -*.ipr -*.iws -.idea/ - -# The .vscode folder contains launch configuration and tasks you configure in -# VS Code which you may wish to be included in version control, so this line -# is commented out by default. -#.vscode/ - -# Flutter/Dart/Pub related -**/doc/api/ -**/ios/Flutter/.last_build_id -.dart_tool/ -.flutter-plugins -.flutter-plugins-dependencies -.packages -.pub-cache/ -.pub/ -/build/ - -# Web related -lib/generated_plugin_registrant.dart - -# Symbolication related -app.*.symbols - -# Obfuscation related -app.*.map.json - -# Android Studio will place build artifacts here -/android/app/debug -/android/app/profile -/android/app/release diff --git a/packages/dart_client/example/.metadata b/packages/dart_client/example/.metadata deleted file mode 100644 index 48acef37..00000000 --- a/packages/dart_client/example/.metadata +++ /dev/null @@ -1,10 +0,0 @@ -# This file tracks properties of this Flutter project. -# Used by Flutter tool to assess capabilities and perform upgrades etc. -# -# This file should be version controlled and should not be manually edited. - -version: - revision: 5d36f2e7f5387b6c751449258ade8e4e6edf99be - channel: beta - -project_type: app diff --git a/packages/dart_client/example/README.md b/packages/dart_client/example/README.md deleted file mode 100644 index 11089159..00000000 --- a/packages/dart_client/example/README.md +++ /dev/null @@ -1,2 +0,0 @@ -# Stream Chat Dart Example -Please see `lib/` for example code. \ No newline at end of file diff --git a/packages/dart_client/example/android/.gitignore b/packages/dart_client/example/android/.gitignore deleted file mode 100644 index 0a741cb4..00000000 --- a/packages/dart_client/example/android/.gitignore +++ /dev/null @@ -1,11 +0,0 @@ -gradle-wrapper.jar -/.gradle -/captures/ -/gradlew -/gradlew.bat -/local.properties -GeneratedPluginRegistrant.java - -# Remember to never publicly share your keystore. -# See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app -key.properties diff --git a/packages/dart_client/example/android/app/build.gradle b/packages/dart_client/example/android/app/build.gradle deleted file mode 100644 index 0a93e89f..00000000 --- a/packages/dart_client/example/android/app/build.gradle +++ /dev/null @@ -1,59 +0,0 @@ -def localProperties = new Properties() -def localPropertiesFile = rootProject.file('local.properties') -if (localPropertiesFile.exists()) { - localPropertiesFile.withReader('UTF-8') { reader -> - localProperties.load(reader) - } -} - -def flutterRoot = localProperties.getProperty('flutter.sdk') -if (flutterRoot == null) { - throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") -} - -def flutterVersionCode = localProperties.getProperty('flutter.versionCode') -if (flutterVersionCode == null) { - flutterVersionCode = '1' -} - -def flutterVersionName = localProperties.getProperty('flutter.versionName') -if (flutterVersionName == null) { - flutterVersionName = '1.0' -} - -apply plugin: 'com.android.application' -apply plugin: 'kotlin-android' -apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" - -android { - compileSdkVersion 30 - - sourceSets { - main.java.srcDirs += 'src/main/kotlin' - } - - defaultConfig { - // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). - applicationId "io.getstream.stream_chat_dart_example.stream_chat_dart_example" - minSdkVersion 16 - targetSdkVersion 30 - versionCode flutterVersionCode.toInteger() - versionName flutterVersionName - } - - buildTypes { - release { - // TODO: Add your own signing config for the release build. - // Signing with the debug keys for now, so `flutter run --release` works. - signingConfig signingConfigs.debug - } - } -} - -flutter { - source '../..' -} - -dependencies { - implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" -} diff --git a/packages/dart_client/example/android/app/src/debug/AndroidManifest.xml b/packages/dart_client/example/android/app/src/debug/AndroidManifest.xml deleted file mode 100644 index f590dd7e..00000000 --- a/packages/dart_client/example/android/app/src/debug/AndroidManifest.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - diff --git a/packages/dart_client/example/android/app/src/main/AndroidManifest.xml b/packages/dart_client/example/android/app/src/main/AndroidManifest.xml deleted file mode 100644 index 54736655..00000000 --- a/packages/dart_client/example/android/app/src/main/AndroidManifest.xml +++ /dev/null @@ -1,41 +0,0 @@ - - - - - - - - - - - - - - - - diff --git a/packages/dart_client/example/android/app/src/main/kotlin/io/getstream/stream_chat_dart_example/stream_chat_dart_example/MainActivity.kt b/packages/dart_client/example/android/app/src/main/kotlin/io/getstream/stream_chat_dart_example/stream_chat_dart_example/MainActivity.kt deleted file mode 100644 index da72a2e2..00000000 --- a/packages/dart_client/example/android/app/src/main/kotlin/io/getstream/stream_chat_dart_example/stream_chat_dart_example/MainActivity.kt +++ /dev/null @@ -1,6 +0,0 @@ -package io.getstream.stream_chat_dart_example.stream_chat_dart_example - -import io.flutter.embedding.android.FlutterActivity - -class MainActivity: FlutterActivity() { -} diff --git a/packages/dart_client/example/android/app/src/main/res/drawable-v21/launch_background.xml b/packages/dart_client/example/android/app/src/main/res/drawable-v21/launch_background.xml deleted file mode 100644 index f74085f3..00000000 --- a/packages/dart_client/example/android/app/src/main/res/drawable-v21/launch_background.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - diff --git a/packages/dart_client/example/android/app/src/main/res/drawable/launch_background.xml b/packages/dart_client/example/android/app/src/main/res/drawable/launch_background.xml deleted file mode 100644 index 304732f8..00000000 --- a/packages/dart_client/example/android/app/src/main/res/drawable/launch_background.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - diff --git a/packages/dart_client/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/packages/dart_client/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png deleted file mode 100644 index db77bb4b7b0906d62b1847e87f15cdcacf6a4f29..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 544 zcmeAS@N?(olHy`uVBq!ia0vp^9w5xY3?!3`olAj~WQl7;NpOBzNqJ&XDuZK6ep0G} zXKrG8YEWuoN@d~6R2!h8bpbvhu0Wd6uZuB!w&u2PAxD2eNXD>P5D~Wn-+_Wa#27Xc zC?Zj|6r#X(-D3u$NCt}(Ms06KgJ4FxJVv{GM)!I~&n8Bnc94O7-Hd)cjDZswgC;Qs zO=b+9!WcT8F?0rF7!Uys2bs@gozCP?z~o%U|N3vA*22NaGQG zlg@K`O_XuxvZ&Ks^m&R!`&1=spLvfx7oGDKDwpwW`#iqdw@AL`7MR}m`rwr|mZgU`8P7SBkL78fFf!WnuYWm$5Z0 zNXhDbCv&49sM544K|?c)WrFfiZvCi9h0O)B3Pgg&ebxsLQ05GG~ AQ2+n{ diff --git a/packages/dart_client/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/packages/dart_client/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png deleted file mode 100644 index 17987b79bb8a35cc66c3c1fd44f5a5526c1b78be..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 442 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA3?vioaBc-sk|nMYCBgY=CFO}lsSJ)O`AMk? zp1FzXsX?iUDV2pMQ*D5Xx&nMcT!A!W`0S9QKQy;}1Cl^CgaH=;G9cpY;r$Q>i*pfB zP2drbID<_#qf;rPZx^FqH)F_D#*k@@q03KywUtLX8Ua?`H+NMzkczFPK3lFz@i_kW%1NOn0|D2I9n9wzH8m|-tHjsw|9>@K=iMBhxvkv6m8Y-l zytQ?X=U+MF$@3 zt`~i=@j|6y)RWMK--}M|=T`o&^Ni>IoWKHEbBXz7?A@mgWoL>!*SXo`SZH-*HSdS+ yn*9;$7;m`l>wYBC5bq;=U}IMqLzqbYCidGC!)_gkIk_C@Uy!y&wkt5C($~2D>~)O*cj@FGjOCM)M>_ixfudOh)?xMu#Fs z#}Y=@YDTwOM)x{K_j*Q;dPdJ?Mz0n|pLRx{4n|)f>SXlmV)XB04CrSJn#dS5nK2lM zrZ9#~WelCp7&e13Y$jvaEXHskn$2V!!DN-nWS__6T*l;H&Fopn?A6HZ-6WRLFP=R` zqG+CE#d4|IbyAI+rJJ`&x9*T`+a=p|0O(+s{UBcyZdkhj=yS1>AirP+0R;mf2uMgM zC}@~JfByORAh4SyRgi&!(cja>F(l*O+nd+@4m$|6K6KDn_&uvCpV23&>G9HJp{xgg zoq1^2_p9@|WEo z*X_Uko@K)qYYv~>43eQGMdbiGbo>E~Q& zrYBH{QP^@Sti!`2)uG{irBBq@y*$B zi#&(U-*=fp74j)RyIw49+0MRPMRU)+a2r*PJ$L5roHt2$UjExCTZSbq%V!HeS7J$N zdG@vOZB4v_lF7Plrx+hxo7(fCV&}fHq)$ diff --git a/packages/dart_client/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/packages/dart_client/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png deleted file mode 100644 index d5f1c8d34e7a88e3f88bea192c3a370d44689c3c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1031 zcmeAS@N?(olHy`uVBq!ia0vp^6F``Q8Ax83A=Cw=BuiW)N`mv#O3D+9QW+dm@{>{( zJaZG%Q-e|yQz{EjrrIztFa`(sgt!6~Yi|1%a`XoT0ojZ}lNrNjb9xjc(B0U1_% zz5^97Xt*%oq$rQy4?0GKNfJ44uvxI)gC`h-NZ|&0-7(qS@?b!5r36oQ}zyZrNO3 zMO=Or+<~>+A&uN&E!^Sl+>xE!QC-|oJv`ApDhqC^EWD|@=#J`=d#Xzxs4ah}w&Jnc z$|q_opQ^2TrnVZ0o~wh<3t%W&flvYGe#$xqda2bR_R zvPYgMcHgjZ5nSA^lJr%;<&0do;O^tDDh~=pIxA#coaCY>&N%M2^tq^U%3DB@ynvKo}b?yu-bFc-u0JHzced$sg7S3zqI(2 z#Km{dPr7I=pQ5>FuK#)QwK?Y`E`B?nP+}U)I#c1+FM*1kNvWG|a(TpksZQ3B@sD~b zpQ2)*V*TdwjFOtHvV|;OsiDqHi=6%)o4b!)x$)%9pGTsE z-JL={-Ffv+T87W(Xpooq<`r*VzWQcgBN$$`u}f>-ZQI1BB8ykN*=e4rIsJx9>z}*o zo~|9I;xof diff --git a/packages/dart_client/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/packages/dart_client/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png deleted file mode 100644 index 4d6372eebdb28e45604e46eeda8dd24651419bc0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1443 zcmb`G{WsKk6vsdJTdFg%tJav9_E4vzrOaqkWF|A724Nly!y+?N9`YV6wZ}5(X(D_N(?!*n3`|_r0Hc?=PQw&*vnU?QTFY zB_MsH|!j$PP;I}?dppoE_gA(4uc!jV&0!l7_;&p2^pxNo>PEcNJv za5_RT$o2Mf!<+r?&EbHH6nMoTsDOa;mN(wv8RNsHpG)`^ymG-S5By8=l9iVXzN_eG%Xg2@Xeq76tTZ*dGh~Lo9vl;Zfs+W#BydUw zCkZ$o1LqWQO$FC9aKlLl*7x9^0q%0}$OMlp@Kk_jHXOjofdePND+j!A{q!8~Jn+s3 z?~~w@4?egS02}8NuulUA=L~QQfm;MzCGd)XhiftT;+zFO&JVyp2mBww?;QByS_1w! zrQlx%{^cMj0|Bo1FjwY@Q8?Hx0cIPF*@-ZRFpPc#bBw{5@tD(5%sClzIfl8WU~V#u zm5Q;_F!wa$BSpqhN>W@2De?TKWR*!ujY;Yylk_X5#~V!L*Gw~;$%4Q8~Mad z@`-kG?yb$a9cHIApZDVZ^U6Xkp<*4rU82O7%}0jjHlK{id@?-wpN*fCHXyXh(bLt* zPc}H-x0e4E&nQ>y%B-(EL=9}RyC%MyX=upHuFhAk&MLbsF0LP-q`XnH78@fT+pKPW zu72MW`|?8ht^tz$iC}ZwLp4tB;Q49K!QCF3@!iB1qOI=?w z7In!}F~ij(18UYUjnbmC!qKhPo%24?8U1x{7o(+?^Zu0Hx81|FuS?bJ0jgBhEMzf< zCgUq7r2OCB(`XkKcN-TL>u5y#dD6D!)5W?`O5)V^>jb)P)GBdy%t$uUMpf$SNV31$ zb||OojAbvMP?T@$h_ZiFLFVHDmbyMhJF|-_)HX3%m=CDI+ID$0^C>kzxprBW)hw(v zr!Gmda);ICoQyhV_oP5+C%?jcG8v+D@9f?Dk*!BxY}dazmrT@64UrP3hlslANK)bq z$67n83eh}OeW&SV@HG95P|bjfqJ7gw$e+`Hxo!4cx`jdK1bJ>YDSpGKLPZ^1cv$ek zIB?0S<#tX?SJCLWdMd{-ME?$hc7A$zBOdIJ)4!KcAwb=VMov)nK;9z>x~rfT1>dS+ zZ6#`2v@`jgbqq)P22H)Tx2CpmM^o1$B+xT6`(v%5xJ(?j#>Q$+rx_R|7TzDZe{J6q zG1*EcU%tE?!kO%^M;3aM6JN*LAKUVb^xz8-Pxo#jR5(-KBeLJvA@-gxNHx0M-ZJLl z;#JwQoh~9V?`UVo#}{6ka@II>++D@%KqGpMdlQ}?9E*wFcf5(#XQnP$Dk5~%iX^>f z%$y;?M0BLp{O3a(-4A?ewryHrrD%cx#Q^%KY1H zNre$ve+vceSLZcNY4U(RBX&)oZn*Py()h)XkE?PL$!bNb{N5FVI2Y%LKEm%yvpyTP z(1P?z~7YxD~Rf<(a@_y` diff --git a/packages/dart_client/example/android/app/src/main/res/values-night/styles.xml b/packages/dart_client/example/android/app/src/main/res/values-night/styles.xml deleted file mode 100644 index 449a9f93..00000000 --- a/packages/dart_client/example/android/app/src/main/res/values-night/styles.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - diff --git a/packages/dart_client/example/android/app/src/main/res/values/styles.xml b/packages/dart_client/example/android/app/src/main/res/values/styles.xml deleted file mode 100644 index d74aa35c..00000000 --- a/packages/dart_client/example/android/app/src/main/res/values/styles.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - diff --git a/packages/dart_client/example/android/app/src/profile/AndroidManifest.xml b/packages/dart_client/example/android/app/src/profile/AndroidManifest.xml deleted file mode 100644 index f590dd7e..00000000 --- a/packages/dart_client/example/android/app/src/profile/AndroidManifest.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - diff --git a/packages/dart_client/example/android/build.gradle b/packages/dart_client/example/android/build.gradle deleted file mode 100644 index c505a863..00000000 --- a/packages/dart_client/example/android/build.gradle +++ /dev/null @@ -1,31 +0,0 @@ -buildscript { - ext.kotlin_version = '1.3.50' - repositories { - google() - jcenter() - } - - dependencies { - classpath 'com.android.tools.build:gradle:4.1.0' - classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" - } -} - -allprojects { - repositories { - google() - jcenter() - } -} - -rootProject.buildDir = '../build' -subprojects { - project.buildDir = "${rootProject.buildDir}/${project.name}" -} -subprojects { - project.evaluationDependsOn(':app') -} - -task clean(type: Delete) { - delete rootProject.buildDir -} diff --git a/packages/dart_client/example/android/gradle.properties b/packages/dart_client/example/android/gradle.properties deleted file mode 100644 index 94adc3a3..00000000 --- a/packages/dart_client/example/android/gradle.properties +++ /dev/null @@ -1,3 +0,0 @@ -org.gradle.jvmargs=-Xmx1536M -android.useAndroidX=true -android.enableJetifier=true diff --git a/packages/dart_client/example/android/gradle/wrapper/gradle-wrapper.properties b/packages/dart_client/example/android/gradle/wrapper/gradle-wrapper.properties deleted file mode 100644 index bc6a58af..00000000 --- a/packages/dart_client/example/android/gradle/wrapper/gradle-wrapper.properties +++ /dev/null @@ -1,6 +0,0 @@ -#Fri Jun 23 08:50:38 CEST 2017 -distributionBase=GRADLE_USER_HOME -distributionPath=wrapper/dists -zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.7-all.zip diff --git a/packages/dart_client/example/android/settings.gradle b/packages/dart_client/example/android/settings.gradle deleted file mode 100644 index 44e62bcf..00000000 --- a/packages/dart_client/example/android/settings.gradle +++ /dev/null @@ -1,11 +0,0 @@ -include ':app' - -def localPropertiesFile = new File(rootProject.projectDir, "local.properties") -def properties = new Properties() - -assert localPropertiesFile.exists() -localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) } - -def flutterSdkPath = properties.getProperty("flutter.sdk") -assert flutterSdkPath != null, "flutter.sdk not set in local.properties" -apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle" diff --git a/packages/dart_client/example/ios/.gitignore b/packages/dart_client/example/ios/.gitignore deleted file mode 100644 index e96ef602..00000000 --- a/packages/dart_client/example/ios/.gitignore +++ /dev/null @@ -1,32 +0,0 @@ -*.mode1v3 -*.mode2v3 -*.moved-aside -*.pbxuser -*.perspectivev3 -**/*sync/ -.sconsign.dblite -.tags* -**/.vagrant/ -**/DerivedData/ -Icon? -**/Pods/ -**/.symlinks/ -profile -xcuserdata -**/.generated/ -Flutter/App.framework -Flutter/Flutter.framework -Flutter/Flutter.podspec -Flutter/Generated.xcconfig -Flutter/app.flx -Flutter/app.zip -Flutter/flutter_assets/ -Flutter/flutter_export_environment.sh -ServiceDefinitions.json -Runner/GeneratedPluginRegistrant.* - -# Exceptions to above rules. -!default.mode1v3 -!default.mode2v3 -!default.pbxuser -!default.perspectivev3 diff --git a/packages/dart_client/example/ios/Flutter/AppFrameworkInfo.plist b/packages/dart_client/example/ios/Flutter/AppFrameworkInfo.plist deleted file mode 100644 index 9367d483..00000000 --- a/packages/dart_client/example/ios/Flutter/AppFrameworkInfo.plist +++ /dev/null @@ -1,26 +0,0 @@ - - - - - CFBundleDevelopmentRegion - en - CFBundleExecutable - App - CFBundleIdentifier - io.flutter.flutter.app - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - App - CFBundlePackageType - FMWK - CFBundleShortVersionString - 1.0 - CFBundleSignature - ???? - CFBundleVersion - 1.0 - MinimumOSVersion - 8.0 - - diff --git a/packages/dart_client/example/ios/Flutter/Debug.xcconfig b/packages/dart_client/example/ios/Flutter/Debug.xcconfig deleted file mode 100644 index e8efba11..00000000 --- a/packages/dart_client/example/ios/Flutter/Debug.xcconfig +++ /dev/null @@ -1,2 +0,0 @@ -#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" -#include "Generated.xcconfig" diff --git a/packages/dart_client/example/ios/Flutter/Release.xcconfig b/packages/dart_client/example/ios/Flutter/Release.xcconfig deleted file mode 100644 index 399e9340..00000000 --- a/packages/dart_client/example/ios/Flutter/Release.xcconfig +++ /dev/null @@ -1,2 +0,0 @@ -#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" -#include "Generated.xcconfig" diff --git a/packages/dart_client/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/packages/dart_client/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata deleted file mode 100644 index 1d526a16..00000000 --- a/packages/dart_client/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata +++ /dev/null @@ -1,7 +0,0 @@ - - - - - diff --git a/packages/dart_client/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/packages/dart_client/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist deleted file mode 100644 index 18d98100..00000000 --- a/packages/dart_client/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +++ /dev/null @@ -1,8 +0,0 @@ - - - - - IDEDidComputeMac32BitWarning - - - diff --git a/packages/dart_client/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/packages/dart_client/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings deleted file mode 100644 index f9b0d7c5..00000000 --- a/packages/dart_client/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings +++ /dev/null @@ -1,8 +0,0 @@ - - - - - PreviewsEnabled - - - diff --git a/packages/dart_client/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/packages/dart_client/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme deleted file mode 100644 index a28140cf..00000000 --- a/packages/dart_client/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ /dev/null @@ -1,91 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/packages/dart_client/example/ios/Runner.xcworkspace/contents.xcworkspacedata b/packages/dart_client/example/ios/Runner.xcworkspace/contents.xcworkspacedata deleted file mode 100644 index 21a3cc14..00000000 --- a/packages/dart_client/example/ios/Runner.xcworkspace/contents.xcworkspacedata +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - diff --git a/packages/dart_client/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/packages/dart_client/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist deleted file mode 100644 index 18d98100..00000000 --- a/packages/dart_client/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +++ /dev/null @@ -1,8 +0,0 @@ - - - - - IDEDidComputeMac32BitWarning - - - diff --git a/packages/dart_client/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/packages/dart_client/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings deleted file mode 100644 index f9b0d7c5..00000000 --- a/packages/dart_client/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings +++ /dev/null @@ -1,8 +0,0 @@ - - - - - PreviewsEnabled - - - diff --git a/packages/dart_client/example/ios/Runner/AppDelegate.swift b/packages/dart_client/example/ios/Runner/AppDelegate.swift deleted file mode 100644 index 70693e4a..00000000 --- a/packages/dart_client/example/ios/Runner/AppDelegate.swift +++ /dev/null @@ -1,13 +0,0 @@ -import UIKit -import Flutter - -@UIApplicationMain -@objc class AppDelegate: FlutterAppDelegate { - override func application( - _ application: UIApplication, - didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? - ) -> Bool { - GeneratedPluginRegistrant.register(with: self) - return super.application(application, didFinishLaunchingWithOptions: launchOptions) - } -} diff --git a/packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json deleted file mode 100644 index d36b1fab..00000000 --- a/packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json +++ /dev/null @@ -1,122 +0,0 @@ -{ - "images" : [ - { - "size" : "20x20", - "idiom" : "iphone", - "filename" : "Icon-App-20x20@2x.png", - "scale" : "2x" - }, - { - "size" : "20x20", - "idiom" : "iphone", - "filename" : "Icon-App-20x20@3x.png", - "scale" : "3x" - }, - { - "size" : "29x29", - "idiom" : "iphone", - "filename" : "Icon-App-29x29@1x.png", - "scale" : "1x" - }, - { - "size" : "29x29", - "idiom" : "iphone", - "filename" : "Icon-App-29x29@2x.png", - "scale" : "2x" - }, - { - "size" : "29x29", - "idiom" : "iphone", - "filename" : "Icon-App-29x29@3x.png", - "scale" : "3x" - }, - { - "size" : "40x40", - "idiom" : "iphone", - "filename" : "Icon-App-40x40@2x.png", - "scale" : "2x" - }, - { - "size" : "40x40", - "idiom" : "iphone", - "filename" : "Icon-App-40x40@3x.png", - "scale" : "3x" - }, - { - "size" : "60x60", - "idiom" : "iphone", - "filename" : "Icon-App-60x60@2x.png", - "scale" : "2x" - }, - { - "size" : "60x60", - "idiom" : "iphone", - "filename" : "Icon-App-60x60@3x.png", - "scale" : "3x" - }, - { - "size" : "20x20", - "idiom" : "ipad", - "filename" : "Icon-App-20x20@1x.png", - "scale" : "1x" - }, - { - "size" : "20x20", - "idiom" : "ipad", - "filename" : "Icon-App-20x20@2x.png", - "scale" : "2x" - }, - { - "size" : "29x29", - "idiom" : "ipad", - "filename" : "Icon-App-29x29@1x.png", - "scale" : "1x" - }, - { - "size" : "29x29", - "idiom" : "ipad", - "filename" : "Icon-App-29x29@2x.png", - "scale" : "2x" - }, - { - "size" : "40x40", - "idiom" : "ipad", - "filename" : "Icon-App-40x40@1x.png", - "scale" : "1x" - }, - { - "size" : "40x40", - "idiom" : "ipad", - "filename" : "Icon-App-40x40@2x.png", - "scale" : "2x" - }, - { - "size" : "76x76", - "idiom" : "ipad", - "filename" : "Icon-App-76x76@1x.png", - "scale" : "1x" - }, - { - "size" : "76x76", - "idiom" : "ipad", - "filename" : "Icon-App-76x76@2x.png", - "scale" : "2x" - }, - { - "size" : "83.5x83.5", - "idiom" : "ipad", - "filename" : "Icon-App-83.5x83.5@2x.png", - "scale" : "2x" - }, - { - "size" : "1024x1024", - "idiom" : "ios-marketing", - "filename" : "Icon-App-1024x1024@1x.png", - "scale" : "1x" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} diff --git a/packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png b/packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png deleted file mode 100644 index dc9ada4725e9b0ddb1deab583e5b5102493aa332..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10932 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 diff --git a/packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png deleted file mode 100644 index f091b6b0bca859a3f474b03065bef75ba58a9e4c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1588 zcmV-42Fv-0P)C1SqPt}wig>|5Crh^=oyX$BK<}M8eLU3e2hGT;=G|!_SP)7zNI6fqUMB=)y zRAZ>eDe#*r`yDAVgB_R*LB*MAc)8(b{g{9McCXW!lq7r(btRoB9!8B-#AI6JMb~YFBEvdsV)`mEQO^&#eRKx@b&x- z5lZm*!WfD8oCLzfHGz#u7sT0^VLMI1MqGxF^v+`4YYnVYgk*=kU?HsSz{v({E3lb9 z>+xILjBN)t6`=g~IBOelGQ(O990@BfXf(DRI5I$qN$0Gkz-FSc$3a+2fX$AedL4u{ z4V+5Ong(9LiGcIKW?_352sR;LtDPmPJXI{YtT=O8=76o9;*n%_m|xo!i>7$IrZ-{l z-x3`7M}qzHsPV@$v#>H-TpjDh2UE$9g6sysUREDy_R(a)>=eHw-WAyfIN z*qb!_hW>G)Tu8nSw9yn#3wFMiLcfc4pY0ek1}8(NqkBR@t4{~oC>ryc-h_ByH(Cg5 z>ao-}771+xE3um9lWAY1FeQFxowa1(!J(;Jg*wrg!=6FdRX+t_<%z&d&?|Bn){>zm zZQj(aA_HeBY&OC^jj*)N`8fa^ePOU72VpInJoI1?`ty#lvlNzs(&MZX+R%2xS~5Kh zX*|AU4QE#~SgPzOXe9>tRj>hjU@c1k5Y_mW*Jp3fI;)1&g3j|zDgC+}2Q_v%YfDax z!?umcN^n}KYQ|a$Lr+51Nf9dkkYFSjZZjkma$0KOj+;aQ&721~t7QUKx61J3(P4P1 zstI~7-wOACnWP4=8oGOwz%vNDqD8w&Q`qcNGGrbbf&0s9L0De{4{mRS?o0MU+nR_! zrvshUau0G^DeMhM_v{5BuLjb#Hh@r23lDAk8oF(C+P0rsBpv85EP>4CVMx#04MOfG z;P%vktHcXwTj~+IE(~px)3*MY77e}p#|c>TD?sMatC0Tu4iKKJ0(X8jxQY*gYtxsC z(zYC$g|@+I+kY;dg_dE>scBf&bP1Nc@Hz<3R)V`=AGkc;8CXqdi=B4l2k|g;2%#m& z*jfX^%b!A8#bI!j9-0Fi0bOXl(-c^AB9|nQaE`*)Hw+o&jS9@7&Gov#HbD~#d{twV zXd^Tr^mWLfFh$@Dr$e;PBEz4(-2q1FF0}c;~B5sA}+Q>TOoP+t>wf)V9Iy=5ruQa;z)y zI9C9*oUga6=hxw6QasLPnee@3^Rr*M{CdaL5=R41nLs(AHk_=Y+A9$2&H(B7!_pURs&8aNw7?`&Z&xY_Ye z)~D5Bog^td-^QbUtkTirdyK^mTHAOuptDflut!#^lnKqU md>ggs(5nOWAqO?umG&QVYK#ibz}*4>0000U6E9hRK9^#O7(mu>ETqrXGsduA8$)?`v2seloOCza43C{NQ$$gAOH**MCn0Q?+L7dl7qnbRdqZ8LSVp1ItDxhxD?t@5_yHg6A8yI zC*%Wgg22K|8E#!~cTNYR~@Y9KepMPrrB8cABapAFa=`H+UGhkXUZV1GnwR1*lPyZ;*K(i~2gp|@bzp8}og7e*#% zEnr|^CWdVV!-4*Y_7rFvlww2Ze+>j*!Z!pQ?2l->4q#nqRu9`ELo6RMS5=br47g_X zRw}P9a7RRYQ%2Vsd0Me{_(EggTnuN6j=-?uFS6j^u69elMypu?t>op*wBx<=Wx8?( ztpe^(fwM6jJX7M-l*k3kEpWOl_Vk3@(_w4oc}4YF4|Rt=2V^XU?#Yz`8(e?aZ@#li0n*=g^qOcVpd-Wbok=@b#Yw zqn8u9a)z>l(1kEaPYZ6hwubN6i<8QHgsu0oE) ziJ(p;Wxm>sf!K+cw>R-(^Y2_bahB+&KI9y^);#0qt}t-$C|Bo71lHi{_+lg#f%RFy z0um=e3$K3i6K{U_4K!EX?F&rExl^W|G8Z8;`5z-k}OGNZ0#WVb$WCpQu-_YsiqKP?BB# vzVHS-CTUF4Ozn5G+mq_~Qqto~ahA+K`|lyv3(-e}00000NkvXXu0mjfd`9t{ diff --git a/packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png deleted file mode 100644 index d0ef06e7edb86cdfe0d15b4b0d98334a86163658..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1716 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 diff --git a/packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png deleted file mode 100644 index c8f9ed8f5cee1c98386d13b17e89f719e83555b2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1895 zcmV-t2blPYP)FQtfgmafE#=YDCq`qUBt#QpG%*H6QHY765~R=q zZ6iudfM}q!Pz#~9JgOi8QJ|DSu?1-*(kSi1K4#~5?#|rh?sS)(-JQqX*}ciXJ56_H zdw=^s_srbAdqxlvGyrgGet#6T7_|j;95sL%MtM;q86vOxKM$f#puR)Bjv9Zvz9-di zXOTSsZkM83)E9PYBXC<$6(|>lNLVBb&&6y{NByFCp%6+^ALR@NCTse_wqvNmSWI-m z!$%KlHFH2omF!>#%1l3LTZg(s7eof$7*xB)ZQ0h?ejh?Ta9fDv59+u#MokW+1t8Zb zgHv%K(u9G^Lv`lh#f3<6!JVTL3(dCpxHbnbA;kKqQyd1~^Xe0VIaYBSWm6nsr;dFj z4;G-RyL?cYgsN1{L4ZFFNa;8)Rv0fM0C(~Tkit94 zz#~A)59?QjD&pAPSEQ)p8gP|DS{ng)j=2ux)_EzzJ773GmQ_Cic%3JJhC0t2cx>|v zJcVusIB!%F90{+}8hG3QU4KNeKmK%T>mN57NnCZ^56=0?&3@!j>a>B43pi{!u z7JyDj7`6d)qVp^R=%j>UIY6f+3`+qzIc!Y_=+uN^3BYV|o+$vGo-j-Wm<10%A=(Yk^beI{t%ld@yhKjq0iNjqN4XMGgQtbKubPM$JWBz}YA65k%dm*awtC^+f;a-x4+ddbH^7iDWGg&N0n#MW{kA|=8iMUiFYvMoDY@sPC#t$55gn6ykUTPAr`a@!(;np824>2xJthS z*ZdmT`g5-`BuJs`0LVhz+D9NNa3<=6m;cQLaF?tCv8)zcRSh66*Z|vXhG@$I%U~2l z?`Q zykI#*+rQ=z6Jm=Bui-SfpDYLA=|vzGE(dYm=OC8XM&MDo7ux4UF1~0J1+i%aCUpRe zt3L_uNyQ*cE(38Uy03H%I*)*Bh=Lb^Xj3?I^Hnbeq72(EOK^Y93CNp*uAA{5Lc=ky zx=~RKa4{iTm{_>_vSCm?$Ej=i6@=m%@VvAITnigVg{&@!7CDgs908761meDK5azA} z4?=NOH|PdvabgJ&fW2{Mo$Q0CcD8Qc84%{JPYt5EiG{MdLIAeX%T=D7NIP4%Hw}p9 zg)==!2Lbp#j{u_}hMiao9=!VSyx0gHbeCS`;q&vzeq|fs`y&^X-lso(Ls@-706qmA z7u*T5PMo_w3{se1t2`zWeO^hOvTsohG_;>J0wVqVe+n)AbQCx)yh9;w+J6?NF5Lmo zecS@ieAKL8%bVd@+-KT{yI|S}O>pYckUFs;ry9Ow$CD@ztz5K-*D$^{i(_1llhSh^ zEkL$}tsQt5>QA^;QgjgIfBDmcOgi5YDyu?t6vSnbp=1+@6D& z5MJ}B8q;bRlVoxasyhcUF1+)o`&3r0colr}QJ3hcSdLu;9;td>kf@Tcn<@9sIx&=m z;AD;SCh95=&p;$r{Xz3iWCO^MX83AGJ(yH&eTXgv|0=34#-&WAmw{)U7OU9!Wz^!7 zZ%jZFi@JR;>Mhi7S>V7wQ176|FdW2m?&`qa(ScO^CFPR80HucLHOTy%5s*HR0^8)i h0WYBP*#0Ks^FNSabJA*5${_#%002ovPDHLkV1oKhTl@e3 diff --git a/packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png deleted file mode 100644 index a6d6b8609df07bf62e5100a53a01510388bd2b22..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2665 zcmV-v3YPVWP)oFh3q0MFesq&64WThn3$;G69TfjsAv=f2G9}p zgSx99+!YV6qME!>9MD13x)k(+XE7W?_O4LoLb5ND8 zaV{9+P@>42xDfRiYBMSgD$0!vssptcb;&?u9u(LLBKmkZ>RMD=kvD3h`sk6!QYtBa ztlZI#nu$8lJ^q2Z79UTgZe>BU73(Aospiq+?SdMt8lDZ;*?@tyWVZVS_Q7S&*tJaiRlJ z+aSMOmbg3@h5}v;A*c8SbqM3icg-`Cnwl;7Ts%A1RkNIp+Txl-Ckkvg4oxrqGA5ewEgYqwtECD<_3Egu)xGllKt&J8g&+=ac@Jq4-?w6M3b*>w5 z69N3O%=I^6&UL5gZ!}trC7bUj*12xLdkNs~Bz4QdJJ*UDZox2UGR}SNg@lmOvhCc~ z*f_UeXv(=#I#*7>VZx2ObEN~UoGUTl=-@)E;YtCRZ>SVp$p9yG5hEFZ!`wI!spd)n zSk+vK0Vin7FL{7f&6OB%f;SH22dtbcF<|9fi2Fp%q4kxL!b1#l^)8dUwJ zwEf{(wJj@8iYDVnKB`eSU+;ml-t2`@%_)0jDM`+a46xhDbBj2+&Ih>1A>6aky#(-SYyE{R3f#y57wfLs z6w1p~$bp;6!9DX$M+J~S@D6vJAaElETnsX4h9a5tvPhC3L@qB~bOzkL@^z0k_hS{T4PF*TDrgdXp+dzsE? z>V|VR035Pl9n5&-RePFdS{7KAr2vPOqR9=M$vXA1Yy5>w;EsF`;OK{2pkn-kpp9Pw z)r;5JfJKKaT$4qCb{TaXHjb$QA{y0EYy*+b1XI;6Ah- zw13P)xT`>~eFoJC!>{2XL(a_#upp3gaR1#5+L(Jmzp4TBnx{~WHedpJ1ch8JFk~Sw z>F+gN+i+VD?gMXwcIhn8rz`>e>J^TI3E-MW>f}6R-pL}>WMOa0k#jN+`RyUVUC;#D zg|~oS^$6%wpF{^Qr+}X>0PKcr3Fc&>Z>uv@C);pwDs@2bZWhYP!rvGx?_|q{d`t<*XEb#=aOb=N+L@CVBGqImZf&+a zCQEa3$~@#kC);pasdG=f6tuIi0PO-y&tvX%>Mv=oY3U$nD zJ#gMegnQ46pq+3r=;zmgcG+zRc9D~c>z+jo9&D+`E6$LmyFqlmCYw;-Zooma{sR@~ z)_^|YL1&&@|GXo*pivH7k!msl+$Sew3%XJnxajt0K%3M6Bd&YFNy9}tWG^aovK2eX z1aL1%7;KRDrA@eG-Wr6w+;*H_VD~qLiVI`{_;>o)k`{8xa3EJT1O_>#iy_?va0eR? zDV=N%;Zjb%Z2s$@O>w@iqt!I}tLjGk!=p`D23I}N4Be@$(|iSA zf3Ih7b<{zqpDB4WF_5X1(peKe+rASze%u8eKLn#KKXt;UZ+Adf$_TO+vTqshLLJ5c z52HucO=lrNVae5XWOLm!V@n-ObU11!b+DN<$RuU+YsrBq*lYT;?AwJpmNKniF0Q1< zJCo>Q$=v$@&y=sj6{r!Y&y&`0$-I}S!H_~pI&2H8Z1C|BX4VgZ^-! zje3-;x0PBD!M`v*J_)rL^+$<1VJhH*2Fi~aA7s&@_rUHYJ9zD=M%4AFQ`}k8OC$9s XsPq=LnkwKG00000NkvXXu0mjfhAk5^ diff --git a/packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png deleted file mode 100644 index a6d6b8609df07bf62e5100a53a01510388bd2b22..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2665 zcmV-v3YPVWP)oFh3q0MFesq&64WThn3$;G69TfjsAv=f2G9}p zgSx99+!YV6qME!>9MD13x)k(+XE7W?_O4LoLb5ND8 zaV{9+P@>42xDfRiYBMSgD$0!vssptcb;&?u9u(LLBKmkZ>RMD=kvD3h`sk6!QYtBa ztlZI#nu$8lJ^q2Z79UTgZe>BU73(Aospiq+?SdMt8lDZ;*?@tyWVZVS_Q7S&*tJaiRlJ z+aSMOmbg3@h5}v;A*c8SbqM3icg-`Cnwl;7Ts%A1RkNIp+Txl-Ckkvg4oxrqGA5ewEgYqwtECD<_3Egu)xGllKt&J8g&+=ac@Jq4-?w6M3b*>w5 z69N3O%=I^6&UL5gZ!}trC7bUj*12xLdkNs~Bz4QdJJ*UDZox2UGR}SNg@lmOvhCc~ z*f_UeXv(=#I#*7>VZx2ObEN~UoGUTl=-@)E;YtCRZ>SVp$p9yG5hEFZ!`wI!spd)n zSk+vK0Vin7FL{7f&6OB%f;SH22dtbcF<|9fi2Fp%q4kxL!b1#l^)8dUwJ zwEf{(wJj@8iYDVnKB`eSU+;ml-t2`@%_)0jDM`+a46xhDbBj2+&Ih>1A>6aky#(-SYyE{R3f#y57wfLs z6w1p~$bp;6!9DX$M+J~S@D6vJAaElETnsX4h9a5tvPhC3L@qB~bOzkL@^z0k_hS{T4PF*TDrgdXp+dzsE? z>V|VR035Pl9n5&-RePFdS{7KAr2vPOqR9=M$vXA1Yy5>w;EsF`;OK{2pkn-kpp9Pw z)r;5JfJKKaT$4qCb{TaXHjb$QA{y0EYy*+b1XI;6Ah- zw13P)xT`>~eFoJC!>{2XL(a_#upp3gaR1#5+L(Jmzp4TBnx{~WHedpJ1ch8JFk~Sw z>F+gN+i+VD?gMXwcIhn8rz`>e>J^TI3E-MW>f}6R-pL}>WMOa0k#jN+`RyUVUC;#D zg|~oS^$6%wpF{^Qr+}X>0PKcr3Fc&>Z>uv@C);pwDs@2bZWhYP!rvGx?_|q{d`t<*XEb#=aOb=N+L@CVBGqImZf&+a zCQEa3$~@#kC);pasdG=f6tuIi0PO-y&tvX%>Mv=oY3U$nD zJ#gMegnQ46pq+3r=;zmgcG+zRc9D~c>z+jo9&D+`E6$LmyFqlmCYw;-Zooma{sR@~ z)_^|YL1&&@|GXo*pivH7k!msl+$Sew3%XJnxajt0K%3M6Bd&YFNy9}tWG^aovK2eX z1aL1%7;KRDrA@eG-Wr6w+;*H_VD~qLiVI`{_;>o)k`{8xa3EJT1O_>#iy_?va0eR? zDV=N%;Zjb%Z2s$@O>w@iqt!I}tLjGk!=p`D23I}N4Be@$(|iSA zf3Ih7b<{zqpDB4WF_5X1(peKe+rASze%u8eKLn#KKXt;UZ+Adf$_TO+vTqshLLJ5c z52HucO=lrNVae5XWOLm!V@n-ObU11!b+DN<$RuU+YsrBq*lYT;?AwJpmNKniF0Q1< zJCo>Q$=v$@&y=sj6{r!Y&y&`0$-I}S!H_~pI&2H8Z1C|BX4VgZ^-! zje3-;x0PBD!M`v*J_)rL^+$<1VJhH*2Fi~aA7s&@_rUHYJ9zD=M%4AFQ`}k8OC$9s XsPq=LnkwKG00000NkvXXu0mjfhAk5^ diff --git a/packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png deleted file mode 100644 index 75b2d164a5a98e212cca15ea7bf2ab5de5108680..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3831 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 diff --git a/packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png deleted file mode 100644 index c4df70d39da7941ef3f6dcb7f06a192d8dcb308d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1888 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 iW8Zci7-kcv6Uzs@r-FtIZ-&5|)J Q1PU{Fy85}Sb4q9e0B4a5jsO4v diff --git a/packages/dart_client/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png b/packages/dart_client/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png deleted file mode 100644 index 9da19eacad3b03bb08bbddbbf4ac48dd78b3d838..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 68 zcmeAS@N?(olHy`uVBq!ia0vp^j3CUx0wlM}@Gt=>Zci7-kcv6Uzs@r-FtIZ-&5|)J Q1PU{Fy85}Sb4q9e0B4a5jsO4v diff --git a/packages/dart_client/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png b/packages/dart_client/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png deleted file mode 100644 index 9da19eacad3b03bb08bbddbbf4ac48dd78b3d838..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 68 zcmeAS@N?(olHy`uVBq!ia0vp^j3CUx0wlM}@Gt=>Zci7-kcv6Uzs@r-FtIZ-&5|)J Q1PU{Fy85}Sb4q9e0B4a5jsO4v diff --git a/packages/dart_client/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md b/packages/dart_client/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md deleted file mode 100644 index 89c2725b..00000000 --- a/packages/dart_client/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md +++ /dev/null @@ -1,5 +0,0 @@ -# Launch Screen Assets - -You can customize the launch screen with your own desired assets by replacing the image files in this directory. - -You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images. \ No newline at end of file diff --git a/packages/dart_client/example/ios/Runner/Base.lproj/LaunchScreen.storyboard b/packages/dart_client/example/ios/Runner/Base.lproj/LaunchScreen.storyboard deleted file mode 100644 index f2e259c7..00000000 --- a/packages/dart_client/example/ios/Runner/Base.lproj/LaunchScreen.storyboard +++ /dev/null @@ -1,37 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/packages/dart_client/example/ios/Runner/Base.lproj/Main.storyboard b/packages/dart_client/example/ios/Runner/Base.lproj/Main.storyboard deleted file mode 100644 index f3c28516..00000000 --- a/packages/dart_client/example/ios/Runner/Base.lproj/Main.storyboard +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/packages/dart_client/example/ios/Runner/Info.plist b/packages/dart_client/example/ios/Runner/Info.plist deleted file mode 100644 index 816fd9f3..00000000 --- a/packages/dart_client/example/ios/Runner/Info.plist +++ /dev/null @@ -1,45 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - stream_chat_dart_example - CFBundlePackageType - APPL - CFBundleShortVersionString - $(FLUTTER_BUILD_NAME) - CFBundleSignature - ???? - CFBundleVersion - $(FLUTTER_BUILD_NUMBER) - LSRequiresIPhoneOS - - UILaunchStoryboardName - LaunchScreen - UIMainStoryboardFile - Main - UISupportedInterfaceOrientations - - UIInterfaceOrientationPortrait - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - UISupportedInterfaceOrientations~ipad - - UIInterfaceOrientationPortrait - UIInterfaceOrientationPortraitUpsideDown - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - UIViewControllerBasedStatusBarAppearance - - - diff --git a/packages/dart_client/example/ios/Runner/Runner-Bridging-Header.h b/packages/dart_client/example/ios/Runner/Runner-Bridging-Header.h deleted file mode 100644 index 308a2a56..00000000 --- a/packages/dart_client/example/ios/Runner/Runner-Bridging-Header.h +++ /dev/null @@ -1 +0,0 @@ -#import "GeneratedPluginRegistrant.h" diff --git a/packages/dart_client/example/lib/main.dart b/packages/dart_client/example/lib/main.dart deleted file mode 100644 index 8f68c100..00000000 --- a/packages/dart_client/example/lib/main.dart +++ /dev/null @@ -1,248 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:stream_chat/stream_chat.dart'; - -Future main() async { - /// Create a new instance of [Client] passing the apikey obtained from your - /// project dashboard. - final client = Client('b67pax5b2wdq'); - - /// Set the current user. In a production scenario, this should be done using - /// a backend to generate a user token using our server SDK. - /// Please see the following for more information: - /// https://getstream.io/chat/docs/ios_user_setup_and_tokens/ - await client.setUser( - User( - id: 'cool-shadow-7', - extraData: { - 'image': - 'https://getstream.io/random_png/?id=cool-shadow-7&name=Cool+shadow', - }, - ), - 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoiY29vbC1zaGFkb3ctNyJ9.gkOlCRb1qgy4joHPaxFwPOdXcGvSPvp6QY0S4mpRkVo', - ); - - /// Creates a channel using the type `messaging` and `godevs`. - /// Channels are containers for holding messages between different members. To - /// learn more about channels and some of our predefined types, checkout our - /// our channel docs: https://getstream.io/chat/docs/initialize_channel/?language=dart - final channel = client.channel('messaging', id: 'godevs'); - - /// `.watch()` is used to create and listen to the channel for updates. If the - /// channel already exists, it will simply listen for new events. - await channel.watch(); - - runApp( - StreamExample( - client: client, - channel: channel, - ), - ); -} - -/// Example using Stream's Low Level Dart client. -class StreamExample extends StatelessWidget { - /// To initialize this example, an instance of [client] and [channel] is required. - const StreamExample({ - Key key, - @required this.client, - @required this.channel, - }) : super(key: key); - - /// Instance of [Client] we created earlier. This contains information about - /// our application and connection state. - final Client client; - - /// The channel we'd like to observe and participate. - final Channel channel; - - @override - Widget build(BuildContext context) { - return MaterialApp( - title: 'Stream Chat Dart Example', - home: HomeScreen(channel: channel), - ); - } -} - -/// Main screen of our application. The layout is comprised of an [AppBar] -/// containing the channel name and a [MessageView] displaying recent messages. -class HomeScreen extends StatelessWidget { - /// [HomeScreen] is constructed using the [Channel] we defined earlier. - const HomeScreen({Key key, @required this.channel}) : super(key: key); - - /// Channel object containing the [Channel.id] we'd like to observe. - final Channel channel; - - @override - Widget build(BuildContext context) { - final messages = channel.state.channelStateStream; - return Scaffold( - appBar: AppBar( - title: Text('Channel: ${channel.id}'), - ), - body: SafeArea( - child: StreamBuilder( - stream: messages, - builder: ( - BuildContext context, - AsyncSnapshot snapshot, - ) { - if (snapshot.hasData && snapshot.data != null) { - return MessageView( - messages: snapshot.data.messages.reversed.toList(), - channel: channel, - ); - } else if (snapshot.hasError) { - return const Center( - child: Text( - 'There was an error loading messages. Please see logs.', - ), - ); - } - return const Center( - child: SizedBox( - width: 100.0, - height: 100.0, - child: CircularProgressIndicator(), - ), - ); - }, - ), - ), - ); - } -} - -/// UI used to display a list of recent messages and a [TextField] for sending -/// new messages. -class MessageView extends StatefulWidget { - /// Message takes the latest list of messages and the current channel. - const MessageView({ - Key key, - @required this.messages, - @required this.channel, - }) : super(key: key); - - /// List of messages sent in the given channel. - final List messages; - - /// Current channel being observed. - final Channel channel; - - @override - _MessageViewState createState() => _MessageViewState(); -} - -class _MessageViewState extends State { - TextEditingController _controller; - ScrollController _scrollController; - - List get _messages => widget.messages; - - @override - void initState() { - super.initState(); - _controller = TextEditingController(); - _scrollController = ScrollController(); - } - - @override - void dispose() { - _controller.dispose(); - _scrollController.dispose(); - super.dispose(); - } - - /// Convenience method for scrolling the list view when a new message is sent. - void _updateList() { - _scrollController.animateTo( - _scrollController.position.maxScrollExtent, - duration: const Duration(milliseconds: 200), - curve: Curves.easeOut, - ); - } - - @override - Widget build(BuildContext context) { - return Column( - children: [ - Expanded( - child: ListView.builder( - controller: _scrollController, - itemCount: _messages.length, - reverse: true, - itemBuilder: (BuildContext context, int index) { - final item = _messages[index]; - if (item.user.id == widget.channel.client.uid) { - return Align( - alignment: Alignment.centerRight, - child: Padding( - padding: const EdgeInsets.all(8.0), - child: Text(item.text), - ), - ); - } else { - return Align( - alignment: Alignment.centerLeft, - child: Padding( - padding: const EdgeInsets.all(8.0), - child: Text(item.text), - ), - ); - } - }, - ), - ), - Padding( - padding: const EdgeInsets.all(8.0), - child: Row( - children: [ - Expanded( - child: TextField( - controller: _controller, - decoration: const InputDecoration( - hintText: 'Enter your message', - ), - ), - ), - Material( - type: MaterialType.circle, - color: Colors.blue, - clipBehavior: Clip.hardEdge, - child: InkWell( - onTap: () async { - // We can send a new message by calling `sendMessage` on - // the current channel. After sending a message, the - // TextField is cleared and the list view is scrolled - // to show the new item. - if (_controller.value.text.isNotEmpty) { - await widget.channel.sendMessage( - Message(text: _controller.value.text), - ); - _controller.clear(); - _updateList(); - } - }, - child: const Padding( - padding: EdgeInsets.all(8.0), - child: Center( - child: Icon( - Icons.send, - color: Colors.white, - ), - ), - ), - ), - ) - ], - ), - ) - ], - ); - } -} - -/// Helper extension for quickly retrieving the current user id from a [Client]. -extension on Client { - String get uid => state.user.id; -} diff --git a/packages/dart_client/example/pubspec.yaml b/packages/dart_client/example/pubspec.yaml deleted file mode 100644 index 4d07128c..00000000 --- a/packages/dart_client/example/pubspec.yaml +++ /dev/null @@ -1,23 +0,0 @@ -name: stream_chat_dart_example -description: Example using Stream's LLC - -publish_to: 'none' -version: 1.0.0+1 - -environment: - sdk: ">=2.7.0 <3.0.0" - -dependencies: - flutter: - sdk: flutter - stream_chat: - path: ../ - -dev_dependencies: - flutter_test: - sdk: flutter - integration_test: - sdk: flutter - -flutter: - uses-material-design: true \ No newline at end of file diff --git a/packages/dart_client/example/web/favicon.png b/packages/dart_client/example/web/favicon.png deleted file mode 100644 index 8aaa46ac1ae21512746f852a42ba87e4165dfdd1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 917 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|I14-?iy0X7 zltGxWVyS%@P(fs7NJL45ua8x7ey(0(N`6wRUPW#JP&EUCO@$SZnVVXYs8ErclUHn2 zVXFjIVFhG^g!Ppaz)DK8ZIvQ?0~DO|i&7O#^-S~(l1AfjnEK zjFOT9D}DX)@^Za$W4-*MbbUihOG|wNBYh(yU7!lx;>x^|#0uTKVr7USFmqf|i<65o z3raHc^AtelCMM;Vme?vOfh>Xph&xL%(-1c06+^uR^q@XSM&D4+Kp$>4P^%3{)XKjo zGZknv$b36P8?Z_gF{nK@`XI}Z90TzwSQO}0J1!f2c(B=V`5aP@1P1a|PZ!4!3&Gl8 zTYqUsf!gYFyJnXpu0!n&N*SYAX-%d(5gVjrHJWqXQshj@!Zm{!01WsQrH~9=kTxW#6SvuapgMqt>$=j#%eyGrQzr zP{L-3gsMA^$I1&gsBAEL+vxi1*Igl=8#8`5?A-T5=z-sk46WA1IUT)AIZHx1rdUrf zVJrJn<74DDw`j)Ki#gt}mIT-Q`XRa2-jQXQoI%w`nb|XblvzK${ZzlV)m-XcwC(od z71_OEC5Bt9GEXosOXaPTYOia#R4ID2TiU~`zVMl08TV_C%DnU4^+HE>9(CE4D6?Fz oujB08i7adh9xk7*FX66dWH6F5TM;?E2b5PlUHx3vIVCg!0Dx9vYXATM diff --git a/packages/dart_client/example/web/icons/Icon-192.png b/packages/dart_client/example/web/icons/Icon-192.png deleted file mode 100644 index b749bfef07473333cf1dd31e9eed89862a5d52aa..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5292 zcmZ`-2T+sGz6~)*FVZ`aW+(v>MIm&M-g^@e2u-B-DoB?qO+b1Tq<5uCCv>ESfRum& zp%X;f!~1{tzL__3=gjVJ=j=J>+nMj%ncXj1Q(b|Ckbw{Y0FWpt%4y%$uD=Z*c-x~o zE;IoE;xa#7Ll5nj-e4CuXB&G*IM~D21rCP$*xLXAK8rIMCSHuSu%bL&S3)8YI~vyp@KBu9Ph7R_pvKQ@xv>NQ`dZp(u{Z8K3yOB zn7-AR+d2JkW)KiGx0hosml;+eCXp6+w%@STjFY*CJ?udJ64&{BCbuebcuH;}(($@@ znNlgBA@ZXB)mcl9nbX#F!f_5Z=W>0kh|UVWnf!At4V*LQP%*gPdCXd6P@J4Td;!Ur z<2ZLmwr(NG`u#gDEMP19UcSzRTL@HsK+PnIXbVBT@oHm53DZr?~V(0{rsalAfwgo zEh=GviaqkF;}F_5-yA!1u3!gxaR&Mj)hLuj5Q-N-@Lra{%<4ONja8pycD90&>yMB` zchhd>0CsH`^|&TstH-8+R`CfoWqmTTF_0?zDOY`E`b)cVi!$4xA@oO;SyOjJyP^_j zx^@Gdf+w|FW@DMdOi8=4+LJl$#@R&&=UM`)G!y%6ZzQLoSL%*KE8IO0~&5XYR9 z&N)?goEiWA(YoRfT{06&D6Yuu@Qt&XVbuW@COb;>SP9~aRc+z`m`80pB2o%`#{xD@ zI3RAlukL5L>px6b?QW1Ac_0>ew%NM!XB2(H+1Y3AJC?C?O`GGs`331Nd4ZvG~bMo{lh~GeL zSL|tT*fF-HXxXYtfu5z+T5Mx9OdP7J4g%@oeC2FaWO1D{=NvL|DNZ}GO?O3`+H*SI z=grGv=7dL{+oY0eJFGO!Qe(e2F?CHW(i!!XkGo2tUvsQ)I9ev`H&=;`N%Z{L zO?vV%rDv$y(@1Yj@xfr7Kzr<~0{^T8wM80xf7IGQF_S-2c0)0D6b0~yD7BsCy+(zL z#N~%&e4iAwi4F$&dI7x6cE|B{f@lY5epaDh=2-(4N05VO~A zQT3hanGy_&p+7Fb^I#ewGsjyCEUmSCaP6JDB*=_()FgQ(-pZ28-{qx~2foO4%pM9e z*_63RT8XjgiaWY|*xydf;8MKLd{HnfZ2kM%iq}fstImB-K6A79B~YoPVa@tYN@T_$ zea+9)<%?=Fl!kd(Y!G(-o}ko28hg2!MR-o5BEa_72uj7Mrc&{lRh3u2%Y=Xk9^-qa zBPWaD=2qcuJ&@Tf6ue&)4_V*45=zWk@Z}Q?f5)*z)-+E|-yC4fs5CE6L_PH3=zI8p z*Z3!it{1e5_^(sF*v=0{`U9C741&lub89gdhKp|Y8CeC{_{wYK-LSbp{h)b~9^j!s z7e?Y{Z3pZv0J)(VL=g>l;<}xk=T*O5YR|hg0eg4u98f2IrA-MY+StQIuK-(*J6TRR z|IM(%uI~?`wsfyO6Tgmsy1b3a)j6M&-jgUjVg+mP*oTKdHg?5E`!r`7AE_#?Fc)&a z08KCq>Gc=ne{PCbRvs6gVW|tKdcE1#7C4e`M|j$C5EYZ~Y=jUtc zj`+?p4ba3uy7><7wIokM79jPza``{Lx0)zGWg;FW1^NKY+GpEi=rHJ+fVRGfXO zPHV52k?jxei_!YYAw1HIz}y8ZMwdZqU%ESwMn7~t zdI5%B;U7RF=jzRz^NuY9nM)&<%M>x>0(e$GpU9th%rHiZsIT>_qp%V~ILlyt^V`=d z!1+DX@ah?RnB$X!0xpTA0}lN@9V-ePx>wQ?-xrJr^qDlw?#O(RsXeAvM%}rg0NT#t z!CsT;-vB=B87ShG`GwO;OEbeL;a}LIu=&@9cb~Rsx(ZPNQ!NT7H{@j0e(DiLea>QD zPmpe90gEKHEZ8oQ@6%E7k-Ptn#z)b9NbD@_GTxEhbS+}Bb74WUaRy{w;E|MgDAvHw zL)ycgM7mB?XVh^OzbC?LKFMotw3r@i&VdUV%^Efdib)3@soX%vWCbnOyt@Y4swW925@bt45y0HY3YI~BnnzZYrinFy;L?2D3BAL`UQ zEj))+f>H7~g8*VuWQ83EtGcx`hun$QvuurSMg3l4IP8Fe`#C|N6mbYJ=n;+}EQm;< z!!N=5j1aAr_uEnnzrEV%_E|JpTb#1p1*}5!Ce!R@d$EtMR~%9# zd;h8=QGT)KMW2IKu_fA_>p_und#-;Q)p%%l0XZOXQicfX8M~7?8}@U^ihu;mizj)t zgV7wk%n-UOb z#!P5q?Ex+*Kx@*p`o$q8FWL*E^$&1*!gpv?Za$YO~{BHeGY*5%4HXUKa_A~~^d z=E*gf6&+LFF^`j4$T~dR)%{I)T?>@Ma?D!gi9I^HqvjPc3-v~=qpX1Mne@*rzT&Xw zQ9DXsSV@PqpEJO-g4A&L{F&;K6W60D!_vs?Vx!?w27XbEuJJP&);)^+VF1nHqHBWu z^>kI$M9yfOY8~|hZ9WB!q-9u&mKhEcRjlf2nm_@s;0D#c|@ED7NZE% zzR;>P5B{o4fzlfsn3CkBK&`OSb-YNrqx@N#4CK!>bQ(V(D#9|l!e9(%sz~PYk@8zt zPN9oK78&-IL_F zhsk1$6p;GqFbtB^ZHHP+cjMvA0(LqlskbdYE_rda>gvQLTiqOQ1~*7lg%z*&p`Ry& zRcG^DbbPj_jOKHTr8uk^15Boj6>hA2S-QY(W-6!FIq8h$<>MI>PYYRenQDBamO#Fv zAH5&ImqKBDn0v5kb|8i0wFhUBJTpT!rB-`zK)^SNnRmLraZcPYK7b{I@+}wXVdW-{Ps17qdRA3JatEd?rPV z4@}(DAMf5EqXCr4-B+~H1P#;t@O}B)tIJ(W6$LrK&0plTmnPpb1TKn3?f?Kk``?D+ zQ!MFqOX7JbsXfQrz`-M@hq7xlfNz;_B{^wbpG8des56x(Q)H)5eLeDwCrVR}hzr~= zM{yXR6IM?kXxauLza#@#u?Y|o;904HCqF<8yT~~c-xyRc0-vxofnxG^(x%>bj5r}N zyFT+xnn-?B`ohA>{+ZZQem=*Xpqz{=j8i2TAC#x-m;;mo{{sLB_z(UoAqD=A#*juZ zCv=J~i*O8;F}A^Wf#+zx;~3B{57xtoxC&j^ie^?**T`WT2OPRtC`xj~+3Kprn=rVM zVJ|h5ux%S{dO}!mq93}P+h36mZ5aZg1-?vhL$ke1d52qIiXSE(llCr5i=QUS?LIjc zV$4q=-)aaR4wsrQv}^shL5u%6;`uiSEs<1nG^?$kl$^6DL z43CjY`M*p}ew}}3rXc7Xck@k41jx}c;NgEIhKZ*jsBRZUP-x2cm;F1<5$jefl|ppO zmZd%%?gMJ^g9=RZ^#8Mf5aWNVhjAS^|DQO+q$)oeob_&ZLFL(zur$)); zU19yRm)z<4&4-M}7!9+^Wl}Uk?`S$#V2%pQ*SIH5KI-mn%i;Z7-)m$mN9CnI$G7?# zo`zVrUwoSL&_dJ92YhX5TKqaRkfPgC4=Q&=K+;_aDs&OU0&{WFH}kKX6uNQC6%oUH z2DZa1s3%Vtk|bglbxep-w)PbFG!J17`<$g8lVhqD2w;Z0zGsh-r zxZ13G$G<48leNqR!DCVt9)@}(zMI5w6Wo=N zpP1*3DI;~h2WDWgcKn*f!+ORD)f$DZFwgKBafEZmeXQMAsq9sxP9A)7zOYnkHT9JU zRA`umgmP9d6=PHmFIgx=0$(sjb>+0CHG)K@cPG{IxaJ&Ueo8)0RWgV9+gO7+Bl1(F z7!BslJ2MP*PWJ;x)QXbR$6jEr5q3 z(3}F@YO_P1NyTdEXRLU6fp?9V2-S=E+YaeLL{Y)W%6`k7$(EW8EZSA*(+;e5@jgD^I zaJQ2|oCM1n!A&-8`;#RDcZyk*+RPkn_r8?Ak@agHiSp*qFNX)&i21HE?yuZ;-C<3C zwJGd1lx5UzViP7sZJ&|LqH*mryb}y|%AOw+v)yc`qM)03qyyrqhX?ub`Cjwx2PrR! z)_z>5*!*$x1=Qa-0uE7jy0z`>|Ni#X+uV|%_81F7)b+nf%iz=`fF4g5UfHS_?PHbr zB;0$bK@=di?f`dS(j{l3-tSCfp~zUuva+=EWxJcRfp(<$@vd(GigM&~vaYZ0c#BTs z3ijkxMl=vw5AS&DcXQ%eeKt!uKvh2l3W?&3=dBHU=Gz?O!40S&&~ei2vg**c$o;i89~6DVns zG>9a*`k5)NI9|?W!@9>rzJ;9EJ=YlJTx1r1BA?H`LWijk(rTax9(OAu;q4_wTj-yj z1%W4GW&K4T=uEGb+E!>W0SD_C0RR91 diff --git a/packages/dart_client/example/web/icons/Icon-512.png b/packages/dart_client/example/web/icons/Icon-512.png deleted file mode 100644 index 88cfd48dff1169879ba46840804b412fe02fefd6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8252 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 diff --git a/packages/dart_client/example/web/index.html b/packages/dart_client/example/web/index.html deleted file mode 100644 index 6f6d6461..00000000 --- a/packages/dart_client/example/web/index.html +++ /dev/null @@ -1,45 +0,0 @@ - - - - - - - - - - - - - - - - - - - - stream_chat_dart_example - - - - - - - - diff --git a/packages/dart_client/example/web/manifest.json b/packages/dart_client/example/web/manifest.json deleted file mode 100644 index 5ee3b42d..00000000 --- a/packages/dart_client/example/web/manifest.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "name": "stream_chat_dart_example", - "short_name": "stream_chat_dart_example", - "start_url": ".", - "display": "standalone", - "background_color": "#0175C2", - "theme_color": "#0175C2", - "description": "Example using Stream's LLC", - "orientation": "portrait-primary", - "prefer_related_applications": false, - "icons": [ - { - "src": "icons/Icon-192.png", - "sizes": "192x192", - "type": "image/png" - }, - { - "src": "icons/Icon-512.png", - "sizes": "512x512", - "type": "image/png" - } - ] -} From e27f3f8de15792ab05f6136d57f1df01efbead57 Mon Sep 17 00:00:00 2001 From: Neevash Ramdial Date: Thu, 21 Jan 2021 06:35:10 -0400 Subject: [PATCH 0993/1140] reinialize LLC example --- packages/dart_client/example/.gitignore | 41 +++ packages/dart_client/example/.metadata | 10 + packages/dart_client/example/README.md | 2 + .../dart_client/example/android/.gitignore | 11 + .../example/android/app/build.gradle | 63 +++++ .../android/app/src/debug/AndroidManifest.xml | 7 + .../android/app/src/main/AndroidManifest.xml | 47 ++++ .../com/example/example/MainActivity.kt | 6 + .../main/res/drawable/launch_background.xml | 12 + .../src/main/res/mipmap-hdpi/ic_launcher.png | Bin 0 -> 544 bytes .../src/main/res/mipmap-mdpi/ic_launcher.png | Bin 0 -> 442 bytes .../src/main/res/mipmap-xhdpi/ic_launcher.png | Bin 0 -> 721 bytes .../main/res/mipmap-xxhdpi/ic_launcher.png | Bin 0 -> 1031 bytes .../main/res/mipmap-xxxhdpi/ic_launcher.png | Bin 0 -> 1443 bytes .../app/src/main/res/values/styles.xml | 18 ++ .../app/src/profile/AndroidManifest.xml | 7 + .../dart_client/example/android/build.gradle | 31 +++ .../example/android/gradle.properties | 3 + .../gradle/wrapper/gradle-wrapper.properties | 6 + .../example/android/settings.gradle | 11 + packages/dart_client/example/ios/.gitignore | 32 +++ .../ios/Flutter/AppFrameworkInfo.plist | 26 ++ .../example/ios/Flutter/Debug.xcconfig | 1 + .../example/ios/Flutter/Release.xcconfig | 1 + .../contents.xcworkspacedata | 7 + .../xcshareddata/IDEWorkspaceChecks.plist | 8 + .../xcshareddata/WorkspaceSettings.xcsettings | 8 + .../xcshareddata/xcschemes/Runner.xcscheme | 91 +++++++ .../contents.xcworkspacedata | 7 + .../xcshareddata/IDEWorkspaceChecks.plist | 8 + .../xcshareddata/WorkspaceSettings.xcsettings | 8 + .../example/ios/Runner/AppDelegate.swift | 13 + .../AppIcon.appiconset/Contents.json | 122 +++++++++ .../Icon-App-1024x1024@1x.png | Bin 0 -> 10932 bytes .../AppIcon.appiconset/Icon-App-20x20@1x.png | Bin 0 -> 564 bytes .../AppIcon.appiconset/Icon-App-20x20@2x.png | Bin 0 -> 1283 bytes .../AppIcon.appiconset/Icon-App-20x20@3x.png | Bin 0 -> 1588 bytes .../AppIcon.appiconset/Icon-App-29x29@1x.png | Bin 0 -> 1025 bytes .../AppIcon.appiconset/Icon-App-29x29@2x.png | Bin 0 -> 1716 bytes .../AppIcon.appiconset/Icon-App-29x29@3x.png | Bin 0 -> 1920 bytes .../AppIcon.appiconset/Icon-App-40x40@1x.png | Bin 0 -> 1283 bytes .../AppIcon.appiconset/Icon-App-40x40@2x.png | Bin 0 -> 1895 bytes .../AppIcon.appiconset/Icon-App-40x40@3x.png | Bin 0 -> 2665 bytes .../AppIcon.appiconset/Icon-App-60x60@2x.png | Bin 0 -> 2665 bytes .../AppIcon.appiconset/Icon-App-60x60@3x.png | Bin 0 -> 3831 bytes .../AppIcon.appiconset/Icon-App-76x76@1x.png | Bin 0 -> 1888 bytes .../AppIcon.appiconset/Icon-App-76x76@2x.png | Bin 0 -> 3294 bytes .../Icon-App-83.5x83.5@2x.png | Bin 0 -> 3612 bytes .../LaunchImage.imageset/Contents.json | 23 ++ .../LaunchImage.imageset/LaunchImage.png | Bin 0 -> 68 bytes .../LaunchImage.imageset/LaunchImage@2x.png | Bin 0 -> 68 bytes .../LaunchImage.imageset/LaunchImage@3x.png | Bin 0 -> 68 bytes .../LaunchImage.imageset/README.md | 5 + .../Runner/Base.lproj/LaunchScreen.storyboard | 37 +++ .../ios/Runner/Base.lproj/Main.storyboard | 26 ++ .../dart_client/example/ios/Runner/Info.plist | 45 ++++ .../ios/Runner/Runner-Bridging-Header.h | 1 + packages/dart_client/example/lib/main.dart | 248 ++++++++++++++++++ packages/dart_client/example/pubspec.yaml | 21 ++ 59 files changed, 1013 insertions(+) create mode 100644 packages/dart_client/example/.gitignore create mode 100644 packages/dart_client/example/.metadata create mode 100644 packages/dart_client/example/README.md create mode 100644 packages/dart_client/example/android/.gitignore create mode 100644 packages/dart_client/example/android/app/build.gradle create mode 100644 packages/dart_client/example/android/app/src/debug/AndroidManifest.xml create mode 100644 packages/dart_client/example/android/app/src/main/AndroidManifest.xml create mode 100644 packages/dart_client/example/android/app/src/main/kotlin/com/example/example/MainActivity.kt create mode 100644 packages/dart_client/example/android/app/src/main/res/drawable/launch_background.xml create mode 100644 packages/dart_client/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png create mode 100644 packages/dart_client/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png create mode 100644 packages/dart_client/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png create mode 100644 packages/dart_client/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png create mode 100644 packages/dart_client/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png create mode 100644 packages/dart_client/example/android/app/src/main/res/values/styles.xml create mode 100644 packages/dart_client/example/android/app/src/profile/AndroidManifest.xml create mode 100644 packages/dart_client/example/android/build.gradle create mode 100644 packages/dart_client/example/android/gradle.properties create mode 100644 packages/dart_client/example/android/gradle/wrapper/gradle-wrapper.properties create mode 100644 packages/dart_client/example/android/settings.gradle create mode 100644 packages/dart_client/example/ios/.gitignore create mode 100644 packages/dart_client/example/ios/Flutter/AppFrameworkInfo.plist create mode 100644 packages/dart_client/example/ios/Flutter/Debug.xcconfig create mode 100644 packages/dart_client/example/ios/Flutter/Release.xcconfig create mode 100644 packages/dart_client/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata create mode 100644 packages/dart_client/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 packages/dart_client/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings create mode 100644 packages/dart_client/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme create mode 100644 packages/dart_client/example/ios/Runner.xcworkspace/contents.xcworkspacedata create mode 100644 packages/dart_client/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 packages/dart_client/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings create mode 100644 packages/dart_client/example/ios/Runner/AppDelegate.swift create mode 100644 packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json create mode 100644 packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png create mode 100644 packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png create mode 100644 packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png create mode 100644 packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png create mode 100644 packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png create mode 100644 packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png create mode 100644 packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png create mode 100644 packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png create mode 100644 packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png create mode 100644 packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png create mode 100644 packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png create mode 100644 packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png create mode 100644 packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png create mode 100644 packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png create mode 100644 packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png create mode 100644 packages/dart_client/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json create mode 100644 packages/dart_client/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png create mode 100644 packages/dart_client/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png create mode 100644 packages/dart_client/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png create mode 100644 packages/dart_client/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md create mode 100644 packages/dart_client/example/ios/Runner/Base.lproj/LaunchScreen.storyboard create mode 100644 packages/dart_client/example/ios/Runner/Base.lproj/Main.storyboard create mode 100644 packages/dart_client/example/ios/Runner/Info.plist create mode 100644 packages/dart_client/example/ios/Runner/Runner-Bridging-Header.h create mode 100644 packages/dart_client/example/lib/main.dart create mode 100644 packages/dart_client/example/pubspec.yaml diff --git a/packages/dart_client/example/.gitignore b/packages/dart_client/example/.gitignore new file mode 100644 index 00000000..9d532b18 --- /dev/null +++ b/packages/dart_client/example/.gitignore @@ -0,0 +1,41 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# IntelliJ related +*.iml +*.ipr +*.iws +.idea/ + +# The .vscode folder contains launch configuration and tasks you configure in +# VS Code which you may wish to be included in version control, so this line +# is commented out by default. +#.vscode/ + +# Flutter/Dart/Pub related +**/doc/api/ +**/ios/Flutter/.last_build_id +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json diff --git a/packages/dart_client/example/.metadata b/packages/dart_client/example/.metadata new file mode 100644 index 00000000..182cccaf --- /dev/null +++ b/packages/dart_client/example/.metadata @@ -0,0 +1,10 @@ +# This file tracks properties of this Flutter project. +# Used by Flutter tool to assess capabilities and perform upgrades etc. +# +# This file should be version controlled and should not be manually edited. + +version: + revision: 78910062997c3a836feee883712c241a5fd22983 + channel: stable + +project_type: app diff --git a/packages/dart_client/example/README.md b/packages/dart_client/example/README.md new file mode 100644 index 00000000..11089159 --- /dev/null +++ b/packages/dart_client/example/README.md @@ -0,0 +1,2 @@ +# Stream Chat Dart Example +Please see `lib/` for example code. \ No newline at end of file diff --git a/packages/dart_client/example/android/.gitignore b/packages/dart_client/example/android/.gitignore new file mode 100644 index 00000000..0a741cb4 --- /dev/null +++ b/packages/dart_client/example/android/.gitignore @@ -0,0 +1,11 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java + +# Remember to never publicly share your keystore. +# See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app +key.properties diff --git a/packages/dart_client/example/android/app/build.gradle b/packages/dart_client/example/android/app/build.gradle new file mode 100644 index 00000000..3932aa91 --- /dev/null +++ b/packages/dart_client/example/android/app/build.gradle @@ -0,0 +1,63 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 29 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.example" + minSdkVersion 16 + targetSdkVersion 29 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + + buildTypes { + release { + // TODO: Add your own signing config for the release build. + // Signing with the debug keys for now, so `flutter run --release` works. + signingConfig signingConfigs.debug + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/packages/dart_client/example/android/app/src/debug/AndroidManifest.xml b/packages/dart_client/example/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 00000000..c208884f --- /dev/null +++ b/packages/dart_client/example/android/app/src/debug/AndroidManifest.xml @@ -0,0 +1,7 @@ + + + + diff --git a/packages/dart_client/example/android/app/src/main/AndroidManifest.xml b/packages/dart_client/example/android/app/src/main/AndroidManifest.xml new file mode 100644 index 00000000..55ca830c --- /dev/null +++ b/packages/dart_client/example/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/packages/dart_client/example/android/app/src/main/kotlin/com/example/example/MainActivity.kt b/packages/dart_client/example/android/app/src/main/kotlin/com/example/example/MainActivity.kt new file mode 100644 index 00000000..e793a000 --- /dev/null +++ b/packages/dart_client/example/android/app/src/main/kotlin/com/example/example/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.example + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} diff --git a/packages/dart_client/example/android/app/src/main/res/drawable/launch_background.xml b/packages/dart_client/example/android/app/src/main/res/drawable/launch_background.xml new file mode 100644 index 00000000..304732f8 --- /dev/null +++ b/packages/dart_client/example/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/packages/dart_client/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/packages/dart_client/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..db77bb4b7b0906d62b1847e87f15cdcacf6a4f29 GIT binary patch literal 544 zcmeAS@N?(olHy`uVBq!ia0vp^9w5xY3?!3`olAj~WQl7;NpOBzNqJ&XDuZK6ep0G} zXKrG8YEWuoN@d~6R2!h8bpbvhu0Wd6uZuB!w&u2PAxD2eNXD>P5D~Wn-+_Wa#27Xc zC?Zj|6r#X(-D3u$NCt}(Ms06KgJ4FxJVv{GM)!I~&n8Bnc94O7-Hd)cjDZswgC;Qs zO=b+9!WcT8F?0rF7!Uys2bs@gozCP?z~o%U|N3vA*22NaGQG zlg@K`O_XuxvZ&Ks^m&R!`&1=spLvfx7oGDKDwpwW`#iqdw@AL`7MR}m`rwr|mZgU`8P7SBkL78fFf!WnuYWm$5Z0 zNXhDbCv&49sM544K|?c)WrFfiZvCi9h0O)B3Pgg&ebxsLQ05GG~ AQ2+n{ literal 0 HcmV?d00001 diff --git a/packages/dart_client/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/packages/dart_client/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..17987b79bb8a35cc66c3c1fd44f5a5526c1b78be GIT binary patch literal 442 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA3?vioaBc-sk|nMYCBgY=CFO}lsSJ)O`AMk? zp1FzXsX?iUDV2pMQ*D5Xx&nMcT!A!W`0S9QKQy;}1Cl^CgaH=;G9cpY;r$Q>i*pfB zP2drbID<_#qf;rPZx^FqH)F_D#*k@@q03KywUtLX8Ua?`H+NMzkczFPK3lFz@i_kW%1NOn0|D2I9n9wzH8m|-tHjsw|9>@K=iMBhxvkv6m8Y-l zytQ?X=U+MF$@3 zt`~i=@j|6y)RWMK--}M|=T`o&^Ni>IoWKHEbBXz7?A@mgWoL>!*SXo`SZH-*HSdS+ yn*9;$7;m`l>wYBC5bq;=U}IMqLzqbYCidGC!)_gkIk_C@Uy!y&wkt5C($~2D>~)O*cj@FGjOCM)M>_ixfudOh)?xMu#Fs z#}Y=@YDTwOM)x{K_j*Q;dPdJ?Mz0n|pLRx{4n|)f>SXlmV)XB04CrSJn#dS5nK2lM zrZ9#~WelCp7&e13Y$jvaEXHskn$2V!!DN-nWS__6T*l;H&Fopn?A6HZ-6WRLFP=R` zqG+CE#d4|IbyAI+rJJ`&x9*T`+a=p|0O(+s{UBcyZdkhj=yS1>AirP+0R;mf2uMgM zC}@~JfByORAh4SyRgi&!(cja>F(l*O+nd+@4m$|6K6KDn_&uvCpV23&>G9HJp{xgg zoq1^2_p9@|WEo z*X_Uko@K)qYYv~>43eQGMdbiGbo>E~Q& zrYBH{QP^@Sti!`2)uG{irBBq@y*$B zi#&(U-*=fp74j)RyIw49+0MRPMRU)+a2r*PJ$L5roHt2$UjExCTZSbq%V!HeS7J$N zdG@vOZB4v_lF7Plrx+hxo7(fCV&}fHq)$ literal 0 HcmV?d00001 diff --git a/packages/dart_client/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/packages/dart_client/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..d5f1c8d34e7a88e3f88bea192c3a370d44689c3c GIT binary patch literal 1031 zcmeAS@N?(olHy`uVBq!ia0vp^6F``Q8Ax83A=Cw=BuiW)N`mv#O3D+9QW+dm@{>{( zJaZG%Q-e|yQz{EjrrIztFa`(sgt!6~Yi|1%a`XoT0ojZ}lNrNjb9xjc(B0U1_% zz5^97Xt*%oq$rQy4?0GKNfJ44uvxI)gC`h-NZ|&0-7(qS@?b!5r36oQ}zyZrNO3 zMO=Or+<~>+A&uN&E!^Sl+>xE!QC-|oJv`ApDhqC^EWD|@=#J`=d#Xzxs4ah}w&Jnc z$|q_opQ^2TrnVZ0o~wh<3t%W&flvYGe#$xqda2bR_R zvPYgMcHgjZ5nSA^lJr%;<&0do;O^tDDh~=pIxA#coaCY>&N%M2^tq^U%3DB@ynvKo}b?yu-bFc-u0JHzced$sg7S3zqI(2 z#Km{dPr7I=pQ5>FuK#)QwK?Y`E`B?nP+}U)I#c1+FM*1kNvWG|a(TpksZQ3B@sD~b zpQ2)*V*TdwjFOtHvV|;OsiDqHi=6%)o4b!)x$)%9pGTsE z-JL={-Ffv+T87W(Xpooq<`r*VzWQcgBN$$`u}f>-ZQI1BB8ykN*=e4rIsJx9>z}*o zo~|9I;xof literal 0 HcmV?d00001 diff --git a/packages/dart_client/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/packages/dart_client/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..4d6372eebdb28e45604e46eeda8dd24651419bc0 GIT binary patch literal 1443 zcmb`G{WsKk6vsdJTdFg%tJav9_E4vzrOaqkWF|A724Nly!y+?N9`YV6wZ}5(X(D_N(?!*n3`|_r0Hc?=PQw&*vnU?QTFY zB_MsH|!j$PP;I}?dppoE_gA(4uc!jV&0!l7_;&p2^pxNo>PEcNJv za5_RT$o2Mf!<+r?&EbHH6nMoTsDOa;mN(wv8RNsHpG)`^ymG-S5By8=l9iVXzN_eG%Xg2@Xeq76tTZ*dGh~Lo9vl;Zfs+W#BydUw zCkZ$o1LqWQO$FC9aKlLl*7x9^0q%0}$OMlp@Kk_jHXOjofdePND+j!A{q!8~Jn+s3 z?~~w@4?egS02}8NuulUA=L~QQfm;MzCGd)XhiftT;+zFO&JVyp2mBww?;QByS_1w! zrQlx%{^cMj0|Bo1FjwY@Q8?Hx0cIPF*@-ZRFpPc#bBw{5@tD(5%sClzIfl8WU~V#u zm5Q;_F!wa$BSpqhN>W@2De?TKWR*!ujY;Yylk_X5#~V!L*Gw~;$%4Q8~Mad z@`-kG?yb$a9cHIApZDVZ^U6Xkp<*4rU82O7%}0jjHlK{id@?-wpN*fCHXyXh(bLt* zPc}H-x0e4E&nQ>y%B-(EL=9}RyC%MyX=upHuFhAk&MLbsF0LP-q`XnH78@fT+pKPW zu72MW`|?8ht^tz$iC}ZwLp4tB;Q49K!QCF3@!iB1qOI=?w z7In!}F~ij(18UYUjnbmC!qKhPo%24?8U1x{7o(+?^Zu0Hx81|FuS?bJ0jgBhEMzf< zCgUq7r2OCB(`XkKcN-TL>u5y#dD6D!)5W?`O5)V^>jb)P)GBdy%t$uUMpf$SNV31$ zb||OojAbvMP?T@$h_ZiFLFVHDmbyMhJF|-_)HX3%m=CDI+ID$0^C>kzxprBW)hw(v zr!Gmda);ICoQyhV_oP5+C%?jcG8v+D@9f?Dk*!BxY}dazmrT@64UrP3hlslANK)bq z$67n83eh}OeW&SV@HG95P|bjfqJ7gw$e+`Hxo!4cx`jdK1bJ>YDSpGKLPZ^1cv$ek zIB?0S<#tX?SJCLWdMd{-ME?$hc7A$zBOdIJ)4!KcAwb=VMov)nK;9z>x~rfT1>dS+ zZ6#`2v@`jgbqq)P22H)Tx2CpmM^o1$B+xT6`(v%5xJ(?j#>Q$+rx_R|7TzDZe{J6q zG1*EcU%tE?!kO%^M;3aM6JN*LAKUVb^xz8-Pxo#jR5(-KBeLJvA@-gxNHx0M-ZJLl z;#JwQoh~9V?`UVo#}{6ka@II>++D@%KqGpMdlQ}?9E*wFcf5(#XQnP$Dk5~%iX^>f z%$y;?M0BLp{O3a(-4A?ewryHrrD%cx#Q^%KY1H zNre$ve+vceSLZcNY4U(RBX&)oZn*Py()h)XkE?PL$!bNb{N5FVI2Y%LKEm%yvpyTP z(1P?z~7YxD~Rf<(a@_y` literal 0 HcmV?d00001 diff --git a/packages/dart_client/example/android/app/src/main/res/values/styles.xml b/packages/dart_client/example/android/app/src/main/res/values/styles.xml new file mode 100644 index 00000000..1f83a33f --- /dev/null +++ b/packages/dart_client/example/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/packages/dart_client/example/android/app/src/profile/AndroidManifest.xml b/packages/dart_client/example/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 00000000..c208884f --- /dev/null +++ b/packages/dart_client/example/android/app/src/profile/AndroidManifest.xml @@ -0,0 +1,7 @@ + + + + diff --git a/packages/dart_client/example/android/build.gradle b/packages/dart_client/example/android/build.gradle new file mode 100644 index 00000000..3100ad2d --- /dev/null +++ b/packages/dart_client/example/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/packages/dart_client/example/android/gradle.properties b/packages/dart_client/example/android/gradle.properties new file mode 100644 index 00000000..94adc3a3 --- /dev/null +++ b/packages/dart_client/example/android/gradle.properties @@ -0,0 +1,3 @@ +org.gradle.jvmargs=-Xmx1536M +android.useAndroidX=true +android.enableJetifier=true diff --git a/packages/dart_client/example/android/gradle/wrapper/gradle-wrapper.properties b/packages/dart_client/example/android/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 00000000..296b146b --- /dev/null +++ b/packages/dart_client/example/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/packages/dart_client/example/android/settings.gradle b/packages/dart_client/example/android/settings.gradle new file mode 100644 index 00000000..44e62bcf --- /dev/null +++ b/packages/dart_client/example/android/settings.gradle @@ -0,0 +1,11 @@ +include ':app' + +def localPropertiesFile = new File(rootProject.projectDir, "local.properties") +def properties = new Properties() + +assert localPropertiesFile.exists() +localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) } + +def flutterSdkPath = properties.getProperty("flutter.sdk") +assert flutterSdkPath != null, "flutter.sdk not set in local.properties" +apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle" diff --git a/packages/dart_client/example/ios/.gitignore b/packages/dart_client/example/ios/.gitignore new file mode 100644 index 00000000..e96ef602 --- /dev/null +++ b/packages/dart_client/example/ios/.gitignore @@ -0,0 +1,32 @@ +*.mode1v3 +*.mode2v3 +*.moved-aside +*.pbxuser +*.perspectivev3 +**/*sync/ +.sconsign.dblite +.tags* +**/.vagrant/ +**/DerivedData/ +Icon? +**/Pods/ +**/.symlinks/ +profile +xcuserdata +**/.generated/ +Flutter/App.framework +Flutter/Flutter.framework +Flutter/Flutter.podspec +Flutter/Generated.xcconfig +Flutter/app.flx +Flutter/app.zip +Flutter/flutter_assets/ +Flutter/flutter_export_environment.sh +ServiceDefinitions.json +Runner/GeneratedPluginRegistrant.* + +# Exceptions to above rules. +!default.mode1v3 +!default.mode2v3 +!default.pbxuser +!default.perspectivev3 diff --git a/packages/dart_client/example/ios/Flutter/AppFrameworkInfo.plist b/packages/dart_client/example/ios/Flutter/AppFrameworkInfo.plist new file mode 100644 index 00000000..6b4c0f78 --- /dev/null +++ b/packages/dart_client/example/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 8.0 + + diff --git a/packages/dart_client/example/ios/Flutter/Debug.xcconfig b/packages/dart_client/example/ios/Flutter/Debug.xcconfig new file mode 100644 index 00000000..592ceee8 --- /dev/null +++ b/packages/dart_client/example/ios/Flutter/Debug.xcconfig @@ -0,0 +1 @@ +#include "Generated.xcconfig" diff --git a/packages/dart_client/example/ios/Flutter/Release.xcconfig b/packages/dart_client/example/ios/Flutter/Release.xcconfig new file mode 100644 index 00000000..592ceee8 --- /dev/null +++ b/packages/dart_client/example/ios/Flutter/Release.xcconfig @@ -0,0 +1 @@ +#include "Generated.xcconfig" diff --git a/packages/dart_client/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/packages/dart_client/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 00000000..1d526a16 --- /dev/null +++ b/packages/dart_client/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/packages/dart_client/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/packages/dart_client/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 00000000..18d98100 --- /dev/null +++ b/packages/dart_client/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/packages/dart_client/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/packages/dart_client/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 00000000..f9b0d7c5 --- /dev/null +++ b/packages/dart_client/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + PreviewsEnabled + + + diff --git a/packages/dart_client/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/packages/dart_client/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme new file mode 100644 index 00000000..a28140cf --- /dev/null +++ b/packages/dart_client/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/dart_client/example/ios/Runner.xcworkspace/contents.xcworkspacedata b/packages/dart_client/example/ios/Runner.xcworkspace/contents.xcworkspacedata new file mode 100644 index 00000000..1d526a16 --- /dev/null +++ b/packages/dart_client/example/ios/Runner.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/packages/dart_client/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/packages/dart_client/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 00000000..18d98100 --- /dev/null +++ b/packages/dart_client/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/packages/dart_client/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/packages/dart_client/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 00000000..f9b0d7c5 --- /dev/null +++ b/packages/dart_client/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + PreviewsEnabled + + + diff --git a/packages/dart_client/example/ios/Runner/AppDelegate.swift b/packages/dart_client/example/ios/Runner/AppDelegate.swift new file mode 100644 index 00000000..70693e4a --- /dev/null +++ b/packages/dart_client/example/ios/Runner/AppDelegate.swift @@ -0,0 +1,13 @@ +import UIKit +import Flutter + +@UIApplicationMain +@objc class AppDelegate: FlutterAppDelegate { + override func application( + _ application: UIApplication, + didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? + ) -> Bool { + GeneratedPluginRegistrant.register(with: self) + return super.application(application, didFinishLaunchingWithOptions: launchOptions) + } +} diff --git a/packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 00000000..d36b1fab --- /dev/null +++ b/packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,122 @@ +{ + "images" : [ + { + "size" : "20x20", + "idiom" : "iphone", + "filename" : "Icon-App-20x20@2x.png", + "scale" : "2x" + }, + { + "size" : "20x20", + "idiom" : "iphone", + "filename" : "Icon-App-20x20@3x.png", + "scale" : "3x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@1x.png", + "scale" : "1x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@2x.png", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@3x.png", + "scale" : "3x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "Icon-App-40x40@2x.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "Icon-App-40x40@3x.png", + "scale" : "3x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "Icon-App-60x60@2x.png", + "scale" : "2x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "Icon-App-60x60@3x.png", + "scale" : "3x" + }, + { + "size" : "20x20", + "idiom" : "ipad", + "filename" : "Icon-App-20x20@1x.png", + "scale" : "1x" + }, + { + "size" : "20x20", + "idiom" : "ipad", + "filename" : "Icon-App-20x20@2x.png", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "Icon-App-29x29@1x.png", + "scale" : "1x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "Icon-App-29x29@2x.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "Icon-App-40x40@1x.png", + "scale" : "1x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "Icon-App-40x40@2x.png", + "scale" : "2x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "Icon-App-76x76@1x.png", + "scale" : "1x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "Icon-App-76x76@2x.png", + "scale" : "2x" + }, + { + "size" : "83.5x83.5", + "idiom" : "ipad", + "filename" : "Icon-App-83.5x83.5@2x.png", + "scale" : "2x" + }, + { + "size" : "1024x1024", + "idiom" : "ios-marketing", + "filename" : "Icon-App-1024x1024@1x.png", + "scale" : "1x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png b/packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png new file mode 100644 index 0000000000000000000000000000000000000000..dc9ada4725e9b0ddb1deab583e5b5102493aa332 GIT binary patch literal 10932 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 literal 0 HcmV?d00001 diff --git a/packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..f091b6b0bca859a3f474b03065bef75ba58a9e4c GIT binary patch literal 1588 zcmV-42Fv-0P)C1SqPt}wig>|5Crh^=oyX$BK<}M8eLU3e2hGT;=G|!_SP)7zNI6fqUMB=)y zRAZ>eDe#*r`yDAVgB_R*LB*MAc)8(b{g{9McCXW!lq7r(btRoB9!8B-#AI6JMb~YFBEvdsV)`mEQO^&#eRKx@b&x- z5lZm*!WfD8oCLzfHGz#u7sT0^VLMI1MqGxF^v+`4YYnVYgk*=kU?HsSz{v({E3lb9 z>+xILjBN)t6`=g~IBOelGQ(O990@BfXf(DRI5I$qN$0Gkz-FSc$3a+2fX$AedL4u{ z4V+5Ong(9LiGcIKW?_352sR;LtDPmPJXI{YtT=O8=76o9;*n%_m|xo!i>7$IrZ-{l z-x3`7M}qzHsPV@$v#>H-TpjDh2UE$9g6sysUREDy_R(a)>=eHw-WAyfIN z*qb!_hW>G)Tu8nSw9yn#3wFMiLcfc4pY0ek1}8(NqkBR@t4{~oC>ryc-h_ByH(Cg5 z>ao-}771+xE3um9lWAY1FeQFxowa1(!J(;Jg*wrg!=6FdRX+t_<%z&d&?|Bn){>zm zZQj(aA_HeBY&OC^jj*)N`8fa^ePOU72VpInJoI1?`ty#lvlNzs(&MZX+R%2xS~5Kh zX*|AU4QE#~SgPzOXe9>tRj>hjU@c1k5Y_mW*Jp3fI;)1&g3j|zDgC+}2Q_v%YfDax z!?umcN^n}KYQ|a$Lr+51Nf9dkkYFSjZZjkma$0KOj+;aQ&721~t7QUKx61J3(P4P1 zstI~7-wOACnWP4=8oGOwz%vNDqD8w&Q`qcNGGrbbf&0s9L0De{4{mRS?o0MU+nR_! zrvshUau0G^DeMhM_v{5BuLjb#Hh@r23lDAk8oF(C+P0rsBpv85EP>4CVMx#04MOfG z;P%vktHcXwTj~+IE(~px)3*MY77e}p#|c>TD?sMatC0Tu4iKKJ0(X8jxQY*gYtxsC z(zYC$g|@+I+kY;dg_dE>scBf&bP1Nc@Hz<3R)V`=AGkc;8CXqdi=B4l2k|g;2%#m& z*jfX^%b!A8#bI!j9-0Fi0bOXl(-c^AB9|nQaE`*)Hw+o&jS9@7&Gov#HbD~#d{twV zXd^Tr^mWLfFh$@Dr$e;PBEz4(-2q1FF0}c;~B5sA}+Q>TOoP+t>wf)V9Iy=5ruQa;z)y zI9C9*oUga6=hxw6QasLPnee@3^Rr*M{CdaL5=R41nLs(AHk_=Y+A9$2&H(B7!_pURs&8aNw7?`&Z&xY_Ye z)~D5Bog^td-^QbUtkTirdyK^mTHAOuptDflut!#^lnKqU md>ggs(5nOWAqO?umG&QVYK#ibz}*4>0000U6E9hRK9^#O7(mu>ETqrXGsduA8$)?`v2seloOCza43C{NQ$$gAOH**MCn0Q?+L7dl7qnbRdqZ8LSVp1ItDxhxD?t@5_yHg6A8yI zC*%Wgg22K|8E#!~cTNYR~@Y9KepMPrrB8cABapAFa=`H+UGhkXUZV1GnwR1*lPyZ;*K(i~2gp|@bzp8}og7e*#% zEnr|^CWdVV!-4*Y_7rFvlww2Ze+>j*!Z!pQ?2l->4q#nqRu9`ELo6RMS5=br47g_X zRw}P9a7RRYQ%2Vsd0Me{_(EggTnuN6j=-?uFS6j^u69elMypu?t>op*wBx<=Wx8?( ztpe^(fwM6jJX7M-l*k3kEpWOl_Vk3@(_w4oc}4YF4|Rt=2V^XU?#Yz`8(e?aZ@#li0n*=g^qOcVpd-Wbok=@b#Yw zqn8u9a)z>l(1kEaPYZ6hwubN6i<8QHgsu0oE) ziJ(p;Wxm>sf!K+cw>R-(^Y2_bahB+&KI9y^);#0qt}t-$C|Bo71lHi{_+lg#f%RFy z0um=e3$K3i6K{U_4K!EX?F&rExl^W|G8Z8;`5z-k}OGNZ0#WVb$WCpQu-_YsiqKP?BB# vzVHS-CTUF4Ozn5G+mq_~Qqto~ahA+K`|lyv3(-e}00000NkvXXu0mjfd`9t{ literal 0 HcmV?d00001 diff --git a/packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..d0ef06e7edb86cdfe0d15b4b0d98334a86163658 GIT binary patch literal 1716 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 literal 0 HcmV?d00001 diff --git a/packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..c8f9ed8f5cee1c98386d13b17e89f719e83555b2 GIT binary patch literal 1895 zcmV-t2blPYP)FQtfgmafE#=YDCq`qUBt#QpG%*H6QHY765~R=q zZ6iudfM}q!Pz#~9JgOi8QJ|DSu?1-*(kSi1K4#~5?#|rh?sS)(-JQqX*}ciXJ56_H zdw=^s_srbAdqxlvGyrgGet#6T7_|j;95sL%MtM;q86vOxKM$f#puR)Bjv9Zvz9-di zXOTSsZkM83)E9PYBXC<$6(|>lNLVBb&&6y{NByFCp%6+^ALR@NCTse_wqvNmSWI-m z!$%KlHFH2omF!>#%1l3LTZg(s7eof$7*xB)ZQ0h?ejh?Ta9fDv59+u#MokW+1t8Zb zgHv%K(u9G^Lv`lh#f3<6!JVTL3(dCpxHbnbA;kKqQyd1~^Xe0VIaYBSWm6nsr;dFj z4;G-RyL?cYgsN1{L4ZFFNa;8)Rv0fM0C(~Tkit94 zz#~A)59?QjD&pAPSEQ)p8gP|DS{ng)j=2ux)_EzzJ773GmQ_Cic%3JJhC0t2cx>|v zJcVusIB!%F90{+}8hG3QU4KNeKmK%T>mN57NnCZ^56=0?&3@!j>a>B43pi{!u z7JyDj7`6d)qVp^R=%j>UIY6f+3`+qzIc!Y_=+uN^3BYV|o+$vGo-j-Wm<10%A=(Yk^beI{t%ld@yhKjq0iNjqN4XMGgQtbKubPM$JWBz}YA65k%dm*awtC^+f;a-x4+ddbH^7iDWGg&N0n#MW{kA|=8iMUiFYvMoDY@sPC#t$55gn6ykUTPAr`a@!(;np824>2xJthS z*ZdmT`g5-`BuJs`0LVhz+D9NNa3<=6m;cQLaF?tCv8)zcRSh66*Z|vXhG@$I%U~2l z?`Q zykI#*+rQ=z6Jm=Bui-SfpDYLA=|vzGE(dYm=OC8XM&MDo7ux4UF1~0J1+i%aCUpRe zt3L_uNyQ*cE(38Uy03H%I*)*Bh=Lb^Xj3?I^Hnbeq72(EOK^Y93CNp*uAA{5Lc=ky zx=~RKa4{iTm{_>_vSCm?$Ej=i6@=m%@VvAITnigVg{&@!7CDgs908761meDK5azA} z4?=NOH|PdvabgJ&fW2{Mo$Q0CcD8Qc84%{JPYt5EiG{MdLIAeX%T=D7NIP4%Hw}p9 zg)==!2Lbp#j{u_}hMiao9=!VSyx0gHbeCS`;q&vzeq|fs`y&^X-lso(Ls@-706qmA z7u*T5PMo_w3{se1t2`zWeO^hOvTsohG_;>J0wVqVe+n)AbQCx)yh9;w+J6?NF5Lmo zecS@ieAKL8%bVd@+-KT{yI|S}O>pYckUFs;ry9Ow$CD@ztz5K-*D$^{i(_1llhSh^ zEkL$}tsQt5>QA^;QgjgIfBDmcOgi5YDyu?t6vSnbp=1+@6D& z5MJ}B8q;bRlVoxasyhcUF1+)o`&3r0colr}QJ3hcSdLu;9;td>kf@Tcn<@9sIx&=m z;AD;SCh95=&p;$r{Xz3iWCO^MX83AGJ(yH&eTXgv|0=34#-&WAmw{)U7OU9!Wz^!7 zZ%jZFi@JR;>Mhi7S>V7wQ176|FdW2m?&`qa(ScO^CFPR80HucLHOTy%5s*HR0^8)i h0WYBP*#0Ks^FNSabJA*5${_#%002ovPDHLkV1oKhTl@e3 literal 0 HcmV?d00001 diff --git a/packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..a6d6b8609df07bf62e5100a53a01510388bd2b22 GIT binary patch literal 2665 zcmV-v3YPVWP)oFh3q0MFesq&64WThn3$;G69TfjsAv=f2G9}p zgSx99+!YV6qME!>9MD13x)k(+XE7W?_O4LoLb5ND8 zaV{9+P@>42xDfRiYBMSgD$0!vssptcb;&?u9u(LLBKmkZ>RMD=kvD3h`sk6!QYtBa ztlZI#nu$8lJ^q2Z79UTgZe>BU73(Aospiq+?SdMt8lDZ;*?@tyWVZVS_Q7S&*tJaiRlJ z+aSMOmbg3@h5}v;A*c8SbqM3icg-`Cnwl;7Ts%A1RkNIp+Txl-Ckkvg4oxrqGA5ewEgYqwtECD<_3Egu)xGllKt&J8g&+=ac@Jq4-?w6M3b*>w5 z69N3O%=I^6&UL5gZ!}trC7bUj*12xLdkNs~Bz4QdJJ*UDZox2UGR}SNg@lmOvhCc~ z*f_UeXv(=#I#*7>VZx2ObEN~UoGUTl=-@)E;YtCRZ>SVp$p9yG5hEFZ!`wI!spd)n zSk+vK0Vin7FL{7f&6OB%f;SH22dtbcF<|9fi2Fp%q4kxL!b1#l^)8dUwJ zwEf{(wJj@8iYDVnKB`eSU+;ml-t2`@%_)0jDM`+a46xhDbBj2+&Ih>1A>6aky#(-SYyE{R3f#y57wfLs z6w1p~$bp;6!9DX$M+J~S@D6vJAaElETnsX4h9a5tvPhC3L@qB~bOzkL@^z0k_hS{T4PF*TDrgdXp+dzsE? z>V|VR035Pl9n5&-RePFdS{7KAr2vPOqR9=M$vXA1Yy5>w;EsF`;OK{2pkn-kpp9Pw z)r;5JfJKKaT$4qCb{TaXHjb$QA{y0EYy*+b1XI;6Ah- zw13P)xT`>~eFoJC!>{2XL(a_#upp3gaR1#5+L(Jmzp4TBnx{~WHedpJ1ch8JFk~Sw z>F+gN+i+VD?gMXwcIhn8rz`>e>J^TI3E-MW>f}6R-pL}>WMOa0k#jN+`RyUVUC;#D zg|~oS^$6%wpF{^Qr+}X>0PKcr3Fc&>Z>uv@C);pwDs@2bZWhYP!rvGx?_|q{d`t<*XEb#=aOb=N+L@CVBGqImZf&+a zCQEa3$~@#kC);pasdG=f6tuIi0PO-y&tvX%>Mv=oY3U$nD zJ#gMegnQ46pq+3r=;zmgcG+zRc9D~c>z+jo9&D+`E6$LmyFqlmCYw;-Zooma{sR@~ z)_^|YL1&&@|GXo*pivH7k!msl+$Sew3%XJnxajt0K%3M6Bd&YFNy9}tWG^aovK2eX z1aL1%7;KRDrA@eG-Wr6w+;*H_VD~qLiVI`{_;>o)k`{8xa3EJT1O_>#iy_?va0eR? zDV=N%;Zjb%Z2s$@O>w@iqt!I}tLjGk!=p`D23I}N4Be@$(|iSA zf3Ih7b<{zqpDB4WF_5X1(peKe+rASze%u8eKLn#KKXt;UZ+Adf$_TO+vTqshLLJ5c z52HucO=lrNVae5XWOLm!V@n-ObU11!b+DN<$RuU+YsrBq*lYT;?AwJpmNKniF0Q1< zJCo>Q$=v$@&y=sj6{r!Y&y&`0$-I}S!H_~pI&2H8Z1C|BX4VgZ^-! zje3-;x0PBD!M`v*J_)rL^+$<1VJhH*2Fi~aA7s&@_rUHYJ9zD=M%4AFQ`}k8OC$9s XsPq=LnkwKG00000NkvXXu0mjfhAk5^ literal 0 HcmV?d00001 diff --git a/packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..a6d6b8609df07bf62e5100a53a01510388bd2b22 GIT binary patch literal 2665 zcmV-v3YPVWP)oFh3q0MFesq&64WThn3$;G69TfjsAv=f2G9}p zgSx99+!YV6qME!>9MD13x)k(+XE7W?_O4LoLb5ND8 zaV{9+P@>42xDfRiYBMSgD$0!vssptcb;&?u9u(LLBKmkZ>RMD=kvD3h`sk6!QYtBa ztlZI#nu$8lJ^q2Z79UTgZe>BU73(Aospiq+?SdMt8lDZ;*?@tyWVZVS_Q7S&*tJaiRlJ z+aSMOmbg3@h5}v;A*c8SbqM3icg-`Cnwl;7Ts%A1RkNIp+Txl-Ckkvg4oxrqGA5ewEgYqwtECD<_3Egu)xGllKt&J8g&+=ac@Jq4-?w6M3b*>w5 z69N3O%=I^6&UL5gZ!}trC7bUj*12xLdkNs~Bz4QdJJ*UDZox2UGR}SNg@lmOvhCc~ z*f_UeXv(=#I#*7>VZx2ObEN~UoGUTl=-@)E;YtCRZ>SVp$p9yG5hEFZ!`wI!spd)n zSk+vK0Vin7FL{7f&6OB%f;SH22dtbcF<|9fi2Fp%q4kxL!b1#l^)8dUwJ zwEf{(wJj@8iYDVnKB`eSU+;ml-t2`@%_)0jDM`+a46xhDbBj2+&Ih>1A>6aky#(-SYyE{R3f#y57wfLs z6w1p~$bp;6!9DX$M+J~S@D6vJAaElETnsX4h9a5tvPhC3L@qB~bOzkL@^z0k_hS{T4PF*TDrgdXp+dzsE? z>V|VR035Pl9n5&-RePFdS{7KAr2vPOqR9=M$vXA1Yy5>w;EsF`;OK{2pkn-kpp9Pw z)r;5JfJKKaT$4qCb{TaXHjb$QA{y0EYy*+b1XI;6Ah- zw13P)xT`>~eFoJC!>{2XL(a_#upp3gaR1#5+L(Jmzp4TBnx{~WHedpJ1ch8JFk~Sw z>F+gN+i+VD?gMXwcIhn8rz`>e>J^TI3E-MW>f}6R-pL}>WMOa0k#jN+`RyUVUC;#D zg|~oS^$6%wpF{^Qr+}X>0PKcr3Fc&>Z>uv@C);pwDs@2bZWhYP!rvGx?_|q{d`t<*XEb#=aOb=N+L@CVBGqImZf&+a zCQEa3$~@#kC);pasdG=f6tuIi0PO-y&tvX%>Mv=oY3U$nD zJ#gMegnQ46pq+3r=;zmgcG+zRc9D~c>z+jo9&D+`E6$LmyFqlmCYw;-Zooma{sR@~ z)_^|YL1&&@|GXo*pivH7k!msl+$Sew3%XJnxajt0K%3M6Bd&YFNy9}tWG^aovK2eX z1aL1%7;KRDrA@eG-Wr6w+;*H_VD~qLiVI`{_;>o)k`{8xa3EJT1O_>#iy_?va0eR? zDV=N%;Zjb%Z2s$@O>w@iqt!I}tLjGk!=p`D23I}N4Be@$(|iSA zf3Ih7b<{zqpDB4WF_5X1(peKe+rASze%u8eKLn#KKXt;UZ+Adf$_TO+vTqshLLJ5c z52HucO=lrNVae5XWOLm!V@n-ObU11!b+DN<$RuU+YsrBq*lYT;?AwJpmNKniF0Q1< zJCo>Q$=v$@&y=sj6{r!Y&y&`0$-I}S!H_~pI&2H8Z1C|BX4VgZ^-! zje3-;x0PBD!M`v*J_)rL^+$<1VJhH*2Fi~aA7s&@_rUHYJ9zD=M%4AFQ`}k8OC$9s XsPq=LnkwKG00000NkvXXu0mjfhAk5^ literal 0 HcmV?d00001 diff --git a/packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..75b2d164a5a98e212cca15ea7bf2ab5de5108680 GIT binary patch literal 3831 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 literal 0 HcmV?d00001 diff --git a/packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png new file mode 100644 index 0000000000000000000000000000000000000000..c4df70d39da7941ef3f6dcb7f06a192d8dcb308d GIT binary patch literal 1888 zcmV-m2cP(fP)x~L`~4d)Rspd&<9kFh{hn*KP1LP0~$;u(LfAu zp%fx&qLBcRHx$G|3q(bv@+b;o0*D|jwD-Q9uQR(l*ST}s+uPgQ-MeFwZ#GS?b332? z&Tk$&_miXn3IGq)AmQ)3sisq{raD4(k*bHvpCe-TdWq^NRTEVM)i9xbgQ&ccnUVx* zEY%vS%gDcSg=!tuIK8$Th2_((_h^+7;R|G{n06&O2#6%LK`a}n?h_fL18btz<@lFG za}xS}u?#DBMB> zw^b($1Z)`9G?eP95EKi&$eOy@K%h;ryrR3la%;>|o*>CgB(s>dDcNOXg}CK9SPmD? zmr-s{0wRmxUnbDrYfRvnZ@d z6johZ2sMX{YkGSKWd}m|@V7`Degt-43=2M?+jR%8{(H$&MLLmS;-|JxnX2pnz;el1jsvqQz}pGSF<`mqEXRQ5sC4#BbwnB_4` zc5bFE-Gb#JV3tox9fp-vVEN{(tOCpRse`S+@)?%pz+zVJXSooTrNCUg`R6`hxwb{) zC@{O6MKY8tfZ5@!yy=p5Y|#+myRL=^{tc(6YgAnkg3I(Cd!r5l;|;l-MQ8B`;*SCE z{u)uP^C$lOPM z5d~UhKhRRmvv{LIa^|oavk1$QiEApSrP@~Jjbg`<*dW4TO?4qG%a%sTPUFz(QtW5( zM)lA+5)0TvH~aBaOAs|}?u2FO;yc-CZ1gNM1dAxJ?%m?YsGR`}-xk2*dxC}r5j$d* zE!#Vtbo69h>V4V`BL%_&$} z+oJAo@jQ^Tk`;%xw-4G>hhb&)B?##U+(6Fi7nno`C<|#PVA%$Y{}N-?(Gc$1%tr4Pc}}hm~yY#fTOe!@v9s-ik$dX~|ygArPhByaXn8 zpI^FUjNWMsTFKTP3X7m?UK)3m zp6rI^_zxRYrx6_QmhoWoDR`fp4R7gu6;gdO)!KexaoO2D88F9x#TM1(9Bn7g;|?|o z)~$n&Lh#hCP6_LOPD>a)NmhW})LADx2kq=X7}7wYRj-0?dXr&bHaRWCfSqvzFa=sn z-8^gSyn-RmH=BZ{AJZ~!8n5621GbUJV7Qvs%JNv&$%Q17s_X%s-41vAPfIR>;x0Wlqr5?09S>x#%Qkt>?(&XjFRY}*L6BeQ3 z<6XEBh^S7>AbwGm@XP{RkeEKj6@_o%oV?hDuUpUJ+r#JZO?!IUc;r0R?>mi)*ZpQ) z#((dn=A#i_&EQn|hd)N$#A*fjBFuiHcYvo?@y1 z5|fV=a^a~d!c-%ZbMNqkMKiSzM{Yq=7_c&1H!mXk60Uv32dV;vMg&-kQ)Q{+PFtwc zj|-uQ;b^gts??J*9VxxOro}W~Q9j4Em|zSRv)(WSO9$F$s=Ydu%Q+5DOid~lwk&we zY%W(Z@ofdwPHncEZzZgmqS|!gTj3wQq9rxQy+^eNYKr1mj&?tm@wkO*9@UtnRMG>c aR{jt9+;fr}hV%pg00001^@s67{VYS000c7NklQEG_j zup^)eW&WUIApqy$=APz8jE@awGp)!bsTjDbrJO`$x^ZR^dr;>)LW>{ zs70vpsD38v)19rI=GNk1b(0?Js9~rjsQsu*K;@SD40RB-3^gKU-MYC7G!Bw{fZsqp zih4iIi;Hr_xZ033Iu{sQxLS=}yBXgLMn40d++>aQ0#%8D1EbGZp7+ z5=mK?t31BkVYbGOxE9`i748x`YgCMwL$qMsChbSGSE1`p{nSmadR zcQ#R)(?!~dmtD0+D2!K zR9%!Xp1oOJzm(vbLvT^$IKp@+W2=-}qTzTgVtQ!#Y7Gxz}stUIm<1;oBQ^Sh2X{F4ibaOOx;5ZGSNK z0maF^@(UtV$=p6DXLgRURwF95C=|U8?osGhgOED*b z7woJ_PWXBD>V-NjQAm{~T%sjyJ{5tn2f{G%?J!KRSrrGvQ1(^`YLA5B!~eycY(e5_ z*%aa{at13SxC(=7JT7$IQF~R3sy`Nn%EMv!$-8ZEAryB*yB1k&stni)=)8-ODo41g zkJu~roIgAih94tb=YsL%iH5@^b~kU9M-=aqgXIrbtxMpFy5mekFm#edF9z7RQ6V}R zBIhbXs~pMzt0VWy1Fi$^fh+1xxLDoK09&5&MJl(q#THjPm(0=z2H2Yfm^a&E)V+a5 zbi>08u;bJsDRUKR9(INSc7XyuWv(JsD+BB*0hS)FO&l&7MdViuur@-<-EHw>kHRGY zqoT}3fDv2-m{NhBG8X}+rgOEZ;amh*DqN?jEfQdqxdj08`Sr=C-KmT)qU1 z+9Cl)a1mgXxhQiHVB}l`m;-RpmKy?0*|yl?FXvJkFxuu!fKlcmz$kN(a}i*saM3nr z0!;a~_%Xqy24IxA2rz<+08=B-Q|2PT)O4;EaxP^6qixOv7-cRh?*T?zZU`{nIM-at zTKYWr9rJ=tppQ9I#Z#mLgINVB!pO-^FOcvFw6NhV0gztuO?g ztoA*C-52Q-Z-P#xB4HAY3KQVd%dz1S4PA3vHp0aa=zAO?FCt zC_GaTyVBg2F!bBr3U@Zy2iJgIAt>1sf$JWA9kh{;L+P*HfUBX1Zy{4MgNbDfBV_ly z!y#+753arsZUt@366jIC0klaC@ckuk!qu=pAyf7&QmiBUT^L1&tOHzsK)4n|pmrVT zs2($4=?s~VejTFHbFdDOwG;_58LkIj1Fh@{glkO#F1>a==ymJS$z;gdedT1zPx4Kj ztjS`y_C}%af-RtpehdQDt3a<=W5C4$)9W@QAse;WUry$WYmr51ml9lkeunUrE`-3e zmq1SgSOPNEE-Mf+AGJ$g0M;3@w!$Ej;hMh=v=I+Lpz^n%Pg^MgwyqOkNyu2c^of)C z1~ALor3}}+RiF*K4+4{(1%1j3pif1>sv0r^mTZ?5Jd-It!tfPfiG_p$AY*Vfak%FG z4z#;wLtw&E&?}w+eKG^=#jF7HQzr8rV0mY<1YAJ_uGz~$E13p?F^fPSzXSn$8UcI$ z8er9{5w5iv0qf8%70zV71T1IBB1N}R5Kp%NO0=5wJalZt8;xYp;b{1K) zHY>2wW-`Sl{=NpR%iu3(u6l&)rc%%cSA#aV7WCowfbFR4wcc{LQZv~o1u_`}EJA3>ki`?9CKYTA!rhO)if*zRdd}Kn zEPfYbhoVE~!FI_2YbC5qAj1kq;xP6%J8+?2PAs?`V3}nyFVD#sV3+uP`pi}{$l9U^ zSz}_M9f7RgnnRhaoIJgT8us!1aB&4!*vYF07Hp&}L zCRlop0oK4DL@ISz{2_BPlezc;xj2|I z23RlDNpi9LgTG_#(w%cMaS)%N`e>~1&a3<{Xy}>?WbF>OOLuO+j&hc^YohQ$4F&ze z+hwnro1puQjnKm;vFG~o>`kCeUIlkA-2tI?WBKCFLMBY=J{hpSsQ=PDtU$=duS_hq zHpymHt^uuV1q@uc4bFb{MdG*|VoW@15Osrqt2@8ll0qO=j*uOXn{M0UJX#SUztui9FN4)K3{9!y8PC-AHHvpVTU;x|-7P+taAtyglk#rjlH2 z5Gq8ik}BPaGiM{#Woyg;*&N9R2{J0V+WGB69cEtH7F?U~Kbi6ksi*`CFXsi931q7Y zGO82?whBhN%w1iDetv%~wM*Y;E^)@Vl?VDj-f*RX>{;o_=$fU!&KAXbuadYZ46Zbg z&6jMF=49$uL^73y;;N5jaHYv)BTyfh&`qVLYn?`o6BCA_z-0niZz=qPG!vonK3MW_ zo$V96zM!+kJRs{P-5-rQVse0VBH*n6A58)4uc&gfHMa{gIhV2fGf{st>E8sKyP-$8zp~wJX^A*@DI&-;8>gANXZj zU)R+Y)PB?=)a|Kj>8NXEu^S_h^7R`~Q&7*Kn!xyvzVv&^>?^iu;S~R2e-2fJx-oUb cX)(b1KSk$MOV07*qoM6N<$f&6$jw%VRuvdN2+38CZWny1cRtlsl+0_KtW)EU14Ei(F!UtWuj4IK+3{sK@>rh zs1Z;=(DD&U6+tlyL?UnHVN^&g6QhFi2#HS+*qz;(>63G(`|jRtW|nz$Pv7qTovP!^ zP_jES{mr@O-02w%!^a?^1ZP!_KmQiz0L~jZ=W@Qt`8wzOoclQsAS<5YdH;a(4bGLE zk8s}1If(PSIgVi!XE!5kA?~z*sobvNyohr;=Q_@h2@$6Flyej3J)D-6YfheRGl`HEcPk|~huT_2-U?PfL=4BPV)f1o!%rQ!NMt_MYw-5bUSwQ9Z&zC>u zOrl~UJglJNa%f50Ok}?WB{on`Ci`p^Y!xBA?m@rcJXLxtrE0FhRF3d*ir>yzO|BD$ z3V}HpFcCh6bTzY}Nt_(W%QYd3NG)jJ4<`F<1Od) zfQblTdC&h2lCz`>y?>|9o2CdvC8qZeIZt%jN;B7Hdn2l*k4M4MFEtq`q_#5?}c$b$pf_3y{Y!cRDafZBEj-*OD|gz#PBDeu3QoueOesLzB+O zxjf2wvf6Wwz>@AiOo2mO4=TkAV+g~%_n&R;)l#!cBxjuoD$aS-`IIJv7cdX%2{WT7 zOm%5rs(wqyPE^k5SIpUZ!&Lq4<~%{*>_Hu$2|~Xa;iX*tz8~G6O3uFOS?+)tWtdi| zV2b#;zRN!m@H&jd=!$7YY6_}|=!IU@=SjvGDFtL;aCtw06U;-v^0%k0FOyESt z1Wv$={b_H&8FiRV?MrzoHWd>%v6KTRU;-v^Miiz+@q`(BoT!+<37CKhoKb)|8!+RG z6BQFU^@fRW;s8!mOf2QViKQGk0TVER6EG1`#;Nm39Do^PoT!+<37AD!%oJe86(=et zZ~|sLzU>V-qYiU6V8$0GmU7_K8|Fd0B?+9Un1BhKAz#V~Fk^`mJtlCX#{^8^M8!me z8Yg;8-~>!e<-iG;h*0B1kBKm}hItVGY6WnjVpgnTTAC$rqQ^v)4KvOtpY|sIj@WYg zyw##ZZ5AC2IKNC;^hwg9BPk0wLStlmBr;E|$5GoAo$&Ui_;S9WY62n3)i49|T%C#i017z3J=$RF|KyZWnci*@lW4 z=AKhNN6+m`Q!V3Ye68|8y@%=am>YD0nG99M)NWc20%)gwO!96j7muR}Fr&54SxKP2 zP30S~lt=a*qDlbu3+Av57=9v&vr<6g0&`!8E2fq>I|EJGKs}t|{h7+KT@)LfIV-3K zK)r_fr2?}FFyn*MYoLC>oV-J~eavL2ho4a4^r{E-8m2hi>~hA?_vIG4a*KT;2eyl1 zh_hUvUJpNCFwBvRq5BI*srSle>c6%n`#VNsyC|MGa{(P&08p=C9+WUw9Hl<1o9T4M zdD=_C0F7#o8A_bRR?sFNmU0R6tW`ElnF8p53IdHo#S9(JoZCz}fHwJ6F<&?qrpVqE zte|m%89JQD+XwaPU#%#lVs-@-OL);|MdfINd6!XwP2h(eyafTUsoRkA%&@fe?9m@jw-v(yTTiV2(*fthQH9}SqmsRPVnwwbV$1E(_lkmo&S zF-truCU914_$jpqjr(>Ha4HkM4YMT>m~NosUu&UZ>zirfHo%N6PPs9^_o$WqPA0#5 z%tG>qFCL+b*0s?sZ;Sht0nE7Kl>OVXy=gjWxxK;OJ3yGd7-pZf7JYNcZo2*1SF`u6 zHJyRRxGw9mDlOiXqVMsNe#WX`fC`vrtjSQ%KmLcl(lC>ZOQzG^%iql2w-f_K@r?OE zwCICifM#L-HJyc7Gm>Ern?+Sk3&|Khmu4(~3qa$(m6Ub^U0E5RHq49za|XklN#?kP zl;EstdW?(_4D>kwjWy2f!LM)y?F94kyU3`W!6+AyId-89v}sXJpuic^NLL7GJItl~ zsiuB98AI-(#Mnm|=A-R6&2fwJ0JVSY#Q>&3$zFh|@;#%0qeF=j5Ajq@4i0tIIW z&}sk$&fGwoJpe&u-JeGLi^r?dO`m=y(QO{@h zQqAC7$rvz&5+mo3IqE?h=a~6m>%r5Quapvzq;{y~p zJpyXOBgD9VrW7@#p6l7O?o3feml(DtSL>D^R) zZUY%T2b0-vBAFN7VB;M88!~HuOXi4KcI6aRQ&h|XQ0A?m%j2=l1f0cGP}h(oVfJ`N zz#PpmFC*ieab)zJK<4?^k=g%OjPnkANzbAbmGZHoVRk*mTfm75s_cWVa`l*f$B@xu z5E*?&@seIo#*Y~1rBm!7sF9~~u6Wrj5oICUOuz}CS)jdNIznfzCA(stJ(7$c^e5wN z?lt>eYgbA!kvAR7zYSD&*r1$b|(@;9dcZ^67R0 zXAXJKa|5Sdmj!g578Nwt6d$sXuc&MWezA0Whd`94$h{{?1IwXP4)Tx4obDK%xoFZ_Z zjjHJ_P@R_e5blG@yEjnaJb`l;s%Lb2&=8$&Ct-fV`E^4CUs)=jTk!I}2d&n!f@)bm z@ z_4Dc86+3l2*p|~;o-Sb~oXb_RuLmoifDU^&Te$*FevycC0*nE3Xws8gsWp|Rj2>SM zns)qcYj?^2sd8?N!_w~4v+f-HCF|a$TNZDoNl$I1Uq87euoNgKb6&r26TNrfkUa@o zfdiFA@p{K&mH3b8i!lcoz)V{n8Q@g(vR4ns4r6w;K z>1~ecQR0-<^J|Ndg5fvVUM9g;lbu-){#ghGw(fg>L zh)T5Ljb%lWE;V9L!;Cqk>AV1(rULYF07ZBJbGb9qbSoLAd;in9{)95YqX$J43-dY7YU*k~vrM25 zxh5_IqO0LYZW%oxQ5HOzmk4x{atE*vipUk}sh88$b2tn?!ujEHn`tQLe&vo}nMb&{ zio`xzZ&GG6&ZyN3jnaQy#iVqXE9VT(3tWY$n-)uWDQ|tc{`?fq2F`oQ{;d3aWPg4Hp-(iE{ry>MIPWL> iW8Zci7-kcv6Uzs@r-FtIZ-&5|)J Q1PU{Fy85}Sb4q9e0B4a5jsO4v literal 0 HcmV?d00001 diff --git a/packages/dart_client/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png b/packages/dart_client/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..9da19eacad3b03bb08bbddbbf4ac48dd78b3d838 GIT binary patch literal 68 zcmeAS@N?(olHy`uVBq!ia0vp^j3CUx0wlM}@Gt=>Zci7-kcv6Uzs@r-FtIZ-&5|)J Q1PU{Fy85}Sb4q9e0B4a5jsO4v literal 0 HcmV?d00001 diff --git a/packages/dart_client/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png b/packages/dart_client/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..9da19eacad3b03bb08bbddbbf4ac48dd78b3d838 GIT binary patch literal 68 zcmeAS@N?(olHy`uVBq!ia0vp^j3CUx0wlM}@Gt=>Zci7-kcv6Uzs@r-FtIZ-&5|)J Q1PU{Fy85}Sb4q9e0B4a5jsO4v literal 0 HcmV?d00001 diff --git a/packages/dart_client/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md b/packages/dart_client/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md new file mode 100644 index 00000000..89c2725b --- /dev/null +++ b/packages/dart_client/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md @@ -0,0 +1,5 @@ +# Launch Screen Assets + +You can customize the launch screen with your own desired assets by replacing the image files in this directory. + +You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images. \ No newline at end of file diff --git a/packages/dart_client/example/ios/Runner/Base.lproj/LaunchScreen.storyboard b/packages/dart_client/example/ios/Runner/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 00000000..f2e259c7 --- /dev/null +++ b/packages/dart_client/example/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/dart_client/example/ios/Runner/Base.lproj/Main.storyboard b/packages/dart_client/example/ios/Runner/Base.lproj/Main.storyboard new file mode 100644 index 00000000..f3c28516 --- /dev/null +++ b/packages/dart_client/example/ios/Runner/Base.lproj/Main.storyboard @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/dart_client/example/ios/Runner/Info.plist b/packages/dart_client/example/ios/Runner/Info.plist new file mode 100644 index 00000000..a060db61 --- /dev/null +++ b/packages/dart_client/example/ios/Runner/Info.plist @@ -0,0 +1,45 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + example + CFBundlePackageType + APPL + CFBundleShortVersionString + $(FLUTTER_BUILD_NAME) + CFBundleSignature + ???? + CFBundleVersion + $(FLUTTER_BUILD_NUMBER) + LSRequiresIPhoneOS + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UIViewControllerBasedStatusBarAppearance + + + diff --git a/packages/dart_client/example/ios/Runner/Runner-Bridging-Header.h b/packages/dart_client/example/ios/Runner/Runner-Bridging-Header.h new file mode 100644 index 00000000..308a2a56 --- /dev/null +++ b/packages/dart_client/example/ios/Runner/Runner-Bridging-Header.h @@ -0,0 +1 @@ +#import "GeneratedPluginRegistrant.h" diff --git a/packages/dart_client/example/lib/main.dart b/packages/dart_client/example/lib/main.dart new file mode 100644 index 00000000..8f68c100 --- /dev/null +++ b/packages/dart_client/example/lib/main.dart @@ -0,0 +1,248 @@ +import 'package:flutter/material.dart'; +import 'package:stream_chat/stream_chat.dart'; + +Future main() async { + /// Create a new instance of [Client] passing the apikey obtained from your + /// project dashboard. + final client = Client('b67pax5b2wdq'); + + /// Set the current user. In a production scenario, this should be done using + /// a backend to generate a user token using our server SDK. + /// Please see the following for more information: + /// https://getstream.io/chat/docs/ios_user_setup_and_tokens/ + await client.setUser( + User( + id: 'cool-shadow-7', + extraData: { + 'image': + 'https://getstream.io/random_png/?id=cool-shadow-7&name=Cool+shadow', + }, + ), + 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoiY29vbC1zaGFkb3ctNyJ9.gkOlCRb1qgy4joHPaxFwPOdXcGvSPvp6QY0S4mpRkVo', + ); + + /// Creates a channel using the type `messaging` and `godevs`. + /// Channels are containers for holding messages between different members. To + /// learn more about channels and some of our predefined types, checkout our + /// our channel docs: https://getstream.io/chat/docs/initialize_channel/?language=dart + final channel = client.channel('messaging', id: 'godevs'); + + /// `.watch()` is used to create and listen to the channel for updates. If the + /// channel already exists, it will simply listen for new events. + await channel.watch(); + + runApp( + StreamExample( + client: client, + channel: channel, + ), + ); +} + +/// Example using Stream's Low Level Dart client. +class StreamExample extends StatelessWidget { + /// To initialize this example, an instance of [client] and [channel] is required. + const StreamExample({ + Key key, + @required this.client, + @required this.channel, + }) : super(key: key); + + /// Instance of [Client] we created earlier. This contains information about + /// our application and connection state. + final Client client; + + /// The channel we'd like to observe and participate. + final Channel channel; + + @override + Widget build(BuildContext context) { + return MaterialApp( + title: 'Stream Chat Dart Example', + home: HomeScreen(channel: channel), + ); + } +} + +/// Main screen of our application. The layout is comprised of an [AppBar] +/// containing the channel name and a [MessageView] displaying recent messages. +class HomeScreen extends StatelessWidget { + /// [HomeScreen] is constructed using the [Channel] we defined earlier. + const HomeScreen({Key key, @required this.channel}) : super(key: key); + + /// Channel object containing the [Channel.id] we'd like to observe. + final Channel channel; + + @override + Widget build(BuildContext context) { + final messages = channel.state.channelStateStream; + return Scaffold( + appBar: AppBar( + title: Text('Channel: ${channel.id}'), + ), + body: SafeArea( + child: StreamBuilder( + stream: messages, + builder: ( + BuildContext context, + AsyncSnapshot snapshot, + ) { + if (snapshot.hasData && snapshot.data != null) { + return MessageView( + messages: snapshot.data.messages.reversed.toList(), + channel: channel, + ); + } else if (snapshot.hasError) { + return const Center( + child: Text( + 'There was an error loading messages. Please see logs.', + ), + ); + } + return const Center( + child: SizedBox( + width: 100.0, + height: 100.0, + child: CircularProgressIndicator(), + ), + ); + }, + ), + ), + ); + } +} + +/// UI used to display a list of recent messages and a [TextField] for sending +/// new messages. +class MessageView extends StatefulWidget { + /// Message takes the latest list of messages and the current channel. + const MessageView({ + Key key, + @required this.messages, + @required this.channel, + }) : super(key: key); + + /// List of messages sent in the given channel. + final List messages; + + /// Current channel being observed. + final Channel channel; + + @override + _MessageViewState createState() => _MessageViewState(); +} + +class _MessageViewState extends State { + TextEditingController _controller; + ScrollController _scrollController; + + List get _messages => widget.messages; + + @override + void initState() { + super.initState(); + _controller = TextEditingController(); + _scrollController = ScrollController(); + } + + @override + void dispose() { + _controller.dispose(); + _scrollController.dispose(); + super.dispose(); + } + + /// Convenience method for scrolling the list view when a new message is sent. + void _updateList() { + _scrollController.animateTo( + _scrollController.position.maxScrollExtent, + duration: const Duration(milliseconds: 200), + curve: Curves.easeOut, + ); + } + + @override + Widget build(BuildContext context) { + return Column( + children: [ + Expanded( + child: ListView.builder( + controller: _scrollController, + itemCount: _messages.length, + reverse: true, + itemBuilder: (BuildContext context, int index) { + final item = _messages[index]; + if (item.user.id == widget.channel.client.uid) { + return Align( + alignment: Alignment.centerRight, + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Text(item.text), + ), + ); + } else { + return Align( + alignment: Alignment.centerLeft, + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Text(item.text), + ), + ); + } + }, + ), + ), + Padding( + padding: const EdgeInsets.all(8.0), + child: Row( + children: [ + Expanded( + child: TextField( + controller: _controller, + decoration: const InputDecoration( + hintText: 'Enter your message', + ), + ), + ), + Material( + type: MaterialType.circle, + color: Colors.blue, + clipBehavior: Clip.hardEdge, + child: InkWell( + onTap: () async { + // We can send a new message by calling `sendMessage` on + // the current channel. After sending a message, the + // TextField is cleared and the list view is scrolled + // to show the new item. + if (_controller.value.text.isNotEmpty) { + await widget.channel.sendMessage( + Message(text: _controller.value.text), + ); + _controller.clear(); + _updateList(); + } + }, + child: const Padding( + padding: EdgeInsets.all(8.0), + child: Center( + child: Icon( + Icons.send, + color: Colors.white, + ), + ), + ), + ), + ) + ], + ), + ) + ], + ); + } +} + +/// Helper extension for quickly retrieving the current user id from a [Client]. +extension on Client { + String get uid => state.user.id; +} diff --git a/packages/dart_client/example/pubspec.yaml b/packages/dart_client/example/pubspec.yaml new file mode 100644 index 00000000..2a8b7eb2 --- /dev/null +++ b/packages/dart_client/example/pubspec.yaml @@ -0,0 +1,21 @@ +name: example +description: A new Flutter project. + +publish_to: 'none' +version: 1.0.0+1 + +environment: + sdk: ">=2.7.0 <3.0.0" + +dependencies: + flutter: + sdk: flutter + cupertino_icons: ^1.0.0 + stream_chat: + path: ../ + +dev_dependencies: + flutter_test: + sdk: flutter +flutter: + uses-material-design: true \ No newline at end of file From b3d12974313bc46ffaf700b350bee42ee5d7eb9b Mon Sep 17 00:00:00 2001 From: Neevash Ramdial Date: Thu, 21 Jan 2021 06:35:24 -0400 Subject: [PATCH 0994/1140] update melos environment --- melos.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/melos.yaml b/melos.yaml index ea99c335..7e02909f 100644 --- a/melos.yaml +++ b/melos.yaml @@ -55,5 +55,5 @@ dev_dependencies: pedantic: 1.9.2 environment: - sdk: ">=2.1.0 <3.0.0" - flutter: ">=1.12.13+hotfix.5 <2.0.0" \ No newline at end of file + sdk: ">=2.7.0 <3.0.0" + flutter: ">=1.22.4 <2.0.0" \ No newline at end of file From e0474b8ded44706e8a2d78ca04645397bd12faeb Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Thu, 21 Jan 2021 17:55:31 +0530 Subject: [PATCH 0995/1140] feat: Added first widgets --- .../lib/src/lazy_load_scroll_view.dart | 148 +++ .../lib/src/reaction_icon.dart | 9 + .../lib/src/stream_chat.dart | 177 ++++ .../lib/src/stream_chat_theme.dart | 898 ++++++++++++++++++ .../lib/src/user_list_view.dart | 507 ++++++++++ .../lib/src/users_bloc.dart | 108 +++ .../stream_chat_flutter_core/pubspec.yaml | 1 + 7 files changed, 1848 insertions(+) create mode 100644 packages/stream_chat_flutter_core/lib/src/lazy_load_scroll_view.dart create mode 100644 packages/stream_chat_flutter_core/lib/src/reaction_icon.dart create mode 100644 packages/stream_chat_flutter_core/lib/src/stream_chat.dart create mode 100644 packages/stream_chat_flutter_core/lib/src/stream_chat_theme.dart create mode 100644 packages/stream_chat_flutter_core/lib/src/user_list_view.dart create mode 100644 packages/stream_chat_flutter_core/lib/src/users_bloc.dart diff --git a/packages/stream_chat_flutter_core/lib/src/lazy_load_scroll_view.dart b/packages/stream_chat_flutter_core/lib/src/lazy_load_scroll_view.dart new file mode 100644 index 00000000..bc1f4d1b --- /dev/null +++ b/packages/stream_chat_flutter_core/lib/src/lazy_load_scroll_view.dart @@ -0,0 +1,148 @@ +import 'package:flutter/foundation.dart'; +import 'package:flutter/widgets.dart'; + +enum _LoadingStatus { LOADING, STABLE } + +/// A widget that wraps a [Widget] and will trigger [onEndOfPage]/[onStartOfPage] when it +/// reaches the bottom/start of the list +class LazyLoadScrollView extends StatefulWidget { + /// The [Widget] that this widget watches for changes on + final Widget child; + + /// Called when the [child] reaches the start of the list + final AsyncCallback onStartOfPage; + + /// Called when the [child] reaches the end of the list + final AsyncCallback onEndOfPage; + + /// Called when the list scrolling starts + final VoidCallback onPageScrollStart; + + /// Called when the list scrolling ends + final VoidCallback onPageScrollEnd; + + /// Called every time the [child] is in-between the list + final VoidCallback onInBetweenOfPage; + + /// The offset to take into account when triggering [onEndOfPage]/[onStartOfPage] in pixels + final double scrollOffset; + + /// Used to determine if loading of new data has finished. You should use set this if you aren't using a FutureBuilder or StreamBuilder + final bool isLoading; + + /// Initiates a LazyLoadScrollView widget + const LazyLoadScrollView({ + Key key, + @required this.child, + this.onStartOfPage, + this.onEndOfPage, + this.onPageScrollStart, + this.onPageScrollEnd, + this.onInBetweenOfPage, + this.isLoading = false, + this.scrollOffset = 100, + }) : assert(child != null), + super(key: key); + + @override + State createState() => _LazyLoadScrollViewState(); +} + +class _LazyLoadScrollViewState extends State { + _LoadingStatus _loadMoreStatus = _LoadingStatus.STABLE; + double _scrollPosition = 0.0; + + @override + Widget build(BuildContext context) { + return NotificationListener( + child: widget.child, + onNotification: _onNotification, + ); + } + + bool _onNotification(Notification notification) { + if (notification is ScrollStartNotification) { + if (widget.onPageScrollStart != null) { + widget.onPageScrollStart(); + return true; + } + } + if (notification is ScrollEndNotification) { + if (widget.onPageScrollEnd != null) { + widget.onPageScrollEnd(); + return true; + } + } + if (notification is ScrollUpdateNotification) { + final pixels = notification.metrics.pixels; + final maxScrollExtent = notification.metrics.maxScrollExtent; + final minScrollExtent = notification.metrics.minScrollExtent; + final scrollOffset = widget.scrollOffset; + + if (pixels > (minScrollExtent + scrollOffset) && + pixels < (maxScrollExtent - scrollOffset)) { + if (widget.onInBetweenOfPage != null) { + widget.onInBetweenOfPage(); + return true; + } + } + + final extentBefore = notification.metrics.extentBefore; + final extentAfter = notification.metrics.extentAfter; + final scrollingDown = _scrollPosition < pixels; + + if (scrollOffset == null || scrollOffset == 0) { + if (extentAfter == 0) { + _onEndOfPage(); + } + if (extentBefore == 0) { + _onStartOfPage(); + } + } else { + if (scrollingDown) { + if (extentAfter <= scrollOffset) { + _onEndOfPage(); + } + } else { + if (extentBefore <= scrollOffset) { + _onStartOfPage(); + } + } + } + _scrollPosition = pixels; + return true; + } + if (notification is OverscrollNotification) { + if (notification.overscroll > 0) { + _onEndOfPage(); + } + if (notification.overscroll < 0) { + _onStartOfPage(); + } + return true; + } + return false; + } + + void _onEndOfPage() { + if (_loadMoreStatus != null && _loadMoreStatus == _LoadingStatus.STABLE) { + _loadMoreStatus = _LoadingStatus.LOADING; + if (widget.onEndOfPage != null) { + widget.onEndOfPage().whenComplete(() { + _loadMoreStatus = _LoadingStatus.STABLE; + }); + } + } + } + + void _onStartOfPage() { + if (_loadMoreStatus != null && _loadMoreStatus == _LoadingStatus.STABLE) { + _loadMoreStatus = _LoadingStatus.LOADING; + if (widget.onStartOfPage != null) { + widget.onStartOfPage().whenComplete(() { + _loadMoreStatus = _LoadingStatus.STABLE; + }); + } + } + } +} diff --git a/packages/stream_chat_flutter_core/lib/src/reaction_icon.dart b/packages/stream_chat_flutter_core/lib/src/reaction_icon.dart new file mode 100644 index 00000000..99b93328 --- /dev/null +++ b/packages/stream_chat_flutter_core/lib/src/reaction_icon.dart @@ -0,0 +1,9 @@ +class ReactionIcon { + final String type; + final String assetName; + + ReactionIcon({ + this.type, + this.assetName, + }); +} diff --git a/packages/stream_chat_flutter_core/lib/src/stream_chat.dart b/packages/stream_chat_flutter_core/lib/src/stream_chat.dart new file mode 100644 index 00000000..e6c47c9d --- /dev/null +++ b/packages/stream_chat_flutter_core/lib/src/stream_chat.dart @@ -0,0 +1,177 @@ +import 'dart:async'; + +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:stream_chat/stream_chat.dart'; +import 'package:stream_chat_flutter_core/src/stream_chat_theme.dart'; + +/// Widget used to provide information about the chat to the widget tree +/// +/// class MyApp extends StatelessWidget { +/// final Client client; +/// +/// MyApp(this.client); +/// +/// @override +/// Widget build(BuildContext context) { +/// return MaterialApp( +/// home: Container( +/// child: StreamChat( +/// client: client, +/// child: ChannelListPage(), +/// ), +/// ), +/// ); +/// } +/// } +/// +/// Use [StreamChat.of] to get the current [StreamChatState] instance. +class StreamChat extends StatefulWidget { + final Client client; + final Widget child; + final StreamChatThemeData streamChatThemeData; + + StreamChat({ + Key key, + @required this.client, + @required this.child, + this.streamChatThemeData, + }) : super( + key: key, + ); + + @override + StreamChatState createState() => StreamChatState(); + + /// Use this method to get the current [StreamChatState] instance + static StreamChatState of(BuildContext context) { + StreamChatState streamChatState; + + streamChatState = context.findAncestorStateOfType(); + + if (streamChatState == null) { + throw Exception( + 'You must have a StreamChat widget at the top of your widget tree'); + } + + return streamChatState; + } +} + +/// The current state of the StreamChat widget +class StreamChatState extends State with WidgetsBindingObserver { + Client get client => widget.client; + Timer _disconnectTimer; + + @override + Widget build(BuildContext context) { + final theme = _getTheme(context, widget.streamChatThemeData); + return StreamChatTheme( + data: theme, + child: Builder( + builder: (context) { + final materialTheme = Theme.of(context); + final streamTheme = StreamChatTheme.of(context); + return Theme( + data: materialTheme.copyWith( + primaryIconTheme: streamTheme.primaryIconTheme, + accentColor: streamTheme.colorTheme.accentBlue, + scaffoldBackgroundColor: streamTheme.colorTheme.white, + ), + child: widget.child, + ); + }, + ), + ); + } + + StreamChatThemeData _getTheme( + BuildContext context, + StreamChatThemeData themeData, + ) { + final defaultTheme = StreamChatThemeData.getDefaultTheme(Theme.of(context)); + return defaultTheme.merge(themeData) ?? themeData; + } + + /// The current user + User get user => widget.client.state.user; + + /// The current user as a stream + Stream get userStream => widget.client.state.userStream; + + @override + void initState() { + super.initState(); + WidgetsBinding.instance.addObserver(this); + // client.state?.totalUnreadCountStream?.listen((count) { + // if (count > 0) { + // FlutterAppBadger.updateBadgeCount(count); + // } else { + // FlutterAppBadger.removeBadge(); + // } + // }); + } + + StreamSubscription _newMessageSubscription; + + @override + void didChangeAppLifecycleState(AppLifecycleState state) { + if (client.state?.user != null) { + if (state == AppLifecycleState.paused) { + if (client.showLocalNotification != null) { + _newMessageSubscription = client + .on(EventType.messageNew) + .where((e) => e.user?.id != user.id) + .where((e) => e.message.silent != true) + .where((e) => e.message.shadowed != true) + .listen((event) async { + final channel = client.channel( + event.channelType, + id: event.channelId, + ); + + client.showLocalNotification( + event.message, + ChannelModel( + id: channel.id, + createdAt: channel.createdAt, + extraData: channel.extraData, + type: channel.type, + memberCount: channel.memberCount, + frozen: channel.frozen, + cid: channel.cid, + deletedAt: channel.deletedAt, + config: channel.config, + createdBy: channel.createdBy, + updatedAt: channel.updatedAt, + lastMessageAt: channel.lastMessageAt, + ), + ); + }); + _disconnectTimer = Timer(client.backgroundKeepAlive, () { + client.disconnect(); + }); + } else { + client.disconnect(); + } + } else if (state == AppLifecycleState.resumed) { + _newMessageSubscription?.cancel(); + if (_disconnectTimer?.isActive == true) { + _disconnectTimer.cancel(); + } else { + if (client.wsConnectionStatus.value == + ConnectionStatus.disconnected) { + NotificationService.handleIosMessageQueue(client); + client.connect(); + } + } + } + } + } + + @override + void dispose() { + WidgetsBinding.instance.removeObserver(this); + super.dispose(); + } +} diff --git a/packages/stream_chat_flutter_core/lib/src/stream_chat_theme.dart b/packages/stream_chat_flutter_core/lib/src/stream_chat_theme.dart new file mode 100644 index 00000000..be584492 --- /dev/null +++ b/packages/stream_chat_flutter_core/lib/src/stream_chat_theme.dart @@ -0,0 +1,898 @@ +import 'package:flutter/material.dart'; +import 'package:stream_chat/stream_chat.dart'; +import 'package:stream_chat_flutter_core/src/reaction_icon.dart'; + +/// Inherited widget providing the [StreamChatThemeData] to the widget tree +class StreamChatTheme extends InheritedWidget { + final StreamChatThemeData data; + + StreamChatTheme({ + Key key, + @required this.data, + Widget child, + }) : super( + key: key, + child: child, + ); + + @override + bool updateShouldNotify(StreamChatTheme old) { + return data != old.data; + } + + /// Use this method to get the current [StreamChatThemeData] instance + static StreamChatThemeData of(BuildContext context) { + final streamChatTheme = + context.dependOnInheritedWidgetOfExactType(); + + if (streamChatTheme == null) { + throw Exception( + 'You must have a StreamChatTheme widget at the top of your widget tree', + ); + } + + return streamChatTheme.data; + } +} + +/// Theme data +class StreamChatThemeData { + /// The text themes used in the widgets + final TextTheme textTheme; + + /// The button themes used in the widgets + final ButtonThemeData buttonTheme; + + /// The text themes used in the widgets + final ColorTheme colorTheme; + + /// Theme of the [ChannelPreview] + final ChannelPreviewTheme channelPreviewTheme; + + /// Theme of the chat widgets dedicated to a channel + final ChannelTheme channelTheme; + + /// Theme of the current user messages + final MessageTheme ownMessageTheme; + + /// Theme of other users messages + final MessageTheme otherMessageTheme; + + /// The widget that will be built when the channel image is unavailable + final Widget Function(BuildContext, Channel) defaultChannelImage; + + /// The widget that will be built when the user image is unavailable + final Widget Function(BuildContext, User) defaultUserImage; + + /// Primary icon theme + final IconThemeData primaryIconTheme; + + /// Assets used for rendering reactions + final List reactionIcons; + + /// Create a theme from scratch + const StreamChatThemeData({ + this.textTheme, + this.buttonTheme, + this.colorTheme, + this.channelPreviewTheme, + this.channelTheme, + this.otherMessageTheme, + this.ownMessageTheme, + this.defaultChannelImage, + this.defaultUserImage, + this.primaryIconTheme, + this.reactionIcons, + }); + + /// Create a theme from a Material [Theme] + factory StreamChatThemeData.fromTheme(ThemeData theme) { + final defaultTheme = getDefaultTheme(theme); + final customizedTheme = StreamChatThemeData( + primaryIconTheme: theme.primaryIconTheme, + ownMessageTheme: MessageTheme( + replies: TextStyle(color: theme.accentColor), + messageLinks: TextStyle(color: theme.accentColor), + ), + otherMessageTheme: MessageTheme( + replies: TextStyle(color: theme.accentColor), + messageLinks: TextStyle(color: theme.accentColor), + ), + ); + return defaultTheme.merge(customizedTheme) ?? customizedTheme; + } + + /// Creates a copy of [StreamChatThemeData] with specified attributes overridden. + StreamChatThemeData copyWith({ + TextTheme textTheme, + ButtonThemeData buttonTheme, + ColorTheme colorTheme, + ChannelPreviewTheme channelPreviewTheme, + ChannelTheme channelTheme, + MessageTheme ownMessageTheme, + MessageTheme otherMessageTheme, + Widget Function(BuildContext, Channel) defaultChannelImage, + Widget Function(BuildContext, User) defaultUserImage, + IconThemeData primaryIconTheme, + List reactionIcons, + }) => + StreamChatThemeData( + textTheme: textTheme ?? this.textTheme, + buttonTheme: buttonTheme ?? this.buttonTheme, + colorTheme: colorTheme ?? this.colorTheme, + primaryIconTheme: primaryIconTheme ?? this.primaryIconTheme, + defaultChannelImage: defaultChannelImage ?? this.defaultChannelImage, + defaultUserImage: defaultUserImage ?? this.defaultUserImage, + channelPreviewTheme: channelPreviewTheme ?? this.channelPreviewTheme, + channelTheme: channelTheme ?? this.channelTheme, + ownMessageTheme: ownMessageTheme ?? this.ownMessageTheme, + otherMessageTheme: otherMessageTheme ?? this.otherMessageTheme, + reactionIcons: reactionIcons ?? this.reactionIcons, + ); + + StreamChatThemeData merge(StreamChatThemeData other) { + if (other == null) return this; + return copyWith( + textTheme: textTheme?.merge(other.textTheme) ?? other.textTheme, + buttonTheme: other.buttonTheme, + colorTheme: colorTheme?.merge(other.colorTheme) ?? other.colorTheme, + primaryIconTheme: other.primaryIconTheme, + defaultChannelImage: other.defaultChannelImage, + defaultUserImage: other.defaultUserImage, + channelPreviewTheme: + channelPreviewTheme?.merge(other.channelPreviewTheme) ?? + other.channelPreviewTheme, + channelTheme: + channelTheme?.merge(other.channelTheme) ?? other.channelTheme, + ownMessageTheme: ownMessageTheme?.merge(other.ownMessageTheme) ?? + other.ownMessageTheme, + otherMessageTheme: otherMessageTheme?.merge(other.otherMessageTheme) ?? + other.otherMessageTheme, + reactionIcons: other.reactionIcons, + ); + } + + /// Get the default Stream Chat theme + static StreamChatThemeData getDefaultTheme(ThemeData theme) { + final accentColor = Color(0xff006cff); + final isDark = theme.brightness == Brightness.dark; + final textTheme = isDark ? TextTheme.dark() : TextTheme.light(); + final colorTheme = isDark ? ColorTheme.dark() : ColorTheme.light(); + return StreamChatThemeData( + textTheme: textTheme, + colorTheme: colorTheme, + buttonTheme: ButtonThemeData( + height: 48.0, + buttonColor: isDark ? Color(0xffffffff) : Color(0xff006aff), + textTheme: ButtonTextTheme.accent, + colorScheme: theme.colorScheme.copyWith( + secondary: isDark ? Color(0xff005eff) : Color(0xffffffff), + ), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(26), + ), + ), + primaryIconTheme: IconThemeData(color: colorTheme.black.withOpacity(.5)), + defaultChannelImage: (context, channel) => SizedBox(), + defaultUserImage: (context, user) => Center( + child: Image.network( + getRandomPicUrl(user), + filterQuality: FilterQuality.high, + fit: BoxFit.cover, + ), + ), + channelPreviewTheme: ChannelPreviewTheme( + unreadCounterColor: colorTheme.accentRed, + avatarTheme: AvatarTheme( + borderRadius: BorderRadius.circular(20), + constraints: BoxConstraints.tightFor( + height: 40, + width: 40, + ), + ), + title: textTheme.bodyBold, + subtitle: textTheme.footnote.copyWith( + color: Color(0xff7A7A7A), + ), + lastMessageAt: textTheme.footnote.copyWith( + color: colorTheme.black.withOpacity(.5), + ), + indicatorIconSize: 16.0), + channelTheme: ChannelTheme( + messageInputButtonIconTheme: theme.iconTheme.copyWith( + color: accentColor, + ), + channelHeaderTheme: ChannelHeaderTheme( + avatarTheme: AvatarTheme( + borderRadius: BorderRadius.circular(20), + constraints: BoxConstraints.tightFor( + height: 40, + width: 40, + ), + ), + color: colorTheme.white, + title: TextStyle( + fontSize: 14, + color: colorTheme.black, + ), + lastMessageAt: TextStyle( + fontSize: 11, + color: colorTheme.black.withOpacity(.5), + ), + ), + inputBackground: colorTheme.white.withAlpha(12), + ), + ownMessageTheme: MessageTheme( + 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, + reactionsMaskColor: colorTheme.whiteSnow, + messageBorderColor: colorTheme.greyGainsboro, + avatarTheme: AvatarTheme( + borderRadius: BorderRadius.circular(20), + constraints: BoxConstraints.tightFor( + height: 32, + width: 32, + ), + ), + messageLinks: TextStyle( + color: accentColor, + ), + ), + otherMessageTheme: MessageTheme( + reactionsBackgroundColor: colorTheme.greyGainsboro, + reactionsBorderColor: colorTheme.white, + reactionsMaskColor: colorTheme.whiteSnow, + messageText: textTheme.body, + createdAt: textTheme.footnote.copyWith(color: colorTheme.grey), + replies: textTheme.footnoteBold.copyWith(color: accentColor), + messageLinks: TextStyle( + color: accentColor, + ), + messageBackgroundColor: colorTheme.white, + messageBorderColor: colorTheme.greyWhisper, + avatarTheme: AvatarTheme( + borderRadius: BorderRadius.circular(20), + constraints: BoxConstraints.tightFor( + height: 32, + width: 32, + ), + ), + ), + reactionIcons: [ + ReactionIcon( + type: 'love', + assetName: 'Icon_love_reaction.svg', + ), + ReactionIcon( + type: 'like', + assetName: 'Icon_thumbs_up_reaction.svg', + ), + ReactionIcon( + type: 'sad', + assetName: 'Icon_thumbs_down_reaction.svg', + ), + ReactionIcon( + type: 'haha', + assetName: 'Icon_LOL_reaction.svg', + ), + ReactionIcon( + type: 'wow', + assetName: 'Icon_wut_reaction.svg', + ), + ], + ); + } +} + +enum TextThemeType { + light, + dark, +} + +class TextTheme { + final TextStyle title; + final TextStyle headlineBold; + final TextStyle headline; + final TextStyle bodyBold; + final TextStyle body; + final TextStyle footnoteBold; + final TextStyle footnote; + final TextStyle captionBold; + + TextTheme.light({ + this.title = const TextStyle( + fontSize: 22, + fontWeight: FontWeight.bold, + color: Colors.black, + ), + this.headlineBold = const TextStyle( + fontSize: 16, + fontWeight: FontWeight.bold, + color: Colors.black, + ), + this.headline = const TextStyle( + fontSize: 16, + fontWeight: FontWeight.w500, + color: Colors.black, + ), + this.bodyBold = const TextStyle( + fontSize: 14, + fontWeight: FontWeight.bold, + color: Colors.black, + ), + this.body = const TextStyle( + fontSize: 14, + fontWeight: FontWeight.w500, + color: Colors.black, + ), + this.footnoteBold = const TextStyle( + fontSize: 12, + fontWeight: FontWeight.w500, + color: Colors.black, + ), + this.footnote = const TextStyle( + fontSize: 12, + color: Colors.black, + ), + this.captionBold = const TextStyle( + fontSize: 10, + fontWeight: FontWeight.bold, + color: Colors.black, + ), + }); + + TextTheme.dark({ + this.title = const TextStyle( + fontSize: 22, + fontWeight: FontWeight.bold, + color: Colors.white, + ), + this.headlineBold = const TextStyle( + fontSize: 16, + fontWeight: FontWeight.bold, + color: Colors.white, + ), + this.headline = const TextStyle( + fontSize: 16, + fontWeight: FontWeight.w500, + color: Colors.white, + ), + this.bodyBold = const TextStyle( + fontSize: 14, + fontWeight: FontWeight.bold, + color: Colors.white, + ), + this.body = const TextStyle( + fontSize: 14, + fontWeight: FontWeight.w500, + color: Colors.white, + ), + this.footnoteBold = const TextStyle( + fontSize: 12, + fontWeight: FontWeight.w500, + color: Colors.white, + ), + this.footnote = const TextStyle( + fontSize: 12, + color: Colors.white, + ), + this.captionBold = const TextStyle( + fontSize: 10, + fontWeight: FontWeight.bold, + color: Colors.white, + ), + }); + + TextTheme copyWith({ + TextThemeType type = TextThemeType.light, + TextStyle body, + TextStyle title, + TextStyle headlineBold, + TextStyle headline, + TextStyle bodyBold, + TextStyle footnoteBold, + TextStyle footnote, + TextStyle captionBold, + }) { + return type == TextThemeType.light + ? TextTheme.light( + body: body ?? this.body, + title: title ?? this.title, + headlineBold: headlineBold ?? this.headlineBold, + headline: headline ?? this.headline, + bodyBold: bodyBold ?? this.bodyBold, + footnoteBold: footnoteBold ?? this.footnoteBold, + footnote: footnote ?? this.footnote, + captionBold: captionBold ?? this.captionBold, + ) + : TextTheme.dark( + body: body ?? this.body, + title: title ?? this.title, + headlineBold: headlineBold ?? this.headlineBold, + headline: headline ?? this.headline, + bodyBold: bodyBold ?? this.bodyBold, + footnoteBold: footnoteBold ?? this.footnoteBold, + footnote: footnote ?? this.footnote, + captionBold: captionBold ?? this.captionBold, + ); + } + + TextTheme merge(TextTheme other) { + if (other == null) return this; + return copyWith( + body: body?.merge(other.body) ?? other.body, + title: title?.merge(other.title) ?? other.title, + headlineBold: + headlineBold?.merge(other.headlineBold) ?? other.headlineBold, + headline: headline?.merge(other.headline) ?? other.headline, + bodyBold: bodyBold?.merge(other.bodyBold) ?? other.bodyBold, + footnoteBold: + footnoteBold?.merge(other.footnoteBold) ?? other.footnoteBold, + footnote: footnote?.merge(other.footnote) ?? other.footnote, + captionBold: captionBold?.merge(other.captionBold) ?? other.captionBold, + ); + } +} + +enum ColorThemeType { + light, + dark, +} + +class ColorTheme { + final Color black; + final Color grey; + final Color greyGainsboro; + final Color greyWhisper; + final Color whiteSmoke; + final Color whiteSnow; + final Color white; + final Color blueAlice; + final Color accentBlue; + final Color accentRed; + final Color accentGreen; + final Effect borderTop; + final Effect borderBottom; + final Effect shadowIconButton; + final Effect modalShadow; + final Color highlight; + final Color overlay; + final Color overlayDark; + final Gradient bgGradient; + + ColorTheme.light({ + this.black = const Color(0xff000000), + this.grey = const Color(0xff7a7a7a), + this.greyGainsboro = const Color(0xffdbdbdb), + this.greyWhisper = const Color(0xffecebeb), + this.whiteSmoke = const Color(0xfff2f2f2), + this.whiteSnow = const Color(0xfffcfcfc), + this.white = const Color(0xffffffff), + this.blueAlice = const Color(0xffe9f2ff), + this.accentBlue = const Color(0xff005FFF), + this.accentRed = const Color(0xffFF3842), + this.accentGreen = const Color(0xff20E070), + this.highlight = const Color(0xfffbf4dd), + this.overlay = const Color.fromRGBO(0, 0, 0, 0.2), + this.overlayDark = const Color.fromRGBO(0, 0, 0, 0.6), + this.bgGradient = const LinearGradient( + begin: Alignment.topCenter, + end: Alignment.bottomCenter, + colors: [const Color(0xfff7f7f7), const Color(0xfffcfcfc)], + stops: [0, 1], + ), + this.borderTop = const Effect( + sigmaX: 0, + sigmaY: -1, + color: Color(0xff000000), + blur: 0.0, + alpha: 0.08), + this.borderBottom = const Effect( + sigmaX: 0, sigmaY: 1, color: Color(0xff000000), blur: 0.0, alpha: 0.08), + this.shadowIconButton = const Effect( + sigmaX: 0, sigmaY: 2, color: Color(0xff000000), alpha: 0.5, blur: 4.0), + this.modalShadow = const Effect( + sigmaX: 0, sigmaY: 0, color: Color(0xff000000), alpha: 1, blur: 8.0), + }); + + ColorTheme.dark({ + this.black = const Color(0xffffffff), + this.grey = const Color(0xff7a7a7a), + this.greyGainsboro = const Color(0xff2d2f2f), + this.greyWhisper = const Color(0xff1c1e22), + this.whiteSmoke = const Color(0xff13151b), + this.whiteSnow = const Color(0xff070A0D), + this.white = const Color(0xff101418), + this.blueAlice = const Color(0xff00193D), + this.accentBlue = const Color(0xff005FFF), + this.accentRed = const Color(0xffFF3742), + this.accentGreen = const Color(0xff20E070), + this.borderTop = const Effect( + sigmaX: 0, sigmaY: -1, color: Color(0xff141924), blur: 0.0), + this.borderBottom = const Effect( + sigmaX: 0, sigmaY: 1, color: Color(0xff141924), blur: 0.0, alpha: 1.0), + this.shadowIconButton = const Effect( + sigmaX: 0, sigmaY: 2, color: Color(0xff000000), alpha: 0.5, blur: 4.0), + this.modalShadow = const Effect( + sigmaX: 0, sigmaY: 0, color: Color(0xff000000), alpha: 1, blur: 8.0), + this.highlight = const Color(0xff302d22), + this.overlay = const Color.fromRGBO(0, 0, 0, 0.4), + this.overlayDark = const Color.fromRGBO(255, 255, 255, 0.6), + this.bgGradient = const LinearGradient( + begin: Alignment.topCenter, + end: Alignment.bottomCenter, + colors: [const Color(0xff101214), const Color(0xff070a0d)], + stops: [0, 1], + ), + }); + + ColorTheme copyWith({ + ColorThemeType type = ColorThemeType.light, + Color black, + Color grey, + Color greyGainsboro, + Color greyWhisper, + Color whiteSmoke, + Color whiteSnow, + Color white, + Color blueAlice, + Color accentBlue, + Color accentRed, + Color accentGreen, + Effect borderTop, + Effect borderBottom, + Effect shadowIconButton, + Effect modalShadow, + Color highlight, + Color overlay, + Color overlayDark, + Gradient bgGradient, + }) { + return type == ColorThemeType.light + ? ColorTheme.light( + black: black ?? this.black, + grey: grey ?? this.grey, + greyGainsboro: greyGainsboro ?? this.greyGainsboro, + greyWhisper: greyWhisper ?? this.greyWhisper, + whiteSmoke: whiteSmoke ?? this.whiteSmoke, + whiteSnow: whiteSnow ?? this.whiteSnow, + white: white ?? this.white, + blueAlice: blueAlice ?? this.blueAlice, + accentBlue: accentBlue ?? this.accentBlue, + accentRed: accentRed ?? this.accentRed, + accentGreen: accentGreen ?? this.accentGreen, + borderTop: borderTop ?? this.borderTop, + borderBottom: borderBottom ?? this.borderBottom, + shadowIconButton: shadowIconButton ?? this.shadowIconButton, + modalShadow: modalShadow ?? this.modalShadow, + highlight: highlight ?? this.highlight, + overlay: overlay ?? this.overlay, + overlayDark: overlayDark ?? this.overlayDark, + bgGradient: bgGradient ?? this.bgGradient, + ) + : ColorTheme.dark( + black: black ?? this.black, + grey: grey ?? this.grey, + greyGainsboro: greyGainsboro ?? this.greyGainsboro, + greyWhisper: greyWhisper ?? this.greyWhisper, + whiteSmoke: whiteSmoke ?? this.whiteSmoke, + whiteSnow: whiteSnow ?? this.whiteSnow, + white: white ?? this.white, + blueAlice: blueAlice ?? this.blueAlice, + accentBlue: accentBlue ?? this.accentBlue, + accentRed: accentRed ?? this.accentRed, + accentGreen: accentGreen ?? this.accentGreen, + borderTop: borderTop ?? this.borderTop, + borderBottom: borderBottom ?? this.borderBottom, + shadowIconButton: shadowIconButton ?? this.shadowIconButton, + modalShadow: modalShadow ?? this.modalShadow, + highlight: highlight ?? this.highlight, + overlay: overlay ?? this.overlay, + overlayDark: overlayDark ?? this.overlayDark, + bgGradient: bgGradient ?? this.bgGradient, + ); + } + + ColorTheme merge(ColorTheme other) { + if (other == null) return this; + return copyWith( + black: other.black, + grey: other.grey, + greyGainsboro: other.greyGainsboro, + greyWhisper: other.greyWhisper, + whiteSmoke: other.whiteSmoke, + whiteSnow: other.whiteSnow, + white: other.white, + blueAlice: other.blueAlice, + accentBlue: other.accentBlue, + accentRed: other.accentRed, + accentGreen: other.accentGreen, + highlight: other.highlight, + overlay: other.overlay, + overlayDark: other.overlayDark, + bgGradient: other.bgGradient, + borderTop: other.borderTop, + borderBottom: other.borderBottom, + shadowIconButton: other.shadowIconButton, + modalShadow: other.modalShadow, + ); + } +} + +/// Channel theme data +class ChannelTheme { + /// Theme of the [ChannelHeader] widget + final ChannelHeaderTheme channelHeaderTheme; + + /// IconTheme of the send button in [MessageInput] + final IconThemeData messageInputButtonIconTheme; + + /// Theme of the send button in [MessageInput] + final ButtonThemeData messageInputButtonTheme; + + /// Background color of [MessageInput] + final Color inputBackground; + + ChannelTheme({ + this.channelHeaderTheme, + this.messageInputButtonIconTheme, + this.messageInputButtonTheme, + this.inputBackground, + }); + + /// Creates a copy of [ChannelTheme] with specified attributes overridden. + ChannelTheme copyWith({ + ChannelHeaderTheme channelHeaderTheme, + IconThemeData messageInputButtonIconTheme, + ButtonThemeData messageInputButtonTheme, + Color inputBackground, + }) => + ChannelTheme( + channelHeaderTheme: channelHeaderTheme ?? this.channelHeaderTheme, + messageInputButtonIconTheme: + messageInputButtonIconTheme ?? this.messageInputButtonIconTheme, + messageInputButtonTheme: + messageInputButtonTheme ?? this.messageInputButtonTheme, + inputBackground: inputBackground ?? this.inputBackground, + ); + + ChannelTheme merge(ChannelTheme other) { + if (other == null) return this; + return copyWith( + channelHeaderTheme: channelHeaderTheme?.merge(other.channelHeaderTheme) ?? + other.channelHeaderTheme, + messageInputButtonIconTheme: messageInputButtonIconTheme + ?.merge(other.messageInputButtonIconTheme) ?? + other.messageInputButtonIconTheme, + messageInputButtonTheme: other.messageInputButtonTheme, + inputBackground: other.inputBackground, + ); + } +} + +class AvatarTheme { + final BoxConstraints constraints; + final BorderRadius borderRadius; + + AvatarTheme({ + this.constraints, + this.borderRadius, + }); + + AvatarTheme copyWith({ + BoxConstraints constraints, + BorderRadius borderRadius, + }) => + AvatarTheme( + constraints: constraints ?? this.constraints, + borderRadius: borderRadius ?? this.borderRadius, + ); + + AvatarTheme merge(AvatarTheme other) { + if (other == null) return this; + return copyWith( + constraints: other.constraints, + borderRadius: other.borderRadius, + ); + } +} + +class MessageTheme { + final TextStyle messageText; + final TextStyle messageAuthor; + final TextStyle messageLinks; + final TextStyle createdAt; + final TextStyle replies; + final Color messageBackgroundColor; + final Color messageBorderColor; + final Color reactionsBackgroundColor; + final Color reactionsBorderColor; + final Color reactionsMaskColor; + final AvatarTheme avatarTheme; + + const MessageTheme({ + this.replies, + this.messageText, + this.messageAuthor, + this.messageLinks, + this.messageBackgroundColor, + this.messageBorderColor, + this.reactionsBackgroundColor, + this.reactionsBorderColor, + this.reactionsMaskColor, + this.avatarTheme, + this.createdAt, + }); + + MessageTheme copyWith({ + TextStyle messageText, + TextStyle messageAuthor, + TextStyle messageLinks, + TextStyle createdAt, + TextStyle replies, + Color messageBackgroundColor, + Color messageBorderColor, + AvatarTheme avatarTheme, + Color reactionsBackgroundColor, + Color reactionsBorderColor, + Color reactionsMaskColor, + }) => + MessageTheme( + messageText: messageText ?? this.messageText, + messageAuthor: messageAuthor ?? this.messageAuthor, + messageLinks: messageLinks ?? this.messageLinks, + createdAt: createdAt ?? this.createdAt, + messageBackgroundColor: + messageBackgroundColor ?? this.messageBackgroundColor, + messageBorderColor: messageBorderColor ?? this.messageBorderColor, + avatarTheme: avatarTheme ?? this.avatarTheme, + replies: replies ?? this.replies, + reactionsBackgroundColor: + reactionsBackgroundColor ?? this.reactionsBackgroundColor, + reactionsBorderColor: reactionsBorderColor ?? this.reactionsBorderColor, + reactionsMaskColor: reactionsMaskColor ?? this.reactionsMaskColor, + ); + + MessageTheme merge(MessageTheme other) { + if (other == null) return this; + return copyWith( + messageText: messageText?.merge(other.messageText) ?? other.messageText, + messageAuthor: + messageAuthor?.merge(other.messageAuthor) ?? other.messageAuthor, + messageLinks: + messageLinks?.merge(other.messageLinks) ?? other.messageLinks, + createdAt: createdAt?.merge(other.createdAt) ?? other.createdAt, + replies: replies?.merge(other.replies) ?? other.replies, + messageBackgroundColor: other.messageBackgroundColor, + messageBorderColor: other.messageBorderColor, + avatarTheme: avatarTheme?.merge(other.avatarTheme) ?? other.avatarTheme, + reactionsBackgroundColor: other.reactionsBackgroundColor, + reactionsBorderColor: other.reactionsBorderColor, + reactionsMaskColor: other.reactionsMaskColor, + ); + } +} + +class ChannelPreviewTheme { + final TextStyle title; + final TextStyle subtitle; + final TextStyle lastMessageAt; + final AvatarTheme avatarTheme; + final Color unreadCounterColor; + final double indicatorIconSize; + + const ChannelPreviewTheme({ + this.title, + this.subtitle, + this.lastMessageAt, + this.avatarTheme, + this.unreadCounterColor, + this.indicatorIconSize, + }); + + ChannelPreviewTheme copyWith({ + TextStyle title, + TextStyle subtitle, + TextStyle lastMessageAt, + AvatarTheme avatarTheme, + Color unreadCounterColor, + double indicatorIconSize, + }) => + ChannelPreviewTheme( + title: title ?? this.title, + subtitle: subtitle ?? this.subtitle, + lastMessageAt: lastMessageAt ?? this.lastMessageAt, + avatarTheme: avatarTheme ?? this.avatarTheme, + unreadCounterColor: unreadCounterColor ?? this.unreadCounterColor, + indicatorIconSize: indicatorIconSize ?? this.indicatorIconSize, + ); + + ChannelPreviewTheme merge(ChannelPreviewTheme other) { + if (other == null) return this; + return copyWith( + title: title?.merge(other.title) ?? other.title, + subtitle: subtitle?.merge(other.subtitle) ?? other.subtitle, + lastMessageAt: + lastMessageAt?.merge(other.lastMessageAt) ?? other.lastMessageAt, + avatarTheme: avatarTheme?.merge(other.avatarTheme) ?? other.avatarTheme, + unreadCounterColor: other.unreadCounterColor, + ); + } +} + +class ChannelHeaderTheme { + final TextStyle title; + final TextStyle lastMessageAt; + final AvatarTheme avatarTheme; + final Color color; + + const ChannelHeaderTheme({ + this.title, + this.lastMessageAt, + this.avatarTheme, + this.color, + }); + + ChannelHeaderTheme copyWith({ + TextStyle title, + TextStyle lastMessageAt, + AvatarTheme avatarTheme, + Color color, + }) => + ChannelHeaderTheme( + title: title ?? this.title, + lastMessageAt: lastMessageAt ?? this.lastMessageAt, + avatarTheme: avatarTheme ?? this.avatarTheme, + color: color ?? this.color, + ); + + ChannelHeaderTheme merge(ChannelHeaderTheme other) { + if (other == null) return this; + return copyWith( + title: title?.merge(other.title) ?? other.title, + lastMessageAt: + lastMessageAt?.merge(other.lastMessageAt) ?? other.lastMessageAt, + avatarTheme: avatarTheme?.merge(other.avatarTheme) ?? other.avatarTheme, + color: other.color, + ); + } +} + +class Effect { + final double sigmaX; + final double sigmaY; + final Color color; + final double alpha; + final double blur; + + const Effect({ + this.sigmaX, + this.sigmaY, + this.color, + this.alpha, + this.blur, + }); + + Effect copyWith({ + double sigmaX, + double sigmaY, + Color color, + double alpha, + double blur, + }) => + Effect( + sigmaX: sigmaX ?? this.sigmaX, + sigmaY: sigmaY ?? this.sigmaY, + color: color ?? this.color, + alpha: color ?? this.alpha, + blur: blur ?? this.blur, + ); +} + +/// Get random png with initials +String getRandomPicUrl(User user) => + 'https://getstream.io/random_png/?id=${user.id}&name=${user.name}'; diff --git a/packages/stream_chat_flutter_core/lib/src/user_list_view.dart b/packages/stream_chat_flutter_core/lib/src/user_list_view.dart new file mode 100644 index 00000000..4681d931 --- /dev/null +++ b/packages/stream_chat_flutter_core/lib/src/user_list_view.dart @@ -0,0 +1,507 @@ +import 'dart:convert'; + +import 'package:flutter/material.dart'; +import 'package:stream_chat/stream_chat.dart'; +import 'package:stream_chat_flutter_core/src/lazy_load_scroll_view.dart'; +import 'package:stream_chat_flutter_core/src/users_bloc.dart'; +import 'package:stream_chat_flutter_core/src/stream_chat_theme.dart'; + +/// Callback called when tapping on a user +typedef UserTapCallback = void Function(User, Widget); + +/// Builder used to create a custom [ListUserItem] from a [User] +typedef UserItemBuilder = Widget Function(BuildContext, User, bool); + +/// +/// It shows the list of current users. +/// +/// ```dart +/// class UsersListPage extends StatelessWidget { +/// @override +/// Widget build(BuildContext context) { +/// return Scaffold( +/// body: UsersListView( +/// filter: { +/// 'members': { +/// '\$in': [StreamChat.of(context).user.id], +/// } +/// }, +/// sort: [SortOption('last_message_at')], +/// pagination: PaginationParams( +/// limit: 20, +/// ), +/// channelWidget: ChannelPage(), +/// ), +/// ); +/// } +/// } +/// ``` +/// +/// +/// Make sure to have a [UsersBloc] ancestor in order to provide the information about the users. +/// The widget uses a [ListView.separated], [GridView.builder] to render the list, grid of channels. +/// +/// The widget components render the ui based on the first ancestor of type [StreamChatTheme]. +/// Modify it to change the widget appearance. +class UserListView extends StatefulWidget { + /// Instantiate a new UserListView + const UserListView({ + Key key, + this.errorBuilder, + this.emptyBuilder, + this.filter, + this.options, + this.sort, + this.pagination, + this.onUserTap, + this.onUserLongPress, + this.userWidget, + this.userItemBuilder, + this.separatorBuilder, + this.onImageTap, + this.selectedUsers, + this.pullToRefresh = true, + this.groupAlphabetically = false, + this.crossAxisCount = 1, + }) : assert( + crossAxisCount == 1 || groupAlphabetically == false, + 'Cannot group alphabetically when crossAxisCount > 1', + ), + super(key: key); + + /// The builder that will be used in case of error + final Widget Function(Error error) errorBuilder; + + /// The builder used when the channel list is empty. + final WidgetBuilder emptyBuilder; + + /// The query filters to use. + /// You can query on any of the custom fields you've defined on the [Channel]. + /// You can also filter other built-in channel fields. + final Map filter; + + /// Query channels options. + /// + /// state: if true returns the Channel state + /// watch: if true listen to changes to this Channel in real time. + final Map options; + + /// The sorting used for the channels matching the filters. + /// Sorting is based on field and direction, multiple sorting options can be provided. + /// You can sort based on last_updated, last_message_at, updated_at, created_at or member_count. + /// Direction can be ascending or descending. + final List sort; + + /// Pagination parameters + /// limit: the number of users to return (max is 30) + /// offset: the offset (max is 1000) + /// message_limit: how many messages should be included to each channel + final PaginationParams pagination; + + /// Function called when tapping on a channel + /// By default it calls [Navigator.push] building a [MaterialPageRoute] + /// with the widget [userWidget] as child. + final UserTapCallback onUserTap; + + /// Function called when long pressing on a channel + final Function(User) onUserLongPress; + + /// Widget used when opening a channel + final Widget userWidget; + + /// Builder used to create a custom user preview + final UserItemBuilder userItemBuilder; + + /// Builder used to create a custom item separator + final Function(BuildContext, int) separatorBuilder; + + /// The function called when the image is tapped + final Function(User) onImageTap; + + /// Set it to false to disable the pull-to-refresh widget + final bool pullToRefresh; + + /// Sets a blue trailing checkMark in [ListUserItem] for all the [selectedUsers] + final Set selectedUsers; + + /// Set it to true to group users by their first character + /// + /// defaults to false + final bool groupAlphabetically; + + /// The number of children in the cross axis. + final int crossAxisCount; + + @override + _UserListViewState createState() => _UserListViewState(); +} + +class _UserListViewState extends State + with WidgetsBindingObserver { + bool get _isListView => widget.crossAxisCount == 1; + + @override + void initState() { + super.initState(); + final usersBloc = UsersBloc.of(context); + usersBloc.queryUsers( + filter: widget.filter, + sort: widget.sort, + pagination: widget.pagination, + options: widget.options, + ); + } + + @override + Widget build(BuildContext context) { + final usersBloc = UsersBloc.of(context); + + if (!widget.pullToRefresh) { + return _buildListView(usersBloc); + } + + return RefreshIndicator( + onRefresh: () async { + return usersBloc.queryUsers( + filter: widget.filter, + sort: widget.sort, + options: widget.options, + pagination: widget.pagination, + ); + }, + child: _buildListView(usersBloc), + ); + } + + bool get isListAlreadySorted => + widget.sort?.any((e) => e.field == 'name' && e.direction == 1) ?? false; + + Stream> _buildUserStream( + UsersBlocState usersBlocState, + ) { + return usersBlocState.usersStream.map( + (users) { + if (widget.groupAlphabetically) { + var temp = users; + if (!isListAlreadySorted) { + temp = users..sort((curr, next) => curr.name.compareTo(next.name)); + } + final groupedUsers = >{}; + for (var e in temp) { + final alphabet = e.name[0]?.toUpperCase(); + groupedUsers[alphabet] = [...groupedUsers[alphabet] ?? [], e]; + } + final items = []; + for (var key in groupedUsers.keys) { + items.add(ListHeaderItem(key)); + items.addAll(groupedUsers[key].map((e) => ListUserItem(e))); + } + return items; + } + return users.map((e) => ListUserItem(e)).toList(); + }, + ); + } + + StreamBuilder> _buildListView( + UsersBlocState usersBlocState, + ) { + return StreamBuilder( + stream: _buildUserStream(usersBlocState), + builder: (context, snapshot) { + if (snapshot.hasError) { + if (snapshot.error is Error) { + print((snapshot.error as Error).stackTrace); + } + + if (widget.errorBuilder != null) { + return widget.errorBuilder(snapshot.error); + } + + var message = snapshot.error.toString(); + if (snapshot.error is DioError) { + final dioError = snapshot.error as DioError; + if (dioError.type == DioErrorType.RESPONSE) { + message = dioError.message; + } else { + message = 'Check your connection and retry'; + } + } + return Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text.rich( + TextSpan( + children: [ + WidgetSpan( + child: Padding( + padding: const EdgeInsets.only( + right: 2.0, + ), + child: Icon(Icons.error_outline), + ), + ), + TextSpan(text: 'Error loading channels'), + ], + ), + style: Theme.of(context).textTheme.headline6, + ), + Padding( + padding: const EdgeInsets.only( + top: 16.0, + ), + child: Text(message), + ), + FlatButton( + onPressed: () { + usersBlocState.queryUsers( + filter: widget.filter, + sort: widget.sort, + pagination: widget.pagination, + options: widget.options, + ); + }, + child: Text('Retry'), + ), + ], + ), + ); + } + + if (!snapshot.hasData) { + return LayoutBuilder( + builder: (context, viewportConstraints) { + return SingleChildScrollView( + physics: AlwaysScrollableScrollPhysics(), + child: ConstrainedBox( + constraints: BoxConstraints( + minHeight: viewportConstraints.maxHeight, + ), + child: Center( + child: CircularProgressIndicator(), + ), + ), + ); + }, + ); + } + + final items = snapshot.data; + + if (items.isEmpty && widget.emptyBuilder != null) { + return widget.emptyBuilder(context); + } + + if (items.isEmpty && widget.emptyBuilder == null) { + return LayoutBuilder( + builder: (context, viewportConstraints) { + return SingleChildScrollView( + physics: AlwaysScrollableScrollPhysics(), + child: ConstrainedBox( + constraints: BoxConstraints( + minHeight: viewportConstraints.maxHeight, + ), + child: Center( + child: Text('There are no users currently'), + ), + ), + ); + }, + ); + } + + final child = _isListView + ? ListView.separated( + physics: AlwaysScrollableScrollPhysics(), + itemCount: items.isNotEmpty ? items.length + 1 : items.length, + separatorBuilder: (_, index) { + if (widget.separatorBuilder != null) { + return widget.separatorBuilder(context, index); + } + return _separatorBuilder(context, index); + }, + itemBuilder: (context, index) { + return _listItemBuilder(context, index, items); + }, + ) + : GridView.builder( + gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: widget.crossAxisCount, + ), + itemCount: items.isNotEmpty ? items.length + 1 : items.length, + physics: AlwaysScrollableScrollPhysics(), + itemBuilder: (context, index) { + return _gridItemBuilder(context, index, items); + }, + ); + + return LazyLoadScrollView( + onEndOfPage: () async { + return _listenUserPagination(usersBlocState); + }, + child: child, + ); + }, + ); + } + + Widget _listItemBuilder(BuildContext context, int i, List items) { + final usersProvider = UsersBloc.of(context); + if (i < items.length) { + final item = items[i]; + return item.when( + headerItem: (header) { + return Container( + key: ValueKey('HEADER-$header'), + color: + StreamChatTheme.of(context).colorTheme.black.withOpacity(0.05), + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 8.0, vertical: 6), + child: Text( + header, + style: TextStyle( + fontWeight: FontWeight.bold, + fontSize: 14.5, + color: StreamChatTheme.of(context).colorTheme.grey, + ), + ), + ), + ); + }, + userItem: (user) { + final selected = widget.selectedUsers?.contains(user) ?? false; + return Container( + key: ValueKey('USER-${user.id}'), + child: widget.userItemBuilder(context, user, selected), + ); + }, + ); + } else { + return _buildQueryProgressIndicator(context, usersProvider); + } + } + + Widget _gridItemBuilder(BuildContext context, int i, List items) { + final usersProvider = UsersBloc.of(context); + if (i < items.length) { + final item = items[i]; + return item.when( + headerItem: (_) => Offstage(), + userItem: (user) { + final selected = widget.selectedUsers?.contains(user) ?? false; + return Container( + key: ValueKey('USER-${user.id}'), + child: widget.userItemBuilder(context, user, selected), + ); + }, + ); + } else { + return _buildQueryProgressIndicator(context, usersProvider); + } + } + + Widget _buildQueryProgressIndicator(context, UsersBlocState usersProvider) { + return StreamBuilder( + stream: usersProvider.queryUsersLoading, + initialData: false, + builder: (context, snapshot) { + if (snapshot.hasError) { + return Container( + color: StreamChatTheme.of(context) + .colorTheme + .accentRed + .withOpacity(.2), + child: Padding( + padding: const EdgeInsets.symmetric(vertical: 16.0), + child: Center( + child: Text('Error loading users'), + ), + ), + ); + } + return Container( + height: 100, + padding: EdgeInsets.all(32), + child: Center( + child: snapshot.data ? CircularProgressIndicator() : Container(), + ), + ); + }); + } + + Widget _separatorBuilder(context, i) { + return Container( + height: 1, + color: StreamChatTheme.of(context).colorTheme.greyWhisper, + ); + } + + void _listenUserPagination(UsersBlocState usersProvider) { + usersProvider.queryUsers( + filter: widget.filter, + sort: widget.sort, + pagination: widget.pagination.copyWith( + offset: usersProvider.users?.length ?? 0, + ), + options: widget.options, + ); + } + + @override + void didUpdateWidget(UserListView oldWidget) { + super.didUpdateWidget(oldWidget); + if (widget.filter?.toString() != oldWidget.filter?.toString() || + jsonEncode(widget.sort) != jsonEncode(oldWidget.sort) || + widget.pagination?.toJson()?.toString() != + oldWidget.pagination?.toJson()?.toString() || + widget.options?.toString() != oldWidget.options?.toString()) { + final usersBloc = UsersBloc.of(context); + usersBloc.queryUsers( + filter: widget.filter, + sort: widget.sort, + pagination: widget.pagination, + options: widget.options, + ); + } + } +} + +abstract class ListItem { + String get key { + if (this is ListHeaderItem) { + final header = (this as ListHeaderItem).heading; + return 'HEADER-$header'; + } + if (this is ListUserItem) { + final user = (this as ListUserItem).user; + return 'USER-${user.id}'; + } + return null; + } + + Widget when({ + @required Widget Function(String heading) headerItem, + @required Widget Function(User user) userItem, + }) { + if (this is ListHeaderItem) { + return headerItem((this as ListHeaderItem).heading); + } + if (this is ListUserItem) { + return userItem((this as ListUserItem).user); + } + return SizedBox(); + } +} + +class ListHeaderItem extends ListItem { + final String heading; + + ListHeaderItem(this.heading); +} + +class ListUserItem extends ListItem { + final User user; + + ListUserItem(this.user); +} diff --git a/packages/stream_chat_flutter_core/lib/src/users_bloc.dart b/packages/stream_chat_flutter_core/lib/src/users_bloc.dart new file mode 100644 index 00000000..91cbaf80 --- /dev/null +++ b/packages/stream_chat_flutter_core/lib/src/users_bloc.dart @@ -0,0 +1,108 @@ +import 'package:flutter/material.dart'; +import 'package:rxdart/rxdart.dart'; +import 'package:stream_chat/stream_chat.dart'; + +import 'stream_chat.dart'; + +/// Widget dedicated to the management of a users list with pagination +class UsersBloc extends StatefulWidget { + /// The widget child + final Widget child; + + /// Instantiate a new UsersBloc + const UsersBloc({ + Key key, + @required this.child, + }) : super(key: key); + + @override + UsersBlocState createState() => UsersBlocState(); + + /// Use this method to get the current [UsersBlocState] instance + static UsersBlocState of(BuildContext context) { + UsersBlocState state; + + state = context.findAncestorStateOfType(); + + if (state == null) { + throw Exception('You must have a UsersBloc widget as ancestor'); + } + + return state; + } +} + +/// The current state of the [UsersBloc] +class UsersBlocState extends State + with AutomaticKeepAliveClientMixin { + /// The current users list + List get users => _usersController.value; + + /// The current users list as a stream + Stream> get usersStream => _usersController.stream; + + final BehaviorSubject> _usersController = BehaviorSubject(); + + final BehaviorSubject _queryUsersLoadingController = + BehaviorSubject.seeded(false); + + /// The stream notifying the state of queryUsers call + Stream get queryUsersLoading => _queryUsersLoadingController.stream; + + /// Calls [Client.queryUsers] updating [queryUsersLoading] stream + Future queryUsers({ + Map filter, + List sort, + Map options, + PaginationParams pagination, + }) async { + final client = StreamChat.of(context).client; + + if (client.state?.user == null || + _queryUsersLoadingController.value == true) { + return; + } + _queryUsersLoadingController.add(true); + try { + final clear = pagination == null || + pagination.offset == null || + pagination.offset == 0; + + final oldUsers = List.from(users ?? []); + + final usersResponse = await client.queryUsers( + filter: filter, + sort: sort, + options: options, + pagination: pagination, + ); + + if (clear) { + _usersController.add(usersResponse.users); + } else { + final temp = oldUsers + usersResponse.users; + _usersController.add(temp); + } + + _queryUsersLoadingController.add(false); + } catch (err, stackTrace) { + _queryUsersLoadingController.addError(err, stackTrace); + } + } + + @override + Widget build(BuildContext context) { + super.build(context); + return widget.child; + } + + @override + void dispose() { + _usersController.close(); + _queryUsersLoadingController.close(); + super.dispose(); + } + + @override + bool get wantKeepAlive => true; +} diff --git a/packages/stream_chat_flutter_core/pubspec.yaml b/packages/stream_chat_flutter_core/pubspec.yaml index 9590e0c4..10e0688e 100644 --- a/packages/stream_chat_flutter_core/pubspec.yaml +++ b/packages/stream_chat_flutter_core/pubspec.yaml @@ -9,6 +9,7 @@ environment: flutter: ">=1.17.0" dependencies: + stream_chat: ^0.2.23+3 flutter: sdk: flutter From d156106701489104cf0c139452c5bc042eae60e3 Mon Sep 17 00:00:00 2001 From: Neevash Ramdial Date: Thu, 21 Jan 2021 10:32:50 -0400 Subject: [PATCH 0996/1140] add version to melos --- .github/workflows/scripts/install-tools.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/scripts/install-tools.sh b/.github/workflows/scripts/install-tools.sh index 087cfecb..b83f55f0 100755 --- a/.github/workflows/scripts/install-tools.sh +++ b/.github/workflows/scripts/install-tools.sh @@ -1,6 +1,6 @@ #!/bin/bash -flutter pub global activate melos +flutter pub global activate melos 0.4.0-dev.2 echo "::add-path::$HOME/.pub-cache/bin" echo "::add-path::$GITHUB_WORKSPACE/_flutter/.pub-cache/bin" echo "::add-path::$GITHUB_WORKSPACE/_flutter/bin/cache/dart-sdk/bin" \ No newline at end of file From cf3e1b8363acd9525f3dc1c9f058112fc415f60e Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Fri, 22 Jan 2021 14:54:45 +0530 Subject: [PATCH 0997/1140] feat: Added new widgets --- .../lib/src/channel_list_view.dart | 272 +++++++++++++ .../lib/src/channels_bloc.dart | 184 +++++++++ .../lib/src/message_search_bloc.dart | 150 ++++++++ .../lib/src/stream_channel.dart | 356 ++++++++++++++++++ .../stream_chat_flutter_core/pubspec.yaml | 1 + 5 files changed, 963 insertions(+) create mode 100644 packages/stream_chat_flutter_core/lib/src/channel_list_view.dart create mode 100644 packages/stream_chat_flutter_core/lib/src/channels_bloc.dart create mode 100644 packages/stream_chat_flutter_core/lib/src/message_search_bloc.dart create mode 100644 packages/stream_chat_flutter_core/lib/src/stream_channel.dart diff --git a/packages/stream_chat_flutter_core/lib/src/channel_list_view.dart b/packages/stream_chat_flutter_core/lib/src/channel_list_view.dart new file mode 100644 index 00000000..920ee09b --- /dev/null +++ b/packages/stream_chat_flutter_core/lib/src/channel_list_view.dart @@ -0,0 +1,272 @@ +import 'dart:async'; +import 'dart:convert'; + +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:stream_chat/stream_chat.dart'; +import 'package:stream_chat_flutter_core/src/channels_bloc.dart'; + +import 'stream_chat.dart'; + +/// Callback called when tapping on a channel +typedef ChannelTapCallback = void Function(Channel, Widget); + +/// Builder used to create a custom [ChannelPreview] from a [Channel] +typedef ChannelPreviewBuilder = Widget Function(BuildContext, Channel); + +typedef ViewInfoCallback = void Function(Channel); + +/// ![screenshot](https://raw.githubusercontent.com/GetStream/stream-chat-flutter/master/screenshots/channel_list_view.png) +/// ![screenshot](https://raw.githubusercontent.com/GetStream/stream-chat-flutter/master/screenshots/channel_list_view_paint.png) +/// +/// It shows the list of current channels. +/// +/// ```dart +/// class ChannelListPage extends StatelessWidget { +/// @override +/// Widget build(BuildContext context) { +/// return Scaffold( +/// body: ChannelListView( +/// filter: { +/// 'members': { +/// '\$in': [StreamChat.of(context).user.id], +/// } +/// }, +/// sort: [SortOption('last_message_at')], +/// pagination: PaginationParams( +/// limit: 20, +/// ), +/// channelWidget: ChannelPage(), +/// ), +/// ); +/// } +/// } +/// ``` +/// +/// +/// Make sure to have a [StreamChat] ancestor in order to provide the information about the channels. +/// The widget uses a [ListView.custom] to render the list of channels. +/// +/// The widget components render the ui based on the first ancestor of type [StreamChatTheme]. +/// Modify it to change the widget appearance. +class ChannelListView extends StatefulWidget { + /// Instantiate a new ChannelListView + ChannelListView({ + Key key, + this.filter, + this.options, + this.sort, + this.pagination, + this.separatorBuilder, + this.errorBuilder, + this.swipeToAction = false, + this.pullToRefresh = true, + @required this.emptyBuilder, + @required this.loadingBuilder, + @required this.listBuilder, + }) : super(key: key); + + /// The builder that will be used in case of error + final Widget Function(Error error) errorBuilder; + + final WidgetBuilder loadingBuilder; + + final Function(BuildContext, List) listBuilder; + + /// If true a default swipe to action behaviour will be added to this widget + final bool swipeToAction; + + /// The builder used when the channel list is empty. + final WidgetBuilder emptyBuilder; + + /// The query filters to use. + /// You can query on any of the custom fields you've defined on the [Channel]. + /// You can also filter other built-in channel fields. + final Map filter; + + /// Query channels options. + /// + /// state: if true returns the Channel state + /// watch: if true listen to changes to this Channel in real time. + final Map options; + + /// The sorting used for the channels matching the filters. + /// Sorting is based on field and direction, multiple sorting options can be provided. + /// You can sort based on last_updated, last_message_at, updated_at, created_at or member_count. + /// Direction can be ascending or descending. + final List sort; + + /// Pagination parameters + /// limit: the number of channels to return (max is 30) + /// offset: the offset (max is 1000) + /// message_limit: how many messages should be included to each channel + final PaginationParams pagination; + + /// Builder used to create a custom item separator + final Function(BuildContext, int) separatorBuilder; + + /// Set it to false to disable the pull-to-refresh widget + final bool pullToRefresh; + + @override + _ChannelListViewState createState() => _ChannelListViewState(); +} + +class _ChannelListViewState extends State + with WidgetsBindingObserver { + final ScrollController _scrollController = ScrollController(); + + @override + Widget build(BuildContext context) { + final channelsBloc = ChannelsBloc.of(context); + + if (!widget.pullToRefresh) { + return _buildListView(channelsBloc); + } + + return RefreshIndicator( + onRefresh: () async { + return channelsBloc.queryChannels( + filter: widget.filter, + sortOptions: widget.sort, + paginationParams: widget.pagination, + options: widget.options, + ); + }, + child: _buildListView(channelsBloc), + ); + } + + StreamBuilder> _buildListView( + ChannelsBlocState channelsBlocState, + ) { + return StreamBuilder>( + stream: channelsBlocState.channelsStream, + builder: (context, snapshot) { + var child; + if (snapshot.hasError) { + child = _buildErrorWidget( + snapshot, + context, + channelsBlocState, + ); + } else if (!snapshot.hasData) { + child = _buildLoadingWidget(); + } else { + final channels = snapshot.data; + + child = widget.emptyBuilder(context); + + if (channels.isNotEmpty) { + return widget.listBuilder(context, channels); + } + } + + return AnimatedSwitcher( + child: child, + duration: Duration(milliseconds: 500), + ); + }, + ); + } + + Widget _buildLoadingWidget() { + return widget.loadingBuilder(context); + } + + Widget _buildErrorWidget( + AsyncSnapshot> snapshot, + BuildContext context, + ChannelsBlocState channelsBlocState, + ) { + if (snapshot.error is Error) { + print((snapshot.error as Error).stackTrace); + } + + return widget.errorBuilder(snapshot.error); + } + + void _listenChannelPagination(ChannelsBlocState channelsProvider) { + if (_scrollController.position.maxScrollExtent == + _scrollController.offset && + _scrollController.offset != 0) { + channelsProvider.queryChannels( + filter: widget.filter, + sortOptions: widget.sort, + paginationParams: widget.pagination.copyWith( + offset: channelsProvider.channels?.length ?? 0, + ), + options: widget.options, + ); + } + } + + StreamSubscription _subscription; + + @override + void initState() { + super.initState(); + + WidgetsBinding.instance.addObserver(this); + + final channelsBloc = ChannelsBloc.of(context); + channelsBloc.queryChannels( + filter: widget.filter, + sortOptions: widget.sort, + paginationParams: widget.pagination, + options: widget.options, + ); + + _scrollController.addListener(() { + channelsBloc.queryChannelsLoading.first.then((loading) { + if (!loading) { + _listenChannelPagination(channelsBloc); + } + }); + }); + + final client = StreamChat.of(context).client; + + _subscription = client + .on( + EventType.connectionRecovered, + EventType.notificationAddedToChannel, + EventType.notificationMessageNew, + EventType.channelVisible, + ) + .listen((event) { + channelsBloc.queryChannels( + filter: widget.filter, + sortOptions: widget.sort, + paginationParams: widget.pagination, + options: widget.options, + ); + }); + } + + @override + void didUpdateWidget(ChannelListView oldWidget) { + super.didUpdateWidget(oldWidget); + + if (widget.filter?.toString() != oldWidget.filter?.toString() || + jsonEncode(widget.sort) != jsonEncode(oldWidget.sort) || + widget.pagination?.toJson()?.toString() != + oldWidget.pagination?.toJson()?.toString() || + widget.options?.toString() != oldWidget.options?.toString()) { + final channelsBloc = ChannelsBloc.of(context); + channelsBloc.queryChannels( + filter: widget.filter, + sortOptions: widget.sort, + paginationParams: widget.pagination, + options: widget.options, + ); + } + } + + @override + void dispose() { + _subscription.cancel(); + WidgetsBinding.instance.removeObserver(this); + super.dispose(); + } +} diff --git a/packages/stream_chat_flutter_core/lib/src/channels_bloc.dart b/packages/stream_chat_flutter_core/lib/src/channels_bloc.dart new file mode 100644 index 00000000..a9ab1682 --- /dev/null +++ b/packages/stream_chat_flutter_core/lib/src/channels_bloc.dart @@ -0,0 +1,184 @@ +import 'dart:async'; + +import 'package:flutter/material.dart'; +import 'package:rxdart/rxdart.dart'; +import 'package:stream_chat/stream_chat.dart'; +import 'package:stream_chat_flutter_core/src/stream_chat.dart'; + +/// Widget dedicated to the management of a channel list with pagination +class ChannelsBloc extends StatefulWidget { + /// The widget child + final Widget child; + + /// Set this to true to prevent channels to be brought to the top of the list when a new message arrives + final bool lockChannelsOrder; + + /// Comparator used to sort the channels when a message.new event is received + final Comparator channelsComparator; + + /// Function used to evaluate if a channel should be added to the list when a message.new event is received + final bool Function(Event) shouldAddChannel; + + /// Instantiate a new ChannelsBloc + const ChannelsBloc({ + Key key, + this.child, + this.lockChannelsOrder = false, + this.channelsComparator, + this.shouldAddChannel, + }) : super(key: key); + + @override + ChannelsBlocState createState() => ChannelsBlocState(); + + /// Use this method to get the current [ChannelsBlocState] instance + static ChannelsBlocState of(BuildContext context) { + ChannelsBlocState streamChatState; + + streamChatState = context.findAncestorStateOfType(); + + if (streamChatState == null) { + throw Exception('You must have a ChannelsBloc widget as ancestor'); + } + + return streamChatState; + } +} + +/// The current state of the [ChannelsBloc] +class ChannelsBlocState extends State + with AutomaticKeepAliveClientMixin { + @override + Widget build(BuildContext context) { + super.build(context); + return widget.child; + } + + /// The current channel list + List get channels => _channelsController.value; + + /// The current channel list as a stream + Stream> get channelsStream => _channelsController.stream; + + final BehaviorSubject _queryChannelsLoadingController = + BehaviorSubject.seeded(false); + + final BehaviorSubject> _channelsController = BehaviorSubject(); + + /// The stream notifying the state of queryChannel call + Stream get queryChannelsLoading => + _queryChannelsLoadingController.stream; + + final List _hiddenChannels = []; + + /// Calls [client.queryChannels] updating [queryChannelsLoading] stream + Future queryChannels({ + Map filter, + List sortOptions, + PaginationParams paginationParams, + Map options, + bool onlyOffline = false, + }) async { + final client = StreamChat.of(context).client; + + if (client.state?.user == null || + _queryChannelsLoadingController.value == true) { + return; + } + _queryChannelsLoadingController.sink.add(true); + + try { + final clear = paginationParams == null || + paginationParams.offset == null || + paginationParams.offset == 0; + final oldChannels = List.from(channels ?? []); + final _channels = await client.queryChannels( + filter: filter, + sort: sortOptions, + options: options, + paginationParams: paginationParams, + onlyOffline: onlyOffline, + ); + + if (clear) { + _channelsController.add(_channels); + } else { + final l = oldChannels + _channels; + _channelsController.add(l); + } + _queryChannelsLoadingController.sink.add(false); + } catch (err, stackTrace) { + print(err); + print(stackTrace); + _queryChannelsLoadingController.addError(err, stackTrace); + } + } + + final List _subscriptions = []; + + @override + void initState() { + super.initState(); + + final client = StreamChat.of(context).client; + + if (!widget.lockChannelsOrder) { + _subscriptions.add(client.on(EventType.messageNew).listen((e) { + final newChannels = List.from(channels ?? []); + final index = newChannels.indexWhere((c) => c.cid == e.cid); + if (index > -1) { + if (index > 0) { + final channel = newChannels.removeAt(index); + newChannels.insert(0, channel); + } + } else if (widget.shouldAddChannel != null && + widget.shouldAddChannel(e)) { + final hiddenIndex = _hiddenChannels.indexWhere((c) => c.cid == e.cid); + if (hiddenIndex > -1) { + newChannels.insert(0, _hiddenChannels[hiddenIndex]); + _hiddenChannels.removeAt(hiddenIndex); + } else { + if (client.state?.channels != null && + client.state?.channels[e.cid] != null) { + newChannels.insert(0, client.state.channels[e.cid]); + } + } + } + + if (widget.channelsComparator != null) { + newChannels.sort(widget.channelsComparator); + } + _channelsController.add(newChannels); + })); + } + + _subscriptions.add(client.on(EventType.channelHidden).listen((event) async { + final newChannels = List.from(channels ?? []); + final channelIndex = newChannels.indexWhere((c) => c.cid == event.cid); + if (channelIndex > -1) { + final channel = newChannels.removeAt(channelIndex); + _hiddenChannels.add(channel); + _channelsController.add(newChannels); + } + })); + + _subscriptions.add(client + .on(EventType.channelDeleted, EventType.notificationRemovedFromChannel) + .listen((e) { + final channel = e.channel; + _channelsController + .add(List.from(channels..removeWhere((c) => c.cid == channel.cid))); + })); + } + + @override + void dispose() { + _channelsController.close(); + _queryChannelsLoadingController.close(); + _subscriptions.forEach((s) => s.cancel()); + super.dispose(); + } + + @override + bool get wantKeepAlive => true; +} diff --git a/packages/stream_chat_flutter_core/lib/src/message_search_bloc.dart b/packages/stream_chat_flutter_core/lib/src/message_search_bloc.dart new file mode 100644 index 00000000..67b6455d --- /dev/null +++ b/packages/stream_chat_flutter_core/lib/src/message_search_bloc.dart @@ -0,0 +1,150 @@ +import 'package:flutter/material.dart'; +import 'package:rxdart/rxdart.dart'; +import 'package:stream_chat/stream_chat.dart'; + +import 'stream_chat.dart'; + +/// Widget dedicated to the management of a message list with pagination +class MessageSearchBloc extends StatefulWidget { + /// The widget child + final Widget child; + + /// Instantiate a new MessageSearchBloc + const MessageSearchBloc({ + Key key, + @required this.child, + }) : super(key: key); + + @override + MessageSearchBlocState createState() => MessageSearchBlocState(); + + /// Use this method to get the current [MessageSearchBlocState] instance + static MessageSearchBlocState of(BuildContext context) { + MessageSearchBlocState state; + + state = context.findAncestorStateOfType(); + + if (state == null) { + throw Exception('You must have a MessageSearchBloc widget as ancestor'); + } + + return state; + } +} + +/// The current state of the [MessageSearchBloc] +class MessageSearchBlocState extends State + with AutomaticKeepAliveClientMixin { + /// The current messages list + List get messageResponses => _messageResponses.value; + + /// The current messages list as a stream + Stream> get messagesStream => + _messageResponses.stream; + + final BehaviorSubject> _messageResponses = + BehaviorSubject(); + + final BehaviorSubject _queryMessagesLoadingController = + BehaviorSubject.seeded(false); + + /// The stream notifying the state of queryUsers call + Stream get queryMessagesLoading => + _queryMessagesLoadingController.stream; + + /// Calls [Client.search] updating [messageResponses] stream + Future search({ + Map filter, + Map messageFilter, + List sort, + String query, + PaginationParams pagination, + }) async { + _messageResponses.add(null); + try { + final messages = await _search( + filter: filter, + messageFilter: messageFilter, + sort: sort, + query: query, + pagination: pagination, + ); + _messageResponses.add(messages.results); + } catch (err, stk) { + _messageResponses.addError(err, stk); + } + } + + /// Calls [Client.search] updating [queryMessagesLoading] stream + Future loadMore({ + Map filter, + Map messageFilter, + List sort, + String query, + PaginationParams pagination, + }) async { + if (_queryMessagesLoadingController.value == true) { + return; + } + _queryMessagesLoadingController.add(true); + try { + final clear = pagination == null || + pagination.offset == null || + pagination.offset == 0; + + final oldMessages = List.from(messageResponses ?? []); + + final messages = await _search( + filter: filter, + messageFilter: messageFilter, + sort: sort, + query: query, + pagination: pagination, + ); + + if (clear) { + _messageResponses.add(messages.results); + } else { + final temp = oldMessages + messages.results; + _messageResponses.add(temp); + } + + _queryMessagesLoadingController.add(false); + } catch (err, stackTrace) { + _queryMessagesLoadingController.addError(err, stackTrace); + } + } + + Future _search({ + Map filter, + Map messageFilter, + List sort, + String query, + PaginationParams pagination, + }) { + final client = StreamChat.of(context).client; + return client.search( + filter, + sort, + query, + pagination, + messageFilters: messageFilter, + ); + } + + @override + Widget build(BuildContext context) { + super.build(context); + return widget.child; + } + + @override + void dispose() { + _messageResponses.close(); + _queryMessagesLoadingController.close(); + super.dispose(); + } + + @override + bool get wantKeepAlive => true; +} diff --git a/packages/stream_chat_flutter_core/lib/src/stream_channel.dart b/packages/stream_chat_flutter_core/lib/src/stream_channel.dart new file mode 100644 index 00000000..8b4b97ef --- /dev/null +++ b/packages/stream_chat_flutter_core/lib/src/stream_channel.dart @@ -0,0 +1,356 @@ +import 'dart:async'; + +import 'package:flutter/material.dart'; +import 'package:rxdart/rxdart.dart'; +import 'package:stream_chat/stream_chat.dart'; + +enum QueryDirection { top, bottom } + +/// Widget used to provide information about the channel to the widget tree +/// +/// Use [StreamChannel.of] to get the current [StreamChannelState] instance. +class StreamChannel extends StatefulWidget { + const StreamChannel({ + Key key, + @required this.child, + @required this.channel, + this.showLoading = true, + this.initialMessageId, + }) : assert(child != null), + assert(channel != null), + super(key: key); + + final Widget child; + final Channel channel; + final bool showLoading; + + /// If passed the channel will load from this particular message. + final String initialMessageId; + + /// Use this method to get the current [StreamChannelState] instance + static StreamChannelState of(BuildContext context) { + StreamChannelState streamChannelState; + + streamChannelState = context.findAncestorStateOfType(); + + if (streamChannelState == null) { + throw Exception( + 'You must have a StreamChannel widget at the top of your widget tree'); + } + + return streamChannelState; + } + + @override + StreamChannelState createState() => StreamChannelState(); +} + +class StreamChannelState extends State { + /// Current channel + Channel get channel => widget.channel; + + /// InitialMessageId + String get initialMessageId => widget.initialMessageId; + + /// Current channel state stream + Stream get channelStateStream => + widget.channel.state.channelStateStream; + + final _queryTopMessagesController = BehaviorSubject.seeded(false); + final _queryBottomMessagesController = BehaviorSubject.seeded(false); + + /// The stream notifying the state of [_queryTopMessages] call + Stream get queryTopMessages => _queryTopMessagesController.stream; + + /// The stream notifying the state of [_queryBottomMessages] call + Stream get queryBottomMessages => _queryBottomMessagesController.stream; + + bool _topPaginationEnded = false; + bool _bottomPaginationEnded = false; + + Future _queryTopMessages({ + int limit = 20, + bool preferOffline = false, + }) async { + if (_topPaginationEnded || _queryTopMessagesController?.value == true) { + return; + } + _queryTopMessagesController.add(true); + + if (channel.state.messages.isEmpty) { + return _queryTopMessagesController.add(false); + } + + final oldestMessage = channel.state.messages.first; + + try { + final state = await queryBeforeMessage( + oldestMessage.id, + limit: limit, + preferOffline: preferOffline, + ); + if (state.messages.isEmpty || state.messages.length < limit) { + _topPaginationEnded = true; + } + _queryTopMessagesController.add(false); + } catch (e, stk) { + _queryTopMessagesController.addError(e, stk); + } + } + + Future _queryBottomMessages({ + int limit = 20, + bool preferOffline = false, + }) async { + if (_bottomPaginationEnded || + _queryBottomMessagesController?.value == true || + channel?.state?.isUpToDate == true) return; + _queryBottomMessagesController.add(true); + + if (channel.state.messages.isEmpty) { + return _queryBottomMessagesController.add(false); + } + + final recentMessage = channel.state.messages.last; + + try { + final state = await queryAfterMessage( + recentMessage.id, + limit: limit, + preferOffline: preferOffline, + ); + if (state.messages.isEmpty || state.messages.length < limit) { + _bottomPaginationEnded = true; + } + _queryBottomMessagesController.add(false); + } catch (e, stk) { + _queryBottomMessagesController.addError(e, stk); + } + } + + /// Calls [channel.query] updating [queryMessage] stream + Future queryMessages({QueryDirection direction = QueryDirection.top}) { + if (direction == QueryDirection.top) return _queryTopMessages(); + return _queryBottomMessages(); + } + + /// Calls [channel.getReplies] updating [queryMessage] stream + Future getReplies( + String parentId, { + int limit = 50, + bool preferOffline = false, + }) async { + if (_topPaginationEnded || _queryTopMessagesController.value) return; + _queryTopMessagesController.add(true); + + Message message; + if (channel.state.threads.containsKey(parentId)) { + final thread = channel.state.threads[parentId]; + if (thread.isNotEmpty) { + message = thread.first; + } + } + + try { + final response = await channel.getReplies( + parentId, + PaginationParams( + lessThan: message?.id, + limit: limit, + ), + preferOffline: preferOffline, + ); + if (response.messages.isEmpty || response.messages.length < limit) { + _topPaginationEnded = true; + } + _queryTopMessagesController.add(false); + } catch (e, stk) { + _queryTopMessagesController.addError(e, stk); + } + } + + /// Query the channel members and watchers + Future queryMembersAndWatchers() async { + await widget.channel.query( + membersPagination: PaginationParams( + offset: channel.state.members?.length, + limit: 100, + ), + watchersPagination: PaginationParams( + offset: channel.state.watchers?.length, + limit: 100, + ), + ); + } + + /// Loads channel at specific message + Future loadChannelAtMessage( + String messageId, { + int before = 20, + int after = 20, + bool preferOffline = false, + }) { + return queryAtMessage( + messageId: messageId, + before: before, + after: after, + preferOffline: preferOffline, + ); + } + + /// + Future queryAtMessage({ + String messageId, + int before = 20, + int after = 20, + bool preferOffline = false, + }) async { + if (channel.state == null) return; + channel.state.isUpToDate = false; + channel.state.truncate(); + + if (messageId == null) { + await channel.query( + messagesPagination: PaginationParams( + limit: before, + ), + preferOffline: preferOffline, + ); + channel.state.isUpToDate = true; + return; + } + + return Future.wait([ + queryBeforeMessage( + messageId, + limit: before, + preferOffline: preferOffline, + ), + queryAfterMessage( + messageId, + limit: after, + preferOffline: preferOffline, + ), + ]); + } + + /// + Future queryBeforeMessage( + String messageId, { + int limit = 20, + bool preferOffline = false, + }) { + return channel.query( + messagesPagination: PaginationParams( + lessThan: messageId, + limit: limit, + ), + preferOffline: preferOffline, + ); + } + + /// + Future queryAfterMessage( + String messageId, { + int limit = 20, + bool preferOffline = false, + }) async { + final state = await channel.query( + messagesPagination: PaginationParams( + greaterThanOrEqual: messageId, + limit: limit, + ), + preferOffline: preferOffline, + ); + if (state.messages.isEmpty || state.messages.length < limit) { + channel.state.isUpToDate = true; + } + return state; + } + + /// + Future getMessage(String messageId) async { + var message = channel.state.messages.firstWhere( + (it) => it.id == messageId, + orElse: () => null, + ); + if (message == null) { + final response = await channel.getMessagesById([messageId]); + message = response.messages.first; + } + return message; + } + + /// Reloads the channel with latest message + Future reloadChannel() => queryAtMessage(before: 30); + + List> _futures; + + Future get _loadChannelAtMessage async { + try { + await loadChannelAtMessage(initialMessageId); + return true; + } catch (e, stk) { + print('Error: $e\nStack: $stk'); + rethrow; + } + } + + @override + void initState() { + super.initState(); + _futures = [widget.channel.initialized]; + if (initialMessageId != null) { + _futures.add(_loadChannelAtMessage); + } + } + + @override + void dispose() { + _queryTopMessagesController.close(); + _queryBottomMessagesController.close(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + Widget child = FutureBuilder>( + future: Future.wait(_futures), + initialData: [ + channel.state != null, + if (initialMessageId != null) false, + ], + builder: (context, snapshot) { + if (snapshot.hasError) { + if (snapshot.error is Error) { + print((snapshot.error as Error).stackTrace); + } + var message = snapshot.error.toString(); + if (snapshot.error is DioError) { + final dioError = snapshot.error as DioError; + if (dioError.type == DioErrorType.RESPONSE) { + message = dioError.message; + } else { + message = 'Check your connection and retry'; + } + } + return Center( + child: Text(message), + ); + } + final initialized = snapshot.data[0]; + final dataLoaded = initialMessageId == null ? true : snapshot.data[1]; + if (widget.showLoading && (!initialized || !dataLoaded)) { + return Center( + child: CircularProgressIndicator(), + ); + } + return widget.child; + }, + ); + if (initialMessageId != null) { + child = Material(child: child); + } + return child; + } +} diff --git a/packages/stream_chat_flutter_core/pubspec.yaml b/packages/stream_chat_flutter_core/pubspec.yaml index 10e0688e..e318c67d 100644 --- a/packages/stream_chat_flutter_core/pubspec.yaml +++ b/packages/stream_chat_flutter_core/pubspec.yaml @@ -10,6 +10,7 @@ environment: dependencies: stream_chat: ^0.2.23+3 + rxdart: ^0.24.1 flutter: sdk: flutter From a28d046fcee8f057d4971271a42e2739995ce5ca Mon Sep 17 00:00:00 2001 From: Neevash Ramdial Date: Fri, 22 Jan 2021 06:38:12 -0400 Subject: [PATCH 0998/1140] [Dart-Client] Add enum for supported push providers --- packages/dart_client/lib/src/client.dart | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/packages/dart_client/lib/src/client.dart b/packages/dart_client/lib/src/client.dart index c5a77d11..09ea4232 100644 --- a/packages/dart_client/lib/src/client.dart +++ b/packages/dart_client/lib/src/client.dart @@ -46,6 +46,26 @@ const String KEY_TOKEN = 'KEY_TOKEN'; /// The key used to save the apiKey to sharedPreferences const String KEY_API_KEY = 'KEY_API_KEY'; +/// Provider used to send push notifications. +enum PushProvider { + /// Send notifications using Google's Firebase Cloud Messaging + firebase, + + /// Send notifications using Apple's Push Notification service + apn +} + +extension on PushProvider { + /// Returns the string notion for [PushProvider]. + String get name { + if (this == PushProvider.apn) { + return 'apn'; + } else { + return 'firebase'; + } + } +} + /// The official Dart client for Stream Chat, /// a service for building chat applications. /// This library can be used on any Dart project and on both mobile and web apps with Flutter. @@ -1002,10 +1022,10 @@ class Client { } /// Add a device for Push Notifications. - Future addDevice(String id, String pushProvider) async { + Future addDevice(String id, PushProvider pushProvider) async { final response = await post('/devices', data: { 'id': id, - 'push_provider': pushProvider, + 'push_provider': pushProvider.name, }); return decode(response.data, EmptyResponse.fromJson); } From c50b4938e27b8f9fff61e5c8161d9925772f81e2 Mon Sep 17 00:00:00 2001 From: Neevash Ramdial Date: Fri, 22 Jan 2021 06:39:19 -0400 Subject: [PATCH 0999/1140] [Flutter-SDK] migrate push String to enum --- packages/flutter_widgets/example/lib/notifications_service.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/flutter_widgets/example/lib/notifications_service.dart b/packages/flutter_widgets/example/lib/notifications_service.dart index 83f5047a..298ab3ab 100644 --- a/packages/flutter_widgets/example/lib/notifications_service.dart +++ b/packages/flutter_widgets/example/lib/notifications_service.dart @@ -56,7 +56,7 @@ void initNotifications(Client client) { if (connector.token.value != null) { client.addDevice( connector.token.value, - Platform.isAndroid ? 'firebase' : 'apn', + Platform.isAndroid ? PushProvider.firebase : PushProvider.apn, ); } }); From 74fb3c87af5dc03ee0e532c16e54f76db98cb7e4 Mon Sep 17 00:00:00 2001 From: Neevash Ramdial Date: Fri, 22 Jan 2021 06:46:03 -0400 Subject: [PATCH 1000/1140] migrate example --- packages/flutter_widgets/example/lib/notifications_service.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/flutter_widgets/example/lib/notifications_service.dart b/packages/flutter_widgets/example/lib/notifications_service.dart index 83f5047a..298ab3ab 100644 --- a/packages/flutter_widgets/example/lib/notifications_service.dart +++ b/packages/flutter_widgets/example/lib/notifications_service.dart @@ -56,7 +56,7 @@ void initNotifications(Client client) { if (connector.token.value != null) { client.addDevice( connector.token.value, - Platform.isAndroid ? 'firebase' : 'apn', + Platform.isAndroid ? PushProvider.firebase : PushProvider.apn, ); } }); From e7b4e9acd69c8d56be495f1fe5752074c9004a3d Mon Sep 17 00:00:00 2001 From: Neevash Ramdial Date: Fri, 22 Jan 2021 06:47:28 -0400 Subject: [PATCH 1001/1140] update test --- packages/dart_client/test/src/client_test.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/dart_client/test/src/client_test.dart b/packages/dart_client/test/src/client_test.dart index 738255cc..caca1a34 100644 --- a/packages/dart_client/test/src/client_test.dart +++ b/packages/dart_client/test/src/client_test.dart @@ -269,7 +269,7 @@ void main() { 'push_provider': 'test', })).thenAnswer((_) async => Response(data: '{}', statusCode: 200)); - await client.addDevice('test-id', 'test'); + await client.addDevice('test-id', PushProvider.firebase); verify(mockDio.post('/devices', data: {'id': 'test-id', 'push_provider': 'test'})).called(1); From 423bae2aa88c25421db4da8fa86b7239db50d993 Mon Sep 17 00:00:00 2001 From: Neevash Ramdial Date: Fri, 22 Jan 2021 06:47:28 -0400 Subject: [PATCH 1002/1140] update test --- packages/dart_client/test/src/client_test.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/dart_client/test/src/client_test.dart b/packages/dart_client/test/src/client_test.dart index 738255cc..caca1a34 100644 --- a/packages/dart_client/test/src/client_test.dart +++ b/packages/dart_client/test/src/client_test.dart @@ -269,7 +269,7 @@ void main() { 'push_provider': 'test', })).thenAnswer((_) async => Response(data: '{}', statusCode: 200)); - await client.addDevice('test-id', 'test'); + await client.addDevice('test-id', PushProvider.firebase); verify(mockDio.post('/devices', data: {'id': 'test-id', 'push_provider': 'test'})).called(1); From b292ab2a0ec3a7711bb70e53051c99bda5b21d79 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Fri, 22 Jan 2021 16:20:02 +0530 Subject: [PATCH 1003/1140] [Message, ChannelModel] Add merge helper functions for easier data change --- packages/dart_client/lib/src/api/channel.dart | 40 +------------------ .../lib/src/models/channel_model.dart | 21 ++++++++++ .../dart_client/lib/src/models/message.dart | 32 +++++++++++++++ 3 files changed, 55 insertions(+), 38 deletions(-) diff --git a/packages/dart_client/lib/src/api/channel.dart b/packages/dart_client/lib/src/api/channel.dart index abe31984..d8ef1a03 100644 --- a/packages/dart_client/lib/src/api/channel.dart +++ b/packages/dart_client/lib/src/api/channel.dart @@ -1108,30 +1108,7 @@ class ChannelClientState { final oldIndex = newMessages.indexWhere((m) => m.id == message.id); if (oldIndex != -1) { - newMessages[oldIndex] = newMessages[oldIndex].copyWith( - text: message.text, - type: message.type, - attachments: message.attachments, - mentionedUsers: message.mentionedUsers, - reactionCounts: message.reactionCounts, - reactionScores: message.reactionScores, - latestReactions: message.latestReactions, - ownReactions: message.ownReactions, - parentId: message.parentId, - quotedMessageId: message.quotedMessageId, - quotedMessage: message.quotedMessage, - replyCount: message.replyCount, - showInChannel: message.showInChannel, - command: message.command, - silent: message.silent, - createdAt: message.createdAt, - updatedAt: message.updatedAt, - deletedAt: message.deletedAt, - user: message.user, - status: message.status, - threadParticipants: message.threadParticipants, - extraData: message.extraData, - ); + newMessages[oldIndex] = newMessages[oldIndex].merge(message); } else { newMessages.add(message); } @@ -1395,20 +1372,7 @@ class ChannelClientState { _channelState = _channelState.copyWith( messages: newMessages, - channel: _channelState.channel?.copyWith( - lastMessageAt: updatedState.channel?.lastMessageAt, - createdAt: updatedState.channel?.createdAt, - type: updatedState.channel?.type, - extraData: updatedState.channel?.extraData, - updatedAt: updatedState.channel?.updatedAt, - id: updatedState.channel?.id, - createdBy: updatedState.channel?.createdBy, - config: updatedState.channel?.config, - deletedAt: updatedState.channel?.deletedAt, - cid: updatedState.channel?.cid, - frozen: updatedState.channel?.frozen, - memberCount: updatedState.channel?.memberCount, - ), + channel: _channelState.channel?.merge(updatedState.channel), watchers: newWatchers, watcherCount: updatedState.watcherCount, members: newMembers, diff --git a/packages/dart_client/lib/src/models/channel_model.dart b/packages/dart_client/lib/src/models/channel_model.dart index 10f65e0b..ff9d04a8 100644 --- a/packages/dart_client/lib/src/models/channel_model.dart +++ b/packages/dart_client/lib/src/models/channel_model.dart @@ -142,4 +142,25 @@ class ChannelModel { extraData: extraData ?? this.extraData, team: team ?? this.team, ); + + /// Returns a new [ChannelModel] that is a combination of this channelModel and the given + /// [other] channelModel. + ChannelModel merge(ChannelModel other) { + if (other == null) return null; + return copyWith( + id: other.id, + type: other.type, + cid: other.cid, + config: other.config, + createdBy: other.createdBy, + frozen: other.frozen, + lastMessageAt: other.lastMessageAt, + createdAt: other.createdAt, + updatedAt: other.updatedAt, + deletedAt: other.deletedAt, + memberCount: other.memberCount, + extraData: other.extraData, + team: other.team, + ); + } } diff --git a/packages/dart_client/lib/src/models/message.dart b/packages/dart_client/lib/src/models/message.dart index 46f2551a..2acbea29 100644 --- a/packages/dart_client/lib/src/models/message.dart +++ b/packages/dart_client/lib/src/models/message.dart @@ -250,6 +250,38 @@ class Message { deletedAt: deletedAt ?? this.deletedAt, status: status ?? this.status, ); + + /// Returns a new [Message] that is a combination of this message and the given + /// [other] message. + Message merge(Message other) { + if (other == null) return null; + return copyWith( + id: other.id, + text: other.text, + type: other.type, + attachments: other.attachments, + mentionedUsers: other.mentionedUsers, + reactionCounts: other.reactionCounts, + reactionScores: other.reactionScores, + latestReactions: other.latestReactions, + ownReactions: other.ownReactions, + parentId: other.parentId, + quotedMessage: other.quotedMessage, + quotedMessageId: other.quotedMessageId, + replyCount: other.replyCount, + threadParticipants: other.threadParticipants, + showInChannel: other.showInChannel, + command: other.command, + createdAt: other.createdAt, + silent: other.silent, + extraData: other.extraData, + user: other.user, + shadowed: other.shadowed, + updatedAt: other.updatedAt, + deletedAt: other.deletedAt, + status: other.status, + ); + } } /// A translated message From 48d05720d9e8ff33a2c32e67f6fc593ceaa5cee9 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Fri, 22 Jan 2021 16:36:55 +0530 Subject: [PATCH 1004/1140] minor fix --- packages/dart_client/lib/src/models/channel_model.dart | 2 +- packages/dart_client/lib/src/models/message.dart | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/dart_client/lib/src/models/channel_model.dart b/packages/dart_client/lib/src/models/channel_model.dart index ff9d04a8..046e29c5 100644 --- a/packages/dart_client/lib/src/models/channel_model.dart +++ b/packages/dart_client/lib/src/models/channel_model.dart @@ -146,7 +146,7 @@ class ChannelModel { /// Returns a new [ChannelModel] that is a combination of this channelModel and the given /// [other] channelModel. ChannelModel merge(ChannelModel other) { - if (other == null) return null; + if (other == null) return this; return copyWith( id: other.id, type: other.type, diff --git a/packages/dart_client/lib/src/models/message.dart b/packages/dart_client/lib/src/models/message.dart index 2acbea29..e23eb51a 100644 --- a/packages/dart_client/lib/src/models/message.dart +++ b/packages/dart_client/lib/src/models/message.dart @@ -254,7 +254,7 @@ class Message { /// Returns a new [Message] that is a combination of this message and the given /// [other] message. Message merge(Message other) { - if (other == null) return null; + if (other == null) return this; return copyWith( id: other.id, text: other.text, From c0ebd9efe418e3873c750315eed46d1df6b85e50 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Fri, 22 Jan 2021 17:14:48 +0530 Subject: [PATCH 1005/1140] feat: Removed theme and added new widgets --- .../lib/src/channel_list_view.dart | 69 +- .../lib/src/message_list_view.dart | 166 ++++ .../lib/src/message_search_list_view.dart | 194 ++++ .../lib/src/stream_chat.dart | 37 +- .../lib/src/stream_chat_theme.dart | 898 ------------------ .../lib/src/user_list_view.dart | 293 +----- 6 files changed, 419 insertions(+), 1238 deletions(-) create mode 100644 packages/stream_chat_flutter_core/lib/src/message_list_view.dart create mode 100644 packages/stream_chat_flutter_core/lib/src/message_search_list_view.dart delete mode 100644 packages/stream_chat_flutter_core/lib/src/stream_chat_theme.dart diff --git a/packages/stream_chat_flutter_core/lib/src/channel_list_view.dart b/packages/stream_chat_flutter_core/lib/src/channel_list_view.dart index 920ee09b..38417190 100644 --- a/packages/stream_chat_flutter_core/lib/src/channel_list_view.dart +++ b/packages/stream_chat_flutter_core/lib/src/channel_list_view.dart @@ -8,14 +8,6 @@ import 'package:stream_chat_flutter_core/src/channels_bloc.dart'; import 'stream_chat.dart'; -/// Callback called when tapping on a channel -typedef ChannelTapCallback = void Function(Channel, Widget); - -/// Builder used to create a custom [ChannelPreview] from a [Channel] -typedef ChannelPreviewBuilder = Widget Function(BuildContext, Channel); - -typedef ViewInfoCallback = void Function(Channel); - /// ![screenshot](https://raw.githubusercontent.com/GetStream/stream-chat-flutter/master/screenshots/channel_list_view.png) /// ![screenshot](https://raw.githubusercontent.com/GetStream/stream-chat-flutter/master/screenshots/channel_list_view_paint.png) /// @@ -57,15 +49,16 @@ class ChannelListView extends StatefulWidget { this.options, this.sort, this.pagination, - this.separatorBuilder, - this.errorBuilder, - this.swipeToAction = false, this.pullToRefresh = true, + @required this.errorBuilder, @required this.emptyBuilder, @required this.loadingBuilder, @required this.listBuilder, + this.channelListController, }) : super(key: key); + final ChannelListController channelListController; + /// The builder that will be used in case of error final Widget Function(Error error) errorBuilder; @@ -73,9 +66,6 @@ class ChannelListView extends StatefulWidget { final Function(BuildContext, List) listBuilder; - /// If true a default swipe to action behaviour will be added to this widget - final bool swipeToAction; - /// The builder used when the channel list is empty. final WidgetBuilder emptyBuilder; @@ -102,9 +92,6 @@ class ChannelListView extends StatefulWidget { /// message_limit: how many messages should be included to each channel final PaginationParams pagination; - /// Builder used to create a custom item separator - final Function(BuildContext, int) separatorBuilder; - /// Set it to false to disable the pull-to-refresh widget final bool pullToRefresh; @@ -114,8 +101,6 @@ class ChannelListView extends StatefulWidget { class _ChannelListViewState extends State with WidgetsBindingObserver { - final ScrollController _scrollController = ScrollController(); - @override Widget build(BuildContext context) { final channelsBloc = ChannelsBloc.of(context); @@ -162,10 +147,7 @@ class _ChannelListViewState extends State } } - return AnimatedSwitcher( - child: child, - duration: Duration(milliseconds: 500), - ); + return child; }, ); } @@ -186,19 +168,17 @@ class _ChannelListViewState extends State return widget.errorBuilder(snapshot.error); } - void _listenChannelPagination(ChannelsBlocState channelsProvider) { - if (_scrollController.position.maxScrollExtent == - _scrollController.offset && - _scrollController.offset != 0) { - channelsProvider.queryChannels( - filter: widget.filter, - sortOptions: widget.sort, - paginationParams: widget.pagination.copyWith( - offset: channelsProvider.channels?.length ?? 0, - ), - options: widget.options, - ); - } + void paginateData() { + final channelsBloc = ChannelsBloc.of(context); + + channelsBloc.queryChannels( + filter: widget.filter, + sortOptions: widget.sort, + paginationParams: widget.pagination.copyWith( + offset: channelsBloc.channels?.length ?? 0, + ), + options: widget.options, + ); } StreamSubscription _subscription; @@ -217,14 +197,6 @@ class _ChannelListViewState extends State options: widget.options, ); - _scrollController.addListener(() { - channelsBloc.queryChannelsLoading.first.then((loading) { - if (!loading) { - _listenChannelPagination(channelsBloc); - } - }); - }); - final client = StreamChat.of(context).client; _subscription = client @@ -242,6 +214,10 @@ class _ChannelListViewState extends State options: widget.options, ); }); + + if (widget.channelListController != null) { + widget.channelListController.paginateData = paginateData; + } } @override @@ -270,3 +246,8 @@ class _ChannelListViewState extends State super.dispose(); } } + +/// Controller used for paginating data in [ChannelListView] +class ChannelListController { + VoidCallback paginateData; +} diff --git a/packages/stream_chat_flutter_core/lib/src/message_list_view.dart b/packages/stream_chat_flutter_core/lib/src/message_list_view.dart new file mode 100644 index 00000000..d0a59266 --- /dev/null +++ b/packages/stream_chat_flutter_core/lib/src/message_list_view.dart @@ -0,0 +1,166 @@ +import 'dart:async'; + +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:stream_chat/stream_chat.dart'; +import 'stream_channel.dart'; + +/// ![screenshot](https://raw.githubusercontent.com/GetStream/stream-chat-flutter/master/screenshots/message_listview.png) +/// ![screenshot](https://raw.githubusercontent.com/GetStream/stream-chat-flutter/master/screenshots/message_listview_paint.png) +/// +/// It shows the list of messages of the current channel. +/// +/// ```dart +/// class ChannelPage extends StatelessWidget { +/// const ChannelPage({ +/// Key key, +/// }) : super(key: key); +/// +/// @override +/// Widget build(BuildContext context) { +/// return Scaffold( +/// appBar: ChannelHeader(), +/// body: Column( +/// children: [ +/// Expanded( +/// child: MessageListView( +/// threadBuilder: (_, parentMessage) { +/// return ThreadPage( +/// parent: parentMessage, +/// ); +/// }, +/// ), +/// ), +/// MessageInput(), +/// ], +/// ), +/// ); +/// } +/// } +/// ``` +/// +/// +/// Make sure to have a [StreamChannel] ancestor in order to provide the information about the channels. +/// The widget uses a [ListView.custom] to render the list of channels. +/// +/// The widget components render the ui based on the first ancestor of type [StreamChatTheme]. +/// Modify it to change the widget appearance. +class MessageListView extends StatefulWidget { + /// Instantiate a new MessageListView + MessageListView({ + Key key, + this.showScrollToBottom = true, + this.parentMessage, + this.dateDividerBuilder, + @required this.loadingBuilder, + @required this.emptyBuilder, + @required this.messageListBuilder, + this.messageListController, + }) : super(key: key); + + MessageListController messageListController; + + final Widget Function(BuildContext, List) messageListBuilder; + + /// Function used to build a loading widget + final WidgetBuilder loadingBuilder; + + /// Function used to build an empty widget + final WidgetBuilder emptyBuilder; + + /// If true will show a scroll to bottom message when there are new messages and the scroll offset is not zero + final bool showScrollToBottom; + + /// Parent message in case of a thread + final Message parentMessage; + + /// Builder used to render date dividers + final Widget Function(DateTime) dateDividerBuilder; + + @override + _MessageListViewState createState() => _MessageListViewState(); +} + +class _MessageListViewState extends State { + StreamChannelState streamChannel; + + bool get _upToDate => streamChannel.channel.state.isUpToDate; + + bool get _isThreadConversation => widget.parentMessage != null; + + int initialIndex; + double initialAlignment; + + List messages = []; + + bool initialMessageHighlightComplete = false; + + @override + Widget build(BuildContext context) { + final messagesStream = _isThreadConversation + ? streamChannel.channel.state.threadsStream + .where((threads) => threads.containsKey(widget.parentMessage.id)) + .map((threads) => threads[widget.parentMessage.id]) + : streamChannel.channel.state?.messagesStream; + + return StreamBuilder>( + stream: messagesStream?.map((messages) => messages + ?.where((e) => + (!e.isDeleted && e.shadowed != true) || + (e.isDeleted && + e.user.id == streamChannel.channel.client.state.user.id)) + ?.toList()), + builder: (context, snapshot) { + if (!snapshot.hasData) { + return widget.loadingBuilder(context); + } + + final messageList = snapshot.data?.reversed?.toList() ?? []; + if (messageList.isEmpty) { + if (_upToDate) { + return widget.emptyBuilder(context); + } + } else { + messages = messageList; + } + + return widget.messageListBuilder(context, messages); + }); + } + + Future paginateData(QueryDirection direction) { + if (!_isThreadConversation) { + return streamChannel.queryMessages(direction: direction); + } else { + return streamChannel.getReplies(widget.parentMessage.id); + } + } + + @override + void initState() { + streamChannel = StreamChannel.of(context); + + if (_isThreadConversation) { + streamChannel.getReplies(widget.parentMessage.id); + } + + if (widget.messageListController != null) { + widget.messageListController.paginateData = paginateData; + } + + super.initState(); + } + + @override + void dispose() { + if (!_upToDate) { + streamChannel.reloadChannel(); + } + super.dispose(); + } +} + +/// Controller used for paginating data in [ChannelListView] +class MessageListController { + Function(QueryDirection direction) paginateData; +} diff --git a/packages/stream_chat_flutter_core/lib/src/message_search_list_view.dart b/packages/stream_chat_flutter_core/lib/src/message_search_list_view.dart new file mode 100644 index 00000000..f27f7c8e --- /dev/null +++ b/packages/stream_chat_flutter_core/lib/src/message_search_list_view.dart @@ -0,0 +1,194 @@ +import 'dart:convert'; + +import 'package:flutter/material.dart'; +import 'package:stream_chat/stream_chat.dart'; +import 'lazy_load_scroll_view.dart'; +import 'message_search_bloc.dart'; + +/// Callback called when tapping on a user +typedef MessageSearchItemTapCallback = void Function(GetMessageResponse); + +/// Builder used to create a custom [ListUserItem] from a [User] +typedef MessageSearchItemBuilder = Widget Function( + BuildContext, GetMessageResponse); + +/// Builder used when [MessageSearchListView] is empty +typedef EmptyMessageSearchBuilder = Widget Function( + BuildContext context, String searchQuery); + +/// +/// It shows the list of searched messages. +/// +/// ```dart +/// class MessageSearchPage extends StatelessWidget { +/// @override +/// Widget build(BuildContext context) { +/// return Scaffold( +/// body: MessageSearchListView( +/// messageQuery: _channelQuery, +/// filters: { +/// 'members': { +/// r'$in': [user.id] +/// } +/// }, +/// paginationParams: PaginationParams(limit: 20), +/// ), +/// ); +/// } +/// } +/// ``` +/// +/// +/// Make sure to have a [MessageSearchBloc] ancestor in order to provide the information about the messages. +/// The widget uses a [ListView.separated] to render the list of messages. +/// +/// The widget components render the ui based on the first ancestor of type [StreamChatTheme]. +/// Modify it to change the widget appearance. +class MessageSearchListView extends StatefulWidget { + /// Instantiate a new MessageSearchListView + const MessageSearchListView({ + Key key, + this.messageQuery, + this.filters, + this.sortOptions, + this.paginationParams, + this.messageFilters, + @required this.emptyBuilder, + @required this.errorBuilder, + @required this.loadingBuilder, + @required this.childBuilder, + this.messageSearchListController, + }) : super(key: key); + + final MessageSearchListController messageSearchListController; + + /// Message String to search on + final String messageQuery; + + /// The query filters to use. + /// You can query on any of the custom fields you've defined on the [Channel]. + /// You can also filter other built-in channel fields. + final Map filters; + + /// The sorting used for the channels matching the filters. + /// Sorting is based on field and direction, multiple sorting options can be provided. + /// You can sort based on last_updated, last_message_at, updated_at, created_at or member_count. + /// Direction can be ascending or descending. + final List sortOptions; + + /// Pagination parameters + /// limit: the number of users to return (max is 30) + /// offset: the offset (max is 1000) + /// message_limit: how many messages should be included to each channel + final PaginationParams paginationParams; + + /// The message query filters to use. + /// You can query on any of the custom fields you've defined on the [Channel]. + /// You can also filter other built-in channel fields. + final Map messageFilters; + + final Widget Function(List) childBuilder; + + /// The builder used when the channel list is empty. + final EmptyMessageSearchBuilder emptyBuilder; + + /// The builder that will be used in case of error + final Widget Function(Error error) errorBuilder; + + final WidgetBuilder loadingBuilder; + + @override + _MessageSearchListViewState createState() => _MessageSearchListViewState(); +} + +class _MessageSearchListViewState extends State { + @override + void initState() { + super.initState(); + final messageSearchBloc = MessageSearchBloc.of(context); + messageSearchBloc.search( + filter: widget.filters, + sort: widget.sortOptions, + query: widget.messageQuery, + pagination: widget.paginationParams, + messageFilter: widget.messageFilters, + ); + + if (widget.messageSearchListController != null) { + widget.messageSearchListController.paginateData = paginateData; + } + } + + @override + Widget build(BuildContext context) { + final messageSearchBloc = MessageSearchBloc.of(context); + return _buildListView(messageSearchBloc); + } + + Widget _buildListView(MessageSearchBlocState messageSearchBloc) { + return StreamBuilder>( + stream: messageSearchBloc.messagesStream, + builder: (context, snapshot) { + if (snapshot.hasError) { + if (snapshot.error is Error) { + print((snapshot.error as Error).stackTrace); + } + + return widget.errorBuilder(snapshot.error); + } + + if (!snapshot.hasData) { + return widget.loadingBuilder(context); + } + + final items = snapshot.data; + + if (items.isEmpty) { + return widget.emptyBuilder(context, widget.messageQuery); + } + + return widget.childBuilder(snapshot.data); + }, + ); + } + + void paginateData() { + final messageSearchBloc = MessageSearchBloc.of(context); + + messageSearchBloc.loadMore( + filter: widget.filters, + sort: widget.sortOptions, + pagination: widget.paginationParams.copyWith( + offset: messageSearchBloc.messageResponses?.length ?? 0, + ), + query: widget.messageQuery, + messageFilter: widget.messageFilters, + ); + } + + @override + void didUpdateWidget(MessageSearchListView oldWidget) { + super.didUpdateWidget(oldWidget); + if (widget.filters?.toString() != oldWidget.filters?.toString() || + jsonEncode(widget.sortOptions) != jsonEncode(oldWidget.sortOptions) || + widget.paginationParams?.toJson()?.toString() != + oldWidget.paginationParams?.toJson()?.toString() || + widget.messageQuery?.toString() != oldWidget.messageQuery?.toString() || + widget.messageFilters?.toString() != + oldWidget.messageFilters?.toString()) { + final messageSearchBloc = MessageSearchBloc.of(context); + messageSearchBloc.search( + filter: widget.filters, + sort: widget.sortOptions, + query: widget.messageQuery, + pagination: widget.paginationParams, + messageFilter: widget.messageFilters, + ); + } + } +} + +/// Controller used for paginating data in [ChannelListView] +class MessageSearchListController { + VoidCallback paginateData; +} diff --git a/packages/stream_chat_flutter_core/lib/src/stream_chat.dart b/packages/stream_chat_flutter_core/lib/src/stream_chat.dart index e6c47c9d..17ec62b6 100644 --- a/packages/stream_chat_flutter_core/lib/src/stream_chat.dart +++ b/packages/stream_chat_flutter_core/lib/src/stream_chat.dart @@ -3,7 +3,6 @@ import 'dart:async'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:stream_chat/stream_chat.dart'; -import 'package:stream_chat_flutter_core/src/stream_chat_theme.dart'; /// Widget used to provide information about the chat to the widget tree /// @@ -29,13 +28,11 @@ import 'package:stream_chat_flutter_core/src/stream_chat_theme.dart'; class StreamChat extends StatefulWidget { final Client client; final Widget child; - final StreamChatThemeData streamChatThemeData; StreamChat({ Key key, @required this.client, @required this.child, - this.streamChatThemeData, }) : super( key: key, ); @@ -65,32 +62,7 @@ class StreamChatState extends State with WidgetsBindingObserver { @override Widget build(BuildContext context) { - final theme = _getTheme(context, widget.streamChatThemeData); - return StreamChatTheme( - data: theme, - child: Builder( - builder: (context) { - final materialTheme = Theme.of(context); - final streamTheme = StreamChatTheme.of(context); - return Theme( - data: materialTheme.copyWith( - primaryIconTheme: streamTheme.primaryIconTheme, - accentColor: streamTheme.colorTheme.accentBlue, - scaffoldBackgroundColor: streamTheme.colorTheme.white, - ), - child: widget.child, - ); - }, - ), - ); - } - - StreamChatThemeData _getTheme( - BuildContext context, - StreamChatThemeData themeData, - ) { - final defaultTheme = StreamChatThemeData.getDefaultTheme(Theme.of(context)); - return defaultTheme.merge(themeData) ?? themeData; + return widget.child; } /// The current user @@ -103,13 +75,6 @@ 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/packages/stream_chat_flutter_core/lib/src/stream_chat_theme.dart b/packages/stream_chat_flutter_core/lib/src/stream_chat_theme.dart deleted file mode 100644 index be584492..00000000 --- a/packages/stream_chat_flutter_core/lib/src/stream_chat_theme.dart +++ /dev/null @@ -1,898 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:stream_chat/stream_chat.dart'; -import 'package:stream_chat_flutter_core/src/reaction_icon.dart'; - -/// Inherited widget providing the [StreamChatThemeData] to the widget tree -class StreamChatTheme extends InheritedWidget { - final StreamChatThemeData data; - - StreamChatTheme({ - Key key, - @required this.data, - Widget child, - }) : super( - key: key, - child: child, - ); - - @override - bool updateShouldNotify(StreamChatTheme old) { - return data != old.data; - } - - /// Use this method to get the current [StreamChatThemeData] instance - static StreamChatThemeData of(BuildContext context) { - final streamChatTheme = - context.dependOnInheritedWidgetOfExactType(); - - if (streamChatTheme == null) { - throw Exception( - 'You must have a StreamChatTheme widget at the top of your widget tree', - ); - } - - return streamChatTheme.data; - } -} - -/// Theme data -class StreamChatThemeData { - /// The text themes used in the widgets - final TextTheme textTheme; - - /// The button themes used in the widgets - final ButtonThemeData buttonTheme; - - /// The text themes used in the widgets - final ColorTheme colorTheme; - - /// Theme of the [ChannelPreview] - final ChannelPreviewTheme channelPreviewTheme; - - /// Theme of the chat widgets dedicated to a channel - final ChannelTheme channelTheme; - - /// Theme of the current user messages - final MessageTheme ownMessageTheme; - - /// Theme of other users messages - final MessageTheme otherMessageTheme; - - /// The widget that will be built when the channel image is unavailable - final Widget Function(BuildContext, Channel) defaultChannelImage; - - /// The widget that will be built when the user image is unavailable - final Widget Function(BuildContext, User) defaultUserImage; - - /// Primary icon theme - final IconThemeData primaryIconTheme; - - /// Assets used for rendering reactions - final List reactionIcons; - - /// Create a theme from scratch - const StreamChatThemeData({ - this.textTheme, - this.buttonTheme, - this.colorTheme, - this.channelPreviewTheme, - this.channelTheme, - this.otherMessageTheme, - this.ownMessageTheme, - this.defaultChannelImage, - this.defaultUserImage, - this.primaryIconTheme, - this.reactionIcons, - }); - - /// Create a theme from a Material [Theme] - factory StreamChatThemeData.fromTheme(ThemeData theme) { - final defaultTheme = getDefaultTheme(theme); - final customizedTheme = StreamChatThemeData( - primaryIconTheme: theme.primaryIconTheme, - ownMessageTheme: MessageTheme( - replies: TextStyle(color: theme.accentColor), - messageLinks: TextStyle(color: theme.accentColor), - ), - otherMessageTheme: MessageTheme( - replies: TextStyle(color: theme.accentColor), - messageLinks: TextStyle(color: theme.accentColor), - ), - ); - return defaultTheme.merge(customizedTheme) ?? customizedTheme; - } - - /// Creates a copy of [StreamChatThemeData] with specified attributes overridden. - StreamChatThemeData copyWith({ - TextTheme textTheme, - ButtonThemeData buttonTheme, - ColorTheme colorTheme, - ChannelPreviewTheme channelPreviewTheme, - ChannelTheme channelTheme, - MessageTheme ownMessageTheme, - MessageTheme otherMessageTheme, - Widget Function(BuildContext, Channel) defaultChannelImage, - Widget Function(BuildContext, User) defaultUserImage, - IconThemeData primaryIconTheme, - List reactionIcons, - }) => - StreamChatThemeData( - textTheme: textTheme ?? this.textTheme, - buttonTheme: buttonTheme ?? this.buttonTheme, - colorTheme: colorTheme ?? this.colorTheme, - primaryIconTheme: primaryIconTheme ?? this.primaryIconTheme, - defaultChannelImage: defaultChannelImage ?? this.defaultChannelImage, - defaultUserImage: defaultUserImage ?? this.defaultUserImage, - channelPreviewTheme: channelPreviewTheme ?? this.channelPreviewTheme, - channelTheme: channelTheme ?? this.channelTheme, - ownMessageTheme: ownMessageTheme ?? this.ownMessageTheme, - otherMessageTheme: otherMessageTheme ?? this.otherMessageTheme, - reactionIcons: reactionIcons ?? this.reactionIcons, - ); - - StreamChatThemeData merge(StreamChatThemeData other) { - if (other == null) return this; - return copyWith( - textTheme: textTheme?.merge(other.textTheme) ?? other.textTheme, - buttonTheme: other.buttonTheme, - colorTheme: colorTheme?.merge(other.colorTheme) ?? other.colorTheme, - primaryIconTheme: other.primaryIconTheme, - defaultChannelImage: other.defaultChannelImage, - defaultUserImage: other.defaultUserImage, - channelPreviewTheme: - channelPreviewTheme?.merge(other.channelPreviewTheme) ?? - other.channelPreviewTheme, - channelTheme: - channelTheme?.merge(other.channelTheme) ?? other.channelTheme, - ownMessageTheme: ownMessageTheme?.merge(other.ownMessageTheme) ?? - other.ownMessageTheme, - otherMessageTheme: otherMessageTheme?.merge(other.otherMessageTheme) ?? - other.otherMessageTheme, - reactionIcons: other.reactionIcons, - ); - } - - /// Get the default Stream Chat theme - static StreamChatThemeData getDefaultTheme(ThemeData theme) { - final accentColor = Color(0xff006cff); - final isDark = theme.brightness == Brightness.dark; - final textTheme = isDark ? TextTheme.dark() : TextTheme.light(); - final colorTheme = isDark ? ColorTheme.dark() : ColorTheme.light(); - return StreamChatThemeData( - textTheme: textTheme, - colorTheme: colorTheme, - buttonTheme: ButtonThemeData( - height: 48.0, - buttonColor: isDark ? Color(0xffffffff) : Color(0xff006aff), - textTheme: ButtonTextTheme.accent, - colorScheme: theme.colorScheme.copyWith( - secondary: isDark ? Color(0xff005eff) : Color(0xffffffff), - ), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(26), - ), - ), - primaryIconTheme: IconThemeData(color: colorTheme.black.withOpacity(.5)), - defaultChannelImage: (context, channel) => SizedBox(), - defaultUserImage: (context, user) => Center( - child: Image.network( - getRandomPicUrl(user), - filterQuality: FilterQuality.high, - fit: BoxFit.cover, - ), - ), - channelPreviewTheme: ChannelPreviewTheme( - unreadCounterColor: colorTheme.accentRed, - avatarTheme: AvatarTheme( - borderRadius: BorderRadius.circular(20), - constraints: BoxConstraints.tightFor( - height: 40, - width: 40, - ), - ), - title: textTheme.bodyBold, - subtitle: textTheme.footnote.copyWith( - color: Color(0xff7A7A7A), - ), - lastMessageAt: textTheme.footnote.copyWith( - color: colorTheme.black.withOpacity(.5), - ), - indicatorIconSize: 16.0), - channelTheme: ChannelTheme( - messageInputButtonIconTheme: theme.iconTheme.copyWith( - color: accentColor, - ), - channelHeaderTheme: ChannelHeaderTheme( - avatarTheme: AvatarTheme( - borderRadius: BorderRadius.circular(20), - constraints: BoxConstraints.tightFor( - height: 40, - width: 40, - ), - ), - color: colorTheme.white, - title: TextStyle( - fontSize: 14, - color: colorTheme.black, - ), - lastMessageAt: TextStyle( - fontSize: 11, - color: colorTheme.black.withOpacity(.5), - ), - ), - inputBackground: colorTheme.white.withAlpha(12), - ), - ownMessageTheme: MessageTheme( - 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, - reactionsMaskColor: colorTheme.whiteSnow, - messageBorderColor: colorTheme.greyGainsboro, - avatarTheme: AvatarTheme( - borderRadius: BorderRadius.circular(20), - constraints: BoxConstraints.tightFor( - height: 32, - width: 32, - ), - ), - messageLinks: TextStyle( - color: accentColor, - ), - ), - otherMessageTheme: MessageTheme( - reactionsBackgroundColor: colorTheme.greyGainsboro, - reactionsBorderColor: colorTheme.white, - reactionsMaskColor: colorTheme.whiteSnow, - messageText: textTheme.body, - createdAt: textTheme.footnote.copyWith(color: colorTheme.grey), - replies: textTheme.footnoteBold.copyWith(color: accentColor), - messageLinks: TextStyle( - color: accentColor, - ), - messageBackgroundColor: colorTheme.white, - messageBorderColor: colorTheme.greyWhisper, - avatarTheme: AvatarTheme( - borderRadius: BorderRadius.circular(20), - constraints: BoxConstraints.tightFor( - height: 32, - width: 32, - ), - ), - ), - reactionIcons: [ - ReactionIcon( - type: 'love', - assetName: 'Icon_love_reaction.svg', - ), - ReactionIcon( - type: 'like', - assetName: 'Icon_thumbs_up_reaction.svg', - ), - ReactionIcon( - type: 'sad', - assetName: 'Icon_thumbs_down_reaction.svg', - ), - ReactionIcon( - type: 'haha', - assetName: 'Icon_LOL_reaction.svg', - ), - ReactionIcon( - type: 'wow', - assetName: 'Icon_wut_reaction.svg', - ), - ], - ); - } -} - -enum TextThemeType { - light, - dark, -} - -class TextTheme { - final TextStyle title; - final TextStyle headlineBold; - final TextStyle headline; - final TextStyle bodyBold; - final TextStyle body; - final TextStyle footnoteBold; - final TextStyle footnote; - final TextStyle captionBold; - - TextTheme.light({ - this.title = const TextStyle( - fontSize: 22, - fontWeight: FontWeight.bold, - color: Colors.black, - ), - this.headlineBold = const TextStyle( - fontSize: 16, - fontWeight: FontWeight.bold, - color: Colors.black, - ), - this.headline = const TextStyle( - fontSize: 16, - fontWeight: FontWeight.w500, - color: Colors.black, - ), - this.bodyBold = const TextStyle( - fontSize: 14, - fontWeight: FontWeight.bold, - color: Colors.black, - ), - this.body = const TextStyle( - fontSize: 14, - fontWeight: FontWeight.w500, - color: Colors.black, - ), - this.footnoteBold = const TextStyle( - fontSize: 12, - fontWeight: FontWeight.w500, - color: Colors.black, - ), - this.footnote = const TextStyle( - fontSize: 12, - color: Colors.black, - ), - this.captionBold = const TextStyle( - fontSize: 10, - fontWeight: FontWeight.bold, - color: Colors.black, - ), - }); - - TextTheme.dark({ - this.title = const TextStyle( - fontSize: 22, - fontWeight: FontWeight.bold, - color: Colors.white, - ), - this.headlineBold = const TextStyle( - fontSize: 16, - fontWeight: FontWeight.bold, - color: Colors.white, - ), - this.headline = const TextStyle( - fontSize: 16, - fontWeight: FontWeight.w500, - color: Colors.white, - ), - this.bodyBold = const TextStyle( - fontSize: 14, - fontWeight: FontWeight.bold, - color: Colors.white, - ), - this.body = const TextStyle( - fontSize: 14, - fontWeight: FontWeight.w500, - color: Colors.white, - ), - this.footnoteBold = const TextStyle( - fontSize: 12, - fontWeight: FontWeight.w500, - color: Colors.white, - ), - this.footnote = const TextStyle( - fontSize: 12, - color: Colors.white, - ), - this.captionBold = const TextStyle( - fontSize: 10, - fontWeight: FontWeight.bold, - color: Colors.white, - ), - }); - - TextTheme copyWith({ - TextThemeType type = TextThemeType.light, - TextStyle body, - TextStyle title, - TextStyle headlineBold, - TextStyle headline, - TextStyle bodyBold, - TextStyle footnoteBold, - TextStyle footnote, - TextStyle captionBold, - }) { - return type == TextThemeType.light - ? TextTheme.light( - body: body ?? this.body, - title: title ?? this.title, - headlineBold: headlineBold ?? this.headlineBold, - headline: headline ?? this.headline, - bodyBold: bodyBold ?? this.bodyBold, - footnoteBold: footnoteBold ?? this.footnoteBold, - footnote: footnote ?? this.footnote, - captionBold: captionBold ?? this.captionBold, - ) - : TextTheme.dark( - body: body ?? this.body, - title: title ?? this.title, - headlineBold: headlineBold ?? this.headlineBold, - headline: headline ?? this.headline, - bodyBold: bodyBold ?? this.bodyBold, - footnoteBold: footnoteBold ?? this.footnoteBold, - footnote: footnote ?? this.footnote, - captionBold: captionBold ?? this.captionBold, - ); - } - - TextTheme merge(TextTheme other) { - if (other == null) return this; - return copyWith( - body: body?.merge(other.body) ?? other.body, - title: title?.merge(other.title) ?? other.title, - headlineBold: - headlineBold?.merge(other.headlineBold) ?? other.headlineBold, - headline: headline?.merge(other.headline) ?? other.headline, - bodyBold: bodyBold?.merge(other.bodyBold) ?? other.bodyBold, - footnoteBold: - footnoteBold?.merge(other.footnoteBold) ?? other.footnoteBold, - footnote: footnote?.merge(other.footnote) ?? other.footnote, - captionBold: captionBold?.merge(other.captionBold) ?? other.captionBold, - ); - } -} - -enum ColorThemeType { - light, - dark, -} - -class ColorTheme { - final Color black; - final Color grey; - final Color greyGainsboro; - final Color greyWhisper; - final Color whiteSmoke; - final Color whiteSnow; - final Color white; - final Color blueAlice; - final Color accentBlue; - final Color accentRed; - final Color accentGreen; - final Effect borderTop; - final Effect borderBottom; - final Effect shadowIconButton; - final Effect modalShadow; - final Color highlight; - final Color overlay; - final Color overlayDark; - final Gradient bgGradient; - - ColorTheme.light({ - this.black = const Color(0xff000000), - this.grey = const Color(0xff7a7a7a), - this.greyGainsboro = const Color(0xffdbdbdb), - this.greyWhisper = const Color(0xffecebeb), - this.whiteSmoke = const Color(0xfff2f2f2), - this.whiteSnow = const Color(0xfffcfcfc), - this.white = const Color(0xffffffff), - this.blueAlice = const Color(0xffe9f2ff), - this.accentBlue = const Color(0xff005FFF), - this.accentRed = const Color(0xffFF3842), - this.accentGreen = const Color(0xff20E070), - this.highlight = const Color(0xfffbf4dd), - this.overlay = const Color.fromRGBO(0, 0, 0, 0.2), - this.overlayDark = const Color.fromRGBO(0, 0, 0, 0.6), - this.bgGradient = const LinearGradient( - begin: Alignment.topCenter, - end: Alignment.bottomCenter, - colors: [const Color(0xfff7f7f7), const Color(0xfffcfcfc)], - stops: [0, 1], - ), - this.borderTop = const Effect( - sigmaX: 0, - sigmaY: -1, - color: Color(0xff000000), - blur: 0.0, - alpha: 0.08), - this.borderBottom = const Effect( - sigmaX: 0, sigmaY: 1, color: Color(0xff000000), blur: 0.0, alpha: 0.08), - this.shadowIconButton = const Effect( - sigmaX: 0, sigmaY: 2, color: Color(0xff000000), alpha: 0.5, blur: 4.0), - this.modalShadow = const Effect( - sigmaX: 0, sigmaY: 0, color: Color(0xff000000), alpha: 1, blur: 8.0), - }); - - ColorTheme.dark({ - this.black = const Color(0xffffffff), - this.grey = const Color(0xff7a7a7a), - this.greyGainsboro = const Color(0xff2d2f2f), - this.greyWhisper = const Color(0xff1c1e22), - this.whiteSmoke = const Color(0xff13151b), - this.whiteSnow = const Color(0xff070A0D), - this.white = const Color(0xff101418), - this.blueAlice = const Color(0xff00193D), - this.accentBlue = const Color(0xff005FFF), - this.accentRed = const Color(0xffFF3742), - this.accentGreen = const Color(0xff20E070), - this.borderTop = const Effect( - sigmaX: 0, sigmaY: -1, color: Color(0xff141924), blur: 0.0), - this.borderBottom = const Effect( - sigmaX: 0, sigmaY: 1, color: Color(0xff141924), blur: 0.0, alpha: 1.0), - this.shadowIconButton = const Effect( - sigmaX: 0, sigmaY: 2, color: Color(0xff000000), alpha: 0.5, blur: 4.0), - this.modalShadow = const Effect( - sigmaX: 0, sigmaY: 0, color: Color(0xff000000), alpha: 1, blur: 8.0), - this.highlight = const Color(0xff302d22), - this.overlay = const Color.fromRGBO(0, 0, 0, 0.4), - this.overlayDark = const Color.fromRGBO(255, 255, 255, 0.6), - this.bgGradient = const LinearGradient( - begin: Alignment.topCenter, - end: Alignment.bottomCenter, - colors: [const Color(0xff101214), const Color(0xff070a0d)], - stops: [0, 1], - ), - }); - - ColorTheme copyWith({ - ColorThemeType type = ColorThemeType.light, - Color black, - Color grey, - Color greyGainsboro, - Color greyWhisper, - Color whiteSmoke, - Color whiteSnow, - Color white, - Color blueAlice, - Color accentBlue, - Color accentRed, - Color accentGreen, - Effect borderTop, - Effect borderBottom, - Effect shadowIconButton, - Effect modalShadow, - Color highlight, - Color overlay, - Color overlayDark, - Gradient bgGradient, - }) { - return type == ColorThemeType.light - ? ColorTheme.light( - black: black ?? this.black, - grey: grey ?? this.grey, - greyGainsboro: greyGainsboro ?? this.greyGainsboro, - greyWhisper: greyWhisper ?? this.greyWhisper, - whiteSmoke: whiteSmoke ?? this.whiteSmoke, - whiteSnow: whiteSnow ?? this.whiteSnow, - white: white ?? this.white, - blueAlice: blueAlice ?? this.blueAlice, - accentBlue: accentBlue ?? this.accentBlue, - accentRed: accentRed ?? this.accentRed, - accentGreen: accentGreen ?? this.accentGreen, - borderTop: borderTop ?? this.borderTop, - borderBottom: borderBottom ?? this.borderBottom, - shadowIconButton: shadowIconButton ?? this.shadowIconButton, - modalShadow: modalShadow ?? this.modalShadow, - highlight: highlight ?? this.highlight, - overlay: overlay ?? this.overlay, - overlayDark: overlayDark ?? this.overlayDark, - bgGradient: bgGradient ?? this.bgGradient, - ) - : ColorTheme.dark( - black: black ?? this.black, - grey: grey ?? this.grey, - greyGainsboro: greyGainsboro ?? this.greyGainsboro, - greyWhisper: greyWhisper ?? this.greyWhisper, - whiteSmoke: whiteSmoke ?? this.whiteSmoke, - whiteSnow: whiteSnow ?? this.whiteSnow, - white: white ?? this.white, - blueAlice: blueAlice ?? this.blueAlice, - accentBlue: accentBlue ?? this.accentBlue, - accentRed: accentRed ?? this.accentRed, - accentGreen: accentGreen ?? this.accentGreen, - borderTop: borderTop ?? this.borderTop, - borderBottom: borderBottom ?? this.borderBottom, - shadowIconButton: shadowIconButton ?? this.shadowIconButton, - modalShadow: modalShadow ?? this.modalShadow, - highlight: highlight ?? this.highlight, - overlay: overlay ?? this.overlay, - overlayDark: overlayDark ?? this.overlayDark, - bgGradient: bgGradient ?? this.bgGradient, - ); - } - - ColorTheme merge(ColorTheme other) { - if (other == null) return this; - return copyWith( - black: other.black, - grey: other.grey, - greyGainsboro: other.greyGainsboro, - greyWhisper: other.greyWhisper, - whiteSmoke: other.whiteSmoke, - whiteSnow: other.whiteSnow, - white: other.white, - blueAlice: other.blueAlice, - accentBlue: other.accentBlue, - accentRed: other.accentRed, - accentGreen: other.accentGreen, - highlight: other.highlight, - overlay: other.overlay, - overlayDark: other.overlayDark, - bgGradient: other.bgGradient, - borderTop: other.borderTop, - borderBottom: other.borderBottom, - shadowIconButton: other.shadowIconButton, - modalShadow: other.modalShadow, - ); - } -} - -/// Channel theme data -class ChannelTheme { - /// Theme of the [ChannelHeader] widget - final ChannelHeaderTheme channelHeaderTheme; - - /// IconTheme of the send button in [MessageInput] - final IconThemeData messageInputButtonIconTheme; - - /// Theme of the send button in [MessageInput] - final ButtonThemeData messageInputButtonTheme; - - /// Background color of [MessageInput] - final Color inputBackground; - - ChannelTheme({ - this.channelHeaderTheme, - this.messageInputButtonIconTheme, - this.messageInputButtonTheme, - this.inputBackground, - }); - - /// Creates a copy of [ChannelTheme] with specified attributes overridden. - ChannelTheme copyWith({ - ChannelHeaderTheme channelHeaderTheme, - IconThemeData messageInputButtonIconTheme, - ButtonThemeData messageInputButtonTheme, - Color inputBackground, - }) => - ChannelTheme( - channelHeaderTheme: channelHeaderTheme ?? this.channelHeaderTheme, - messageInputButtonIconTheme: - messageInputButtonIconTheme ?? this.messageInputButtonIconTheme, - messageInputButtonTheme: - messageInputButtonTheme ?? this.messageInputButtonTheme, - inputBackground: inputBackground ?? this.inputBackground, - ); - - ChannelTheme merge(ChannelTheme other) { - if (other == null) return this; - return copyWith( - channelHeaderTheme: channelHeaderTheme?.merge(other.channelHeaderTheme) ?? - other.channelHeaderTheme, - messageInputButtonIconTheme: messageInputButtonIconTheme - ?.merge(other.messageInputButtonIconTheme) ?? - other.messageInputButtonIconTheme, - messageInputButtonTheme: other.messageInputButtonTheme, - inputBackground: other.inputBackground, - ); - } -} - -class AvatarTheme { - final BoxConstraints constraints; - final BorderRadius borderRadius; - - AvatarTheme({ - this.constraints, - this.borderRadius, - }); - - AvatarTheme copyWith({ - BoxConstraints constraints, - BorderRadius borderRadius, - }) => - AvatarTheme( - constraints: constraints ?? this.constraints, - borderRadius: borderRadius ?? this.borderRadius, - ); - - AvatarTheme merge(AvatarTheme other) { - if (other == null) return this; - return copyWith( - constraints: other.constraints, - borderRadius: other.borderRadius, - ); - } -} - -class MessageTheme { - final TextStyle messageText; - final TextStyle messageAuthor; - final TextStyle messageLinks; - final TextStyle createdAt; - final TextStyle replies; - final Color messageBackgroundColor; - final Color messageBorderColor; - final Color reactionsBackgroundColor; - final Color reactionsBorderColor; - final Color reactionsMaskColor; - final AvatarTheme avatarTheme; - - const MessageTheme({ - this.replies, - this.messageText, - this.messageAuthor, - this.messageLinks, - this.messageBackgroundColor, - this.messageBorderColor, - this.reactionsBackgroundColor, - this.reactionsBorderColor, - this.reactionsMaskColor, - this.avatarTheme, - this.createdAt, - }); - - MessageTheme copyWith({ - TextStyle messageText, - TextStyle messageAuthor, - TextStyle messageLinks, - TextStyle createdAt, - TextStyle replies, - Color messageBackgroundColor, - Color messageBorderColor, - AvatarTheme avatarTheme, - Color reactionsBackgroundColor, - Color reactionsBorderColor, - Color reactionsMaskColor, - }) => - MessageTheme( - messageText: messageText ?? this.messageText, - messageAuthor: messageAuthor ?? this.messageAuthor, - messageLinks: messageLinks ?? this.messageLinks, - createdAt: createdAt ?? this.createdAt, - messageBackgroundColor: - messageBackgroundColor ?? this.messageBackgroundColor, - messageBorderColor: messageBorderColor ?? this.messageBorderColor, - avatarTheme: avatarTheme ?? this.avatarTheme, - replies: replies ?? this.replies, - reactionsBackgroundColor: - reactionsBackgroundColor ?? this.reactionsBackgroundColor, - reactionsBorderColor: reactionsBorderColor ?? this.reactionsBorderColor, - reactionsMaskColor: reactionsMaskColor ?? this.reactionsMaskColor, - ); - - MessageTheme merge(MessageTheme other) { - if (other == null) return this; - return copyWith( - messageText: messageText?.merge(other.messageText) ?? other.messageText, - messageAuthor: - messageAuthor?.merge(other.messageAuthor) ?? other.messageAuthor, - messageLinks: - messageLinks?.merge(other.messageLinks) ?? other.messageLinks, - createdAt: createdAt?.merge(other.createdAt) ?? other.createdAt, - replies: replies?.merge(other.replies) ?? other.replies, - messageBackgroundColor: other.messageBackgroundColor, - messageBorderColor: other.messageBorderColor, - avatarTheme: avatarTheme?.merge(other.avatarTheme) ?? other.avatarTheme, - reactionsBackgroundColor: other.reactionsBackgroundColor, - reactionsBorderColor: other.reactionsBorderColor, - reactionsMaskColor: other.reactionsMaskColor, - ); - } -} - -class ChannelPreviewTheme { - final TextStyle title; - final TextStyle subtitle; - final TextStyle lastMessageAt; - final AvatarTheme avatarTheme; - final Color unreadCounterColor; - final double indicatorIconSize; - - const ChannelPreviewTheme({ - this.title, - this.subtitle, - this.lastMessageAt, - this.avatarTheme, - this.unreadCounterColor, - this.indicatorIconSize, - }); - - ChannelPreviewTheme copyWith({ - TextStyle title, - TextStyle subtitle, - TextStyle lastMessageAt, - AvatarTheme avatarTheme, - Color unreadCounterColor, - double indicatorIconSize, - }) => - ChannelPreviewTheme( - title: title ?? this.title, - subtitle: subtitle ?? this.subtitle, - lastMessageAt: lastMessageAt ?? this.lastMessageAt, - avatarTheme: avatarTheme ?? this.avatarTheme, - unreadCounterColor: unreadCounterColor ?? this.unreadCounterColor, - indicatorIconSize: indicatorIconSize ?? this.indicatorIconSize, - ); - - ChannelPreviewTheme merge(ChannelPreviewTheme other) { - if (other == null) return this; - return copyWith( - title: title?.merge(other.title) ?? other.title, - subtitle: subtitle?.merge(other.subtitle) ?? other.subtitle, - lastMessageAt: - lastMessageAt?.merge(other.lastMessageAt) ?? other.lastMessageAt, - avatarTheme: avatarTheme?.merge(other.avatarTheme) ?? other.avatarTheme, - unreadCounterColor: other.unreadCounterColor, - ); - } -} - -class ChannelHeaderTheme { - final TextStyle title; - final TextStyle lastMessageAt; - final AvatarTheme avatarTheme; - final Color color; - - const ChannelHeaderTheme({ - this.title, - this.lastMessageAt, - this.avatarTheme, - this.color, - }); - - ChannelHeaderTheme copyWith({ - TextStyle title, - TextStyle lastMessageAt, - AvatarTheme avatarTheme, - Color color, - }) => - ChannelHeaderTheme( - title: title ?? this.title, - lastMessageAt: lastMessageAt ?? this.lastMessageAt, - avatarTheme: avatarTheme ?? this.avatarTheme, - color: color ?? this.color, - ); - - ChannelHeaderTheme merge(ChannelHeaderTheme other) { - if (other == null) return this; - return copyWith( - title: title?.merge(other.title) ?? other.title, - lastMessageAt: - lastMessageAt?.merge(other.lastMessageAt) ?? other.lastMessageAt, - avatarTheme: avatarTheme?.merge(other.avatarTheme) ?? other.avatarTheme, - color: other.color, - ); - } -} - -class Effect { - final double sigmaX; - final double sigmaY; - final Color color; - final double alpha; - final double blur; - - const Effect({ - this.sigmaX, - this.sigmaY, - this.color, - this.alpha, - this.blur, - }); - - Effect copyWith({ - double sigmaX, - double sigmaY, - Color color, - double alpha, - double blur, - }) => - Effect( - sigmaX: sigmaX ?? this.sigmaX, - sigmaY: sigmaY ?? this.sigmaY, - color: color ?? this.color, - alpha: color ?? this.alpha, - blur: blur ?? this.blur, - ); -} - -/// Get random png with initials -String getRandomPicUrl(User user) => - 'https://getstream.io/random_png/?id=${user.id}&name=${user.name}'; diff --git a/packages/stream_chat_flutter_core/lib/src/user_list_view.dart b/packages/stream_chat_flutter_core/lib/src/user_list_view.dart index 4681d931..1b841333 100644 --- a/packages/stream_chat_flutter_core/lib/src/user_list_view.dart +++ b/packages/stream_chat_flutter_core/lib/src/user_list_view.dart @@ -2,15 +2,7 @@ import 'dart:convert'; import 'package:flutter/material.dart'; import 'package:stream_chat/stream_chat.dart'; -import 'package:stream_chat_flutter_core/src/lazy_load_scroll_view.dart'; import 'package:stream_chat_flutter_core/src/users_bloc.dart'; -import 'package:stream_chat_flutter_core/src/stream_chat_theme.dart'; - -/// Callback called when tapping on a user -typedef UserTapCallback = void Function(User, Widget); - -/// Builder used to create a custom [ListUserItem] from a [User] -typedef UserItemBuilder = Widget Function(BuildContext, User, bool); /// /// It shows the list of current users. @@ -47,31 +39,30 @@ class UserListView extends StatefulWidget { /// Instantiate a new UserListView const UserListView({ Key key, - this.errorBuilder, - this.emptyBuilder, this.filter, this.options, this.sort, this.pagination, - this.onUserTap, - this.onUserLongPress, - this.userWidget, - this.userItemBuilder, - this.separatorBuilder, - this.onImageTap, - this.selectedUsers, this.pullToRefresh = true, this.groupAlphabetically = false, - this.crossAxisCount = 1, - }) : assert( - crossAxisCount == 1 || groupAlphabetically == false, - 'Cannot group alphabetically when crossAxisCount > 1', - ), - super(key: key); + @required this.errorBuilder, + @required this.emptyBuilder, + @required this.loadingBuilder, + @required this.listBuilder, + this.userListController, + }) : super(key: key); + + final UserListController userListController; /// The builder that will be used in case of error final Widget Function(Error error) errorBuilder; + /// The builder that will be used to build the list + final Widget Function(BuildContext context, List users) listBuilder; + + /// The builder that will be used for loading + final WidgetBuilder loadingBuilder; + /// The builder used when the channel list is empty. final WidgetBuilder emptyBuilder; @@ -98,48 +89,20 @@ class UserListView extends StatefulWidget { /// message_limit: how many messages should be included to each channel final PaginationParams pagination; - /// Function called when tapping on a channel - /// By default it calls [Navigator.push] building a [MaterialPageRoute] - /// with the widget [userWidget] as child. - final UserTapCallback onUserTap; - - /// Function called when long pressing on a channel - final Function(User) onUserLongPress; - - /// Widget used when opening a channel - final Widget userWidget; - - /// Builder used to create a custom user preview - final UserItemBuilder userItemBuilder; - - /// Builder used to create a custom item separator - final Function(BuildContext, int) separatorBuilder; - - /// The function called when the image is tapped - final Function(User) onImageTap; - /// Set it to false to disable the pull-to-refresh widget final bool pullToRefresh; - /// Sets a blue trailing checkMark in [ListUserItem] for all the [selectedUsers] - final Set selectedUsers; - /// Set it to true to group users by their first character /// /// defaults to false final bool groupAlphabetically; - /// The number of children in the cross axis. - final int crossAxisCount; - @override _UserListViewState createState() => _UserListViewState(); } class _UserListViewState extends State with WidgetsBindingObserver { - bool get _isListView => widget.crossAxisCount == 1; - @override void initState() { super.initState(); @@ -150,6 +113,10 @@ class _UserListViewState extends State pagination: widget.pagination, options: widget.options, ); + + if (widget.userListController != null) { + widget.userListController.paginateData = paginateData; + } } @override @@ -214,235 +181,36 @@ class _UserListViewState extends State print((snapshot.error as Error).stackTrace); } - if (widget.errorBuilder != null) { - return widget.errorBuilder(snapshot.error); - } - - var message = snapshot.error.toString(); - if (snapshot.error is DioError) { - final dioError = snapshot.error as DioError; - if (dioError.type == DioErrorType.RESPONSE) { - message = dioError.message; - } else { - message = 'Check your connection and retry'; - } - } - return Center( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text.rich( - TextSpan( - children: [ - WidgetSpan( - child: Padding( - padding: const EdgeInsets.only( - right: 2.0, - ), - child: Icon(Icons.error_outline), - ), - ), - TextSpan(text: 'Error loading channels'), - ], - ), - style: Theme.of(context).textTheme.headline6, - ), - Padding( - padding: const EdgeInsets.only( - top: 16.0, - ), - child: Text(message), - ), - FlatButton( - onPressed: () { - usersBlocState.queryUsers( - filter: widget.filter, - sort: widget.sort, - pagination: widget.pagination, - options: widget.options, - ); - }, - child: Text('Retry'), - ), - ], - ), - ); + return widget.errorBuilder(snapshot.error); } if (!snapshot.hasData) { - return LayoutBuilder( - builder: (context, viewportConstraints) { - return SingleChildScrollView( - physics: AlwaysScrollableScrollPhysics(), - child: ConstrainedBox( - constraints: BoxConstraints( - minHeight: viewportConstraints.maxHeight, - ), - child: Center( - child: CircularProgressIndicator(), - ), - ), - ); - }, - ); + return widget.loadingBuilder(context); } final items = snapshot.data; - if (items.isEmpty && widget.emptyBuilder != null) { + if (items.isEmpty) { return widget.emptyBuilder(context); } - if (items.isEmpty && widget.emptyBuilder == null) { - return LayoutBuilder( - builder: (context, viewportConstraints) { - return SingleChildScrollView( - physics: AlwaysScrollableScrollPhysics(), - child: ConstrainedBox( - constraints: BoxConstraints( - minHeight: viewportConstraints.maxHeight, - ), - child: Center( - child: Text('There are no users currently'), - ), - ), - ); - }, - ); + if (items.isEmpty) { + return widget.emptyBuilder(context); } - final child = _isListView - ? ListView.separated( - physics: AlwaysScrollableScrollPhysics(), - itemCount: items.isNotEmpty ? items.length + 1 : items.length, - separatorBuilder: (_, index) { - if (widget.separatorBuilder != null) { - return widget.separatorBuilder(context, index); - } - return _separatorBuilder(context, index); - }, - itemBuilder: (context, index) { - return _listItemBuilder(context, index, items); - }, - ) - : GridView.builder( - gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( - crossAxisCount: widget.crossAxisCount, - ), - itemCount: items.isNotEmpty ? items.length + 1 : items.length, - physics: AlwaysScrollableScrollPhysics(), - itemBuilder: (context, index) { - return _gridItemBuilder(context, index, items); - }, - ); - - return LazyLoadScrollView( - onEndOfPage: () async { - return _listenUserPagination(usersBlocState); - }, - child: child, - ); + return widget.listBuilder(context, items); }, ); } - Widget _listItemBuilder(BuildContext context, int i, List items) { - final usersProvider = UsersBloc.of(context); - if (i < items.length) { - final item = items[i]; - return item.when( - headerItem: (header) { - return Container( - key: ValueKey('HEADER-$header'), - color: - StreamChatTheme.of(context).colorTheme.black.withOpacity(0.05), - child: Padding( - padding: const EdgeInsets.symmetric(horizontal: 8.0, vertical: 6), - child: Text( - header, - style: TextStyle( - fontWeight: FontWeight.bold, - fontSize: 14.5, - color: StreamChatTheme.of(context).colorTheme.grey, - ), - ), - ), - ); - }, - userItem: (user) { - final selected = widget.selectedUsers?.contains(user) ?? false; - return Container( - key: ValueKey('USER-${user.id}'), - child: widget.userItemBuilder(context, user, selected), - ); - }, - ); - } else { - return _buildQueryProgressIndicator(context, usersProvider); - } - } + void paginateData() { + final usersBloc = UsersBloc.of(context); - Widget _gridItemBuilder(BuildContext context, int i, List items) { - final usersProvider = UsersBloc.of(context); - if (i < items.length) { - final item = items[i]; - return item.when( - headerItem: (_) => Offstage(), - userItem: (user) { - final selected = widget.selectedUsers?.contains(user) ?? false; - return Container( - key: ValueKey('USER-${user.id}'), - child: widget.userItemBuilder(context, user, selected), - ); - }, - ); - } else { - return _buildQueryProgressIndicator(context, usersProvider); - } - } - - Widget _buildQueryProgressIndicator(context, UsersBlocState usersProvider) { - return StreamBuilder( - stream: usersProvider.queryUsersLoading, - initialData: false, - builder: (context, snapshot) { - if (snapshot.hasError) { - return Container( - color: StreamChatTheme.of(context) - .colorTheme - .accentRed - .withOpacity(.2), - child: Padding( - padding: const EdgeInsets.symmetric(vertical: 16.0), - child: Center( - child: Text('Error loading users'), - ), - ), - ); - } - return Container( - height: 100, - padding: EdgeInsets.all(32), - child: Center( - child: snapshot.data ? CircularProgressIndicator() : Container(), - ), - ); - }); - } - - Widget _separatorBuilder(context, i) { - return Container( - height: 1, - color: StreamChatTheme.of(context).colorTheme.greyWhisper, - ); - } - - void _listenUserPagination(UsersBlocState usersProvider) { - usersProvider.queryUsers( + usersBloc.queryUsers( filter: widget.filter, sort: widget.sort, pagination: widget.pagination.copyWith( - offset: usersProvider.users?.length ?? 0, + offset: usersBloc.users?.length ?? 0, ), options: widget.options, ); @@ -505,3 +273,8 @@ class ListUserItem extends ListItem { ListUserItem(this.user); } + +/// Controller used for paginating data in [ChannelListView] +class UserListController { + VoidCallback paginateData; +} From 844f3c32776d567a61fa4512446a95e0fcc1cf13 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Fri, 22 Jan 2021 17:25:03 +0530 Subject: [PATCH 1006/1140] feat: Added exports --- .../lib/src/reaction_icon.dart | 9 --------- .../lib/stream_chat_flutter_core.dart | 15 ++++++++++----- .../test/stream_chat_flutter_core_test.dart | 10 +--------- 3 files changed, 11 insertions(+), 23 deletions(-) delete mode 100644 packages/stream_chat_flutter_core/lib/src/reaction_icon.dart diff --git a/packages/stream_chat_flutter_core/lib/src/reaction_icon.dart b/packages/stream_chat_flutter_core/lib/src/reaction_icon.dart deleted file mode 100644 index 99b93328..00000000 --- a/packages/stream_chat_flutter_core/lib/src/reaction_icon.dart +++ /dev/null @@ -1,9 +0,0 @@ -class ReactionIcon { - final String type; - final String assetName; - - ReactionIcon({ - this.type, - this.assetName, - }); -} diff --git a/packages/stream_chat_flutter_core/lib/stream_chat_flutter_core.dart b/packages/stream_chat_flutter_core/lib/stream_chat_flutter_core.dart index 1f8e28bb..638f71be 100644 --- a/packages/stream_chat_flutter_core/lib/stream_chat_flutter_core.dart +++ b/packages/stream_chat_flutter_core/lib/stream_chat_flutter_core.dart @@ -1,7 +1,12 @@ library stream_chat_flutter_core; -/// A Calculator. -class Calculator { - /// Returns [value] plus 1. - int addOne(int value) => value + 1; -} +export 'src/channel_list_view.dart'; +export 'src/channels_bloc.dart'; +export 'src/lazy_load_scroll_view.dart'; +export 'src/message_list_view.dart'; +export 'src/message_search_bloc.dart'; +export 'src/message_search_list_view.dart'; +export 'src/stream_channel.dart'; +export 'src/stream_chat.dart'; +export 'src/user_list_view.dart'; +export 'src/users_bloc.dart'; diff --git a/packages/stream_chat_flutter_core/test/stream_chat_flutter_core_test.dart b/packages/stream_chat_flutter_core/test/stream_chat_flutter_core_test.dart index 626831ae..3e26a916 100644 --- a/packages/stream_chat_flutter_core/test/stream_chat_flutter_core_test.dart +++ b/packages/stream_chat_flutter_core/test/stream_chat_flutter_core_test.dart @@ -2,12 +2,4 @@ import 'package:flutter_test/flutter_test.dart'; import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; -void main() { - test('adds one to input values', () { - final calculator = Calculator(); - expect(calculator.addOne(2), 3); - expect(calculator.addOne(-7), -6); - expect(calculator.addOne(0), 1); - expect(() => calculator.addOne(null), throwsNoSuchMethodError); - }); -} +void main() {} From b6aa030d81c96446621dc831b6357249479343ab Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Fri, 22 Jan 2021 18:16:05 +0530 Subject: [PATCH 1007/1140] feat: Created example app --- .../example/.gitignore | 41 ++ .../example/.metadata | 10 + .../example/README.md | 16 + .../example/android/.gitignore | 11 + .../example/android/app/build.gradle | 54 ++ .../android/app/src/debug/AndroidManifest.xml | 7 + .../android/app/src/main/AndroidManifest.xml | 47 ++ .../java/example/example/MainActivity.java | 6 + .../main/res/drawable/launch_background.xml | 12 + .../src/main/res/mipmap-hdpi/ic_launcher.png | Bin 0 -> 544 bytes .../src/main/res/mipmap-mdpi/ic_launcher.png | Bin 0 -> 442 bytes .../src/main/res/mipmap-xhdpi/ic_launcher.png | Bin 0 -> 721 bytes .../main/res/mipmap-xxhdpi/ic_launcher.png | Bin 0 -> 1031 bytes .../main/res/mipmap-xxxhdpi/ic_launcher.png | Bin 0 -> 1443 bytes .../app/src/main/res/values/styles.xml | 18 + .../app/src/profile/AndroidManifest.xml | 7 + .../example/android/build.gradle | 29 + .../example/android/gradle.properties | 3 + .../gradle/wrapper/gradle-wrapper.properties | 6 + .../example/android/settings.gradle | 11 + .../example/ios/.gitignore | 32 ++ .../ios/Flutter/AppFrameworkInfo.plist | 26 + .../example/ios/Flutter/Debug.xcconfig | 1 + .../example/ios/Flutter/Release.xcconfig | 1 + .../ios/Runner.xcodeproj/project.pbxproj | 495 ++++++++++++++++++ .../contents.xcworkspacedata | 7 + .../xcshareddata/IDEWorkspaceChecks.plist | 8 + .../xcshareddata/WorkspaceSettings.xcsettings | 8 + .../xcshareddata/xcschemes/Runner.xcscheme | 91 ++++ .../contents.xcworkspacedata | 7 + .../xcshareddata/IDEWorkspaceChecks.plist | 8 + .../xcshareddata/WorkspaceSettings.xcsettings | 8 + .../example/ios/Runner/AppDelegate.swift | 13 + .../AppIcon.appiconset/Contents.json | 122 +++++ .../Icon-App-1024x1024@1x.png | Bin 0 -> 10932 bytes .../AppIcon.appiconset/Icon-App-20x20@1x.png | Bin 0 -> 564 bytes .../AppIcon.appiconset/Icon-App-20x20@2x.png | Bin 0 -> 1283 bytes .../AppIcon.appiconset/Icon-App-20x20@3x.png | Bin 0 -> 1588 bytes .../AppIcon.appiconset/Icon-App-29x29@1x.png | Bin 0 -> 1025 bytes .../AppIcon.appiconset/Icon-App-29x29@2x.png | Bin 0 -> 1716 bytes .../AppIcon.appiconset/Icon-App-29x29@3x.png | Bin 0 -> 1920 bytes .../AppIcon.appiconset/Icon-App-40x40@1x.png | Bin 0 -> 1283 bytes .../AppIcon.appiconset/Icon-App-40x40@2x.png | Bin 0 -> 1895 bytes .../AppIcon.appiconset/Icon-App-40x40@3x.png | Bin 0 -> 2665 bytes .../AppIcon.appiconset/Icon-App-60x60@2x.png | Bin 0 -> 2665 bytes .../AppIcon.appiconset/Icon-App-60x60@3x.png | Bin 0 -> 3831 bytes .../AppIcon.appiconset/Icon-App-76x76@1x.png | Bin 0 -> 1888 bytes .../AppIcon.appiconset/Icon-App-76x76@2x.png | Bin 0 -> 3294 bytes .../Icon-App-83.5x83.5@2x.png | Bin 0 -> 3612 bytes .../LaunchImage.imageset/Contents.json | 23 + .../LaunchImage.imageset/LaunchImage.png | Bin 0 -> 68 bytes .../LaunchImage.imageset/LaunchImage@2x.png | Bin 0 -> 68 bytes .../LaunchImage.imageset/LaunchImage@3x.png | Bin 0 -> 68 bytes .../LaunchImage.imageset/README.md | 5 + .../Runner/Base.lproj/LaunchScreen.storyboard | 37 ++ .../ios/Runner/Base.lproj/Main.storyboard | 26 + .../example/ios/Runner/Info.plist | 45 ++ .../ios/Runner/Runner-Bridging-Header.h | 1 + .../example/lib/main.dart | 117 +++++ .../example/pubspec.yaml | 77 +++ .../example/test/widget_test.dart | 30 ++ 61 files changed, 1466 insertions(+) create mode 100644 packages/stream_chat_flutter_core/example/.gitignore create mode 100644 packages/stream_chat_flutter_core/example/.metadata create mode 100644 packages/stream_chat_flutter_core/example/README.md create mode 100644 packages/stream_chat_flutter_core/example/android/.gitignore create mode 100644 packages/stream_chat_flutter_core/example/android/app/build.gradle create mode 100644 packages/stream_chat_flutter_core/example/android/app/src/debug/AndroidManifest.xml create mode 100644 packages/stream_chat_flutter_core/example/android/app/src/main/AndroidManifest.xml create mode 100644 packages/stream_chat_flutter_core/example/android/app/src/main/java/example/example/MainActivity.java create mode 100644 packages/stream_chat_flutter_core/example/android/app/src/main/res/drawable/launch_background.xml create mode 100644 packages/stream_chat_flutter_core/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png create mode 100644 packages/stream_chat_flutter_core/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png create mode 100644 packages/stream_chat_flutter_core/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png create mode 100644 packages/stream_chat_flutter_core/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png create mode 100644 packages/stream_chat_flutter_core/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png create mode 100644 packages/stream_chat_flutter_core/example/android/app/src/main/res/values/styles.xml create mode 100644 packages/stream_chat_flutter_core/example/android/app/src/profile/AndroidManifest.xml create mode 100644 packages/stream_chat_flutter_core/example/android/build.gradle create mode 100644 packages/stream_chat_flutter_core/example/android/gradle.properties create mode 100644 packages/stream_chat_flutter_core/example/android/gradle/wrapper/gradle-wrapper.properties create mode 100644 packages/stream_chat_flutter_core/example/android/settings.gradle create mode 100644 packages/stream_chat_flutter_core/example/ios/.gitignore create mode 100644 packages/stream_chat_flutter_core/example/ios/Flutter/AppFrameworkInfo.plist create mode 100644 packages/stream_chat_flutter_core/example/ios/Flutter/Debug.xcconfig create mode 100644 packages/stream_chat_flutter_core/example/ios/Flutter/Release.xcconfig create mode 100644 packages/stream_chat_flutter_core/example/ios/Runner.xcodeproj/project.pbxproj create mode 100644 packages/stream_chat_flutter_core/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata create mode 100644 packages/stream_chat_flutter_core/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 packages/stream_chat_flutter_core/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings create mode 100644 packages/stream_chat_flutter_core/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme create mode 100644 packages/stream_chat_flutter_core/example/ios/Runner.xcworkspace/contents.xcworkspacedata create mode 100644 packages/stream_chat_flutter_core/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 packages/stream_chat_flutter_core/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings create mode 100644 packages/stream_chat_flutter_core/example/ios/Runner/AppDelegate.swift create mode 100644 packages/stream_chat_flutter_core/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json create mode 100644 packages/stream_chat_flutter_core/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png create mode 100644 packages/stream_chat_flutter_core/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png create mode 100644 packages/stream_chat_flutter_core/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png create mode 100644 packages/stream_chat_flutter_core/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png create mode 100644 packages/stream_chat_flutter_core/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png create mode 100644 packages/stream_chat_flutter_core/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png create mode 100644 packages/stream_chat_flutter_core/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png create mode 100644 packages/stream_chat_flutter_core/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png create mode 100644 packages/stream_chat_flutter_core/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png create mode 100644 packages/stream_chat_flutter_core/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png create mode 100644 packages/stream_chat_flutter_core/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png create mode 100644 packages/stream_chat_flutter_core/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png create mode 100644 packages/stream_chat_flutter_core/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png create mode 100644 packages/stream_chat_flutter_core/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png create mode 100644 packages/stream_chat_flutter_core/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png create mode 100644 packages/stream_chat_flutter_core/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json create mode 100644 packages/stream_chat_flutter_core/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png create mode 100644 packages/stream_chat_flutter_core/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png create mode 100644 packages/stream_chat_flutter_core/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png create mode 100644 packages/stream_chat_flutter_core/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md create mode 100644 packages/stream_chat_flutter_core/example/ios/Runner/Base.lproj/LaunchScreen.storyboard create mode 100644 packages/stream_chat_flutter_core/example/ios/Runner/Base.lproj/Main.storyboard create mode 100644 packages/stream_chat_flutter_core/example/ios/Runner/Info.plist create mode 100644 packages/stream_chat_flutter_core/example/ios/Runner/Runner-Bridging-Header.h create mode 100644 packages/stream_chat_flutter_core/example/lib/main.dart create mode 100644 packages/stream_chat_flutter_core/example/pubspec.yaml create mode 100644 packages/stream_chat_flutter_core/example/test/widget_test.dart diff --git a/packages/stream_chat_flutter_core/example/.gitignore b/packages/stream_chat_flutter_core/example/.gitignore new file mode 100644 index 00000000..9d532b18 --- /dev/null +++ b/packages/stream_chat_flutter_core/example/.gitignore @@ -0,0 +1,41 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# IntelliJ related +*.iml +*.ipr +*.iws +.idea/ + +# The .vscode folder contains launch configuration and tasks you configure in +# VS Code which you may wish to be included in version control, so this line +# is commented out by default. +#.vscode/ + +# Flutter/Dart/Pub related +**/doc/api/ +**/ios/Flutter/.last_build_id +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json diff --git a/packages/stream_chat_flutter_core/example/.metadata b/packages/stream_chat_flutter_core/example/.metadata new file mode 100644 index 00000000..182cccaf --- /dev/null +++ b/packages/stream_chat_flutter_core/example/.metadata @@ -0,0 +1,10 @@ +# This file tracks properties of this Flutter project. +# Used by Flutter tool to assess capabilities and perform upgrades etc. +# +# This file should be version controlled and should not be manually edited. + +version: + revision: 78910062997c3a836feee883712c241a5fd22983 + channel: stable + +project_type: app diff --git a/packages/stream_chat_flutter_core/example/README.md b/packages/stream_chat_flutter_core/example/README.md new file mode 100644 index 00000000..fef640e1 --- /dev/null +++ b/packages/stream_chat_flutter_core/example/README.md @@ -0,0 +1,16 @@ +# example + +Example app for testing stream_chat_flutter_core + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/packages/stream_chat_flutter_core/example/android/.gitignore b/packages/stream_chat_flutter_core/example/android/.gitignore new file mode 100644 index 00000000..0a741cb4 --- /dev/null +++ b/packages/stream_chat_flutter_core/example/android/.gitignore @@ -0,0 +1,11 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java + +# Remember to never publicly share your keystore. +# See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app +key.properties diff --git a/packages/stream_chat_flutter_core/example/android/app/build.gradle b/packages/stream_chat_flutter_core/example/android/app/build.gradle new file mode 100644 index 00000000..edcec7b9 --- /dev/null +++ b/packages/stream_chat_flutter_core/example/android/app/build.gradle @@ -0,0 +1,54 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 29 + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "example.example" + minSdkVersion 16 + targetSdkVersion 29 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + + buildTypes { + release { + // TODO: Add your own signing config for the release build. + // Signing with the debug keys for now, so `flutter run --release` works. + signingConfig signingConfigs.debug + } + } +} + +flutter { + source '../..' +} diff --git a/packages/stream_chat_flutter_core/example/android/app/src/debug/AndroidManifest.xml b/packages/stream_chat_flutter_core/example/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 00000000..397a9492 --- /dev/null +++ b/packages/stream_chat_flutter_core/example/android/app/src/debug/AndroidManifest.xml @@ -0,0 +1,7 @@ + + + + diff --git a/packages/stream_chat_flutter_core/example/android/app/src/main/AndroidManifest.xml b/packages/stream_chat_flutter_core/example/android/app/src/main/AndroidManifest.xml new file mode 100644 index 00000000..d2eb734a --- /dev/null +++ b/packages/stream_chat_flutter_core/example/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/packages/stream_chat_flutter_core/example/android/app/src/main/java/example/example/MainActivity.java b/packages/stream_chat_flutter_core/example/android/app/src/main/java/example/example/MainActivity.java new file mode 100644 index 00000000..e30c2bec --- /dev/null +++ b/packages/stream_chat_flutter_core/example/android/app/src/main/java/example/example/MainActivity.java @@ -0,0 +1,6 @@ +package example.example; + +import io.flutter.embedding.android.FlutterActivity; + +public class MainActivity extends FlutterActivity { +} diff --git a/packages/stream_chat_flutter_core/example/android/app/src/main/res/drawable/launch_background.xml b/packages/stream_chat_flutter_core/example/android/app/src/main/res/drawable/launch_background.xml new file mode 100644 index 00000000..304732f8 --- /dev/null +++ b/packages/stream_chat_flutter_core/example/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/packages/stream_chat_flutter_core/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/packages/stream_chat_flutter_core/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..db77bb4b7b0906d62b1847e87f15cdcacf6a4f29 GIT binary patch literal 544 zcmeAS@N?(olHy`uVBq!ia0vp^9w5xY3?!3`olAj~WQl7;NpOBzNqJ&XDuZK6ep0G} zXKrG8YEWuoN@d~6R2!h8bpbvhu0Wd6uZuB!w&u2PAxD2eNXD>P5D~Wn-+_Wa#27Xc zC?Zj|6r#X(-D3u$NCt}(Ms06KgJ4FxJVv{GM)!I~&n8Bnc94O7-Hd)cjDZswgC;Qs zO=b+9!WcT8F?0rF7!Uys2bs@gozCP?z~o%U|N3vA*22NaGQG zlg@K`O_XuxvZ&Ks^m&R!`&1=spLvfx7oGDKDwpwW`#iqdw@AL`7MR}m`rwr|mZgU`8P7SBkL78fFf!WnuYWm$5Z0 zNXhDbCv&49sM544K|?c)WrFfiZvCi9h0O)B3Pgg&ebxsLQ05GG~ AQ2+n{ literal 0 HcmV?d00001 diff --git a/packages/stream_chat_flutter_core/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/packages/stream_chat_flutter_core/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..17987b79bb8a35cc66c3c1fd44f5a5526c1b78be GIT binary patch literal 442 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA3?vioaBc-sk|nMYCBgY=CFO}lsSJ)O`AMk? zp1FzXsX?iUDV2pMQ*D5Xx&nMcT!A!W`0S9QKQy;}1Cl^CgaH=;G9cpY;r$Q>i*pfB zP2drbID<_#qf;rPZx^FqH)F_D#*k@@q03KywUtLX8Ua?`H+NMzkczFPK3lFz@i_kW%1NOn0|D2I9n9wzH8m|-tHjsw|9>@K=iMBhxvkv6m8Y-l zytQ?X=U+MF$@3 zt`~i=@j|6y)RWMK--}M|=T`o&^Ni>IoWKHEbBXz7?A@mgWoL>!*SXo`SZH-*HSdS+ yn*9;$7;m`l>wYBC5bq;=U}IMqLzqbYCidGC!)_gkIk_C@Uy!y&wkt5C($~2D>~)O*cj@FGjOCM)M>_ixfudOh)?xMu#Fs z#}Y=@YDTwOM)x{K_j*Q;dPdJ?Mz0n|pLRx{4n|)f>SXlmV)XB04CrSJn#dS5nK2lM zrZ9#~WelCp7&e13Y$jvaEXHskn$2V!!DN-nWS__6T*l;H&Fopn?A6HZ-6WRLFP=R` zqG+CE#d4|IbyAI+rJJ`&x9*T`+a=p|0O(+s{UBcyZdkhj=yS1>AirP+0R;mf2uMgM zC}@~JfByORAh4SyRgi&!(cja>F(l*O+nd+@4m$|6K6KDn_&uvCpV23&>G9HJp{xgg zoq1^2_p9@|WEo z*X_Uko@K)qYYv~>43eQGMdbiGbo>E~Q& zrYBH{QP^@Sti!`2)uG{irBBq@y*$B zi#&(U-*=fp74j)RyIw49+0MRPMRU)+a2r*PJ$L5roHt2$UjExCTZSbq%V!HeS7J$N zdG@vOZB4v_lF7Plrx+hxo7(fCV&}fHq)$ literal 0 HcmV?d00001 diff --git a/packages/stream_chat_flutter_core/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/packages/stream_chat_flutter_core/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..d5f1c8d34e7a88e3f88bea192c3a370d44689c3c GIT binary patch literal 1031 zcmeAS@N?(olHy`uVBq!ia0vp^6F``Q8Ax83A=Cw=BuiW)N`mv#O3D+9QW+dm@{>{( zJaZG%Q-e|yQz{EjrrIztFa`(sgt!6~Yi|1%a`XoT0ojZ}lNrNjb9xjc(B0U1_% zz5^97Xt*%oq$rQy4?0GKNfJ44uvxI)gC`h-NZ|&0-7(qS@?b!5r36oQ}zyZrNO3 zMO=Or+<~>+A&uN&E!^Sl+>xE!QC-|oJv`ApDhqC^EWD|@=#J`=d#Xzxs4ah}w&Jnc z$|q_opQ^2TrnVZ0o~wh<3t%W&flvYGe#$xqda2bR_R zvPYgMcHgjZ5nSA^lJr%;<&0do;O^tDDh~=pIxA#coaCY>&N%M2^tq^U%3DB@ynvKo}b?yu-bFc-u0JHzced$sg7S3zqI(2 z#Km{dPr7I=pQ5>FuK#)QwK?Y`E`B?nP+}U)I#c1+FM*1kNvWG|a(TpksZQ3B@sD~b zpQ2)*V*TdwjFOtHvV|;OsiDqHi=6%)o4b!)x$)%9pGTsE z-JL={-Ffv+T87W(Xpooq<`r*VzWQcgBN$$`u}f>-ZQI1BB8ykN*=e4rIsJx9>z}*o zo~|9I;xof literal 0 HcmV?d00001 diff --git a/packages/stream_chat_flutter_core/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/packages/stream_chat_flutter_core/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..4d6372eebdb28e45604e46eeda8dd24651419bc0 GIT binary patch literal 1443 zcmb`G{WsKk6vsdJTdFg%tJav9_E4vzrOaqkWF|A724Nly!y+?N9`YV6wZ}5(X(D_N(?!*n3`|_r0Hc?=PQw&*vnU?QTFY zB_MsH|!j$PP;I}?dppoE_gA(4uc!jV&0!l7_;&p2^pxNo>PEcNJv za5_RT$o2Mf!<+r?&EbHH6nMoTsDOa;mN(wv8RNsHpG)`^ymG-S5By8=l9iVXzN_eG%Xg2@Xeq76tTZ*dGh~Lo9vl;Zfs+W#BydUw zCkZ$o1LqWQO$FC9aKlLl*7x9^0q%0}$OMlp@Kk_jHXOjofdePND+j!A{q!8~Jn+s3 z?~~w@4?egS02}8NuulUA=L~QQfm;MzCGd)XhiftT;+zFO&JVyp2mBww?;QByS_1w! zrQlx%{^cMj0|Bo1FjwY@Q8?Hx0cIPF*@-ZRFpPc#bBw{5@tD(5%sClzIfl8WU~V#u zm5Q;_F!wa$BSpqhN>W@2De?TKWR*!ujY;Yylk_X5#~V!L*Gw~;$%4Q8~Mad z@`-kG?yb$a9cHIApZDVZ^U6Xkp<*4rU82O7%}0jjHlK{id@?-wpN*fCHXyXh(bLt* zPc}H-x0e4E&nQ>y%B-(EL=9}RyC%MyX=upHuFhAk&MLbsF0LP-q`XnH78@fT+pKPW zu72MW`|?8ht^tz$iC}ZwLp4tB;Q49K!QCF3@!iB1qOI=?w z7In!}F~ij(18UYUjnbmC!qKhPo%24?8U1x{7o(+?^Zu0Hx81|FuS?bJ0jgBhEMzf< zCgUq7r2OCB(`XkKcN-TL>u5y#dD6D!)5W?`O5)V^>jb)P)GBdy%t$uUMpf$SNV31$ zb||OojAbvMP?T@$h_ZiFLFVHDmbyMhJF|-_)HX3%m=CDI+ID$0^C>kzxprBW)hw(v zr!Gmda);ICoQyhV_oP5+C%?jcG8v+D@9f?Dk*!BxY}dazmrT@64UrP3hlslANK)bq z$67n83eh}OeW&SV@HG95P|bjfqJ7gw$e+`Hxo!4cx`jdK1bJ>YDSpGKLPZ^1cv$ek zIB?0S<#tX?SJCLWdMd{-ME?$hc7A$zBOdIJ)4!KcAwb=VMov)nK;9z>x~rfT1>dS+ zZ6#`2v@`jgbqq)P22H)Tx2CpmM^o1$B+xT6`(v%5xJ(?j#>Q$+rx_R|7TzDZe{J6q zG1*EcU%tE?!kO%^M;3aM6JN*LAKUVb^xz8-Pxo#jR5(-KBeLJvA@-gxNHx0M-ZJLl z;#JwQoh~9V?`UVo#}{6ka@II>++D@%KqGpMdlQ}?9E*wFcf5(#XQnP$Dk5~%iX^>f z%$y;?M0BLp{O3a(-4A?ewryHrrD%cx#Q^%KY1H zNre$ve+vceSLZcNY4U(RBX&)oZn*Py()h)XkE?PL$!bNb{N5FVI2Y%LKEm%yvpyTP z(1P?z~7YxD~Rf<(a@_y` literal 0 HcmV?d00001 diff --git a/packages/stream_chat_flutter_core/example/android/app/src/main/res/values/styles.xml b/packages/stream_chat_flutter_core/example/android/app/src/main/res/values/styles.xml new file mode 100644 index 00000000..1f83a33f --- /dev/null +++ b/packages/stream_chat_flutter_core/example/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/packages/stream_chat_flutter_core/example/android/app/src/profile/AndroidManifest.xml b/packages/stream_chat_flutter_core/example/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 00000000..397a9492 --- /dev/null +++ b/packages/stream_chat_flutter_core/example/android/app/src/profile/AndroidManifest.xml @@ -0,0 +1,7 @@ + + + + diff --git a/packages/stream_chat_flutter_core/example/android/build.gradle b/packages/stream_chat_flutter_core/example/android/build.gradle new file mode 100644 index 00000000..e0d7ae2c --- /dev/null +++ b/packages/stream_chat_flutter_core/example/android/build.gradle @@ -0,0 +1,29 @@ +buildscript { + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/packages/stream_chat_flutter_core/example/android/gradle.properties b/packages/stream_chat_flutter_core/example/android/gradle.properties new file mode 100644 index 00000000..94adc3a3 --- /dev/null +++ b/packages/stream_chat_flutter_core/example/android/gradle.properties @@ -0,0 +1,3 @@ +org.gradle.jvmargs=-Xmx1536M +android.useAndroidX=true +android.enableJetifier=true diff --git a/packages/stream_chat_flutter_core/example/android/gradle/wrapper/gradle-wrapper.properties b/packages/stream_chat_flutter_core/example/android/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 00000000..296b146b --- /dev/null +++ b/packages/stream_chat_flutter_core/example/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/packages/stream_chat_flutter_core/example/android/settings.gradle b/packages/stream_chat_flutter_core/example/android/settings.gradle new file mode 100644 index 00000000..44e62bcf --- /dev/null +++ b/packages/stream_chat_flutter_core/example/android/settings.gradle @@ -0,0 +1,11 @@ +include ':app' + +def localPropertiesFile = new File(rootProject.projectDir, "local.properties") +def properties = new Properties() + +assert localPropertiesFile.exists() +localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) } + +def flutterSdkPath = properties.getProperty("flutter.sdk") +assert flutterSdkPath != null, "flutter.sdk not set in local.properties" +apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle" diff --git a/packages/stream_chat_flutter_core/example/ios/.gitignore b/packages/stream_chat_flutter_core/example/ios/.gitignore new file mode 100644 index 00000000..e96ef602 --- /dev/null +++ b/packages/stream_chat_flutter_core/example/ios/.gitignore @@ -0,0 +1,32 @@ +*.mode1v3 +*.mode2v3 +*.moved-aside +*.pbxuser +*.perspectivev3 +**/*sync/ +.sconsign.dblite +.tags* +**/.vagrant/ +**/DerivedData/ +Icon? +**/Pods/ +**/.symlinks/ +profile +xcuserdata +**/.generated/ +Flutter/App.framework +Flutter/Flutter.framework +Flutter/Flutter.podspec +Flutter/Generated.xcconfig +Flutter/app.flx +Flutter/app.zip +Flutter/flutter_assets/ +Flutter/flutter_export_environment.sh +ServiceDefinitions.json +Runner/GeneratedPluginRegistrant.* + +# Exceptions to above rules. +!default.mode1v3 +!default.mode2v3 +!default.pbxuser +!default.perspectivev3 diff --git a/packages/stream_chat_flutter_core/example/ios/Flutter/AppFrameworkInfo.plist b/packages/stream_chat_flutter_core/example/ios/Flutter/AppFrameworkInfo.plist new file mode 100644 index 00000000..6b4c0f78 --- /dev/null +++ b/packages/stream_chat_flutter_core/example/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 8.0 + + diff --git a/packages/stream_chat_flutter_core/example/ios/Flutter/Debug.xcconfig b/packages/stream_chat_flutter_core/example/ios/Flutter/Debug.xcconfig new file mode 100644 index 00000000..592ceee8 --- /dev/null +++ b/packages/stream_chat_flutter_core/example/ios/Flutter/Debug.xcconfig @@ -0,0 +1 @@ +#include "Generated.xcconfig" diff --git a/packages/stream_chat_flutter_core/example/ios/Flutter/Release.xcconfig b/packages/stream_chat_flutter_core/example/ios/Flutter/Release.xcconfig new file mode 100644 index 00000000..592ceee8 --- /dev/null +++ b/packages/stream_chat_flutter_core/example/ios/Flutter/Release.xcconfig @@ -0,0 +1 @@ +#include "Generated.xcconfig" diff --git a/packages/stream_chat_flutter_core/example/ios/Runner.xcodeproj/project.pbxproj b/packages/stream_chat_flutter_core/example/ios/Runner.xcodeproj/project.pbxproj new file mode 100644 index 00000000..9943511d --- /dev/null +++ b/packages/stream_chat_flutter_core/example/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,495 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; + 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; + 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; + 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; + 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; + 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 97C146EB1CF9000F007C117D /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 9740EEB11CF90186004384FC /* Flutter */ = { + isa = PBXGroup; + children = ( + 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, + 9740EEB21CF90195004384FC /* Debug.xcconfig */, + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, + 9740EEB31CF90195004384FC /* Generated.xcconfig */, + ); + name = Flutter; + sourceTree = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 97C146ED1CF9000F007C117D /* Runner */ = { + isa = PBXNativeTarget; + buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; + buildPhases = ( + 9740EEB61CF901F6004384FC /* Run Script */, + 97C146EA1CF9000F007C117D /* Sources */, + 97C146EB1CF9000F007C117D /* Frameworks */, + 97C146EC1CF9000F007C117D /* Resources */, + 9705A1C41CF9048500538489 /* Embed Frameworks */, + 3B06AD1E1E4923F5004D2608 /* Thin Binary */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Runner; + productName = Runner; + productReference = 97C146EE1CF9000F007C117D /* Runner.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 97C146E61CF9000F007C117D /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 1020; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Profile; + }; + 249021D4217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + ENABLE_BITCODE = NO; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = example.example; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 97C147061CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + ENABLE_BITCODE = NO; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = example.example; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Debug; + }; + 97C147071CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + ENABLE_BITCODE = NO; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = example.example; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/packages/stream_chat_flutter_core/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/packages/stream_chat_flutter_core/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 00000000..1d526a16 --- /dev/null +++ b/packages/stream_chat_flutter_core/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/packages/stream_chat_flutter_core/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/packages/stream_chat_flutter_core/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 00000000..18d98100 --- /dev/null +++ b/packages/stream_chat_flutter_core/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/packages/stream_chat_flutter_core/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/packages/stream_chat_flutter_core/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 00000000..f9b0d7c5 --- /dev/null +++ b/packages/stream_chat_flutter_core/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + PreviewsEnabled + + + diff --git a/packages/stream_chat_flutter_core/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/packages/stream_chat_flutter_core/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme new file mode 100644 index 00000000..a28140cf --- /dev/null +++ b/packages/stream_chat_flutter_core/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/stream_chat_flutter_core/example/ios/Runner.xcworkspace/contents.xcworkspacedata b/packages/stream_chat_flutter_core/example/ios/Runner.xcworkspace/contents.xcworkspacedata new file mode 100644 index 00000000..1d526a16 --- /dev/null +++ b/packages/stream_chat_flutter_core/example/ios/Runner.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/packages/stream_chat_flutter_core/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/packages/stream_chat_flutter_core/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 00000000..18d98100 --- /dev/null +++ b/packages/stream_chat_flutter_core/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/packages/stream_chat_flutter_core/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/packages/stream_chat_flutter_core/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 00000000..f9b0d7c5 --- /dev/null +++ b/packages/stream_chat_flutter_core/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + PreviewsEnabled + + + diff --git a/packages/stream_chat_flutter_core/example/ios/Runner/AppDelegate.swift b/packages/stream_chat_flutter_core/example/ios/Runner/AppDelegate.swift new file mode 100644 index 00000000..70693e4a --- /dev/null +++ b/packages/stream_chat_flutter_core/example/ios/Runner/AppDelegate.swift @@ -0,0 +1,13 @@ +import UIKit +import Flutter + +@UIApplicationMain +@objc class AppDelegate: FlutterAppDelegate { + override func application( + _ application: UIApplication, + didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? + ) -> Bool { + GeneratedPluginRegistrant.register(with: self) + return super.application(application, didFinishLaunchingWithOptions: launchOptions) + } +} diff --git a/packages/stream_chat_flutter_core/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/packages/stream_chat_flutter_core/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 00000000..d36b1fab --- /dev/null +++ b/packages/stream_chat_flutter_core/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,122 @@ +{ + "images" : [ + { + "size" : "20x20", + "idiom" : "iphone", + "filename" : "Icon-App-20x20@2x.png", + "scale" : "2x" + }, + { + "size" : "20x20", + "idiom" : "iphone", + "filename" : "Icon-App-20x20@3x.png", + "scale" : "3x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@1x.png", + "scale" : "1x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@2x.png", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@3x.png", + "scale" : "3x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "Icon-App-40x40@2x.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "Icon-App-40x40@3x.png", + "scale" : "3x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "Icon-App-60x60@2x.png", + "scale" : "2x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "Icon-App-60x60@3x.png", + "scale" : "3x" + }, + { + "size" : "20x20", + "idiom" : "ipad", + "filename" : "Icon-App-20x20@1x.png", + "scale" : "1x" + }, + { + "size" : "20x20", + "idiom" : "ipad", + "filename" : "Icon-App-20x20@2x.png", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "Icon-App-29x29@1x.png", + "scale" : "1x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "Icon-App-29x29@2x.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "Icon-App-40x40@1x.png", + "scale" : "1x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "Icon-App-40x40@2x.png", + "scale" : "2x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "Icon-App-76x76@1x.png", + "scale" : "1x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "Icon-App-76x76@2x.png", + "scale" : "2x" + }, + { + "size" : "83.5x83.5", + "idiom" : "ipad", + "filename" : "Icon-App-83.5x83.5@2x.png", + "scale" : "2x" + }, + { + "size" : "1024x1024", + "idiom" : "ios-marketing", + "filename" : "Icon-App-1024x1024@1x.png", + "scale" : "1x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/packages/stream_chat_flutter_core/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png b/packages/stream_chat_flutter_core/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png new file mode 100644 index 0000000000000000000000000000000000000000..dc9ada4725e9b0ddb1deab583e5b5102493aa332 GIT binary patch literal 10932 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 literal 0 HcmV?d00001 diff --git a/packages/stream_chat_flutter_core/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/packages/stream_chat_flutter_core/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..f091b6b0bca859a3f474b03065bef75ba58a9e4c GIT binary patch literal 1588 zcmV-42Fv-0P)C1SqPt}wig>|5Crh^=oyX$BK<}M8eLU3e2hGT;=G|!_SP)7zNI6fqUMB=)y zRAZ>eDe#*r`yDAVgB_R*LB*MAc)8(b{g{9McCXW!lq7r(btRoB9!8B-#AI6JMb~YFBEvdsV)`mEQO^&#eRKx@b&x- z5lZm*!WfD8oCLzfHGz#u7sT0^VLMI1MqGxF^v+`4YYnVYgk*=kU?HsSz{v({E3lb9 z>+xILjBN)t6`=g~IBOelGQ(O990@BfXf(DRI5I$qN$0Gkz-FSc$3a+2fX$AedL4u{ z4V+5Ong(9LiGcIKW?_352sR;LtDPmPJXI{YtT=O8=76o9;*n%_m|xo!i>7$IrZ-{l z-x3`7M}qzHsPV@$v#>H-TpjDh2UE$9g6sysUREDy_R(a)>=eHw-WAyfIN z*qb!_hW>G)Tu8nSw9yn#3wFMiLcfc4pY0ek1}8(NqkBR@t4{~oC>ryc-h_ByH(Cg5 z>ao-}771+xE3um9lWAY1FeQFxowa1(!J(;Jg*wrg!=6FdRX+t_<%z&d&?|Bn){>zm zZQj(aA_HeBY&OC^jj*)N`8fa^ePOU72VpInJoI1?`ty#lvlNzs(&MZX+R%2xS~5Kh zX*|AU4QE#~SgPzOXe9>tRj>hjU@c1k5Y_mW*Jp3fI;)1&g3j|zDgC+}2Q_v%YfDax z!?umcN^n}KYQ|a$Lr+51Nf9dkkYFSjZZjkma$0KOj+;aQ&721~t7QUKx61J3(P4P1 zstI~7-wOACnWP4=8oGOwz%vNDqD8w&Q`qcNGGrbbf&0s9L0De{4{mRS?o0MU+nR_! zrvshUau0G^DeMhM_v{5BuLjb#Hh@r23lDAk8oF(C+P0rsBpv85EP>4CVMx#04MOfG z;P%vktHcXwTj~+IE(~px)3*MY77e}p#|c>TD?sMatC0Tu4iKKJ0(X8jxQY*gYtxsC z(zYC$g|@+I+kY;dg_dE>scBf&bP1Nc@Hz<3R)V`=AGkc;8CXqdi=B4l2k|g;2%#m& z*jfX^%b!A8#bI!j9-0Fi0bOXl(-c^AB9|nQaE`*)Hw+o&jS9@7&Gov#HbD~#d{twV zXd^Tr^mWLfFh$@Dr$e;PBEz4(-2q1FF0}c;~B5sA}+Q>TOoP+t>wf)V9Iy=5ruQa;z)y zI9C9*oUga6=hxw6QasLPnee@3^Rr*M{CdaL5=R41nLs(AHk_=Y+A9$2&H(B7!_pURs&8aNw7?`&Z&xY_Ye z)~D5Bog^td-^QbUtkTirdyK^mTHAOuptDflut!#^lnKqU md>ggs(5nOWAqO?umG&QVYK#ibz}*4>0000U6E9hRK9^#O7(mu>ETqrXGsduA8$)?`v2seloOCza43C{NQ$$gAOH**MCn0Q?+L7dl7qnbRdqZ8LSVp1ItDxhxD?t@5_yHg6A8yI zC*%Wgg22K|8E#!~cTNYR~@Y9KepMPrrB8cABapAFa=`H+UGhkXUZV1GnwR1*lPyZ;*K(i~2gp|@bzp8}og7e*#% zEnr|^CWdVV!-4*Y_7rFvlww2Ze+>j*!Z!pQ?2l->4q#nqRu9`ELo6RMS5=br47g_X zRw}P9a7RRYQ%2Vsd0Me{_(EggTnuN6j=-?uFS6j^u69elMypu?t>op*wBx<=Wx8?( ztpe^(fwM6jJX7M-l*k3kEpWOl_Vk3@(_w4oc}4YF4|Rt=2V^XU?#Yz`8(e?aZ@#li0n*=g^qOcVpd-Wbok=@b#Yw zqn8u9a)z>l(1kEaPYZ6hwubN6i<8QHgsu0oE) ziJ(p;Wxm>sf!K+cw>R-(^Y2_bahB+&KI9y^);#0qt}t-$C|Bo71lHi{_+lg#f%RFy z0um=e3$K3i6K{U_4K!EX?F&rExl^W|G8Z8;`5z-k}OGNZ0#WVb$WCpQu-_YsiqKP?BB# vzVHS-CTUF4Ozn5G+mq_~Qqto~ahA+K`|lyv3(-e}00000NkvXXu0mjfd`9t{ literal 0 HcmV?d00001 diff --git a/packages/stream_chat_flutter_core/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/packages/stream_chat_flutter_core/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..d0ef06e7edb86cdfe0d15b4b0d98334a86163658 GIT binary patch literal 1716 zcmds$`#;kQ7{|XelZftyR5~xW7?MLxS4^|Hw3&P7^y)@A9Fj{Xm1~_CIV^XZ%SLBn zA;!r`GqGHg=7>xrB{?psZQs88ZaedDoagm^KF{a*>G|dJWRSe^I$DNW008I^+;Kjt z>9p3GNR^I;v>5_`+91i(*G;u5|L+Bu6M=(afLjtkya#yZ175|z$pU~>2#^Z_pCZ7o z1c6UNcv2B3?; zX%qdxCXQpdKRz=#b*q0P%b&o)5ZrNZt7$fiETSK_VaY=mb4GK`#~0K#~9^ zcY!`#Af+4h?UMR-gMKOmpuYeN5P*RKF!(tb`)oe0j2BH1l?=>y#S5pMqkx6i{*=V9JF%>N8`ewGhRE(|WohnD59R^$_36{4>S zDFlPC5|k?;SPsDo87!B{6*7eqmMdU|QZ84>6)Kd9wNfh90=y=TFQay-0__>=<4pk& zYDjgIhL-jQ9o>z32K)BgAH+HxamL{ZL~ozu)Qqe@a`FpH=oQRA8=L-m-1dam(Ix2V z?du;LdMO+ooBelr^_y4{|44tmgH^2hSzPFd;U^!1p>6d|o)(-01z{i&Kj@)z-yfWQ)V#3Uo!_U}q3u`(fOs`_f^ueFii1xBNUB z6MecwJN$CqV&vhc+)b(p4NzGGEgwWNs z@*lUV6LaduZH)4_g!cE<2G6#+hJrWd5(|p1Z;YJ7ifVHv+n49btR}dq?HHDjl{m$T z!jLZcGkb&XS2OG~u%&R$(X+Z`CWec%QKt>NGYvd5g20)PU(dOn^7%@6kQb}C(%=vr z{?RP(z~C9DPnL{q^@pVw@|Vx~@3v!9dCaBtbh2EdtoNHm4kGxp>i#ct)7p|$QJs+U z-a3qtcPvhihub?wnJqEt>zC@)2suY?%-96cYCm$Q8R%-8$PZYsx3~QOLMDf(piXMm zB=<63yQk1AdOz#-qsEDX>>c)EES%$owHKue;?B3)8aRd}m~_)>SL3h2(9X;|+2#7X z+#2)NpD%qJvCQ0a-uzZLmz*ms+l*N}w)3LRQ*6>|Ub-fyptY(keUxw+)jfwF5K{L9 z|Cl_w=`!l_o><384d&?)$6Nh(GAm=4p_;{qVn#hI8lqewW7~wUlyBM-4Z|)cZr?Rh z=xZ&Ol>4(CU85ea(CZ^aO@2N18K>ftl8>2MqetAR53_JA>Fal`^)1Y--Am~UDa4th zKfCYpcXky$XSFDWBMIl(q=Mxj$iMBX=|j9P)^fDmF(5(5$|?Cx}DKEJa&XZP%OyE`*GvvYQ4PV&!g2|L^Q z?YG}tx;sY@GzMmsY`7r$P+F_YLz)(e}% zyakqFB<6|x9R#TdoP{R$>o7y(-`$$p0NxJ6?2B8tH)4^yF(WhqGZlM3=9Ibs$%U1w zWzcss*_c0=v_+^bfb`kBFsI`d;ElwiU%frgRB%qBjn@!0U2zZehBn|{%uNIKBA7n= zzE`nnwTP85{g;8AkYxA68>#muXa!G>xH22D1I*SiD~7C?7Za+9y7j1SHiuSkKK*^O zsZ==KO(Ua#?YUpXl{ViynyT#Hzk=}5X$e04O@fsMQjb}EMuPWFO0e&8(2N(29$@Vd zn1h8Yd>6z(*p^E{c(L0Lg=wVdupg!z@WG;E0k|4a%s7Up5C0c)55XVK*|x9RQeZ1J@1v9MX;>n34(i>=YE@Iur`0Vah(inE3VUFZNqf~tSz{1fz3Fsn_x4F>o(Yo;kpqvBe-sbwH(*Y zu$JOl0b83zu$JMvy<#oH^Wl>aWL*?aDwnS0iEAwC?DK@aT)GHRLhnz2WCvf3Ba;o=aY7 z2{Asu5MEjGOY4O#Ggz@@J;q*0`kd2n8I3BeNuMmYZf{}pg=jTdTCrIIYuW~luKecn z+E-pHY%ohj@uS0%^ z&(OxwPFPD$+#~`H?fMvi9geVLci(`K?Kj|w{rZ9JgthFHV+=6vMbK~0)Ea<&WY-NC zy-PnZft_k2tfeQ*SuC=nUj4H%SQ&Y$gbH4#2sT0cU0SdFs=*W*4hKGpuR1{)mV;Qf5pw4? zfiQgy0w3fC*w&Bj#{&=7033qFR*<*61B4f9K%CQvxEn&bsWJ{&winp;FP!KBj=(P6 z4Z_n4L7cS;ao2)ax?Tm|I1pH|uLpDSRVghkA_UtFFuZ0b2#>!8;>-_0ELjQSD-DRd z4im;599VHDZYtnWZGAB25W-e(2VrzEh|etsv2YoP#VbIZ{aFkwPrzJ#JvCvA*mXS& z`}Q^v9(W4GiSs}#s7BaN!WA2bniM$0J(#;MR>uIJ^uvgD3GS^%*ikdW6-!VFUU?JV zZc2)4cMsX@j z5HQ^e3BUzOdm}yC-xA%SY``k$rbfk z;CHqifhU*jfGM@DkYCecD9vl*qr58l6x<8URB=&%{!Cu3RO*MrKZ4VO}V6R0a zZw3Eg^0iKWM1dcTYZ0>N899=r6?+adUiBKPciJw}L$=1f4cs^bio&cr9baLF>6#BM z(F}EXe-`F=f_@`A7+Q&|QaZ??Txp_dB#lg!NH=t3$G8&06MFhwR=Iu*Im0s_b2B@| znW>X}sy~m#EW)&6E&!*0%}8UAS)wjt+A(io#wGI@Z2S+Ms1Cxl%YVE800007ip7{`C_J2TxPmfw%h$|%acrYHt)Re^PB%O&&=~a zhS(%I#+V>J-vjIib^<+s%ludY7y^C(P8nmqn9fp!i+?vr`bziDE=bx`%2W#Xyrj|i z!XQ4v1%L`m{7KT7q+LZNB^h8Ha2e=`Wp65^0;J00)_^G=au=8Yo;1b`CV&@#=jIBo zjN^JNVfYSs)+kDdGe7`1&8!?MQYKS?DuHZf3iogk_%#9E|5S zWeHrmAo>P;ejX7mwq#*}W25m^ZI+{(Z8fI?4jM_fffY0nok=+88^|*_DwcW>mR#e+ zX$F_KMdb6sRz!~7KkyN0G(3XQ+;z3X%PZ4gh;n-%62U<*VUKNv(D&Q->Na@Xb&u5Q3`3DGf+a8O5x7c#7+R+EAYl@R5us)CIw z7sT@_y~Ao@uL#&^LIh&QceqiT^+lb0YbFZt_SHOtWA%mgPEKVNvVgCsXy{5+zl*X8 zCJe)Q@y>wH^>l4;h1l^Y*9%-23TSmE>q5nI@?mt%n;Sj4Qq`Z+ib)a*a^cJc%E9^J zB;4s+K@rARbcBLT5P=@r;IVnBMKvT*)ew*R;&8vu%?Z&S>s?8?)3*YawM0P4!q$Kv zMmKh3lgE~&w&v%wVzH3Oe=jeNT=n@Y6J6TdHWTjXfX~-=1A1Bw`EW8rn}MqeI34nh zexFeA?&C3B2(E?0{drE@DA2pu(A#ElY&6el60Rn|Qpn-FkfQ8M93AfWIr)drgDFEU zghdWK)^71EWCP(@(=c4kfH1Y(4iugD4fve6;nSUpLT%!)MUHs1!zJYy4y||C+SwQ! z)KM&$7_tyM`sljP2fz6&Z;jxRn{Wup8IOUx8D4uh&(=O zx-7$a;U><*5L^!%xRlw)vAbh;sdlR||& ze}8_8%)c2Fwy=F&H|LM+p{pZB5DKTx>Y?F1N%BlZkXf!}JeGuMZk~LPi7{cidvUGB zAJ4LVeNV%XO>LTrklB#^-;8nb;}6l;1oW&WS=Mz*Az!4cqqQzbOSFq`$Q%PfD7srM zpKgP-D_0XPTRX*hAqeq0TDkJ;5HB1%$3Np)99#16c{ zJImlNL(npL!W|Gr_kxl1GVmF5&^$^YherS7+~q$p zt}{a=*RiD2Ikv6o=IM1kgc7zqpaZ;OB)P!1zz*i3{U()Dq#jG)egvK}@uFLa`oyWZ zf~=MV)|yJn`M^$N%ul5);JuQvaU1r2wt(}J_Qgyy`qWQI`hEeRX0uC@c1(dQ2}=U$ tNIIaX+dr)NRWXcxoR{>fqI{SF_dm1Ylv~=3YHI)h002ovPDHLkV1g(pWS;;4 literal 0 HcmV?d00001 diff --git a/packages/stream_chat_flutter_core/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/packages/stream_chat_flutter_core/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..c8f9ed8f5cee1c98386d13b17e89f719e83555b2 GIT binary patch literal 1895 zcmV-t2blPYP)FQtfgmafE#=YDCq`qUBt#QpG%*H6QHY765~R=q zZ6iudfM}q!Pz#~9JgOi8QJ|DSu?1-*(kSi1K4#~5?#|rh?sS)(-JQqX*}ciXJ56_H zdw=^s_srbAdqxlvGyrgGet#6T7_|j;95sL%MtM;q86vOxKM$f#puR)Bjv9Zvz9-di zXOTSsZkM83)E9PYBXC<$6(|>lNLVBb&&6y{NByFCp%6+^ALR@NCTse_wqvNmSWI-m z!$%KlHFH2omF!>#%1l3LTZg(s7eof$7*xB)ZQ0h?ejh?Ta9fDv59+u#MokW+1t8Zb zgHv%K(u9G^Lv`lh#f3<6!JVTL3(dCpxHbnbA;kKqQyd1~^Xe0VIaYBSWm6nsr;dFj z4;G-RyL?cYgsN1{L4ZFFNa;8)Rv0fM0C(~Tkit94 zz#~A)59?QjD&pAPSEQ)p8gP|DS{ng)j=2ux)_EzzJ773GmQ_Cic%3JJhC0t2cx>|v zJcVusIB!%F90{+}8hG3QU4KNeKmK%T>mN57NnCZ^56=0?&3@!j>a>B43pi{!u z7JyDj7`6d)qVp^R=%j>UIY6f+3`+qzIc!Y_=+uN^3BYV|o+$vGo-j-Wm<10%A=(Yk^beI{t%ld@yhKjq0iNjqN4XMGgQtbKubPM$JWBz}YA65k%dm*awtC^+f;a-x4+ddbH^7iDWGg&N0n#MW{kA|=8iMUiFYvMoDY@sPC#t$55gn6ykUTPAr`a@!(;np824>2xJthS z*ZdmT`g5-`BuJs`0LVhz+D9NNa3<=6m;cQLaF?tCv8)zcRSh66*Z|vXhG@$I%U~2l z?`Q zykI#*+rQ=z6Jm=Bui-SfpDYLA=|vzGE(dYm=OC8XM&MDo7ux4UF1~0J1+i%aCUpRe zt3L_uNyQ*cE(38Uy03H%I*)*Bh=Lb^Xj3?I^Hnbeq72(EOK^Y93CNp*uAA{5Lc=ky zx=~RKa4{iTm{_>_vSCm?$Ej=i6@=m%@VvAITnigVg{&@!7CDgs908761meDK5azA} z4?=NOH|PdvabgJ&fW2{Mo$Q0CcD8Qc84%{JPYt5EiG{MdLIAeX%T=D7NIP4%Hw}p9 zg)==!2Lbp#j{u_}hMiao9=!VSyx0gHbeCS`;q&vzeq|fs`y&^X-lso(Ls@-706qmA z7u*T5PMo_w3{se1t2`zWeO^hOvTsohG_;>J0wVqVe+n)AbQCx)yh9;w+J6?NF5Lmo zecS@ieAKL8%bVd@+-KT{yI|S}O>pYckUFs;ry9Ow$CD@ztz5K-*D$^{i(_1llhSh^ zEkL$}tsQt5>QA^;QgjgIfBDmcOgi5YDyu?t6vSnbp=1+@6D& z5MJ}B8q;bRlVoxasyhcUF1+)o`&3r0colr}QJ3hcSdLu;9;td>kf@Tcn<@9sIx&=m z;AD;SCh95=&p;$r{Xz3iWCO^MX83AGJ(yH&eTXgv|0=34#-&WAmw{)U7OU9!Wz^!7 zZ%jZFi@JR;>Mhi7S>V7wQ176|FdW2m?&`qa(ScO^CFPR80HucLHOTy%5s*HR0^8)i h0WYBP*#0Ks^FNSabJA*5${_#%002ovPDHLkV1oKhTl@e3 literal 0 HcmV?d00001 diff --git a/packages/stream_chat_flutter_core/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/packages/stream_chat_flutter_core/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..a6d6b8609df07bf62e5100a53a01510388bd2b22 GIT binary patch literal 2665 zcmV-v3YPVWP)oFh3q0MFesq&64WThn3$;G69TfjsAv=f2G9}p zgSx99+!YV6qME!>9MD13x)k(+XE7W?_O4LoLb5ND8 zaV{9+P@>42xDfRiYBMSgD$0!vssptcb;&?u9u(LLBKmkZ>RMD=kvD3h`sk6!QYtBa ztlZI#nu$8lJ^q2Z79UTgZe>BU73(Aospiq+?SdMt8lDZ;*?@tyWVZVS_Q7S&*tJaiRlJ z+aSMOmbg3@h5}v;A*c8SbqM3icg-`Cnwl;7Ts%A1RkNIp+Txl-Ckkvg4oxrqGA5ewEgYqwtECD<_3Egu)xGllKt&J8g&+=ac@Jq4-?w6M3b*>w5 z69N3O%=I^6&UL5gZ!}trC7bUj*12xLdkNs~Bz4QdJJ*UDZox2UGR}SNg@lmOvhCc~ z*f_UeXv(=#I#*7>VZx2ObEN~UoGUTl=-@)E;YtCRZ>SVp$p9yG5hEFZ!`wI!spd)n zSk+vK0Vin7FL{7f&6OB%f;SH22dtbcF<|9fi2Fp%q4kxL!b1#l^)8dUwJ zwEf{(wJj@8iYDVnKB`eSU+;ml-t2`@%_)0jDM`+a46xhDbBj2+&Ih>1A>6aky#(-SYyE{R3f#y57wfLs z6w1p~$bp;6!9DX$M+J~S@D6vJAaElETnsX4h9a5tvPhC3L@qB~bOzkL@^z0k_hS{T4PF*TDrgdXp+dzsE? z>V|VR035Pl9n5&-RePFdS{7KAr2vPOqR9=M$vXA1Yy5>w;EsF`;OK{2pkn-kpp9Pw z)r;5JfJKKaT$4qCb{TaXHjb$QA{y0EYy*+b1XI;6Ah- zw13P)xT`>~eFoJC!>{2XL(a_#upp3gaR1#5+L(Jmzp4TBnx{~WHedpJ1ch8JFk~Sw z>F+gN+i+VD?gMXwcIhn8rz`>e>J^TI3E-MW>f}6R-pL}>WMOa0k#jN+`RyUVUC;#D zg|~oS^$6%wpF{^Qr+}X>0PKcr3Fc&>Z>uv@C);pwDs@2bZWhYP!rvGx?_|q{d`t<*XEb#=aOb=N+L@CVBGqImZf&+a zCQEa3$~@#kC);pasdG=f6tuIi0PO-y&tvX%>Mv=oY3U$nD zJ#gMegnQ46pq+3r=;zmgcG+zRc9D~c>z+jo9&D+`E6$LmyFqlmCYw;-Zooma{sR@~ z)_^|YL1&&@|GXo*pivH7k!msl+$Sew3%XJnxajt0K%3M6Bd&YFNy9}tWG^aovK2eX z1aL1%7;KRDrA@eG-Wr6w+;*H_VD~qLiVI`{_;>o)k`{8xa3EJT1O_>#iy_?va0eR? zDV=N%;Zjb%Z2s$@O>w@iqt!I}tLjGk!=p`D23I}N4Be@$(|iSA zf3Ih7b<{zqpDB4WF_5X1(peKe+rASze%u8eKLn#KKXt;UZ+Adf$_TO+vTqshLLJ5c z52HucO=lrNVae5XWOLm!V@n-ObU11!b+DN<$RuU+YsrBq*lYT;?AwJpmNKniF0Q1< zJCo>Q$=v$@&y=sj6{r!Y&y&`0$-I}S!H_~pI&2H8Z1C|BX4VgZ^-! zje3-;x0PBD!M`v*J_)rL^+$<1VJhH*2Fi~aA7s&@_rUHYJ9zD=M%4AFQ`}k8OC$9s XsPq=LnkwKG00000NkvXXu0mjfhAk5^ literal 0 HcmV?d00001 diff --git a/packages/stream_chat_flutter_core/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/packages/stream_chat_flutter_core/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..a6d6b8609df07bf62e5100a53a01510388bd2b22 GIT binary patch literal 2665 zcmV-v3YPVWP)oFh3q0MFesq&64WThn3$;G69TfjsAv=f2G9}p zgSx99+!YV6qME!>9MD13x)k(+XE7W?_O4LoLb5ND8 zaV{9+P@>42xDfRiYBMSgD$0!vssptcb;&?u9u(LLBKmkZ>RMD=kvD3h`sk6!QYtBa ztlZI#nu$8lJ^q2Z79UTgZe>BU73(Aospiq+?SdMt8lDZ;*?@tyWVZVS_Q7S&*tJaiRlJ z+aSMOmbg3@h5}v;A*c8SbqM3icg-`Cnwl;7Ts%A1RkNIp+Txl-Ckkvg4oxrqGA5ewEgYqwtECD<_3Egu)xGllKt&J8g&+=ac@Jq4-?w6M3b*>w5 z69N3O%=I^6&UL5gZ!}trC7bUj*12xLdkNs~Bz4QdJJ*UDZox2UGR}SNg@lmOvhCc~ z*f_UeXv(=#I#*7>VZx2ObEN~UoGUTl=-@)E;YtCRZ>SVp$p9yG5hEFZ!`wI!spd)n zSk+vK0Vin7FL{7f&6OB%f;SH22dtbcF<|9fi2Fp%q4kxL!b1#l^)8dUwJ zwEf{(wJj@8iYDVnKB`eSU+;ml-t2`@%_)0jDM`+a46xhDbBj2+&Ih>1A>6aky#(-SYyE{R3f#y57wfLs z6w1p~$bp;6!9DX$M+J~S@D6vJAaElETnsX4h9a5tvPhC3L@qB~bOzkL@^z0k_hS{T4PF*TDrgdXp+dzsE? z>V|VR035Pl9n5&-RePFdS{7KAr2vPOqR9=M$vXA1Yy5>w;EsF`;OK{2pkn-kpp9Pw z)r;5JfJKKaT$4qCb{TaXHjb$QA{y0EYy*+b1XI;6Ah- zw13P)xT`>~eFoJC!>{2XL(a_#upp3gaR1#5+L(Jmzp4TBnx{~WHedpJ1ch8JFk~Sw z>F+gN+i+VD?gMXwcIhn8rz`>e>J^TI3E-MW>f}6R-pL}>WMOa0k#jN+`RyUVUC;#D zg|~oS^$6%wpF{^Qr+}X>0PKcr3Fc&>Z>uv@C);pwDs@2bZWhYP!rvGx?_|q{d`t<*XEb#=aOb=N+L@CVBGqImZf&+a zCQEa3$~@#kC);pasdG=f6tuIi0PO-y&tvX%>Mv=oY3U$nD zJ#gMegnQ46pq+3r=;zmgcG+zRc9D~c>z+jo9&D+`E6$LmyFqlmCYw;-Zooma{sR@~ z)_^|YL1&&@|GXo*pivH7k!msl+$Sew3%XJnxajt0K%3M6Bd&YFNy9}tWG^aovK2eX z1aL1%7;KRDrA@eG-Wr6w+;*H_VD~qLiVI`{_;>o)k`{8xa3EJT1O_>#iy_?va0eR? zDV=N%;Zjb%Z2s$@O>w@iqt!I}tLjGk!=p`D23I}N4Be@$(|iSA zf3Ih7b<{zqpDB4WF_5X1(peKe+rASze%u8eKLn#KKXt;UZ+Adf$_TO+vTqshLLJ5c z52HucO=lrNVae5XWOLm!V@n-ObU11!b+DN<$RuU+YsrBq*lYT;?AwJpmNKniF0Q1< zJCo>Q$=v$@&y=sj6{r!Y&y&`0$-I}S!H_~pI&2H8Z1C|BX4VgZ^-! zje3-;x0PBD!M`v*J_)rL^+$<1VJhH*2Fi~aA7s&@_rUHYJ9zD=M%4AFQ`}k8OC$9s XsPq=LnkwKG00000NkvXXu0mjfhAk5^ literal 0 HcmV?d00001 diff --git a/packages/stream_chat_flutter_core/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/packages/stream_chat_flutter_core/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..75b2d164a5a98e212cca15ea7bf2ab5de5108680 GIT binary patch literal 3831 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 literal 0 HcmV?d00001 diff --git a/packages/stream_chat_flutter_core/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/packages/stream_chat_flutter_core/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png new file mode 100644 index 0000000000000000000000000000000000000000..c4df70d39da7941ef3f6dcb7f06a192d8dcb308d GIT binary patch literal 1888 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 iW8Zci7-kcv6Uzs@r-FtIZ-&5|)J Q1PU{Fy85}Sb4q9e0B4a5jsO4v literal 0 HcmV?d00001 diff --git a/packages/stream_chat_flutter_core/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png b/packages/stream_chat_flutter_core/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..9da19eacad3b03bb08bbddbbf4ac48dd78b3d838 GIT binary patch literal 68 zcmeAS@N?(olHy`uVBq!ia0vp^j3CUx0wlM}@Gt=>Zci7-kcv6Uzs@r-FtIZ-&5|)J Q1PU{Fy85}Sb4q9e0B4a5jsO4v literal 0 HcmV?d00001 diff --git a/packages/stream_chat_flutter_core/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png b/packages/stream_chat_flutter_core/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..9da19eacad3b03bb08bbddbbf4ac48dd78b3d838 GIT binary patch literal 68 zcmeAS@N?(olHy`uVBq!ia0vp^j3CUx0wlM}@Gt=>Zci7-kcv6Uzs@r-FtIZ-&5|)J Q1PU{Fy85}Sb4q9e0B4a5jsO4v literal 0 HcmV?d00001 diff --git a/packages/stream_chat_flutter_core/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md b/packages/stream_chat_flutter_core/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md new file mode 100644 index 00000000..89c2725b --- /dev/null +++ b/packages/stream_chat_flutter_core/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md @@ -0,0 +1,5 @@ +# Launch Screen Assets + +You can customize the launch screen with your own desired assets by replacing the image files in this directory. + +You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images. \ No newline at end of file diff --git a/packages/stream_chat_flutter_core/example/ios/Runner/Base.lproj/LaunchScreen.storyboard b/packages/stream_chat_flutter_core/example/ios/Runner/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 00000000..f2e259c7 --- /dev/null +++ b/packages/stream_chat_flutter_core/example/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/stream_chat_flutter_core/example/ios/Runner/Base.lproj/Main.storyboard b/packages/stream_chat_flutter_core/example/ios/Runner/Base.lproj/Main.storyboard new file mode 100644 index 00000000..f3c28516 --- /dev/null +++ b/packages/stream_chat_flutter_core/example/ios/Runner/Base.lproj/Main.storyboard @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/stream_chat_flutter_core/example/ios/Runner/Info.plist b/packages/stream_chat_flutter_core/example/ios/Runner/Info.plist new file mode 100644 index 00000000..a060db61 --- /dev/null +++ b/packages/stream_chat_flutter_core/example/ios/Runner/Info.plist @@ -0,0 +1,45 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + example + CFBundlePackageType + APPL + CFBundleShortVersionString + $(FLUTTER_BUILD_NAME) + CFBundleSignature + ???? + CFBundleVersion + $(FLUTTER_BUILD_NUMBER) + LSRequiresIPhoneOS + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UIViewControllerBasedStatusBarAppearance + + + diff --git a/packages/stream_chat_flutter_core/example/ios/Runner/Runner-Bridging-Header.h b/packages/stream_chat_flutter_core/example/ios/Runner/Runner-Bridging-Header.h new file mode 100644 index 00000000..308a2a56 --- /dev/null +++ b/packages/stream_chat_flutter_core/example/ios/Runner/Runner-Bridging-Header.h @@ -0,0 +1 @@ +#import "GeneratedPluginRegistrant.h" diff --git a/packages/stream_chat_flutter_core/example/lib/main.dart b/packages/stream_chat_flutter_core/example/lib/main.dart new file mode 100644 index 00000000..11655b66 --- /dev/null +++ b/packages/stream_chat_flutter_core/example/lib/main.dart @@ -0,0 +1,117 @@ +import 'package:flutter/material.dart'; + +void main() { + runApp(MyApp()); +} + +class MyApp extends StatelessWidget { + // This widget is the root of your application. + @override + Widget build(BuildContext context) { + return MaterialApp( + title: 'Flutter Demo', + theme: ThemeData( + // This is the theme of your application. + // + // Try running your application with "flutter run". You'll see the + // application has a blue toolbar. Then, without quitting the app, try + // changing the primarySwatch below to Colors.green and then invoke + // "hot reload" (press "r" in the console where you ran "flutter run", + // or simply save your changes to "hot reload" in a Flutter IDE). + // Notice that the counter didn't reset back to zero; the application + // is not restarted. + primarySwatch: Colors.blue, + // This makes the visual density adapt to the platform that you run + // the app on. For desktop platforms, the controls will be smaller and + // closer together (more dense) than on mobile platforms. + visualDensity: VisualDensity.adaptivePlatformDensity, + ), + home: MyHomePage(title: 'Flutter Demo Home Page'), + ); + } +} + +class MyHomePage extends StatefulWidget { + MyHomePage({Key key, this.title}) : super(key: key); + + // This widget is the home page of your application. It is stateful, meaning + // that it has a State object (defined below) that contains fields that affect + // how it looks. + + // This class is the configuration for the state. It holds the values (in this + // case the title) provided by the parent (in this case the App widget) and + // used by the build method of the State. Fields in a Widget subclass are + // always marked "final". + + final String title; + + @override + _MyHomePageState createState() => _MyHomePageState(); +} + +class _MyHomePageState extends State { + int _counter = 0; + + void _incrementCounter() { + setState(() { + // This call to setState tells the Flutter framework that something has + // changed in this State, which causes it to rerun the build method below + // so that the display can reflect the updated values. If we changed + // _counter without calling setState(), then the build method would not be + // called again, and so nothing would appear to happen. + _counter++; + }); + } + + @override + Widget build(BuildContext context) { + // This method is rerun every time setState is called, for instance as done + // by the _incrementCounter method above. + // + // The Flutter framework has been optimized to make rerunning build methods + // fast, so that you can just rebuild anything that needs updating rather + // than having to individually change instances of widgets. + return Scaffold( + appBar: AppBar( + // Here we take the value from the MyHomePage object that was created by + // the App.build method, and use it to set our appbar title. + title: Text(widget.title), + ), + body: Center( + // Center is a layout widget. It takes a single child and positions it + // in the middle of the parent. + child: Column( + // Column is also a layout widget. It takes a list of children and + // arranges them vertically. By default, it sizes itself to fit its + // children horizontally, and tries to be as tall as its parent. + // + // Invoke "debug painting" (press "p" in the console, choose the + // "Toggle Debug Paint" action from the Flutter Inspector in Android + // Studio, or the "Toggle Debug Paint" command in Visual Studio Code) + // to see the wireframe for each widget. + // + // Column has various properties to control how it sizes itself and + // how it positions its children. Here we use mainAxisAlignment to + // center the children vertically; the main axis here is the vertical + // axis because Columns are vertical (the cross axis would be + // horizontal). + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + 'You have pushed the button this many times:', + ), + Text( + '$_counter', + style: Theme.of(context).textTheme.headline4, + ), + ], + ), + ), + floatingActionButton: FloatingActionButton( + onPressed: _incrementCounter, + tooltip: 'Increment', + child: Icon(Icons.add), + ), // This trailing comma makes auto-formatting nicer for build methods. + ); + } +} diff --git a/packages/stream_chat_flutter_core/example/pubspec.yaml b/packages/stream_chat_flutter_core/example/pubspec.yaml new file mode 100644 index 00000000..b0071176 --- /dev/null +++ b/packages/stream_chat_flutter_core/example/pubspec.yaml @@ -0,0 +1,77 @@ +name: example +description: Example app for testing stream_chat_flutter_core + +# The following line prevents the package from being accidentally published to +# pub.dev using `pub publish`. This is preferred for private packages. +publish_to: 'none' # Remove this line if you wish to publish to pub.dev + +# The following defines the version and build number for your application. +# A version number is three numbers separated by dots, like 1.2.43 +# followed by an optional build number separated by a +. +# Both the version and the builder number may be overridden in flutter +# build by specifying --build-name and --build-number, respectively. +# In Android, build-name is used as versionName while build-number used as versionCode. +# Read more about Android versioning at https://developer.android.com/studio/publish/versioning +# In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. +# Read more about iOS versioning at +# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html +version: 1.0.0+1 + +environment: + sdk: ">=2.7.0 <3.0.0" + +dependencies: + flutter: + sdk: flutter + stream_chat_flutter_core: + path: ../ + + # The following adds the Cupertino Icons font to your application. + # Use with the CupertinoIcons class for iOS style icons. + cupertino_icons: ^1.0.0 + +dev_dependencies: + flutter_test: + sdk: flutter + +# For information on the generic Dart part of this file, see the +# following page: https://dart.dev/tools/pub/pubspec + +# The following section is specific to Flutter. +flutter: + + # The following line ensures that the Material Icons font is + # included with your application, so that you can use the icons in + # the material Icons class. + uses-material-design: true + + # To add assets to your application, add an assets section, like this: + # assets: + # - images/a_dot_burr.jpeg + # - images/a_dot_ham.jpeg + + # An image asset can refer to one or more resolution-specific "variants", see + # https://flutter.dev/assets-and-images/#resolution-aware. + + # For details regarding adding assets from package dependencies, see + # https://flutter.dev/assets-and-images/#from-packages + + # To add custom fonts to your application, add a fonts section here, + # in this "flutter" section. Each entry in this list should have a + # "family" key with the font family name, and a "fonts" key with a + # list giving the asset and other descriptors for the font. For + # example: + # fonts: + # - family: Schyler + # fonts: + # - asset: fonts/Schyler-Regular.ttf + # - asset: fonts/Schyler-Italic.ttf + # style: italic + # - family: Trajan Pro + # fonts: + # - asset: fonts/TrajanPro.ttf + # - asset: fonts/TrajanPro_Bold.ttf + # weight: 700 + # + # For details regarding fonts from package dependencies, + # see https://flutter.dev/custom-fonts/#from-packages diff --git a/packages/stream_chat_flutter_core/example/test/widget_test.dart b/packages/stream_chat_flutter_core/example/test/widget_test.dart new file mode 100644 index 00000000..747db1da --- /dev/null +++ b/packages/stream_chat_flutter_core/example/test/widget_test.dart @@ -0,0 +1,30 @@ +// This is a basic Flutter widget test. +// +// To perform an interaction with a widget in your test, use the WidgetTester +// utility that Flutter provides. For example, you can send tap and scroll +// gestures. You can also use WidgetTester to find child widgets in the widget +// tree, read text, and verify that the values of widget properties are correct. + +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; + +import 'package:example/main.dart'; + +void main() { + testWidgets('Counter increments smoke test', (WidgetTester tester) async { + // Build our app and trigger a frame. + await tester.pumpWidget(MyApp()); + + // Verify that our counter starts at 0. + expect(find.text('0'), findsOneWidget); + expect(find.text('1'), findsNothing); + + // Tap the '+' icon and trigger a frame. + await tester.tap(find.byIcon(Icons.add)); + await tester.pump(); + + // Verify that our counter has incremented. + expect(find.text('0'), findsNothing); + expect(find.text('1'), findsOneWidget); + }); +} From 677866a275dc71fdd864d8aa230c32cc63d4a5ab Mon Sep 17 00:00:00 2001 From: Neevash Ramdial Date: Fri, 22 Jan 2021 09:49:42 -0400 Subject: [PATCH 1008/1140] update push provider in client test --- packages/dart_client/test/src/client_test.dart | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/packages/dart_client/test/src/client_test.dart b/packages/dart_client/test/src/client_test.dart index caca1a34..8f4dc41e 100644 --- a/packages/dart_client/test/src/client_test.dart +++ b/packages/dart_client/test/src/client_test.dart @@ -266,13 +266,17 @@ void main() { when(mockDio.post('/devices', data: { 'id': 'test-id', - 'push_provider': 'test', + 'push_provider': 'firebase', })).thenAnswer((_) async => Response(data: '{}', statusCode: 200)); await client.addDevice('test-id', PushProvider.firebase); - verify(mockDio.post('/devices', - data: {'id': 'test-id', 'push_provider': 'test'})).called(1); + verify( + mockDio.post( + '/devices', + data: {'id': 'test-id', 'push_provider': 'firebase'}, + ), + ).called(1); }); test('getDevices', () async { From 6817ec51b2a78c6a9a2b171d8200088afed124dc Mon Sep 17 00:00:00 2001 From: Neevash Ramdial Date: Fri, 22 Jan 2021 09:49:42 -0400 Subject: [PATCH 1009/1140] update push provider in client test --- packages/dart_client/test/src/client_test.dart | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/packages/dart_client/test/src/client_test.dart b/packages/dart_client/test/src/client_test.dart index caca1a34..8f4dc41e 100644 --- a/packages/dart_client/test/src/client_test.dart +++ b/packages/dart_client/test/src/client_test.dart @@ -266,13 +266,17 @@ void main() { when(mockDio.post('/devices', data: { 'id': 'test-id', - 'push_provider': 'test', + 'push_provider': 'firebase', })).thenAnswer((_) async => Response(data: '{}', statusCode: 200)); await client.addDevice('test-id', PushProvider.firebase); - verify(mockDio.post('/devices', - data: {'id': 'test-id', 'push_provider': 'test'})).called(1); + verify( + mockDio.post( + '/devices', + data: {'id': 'test-id', 'push_provider': 'firebase'}, + ), + ).called(1); }); test('getDevices', () async { From 6035f177f9ef3714472d80b0fdd5ecadca9d0fe2 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Fri, 22 Jan 2021 15:24:19 +0100 Subject: [PATCH 1010/1140] fix tutorial examples --- .../example/lib/custom_theme.dart | 5 +- .../lib/customize_channel_preview.dart | 11 ++ .../example/lib/customize_message_widget.dart | 7 +- .../lib/src/channel_list_view.dart | 186 ++++++++---------- .../lib/src/file_attachment.dart | 6 +- .../lib/src/message_widget.dart | 31 +-- .../lib/src/reaction_bubble.dart | 2 +- .../lib/src/stream_chat_theme.dart | 59 +++--- 8 files changed, 147 insertions(+), 160 deletions(-) diff --git a/packages/flutter_widgets/example/lib/custom_theme.dart b/packages/flutter_widgets/example/lib/custom_theme.dart index d8abcb90..817d2e67 100644 --- a/packages/flutter_widgets/example/lib/custom_theme.dart +++ b/packages/flutter_widgets/example/lib/custom_theme.dart @@ -41,11 +41,12 @@ class MyApp extends StatelessWidget { Widget build(BuildContext context) { final themeData = ThemeData(primarySwatch: Colors.green); final defaultTheme = StreamChatThemeData.fromTheme(themeData); + final colorTheme = defaultTheme.colorTheme; final customTheme = defaultTheme.merge(StreamChatThemeData( ownMessageTheme: MessageTheme( - messageBackgroundColor: StreamChatTheme.of(context).colorTheme.black, + messageBackgroundColor: colorTheme.black, messageText: TextStyle( - color: StreamChatTheme.of(context).colorTheme.white, + color: colorTheme.white, ), avatarTheme: AvatarTheme( borderRadius: BorderRadius.circular(8), diff --git a/packages/flutter_widgets/example/lib/customize_channel_preview.dart b/packages/flutter_widgets/example/lib/customize_channel_preview.dart index 29d22a82..9b7deb64 100644 --- a/packages/flutter_widgets/example/lib/customize_channel_preview.dart +++ b/packages/flutter_widgets/example/lib/customize_channel_preview.dart @@ -80,6 +80,17 @@ class ChannelListPage extends StatelessWidget { final opacity = channel.state.unreadCount > .0 ? 1.0 : 0.5; return ListTile( + onTap: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (_) => StreamChannel( + child: ChannelPage(), + channel: channel, + ), + ), + ); + }, leading: ChannelImage( channel: channel, ), diff --git a/packages/flutter_widgets/example/lib/customize_message_widget.dart b/packages/flutter_widgets/example/lib/customize_message_widget.dart index 84e65eab..14233dd7 100644 --- a/packages/flutter_widgets/example/lib/customize_message_widget.dart +++ b/packages/flutter_widgets/example/lib/customize_message_widget.dart @@ -97,7 +97,7 @@ class ChannelPage extends StatelessWidget { List messages, ) { final message = details.message; - final color = details.isMyMessage ? Colors.blueGrey : Colors.blue; + final color = details.isMyMessage ? Colors.red : Colors.blue; if (message.isSystem) { return SizedBox(); } @@ -110,7 +110,10 @@ class ChannelPage extends StatelessWidget { color: color, width: 2, ), - padding: const EdgeInsets.all(2), + padding: const EdgeInsets.symmetric( + vertical: 2, + horizontal: 4, + ), attachmentBorderSide: BorderSide( color: color, width: 2, diff --git a/packages/flutter_widgets/lib/src/channel_list_view.dart b/packages/flutter_widgets/lib/src/channel_list_view.dart index 61a0aabb..0cc7634b 100644 --- a/packages/flutter_widgets/lib/src/channel_list_view.dart +++ b/packages/flutter_widgets/lib/src/channel_list_view.dart @@ -529,123 +529,97 @@ class _ChannelListViewState extends State }; } + final backgroundColor = StreamChatTheme.of(context).colorTheme.whiteSmoke; return StreamChannel( key: ValueKey('CHANNEL-${channel.id}'), channel: channel, child: Builder( builder: (context) { - Widget child; - if (widget.channelPreviewBuilder != null) { - child = Stack( - children: [ - widget.channelPreviewBuilder( - context, - channel, - ), - Positioned.fill( - child: Material( - color: Colors.transparent, - child: InkWell( - onTap: () { - onTap(channel, widget.channelWidget); - }, - onLongPress: widget.onChannelLongPress != null - ? () { - widget.onChannelLongPress(channel); - } - : null, + return Slidable( + controller: _slideController, + enabled: widget.swipeToAction, + actionPane: SlidableBehindActionPane(), + actionExtentRatio: 0.12, + closeOnScroll: true, + secondaryActions: [ + IconSlideAction( + color: backgroundColor, + icon: Icons.more_horiz, + onTap: () { + showModalBottomSheet( + clipBehavior: Clip.hardEdge, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.only( + topLeft: Radius.circular(32), + topRight: Radius.circular(32), + ), ), - ), - ), - ], - ); - } else { - final backgroundColor = - StreamChatTheme.of(context).colorTheme.whiteSmoke; - child = Slidable( - controller: _slideController, - enabled: widget.swipeToAction, - actionPane: SlidableBehindActionPane(), - actionExtentRatio: 0.12, - closeOnScroll: true, - secondaryActions: [ + context: context, + builder: (context) { + return StreamChannel( + child: ChannelBottomSheet( + onViewInfoTap: () { + widget.onViewInfoTap(channel); + }, + ), + channel: channel, + ); + }, + ); + }, + ), + if ([ + 'admin', + 'owner', + ].contains(channel.state.members + .firstWhere((m) => m.userId == channel.client.state.user.id, + orElse: () => null) + ?.role)) IconSlideAction( color: backgroundColor, - icon: Icons.more_horiz, - onTap: () { - showModalBottomSheet( - clipBehavior: Clip.hardEdge, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.only( - topLeft: Radius.circular(32), - topRight: Radius.circular(32), - ), - ), - context: context, - builder: (context) { - return StreamChannel( - child: ChannelBottomSheet( - onViewInfoTap: () { - widget.onViewInfoTap(channel); - }, - ), - channel: channel, - ); - }, - ); - }, - ), - if ([ - 'admin', - 'owner', - ].contains(channel.state.members - .firstWhere( - (m) => m.userId == channel.client.state.user.id, - orElse: () => null) - ?.role)) - IconSlideAction( - color: backgroundColor, - iconWidget: StreamSvgIcon.delete( - color: StreamChatTheme.of(context).colorTheme.accentRed, - ), - onTap: () async { - final res = await showConfirmationDialog( - context, - title: 'Delete Conversation', - okText: 'DELETE', - question: - 'Are you sure you want to delete this conversation?', - cancelText: 'CANCEL', - icon: StreamSvgIcon.delete( - color: StreamChatTheme.of(context) - .colorTheme - .accentRed, - ), - ); - if (res == true) { - await channel.delete(); - } - }, + iconWidget: StreamSvgIcon.delete( + color: StreamChatTheme.of(context).colorTheme.accentRed, ), - ], - child: Container( - color: StreamChatTheme.of(context).colorTheme.whiteSnow, - child: ChannelPreview( - onLongPress: widget.onChannelLongPress, - channel: channel, - onImageTap: widget.onImageTap != null - ? () { - widget.onImageTap(channel); - } - : null, - onTap: (channel) { - onTap(channel, widget.channelWidget); + onTap: () async { + final res = await showConfirmationDialog( + context, + title: 'Delete Conversation', + okText: 'DELETE', + question: + 'Are you sure you want to delete this conversation?', + cancelText: 'CANCEL', + icon: StreamSvgIcon.delete( + color: + StreamChatTheme.of(context).colorTheme.accentRed, + ), + ); + if (res == true) { + await channel.delete(); + } }, ), - ), - ); - } - return child; + ], + child: Container( + color: StreamChatTheme.of(context).colorTheme.whiteSnow, + child: widget.channelPreviewBuilder != null + ? widget.channelPreviewBuilder( + context, + channel, + ) + : ChannelPreview( + onLongPress: widget.onChannelLongPress, + channel: channel, + onImageTap: widget.onImageTap != null + ? () { + widget.onImageTap(channel); + } + : null, + onTap: (channel) { + onTap(channel, widget.channelWidget); + }, + ), + ), + ); }, ), ); diff --git a/packages/flutter_widgets/lib/src/file_attachment.dart b/packages/flutter_widgets/lib/src/file_attachment.dart index 8e3ef4d6..dc7fae4b 100644 --- a/packages/flutter_widgets/lib/src/file_attachment.dart +++ b/packages/flutter_widgets/lib/src/file_attachment.dart @@ -41,7 +41,7 @@ class _FileAttachmentState extends State { @override void initState() { super.initState(); - if (MediaUtils.getMimeType(widget.attachment.title).type == 'video') { + if (MediaUtils.getMimeType(widget.attachment.title)?.type == 'video') { if (widget.attachmentType == FileAttachmentType.online) { _controller = VideoPlayerController.network( widget.attachment.assetUrl, @@ -128,7 +128,7 @@ class _FileAttachmentState extends State { } Widget _getFileTypeImage() { - if ((MediaUtils.getMimeType(widget.attachment.title).type == 'image')) { + if ((MediaUtils.getMimeType(widget.attachment.title)?.type == 'image')) { switch (widget.attachmentType) { case FileAttachmentType.local: return Image.memory( @@ -165,7 +165,7 @@ class _FileAttachmentState extends State { } } - if ((MediaUtils.getMimeType(widget.attachment.title).type == 'video')) { + if ((MediaUtils.getMimeType(widget.attachment.title)?.type == 'video')) { switch (widget.attachmentType) { case FileAttachmentType.local: return FutureBuilder( diff --git a/packages/flutter_widgets/lib/src/message_widget.dart b/packages/flutter_widgets/lib/src/message_widget.dart index eeabaa13..2a15f898 100644 --- a/packages/flutter_widgets/lib/src/message_widget.dart +++ b/packages/flutter_widgets/lib/src/message_widget.dart @@ -159,8 +159,8 @@ class MessageWidget extends StatefulWidget { this.showReactionPickerIndicator = false, this.showUserAvatar = DisplayWidget.show, this.showSendingIndicator = true, - this.showThreadReplyIndicator = true, - this.showInChannelIndicator = true, + this.showThreadReplyIndicator = false, + this.showInChannelIndicator = false, this.onReplyTap, this.onThreadTap, this.showUsername = true, @@ -371,15 +371,24 @@ class _MessageWidgetState extends State { alignment: Alignment.center, transform: Matrix4.rotationY( widget.reverse ? pi : 0), - child: DeletedMessage( - reverse: widget.reverse, - borderRadiusGeometry: widget - .borderRadiusGeometry, - borderSide: - widget.borderSide, - shape: widget.shape, - messageTheme: - widget.messageTheme, + child: Container( + margin: EdgeInsets.symmetric( + horizontal: + widget.showUserAvatar == + DisplayWidget + .gone + ? 0 + : 4.0), + child: DeletedMessage( + reverse: widget.reverse, + borderRadiusGeometry: widget + .borderRadiusGeometry, + borderSide: + widget.borderSide, + shape: widget.shape, + messageTheme: + widget.messageTheme, + ), ), ) : Card( diff --git a/packages/flutter_widgets/lib/src/reaction_bubble.dart b/packages/flutter_widgets/lib/src/reaction_bubble.dart index 74a2ae99..4ddcca93 100644 --- a/packages/flutter_widgets/lib/src/reaction_bubble.dart +++ b/packages/flutter_widgets/lib/src/reaction_bubble.dart @@ -67,7 +67,7 @@ class ReactionBubble extends StatelessWidget { children: [ if (constraints.maxWidth < double.infinity) ...reactions - .take((constraints.maxWidth) ~/ 22) + .take((constraints.maxWidth) ~/ 24) .map((reaction) { return _buildReaction( reactionIcons, diff --git a/packages/flutter_widgets/lib/src/stream_chat_theme.dart b/packages/flutter_widgets/lib/src/stream_chat_theme.dart index 5b5927c8..3945a033 100644 --- a/packages/flutter_widgets/lib/src/stream_chat_theme.dart +++ b/packages/flutter_widgets/lib/src/stream_chat_theme.dart @@ -45,9 +45,6 @@ class StreamChatThemeData { /// The text themes used in the widgets final TextTheme textTheme; - /// The button themes used in the widgets - final ButtonThemeData buttonTheme; - /// The text themes used in the widgets final ColorTheme colorTheme; @@ -78,7 +75,6 @@ class StreamChatThemeData { /// Create a theme from scratch const StreamChatThemeData({ this.textTheme, - this.buttonTheme, this.colorTheme, this.channelPreviewTheme, this.channelTheme, @@ -93,24 +89,20 @@ class StreamChatThemeData { /// Create a theme from a Material [Theme] factory StreamChatThemeData.fromTheme(ThemeData theme) { final defaultTheme = getDefaultTheme(theme); - final customizedTheme = StreamChatThemeData( - primaryIconTheme: theme.primaryIconTheme, - ownMessageTheme: MessageTheme( - replies: TextStyle(color: theme.accentColor), - messageLinks: TextStyle(color: theme.accentColor), + final customizedTheme = StreamChatThemeData.fromColorAndTextTheme( + defaultTheme.colorTheme.copyWith( + accentBlue: theme.accentColor, ), - otherMessageTheme: MessageTheme( - replies: TextStyle(color: theme.accentColor), - messageLinks: TextStyle(color: theme.accentColor), - ), - ); + defaultTheme.textTheme, + ).copyWith( + // primaryIconTheme: theme.primaryIconTheme, + ); return defaultTheme.merge(customizedTheme) ?? customizedTheme; } /// Creates a copy of [StreamChatThemeData] with specified attributes overridden. StreamChatThemeData copyWith({ TextTheme textTheme, - ButtonThemeData buttonTheme, ColorTheme colorTheme, ChannelPreviewTheme channelPreviewTheme, ChannelTheme channelTheme, @@ -123,7 +115,6 @@ class StreamChatThemeData { }) => StreamChatThemeData( textTheme: textTheme ?? this.textTheme, - buttonTheme: buttonTheme ?? this.buttonTheme, colorTheme: colorTheme ?? this.colorTheme, primaryIconTheme: primaryIconTheme ?? this.primaryIconTheme, defaultChannelImage: defaultChannelImage ?? this.defaultChannelImage, @@ -139,7 +130,6 @@ class StreamChatThemeData { if (other == null) return this; return copyWith( textTheme: textTheme?.merge(other.textTheme) ?? other.textTheme, - buttonTheme: other.buttonTheme, colorTheme: colorTheme?.merge(other.colorTheme) ?? other.colorTheme, primaryIconTheme: other.primaryIconTheme, defaultChannelImage: other.defaultChannelImage, @@ -157,26 +147,14 @@ class StreamChatThemeData { ); } - /// Get the default Stream Chat theme - static StreamChatThemeData getDefaultTheme(ThemeData theme) { - final accentColor = Color(0xff006cff); - final isDark = theme.brightness == Brightness.dark; - final textTheme = isDark ? TextTheme.dark() : TextTheme.light(); - final colorTheme = isDark ? ColorTheme.dark() : ColorTheme.light(); + static StreamChatThemeData fromColorAndTextTheme( + ColorTheme colorTheme, + TextTheme textTheme, + ) { + final accentColor = colorTheme.accentBlue; return StreamChatThemeData( textTheme: textTheme, colorTheme: colorTheme, - buttonTheme: ButtonThemeData( - height: 48.0, - buttonColor: isDark ? Color(0xffffffff) : Color(0xff006aff), - textTheme: ButtonTextTheme.accent, - colorScheme: theme.colorScheme.copyWith( - secondary: isDark ? Color(0xff005eff) : Color(0xffffffff), - ), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(26), - ), - ), primaryIconTheme: IconThemeData(color: colorTheme.black.withOpacity(.5)), defaultChannelImage: (context, channel) => SizedBox(), defaultUserImage: (context, user) => Center( @@ -204,7 +182,7 @@ class StreamChatThemeData { ), indicatorIconSize: 16.0), channelTheme: ChannelTheme( - messageInputButtonIconTheme: theme.iconTheme.copyWith( + messageInputButtonIconTheme: IconThemeData( color: accentColor, ), channelHeaderTheme: ChannelHeaderTheme( @@ -291,6 +269,17 @@ class StreamChatThemeData { ], ); } + + /// Get the default Stream Chat theme + static StreamChatThemeData getDefaultTheme(ThemeData theme) { + final isDark = theme.brightness == Brightness.dark; + final textTheme = isDark ? TextTheme.dark() : TextTheme.light(); + final colorTheme = isDark ? ColorTheme.dark() : ColorTheme.light(); + return fromColorAndTextTheme( + colorTheme, + textTheme, + ); + } } enum TextThemeType { From ad112d33900df63143cdc7c9851a19c4211ca489 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Fri, 22 Jan 2021 15:26:48 +0100 Subject: [PATCH 1011/1140] bump version --- packages/dart_client/CHANGELOG.md | 5 +++++ packages/dart_client/example/ios/Flutter/Debug.xcconfig | 1 + packages/dart_client/example/ios/Flutter/Release.xcconfig | 1 + packages/dart_client/lib/version.dart | 2 +- packages/dart_client/pubspec.yaml | 2 +- 5 files changed, 9 insertions(+), 2 deletions(-) diff --git a/packages/dart_client/CHANGELOG.md b/packages/dart_client/CHANGELOG.md index dbab1dcb..5c799a17 100644 --- a/packages/dart_client/CHANGELOG.md +++ b/packages/dart_client/CHANGELOG.md @@ -1,3 +1,8 @@ +## 0.2.24 + +- Create enum for push providers +- Add merge helper functions in `Message` and `ChannelModel` for easier data manipulation + ## 0.2.23+3 - Remove + notation from userAgent diff --git a/packages/dart_client/example/ios/Flutter/Debug.xcconfig b/packages/dart_client/example/ios/Flutter/Debug.xcconfig index 592ceee8..e8efba11 100644 --- a/packages/dart_client/example/ios/Flutter/Debug.xcconfig +++ b/packages/dart_client/example/ios/Flutter/Debug.xcconfig @@ -1 +1,2 @@ +#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" #include "Generated.xcconfig" diff --git a/packages/dart_client/example/ios/Flutter/Release.xcconfig b/packages/dart_client/example/ios/Flutter/Release.xcconfig index 592ceee8..399e9340 100644 --- a/packages/dart_client/example/ios/Flutter/Release.xcconfig +++ b/packages/dart_client/example/ios/Flutter/Release.xcconfig @@ -1 +1,2 @@ +#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" #include "Generated.xcconfig" diff --git a/packages/dart_client/lib/version.dart b/packages/dart_client/lib/version.dart index 4650f5b2..bc746ab0 100644 --- a/packages/dart_client/lib/version.dart +++ b/packages/dart_client/lib/version.dart @@ -2,4 +2,4 @@ import 'package:stream_chat/src/client.dart'; /// Current package version /// Used in [Client] to build the `x-stream-client` header -const PACKAGE_VERSION = '0.2.23+3'; +const PACKAGE_VERSION = '0.2.24'; diff --git a/packages/dart_client/pubspec.yaml b/packages/dart_client/pubspec.yaml index 71ce5a22..9fd0d9e0 100644 --- a/packages/dart_client/pubspec.yaml +++ b/packages/dart_client/pubspec.yaml @@ -1,7 +1,7 @@ name: stream_chat homepage: https://getstream.io/ description: The official Dart client for Stream Chat, a service for building chat applications. -version: 0.2.23+3 +version: 0.2.24 repository: https://github.com/GetStream/stream-chat-dart issue_tracker: https://github.com/GetStream/stream-chat-dart/issues From 9d48d10666ff38b8c42c27a58f8e9cf3800e19ab Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Fri, 22 Jan 2021 15:32:51 +0100 Subject: [PATCH 1012/1140] upgrade llc --- packages/flutter_widgets/pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/flutter_widgets/pubspec.yaml b/packages/flutter_widgets/pubspec.yaml index 277618a6..2b82aca2 100644 --- a/packages/flutter_widgets/pubspec.yaml +++ b/packages/flutter_widgets/pubspec.yaml @@ -29,7 +29,7 @@ dependencies: image_picker: ^0.6.7+17 flutter_keyboard_visibility: ^4.0.2 mime: ^0.9.7 - stream_chat: ^0.2.23+3 + stream_chat: ^0.2.24 video_compress: ^2.1.1 visibility_detector: ^0.1.5 http_parser: ^3.1.4 From 82acc9767586392a20a95e4f1f6960b82f7d41c2 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Fri, 22 Jan 2021 17:22:18 +0100 Subject: [PATCH 1013/1140] fix formatting --- .../app/src/main/java/example/example/MainActivity.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/stream_chat_flutter_core/example/android/app/src/main/java/example/example/MainActivity.java b/packages/stream_chat_flutter_core/example/android/app/src/main/java/example/example/MainActivity.java index e30c2bec..334c0856 100644 --- a/packages/stream_chat_flutter_core/example/android/app/src/main/java/example/example/MainActivity.java +++ b/packages/stream_chat_flutter_core/example/android/app/src/main/java/example/example/MainActivity.java @@ -2,5 +2,4 @@ package example.example; import io.flutter.embedding.android.FlutterActivity; -public class MainActivity extends FlutterActivity { -} +public class MainActivity extends FlutterActivity {} From 88777da2a7d59a08aead82c7a5f56a096edfd9a1 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Fri, 22 Jan 2021 17:23:50 +0100 Subject: [PATCH 1014/1140] fix formatting --- .../test/stream_chat_flutter_core_test.dart | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/stream_chat_flutter_core/test/stream_chat_flutter_core_test.dart b/packages/stream_chat_flutter_core/test/stream_chat_flutter_core_test.dart index 3e26a916..ee9468ab 100644 --- a/packages/stream_chat_flutter_core/test/stream_chat_flutter_core_test.dart +++ b/packages/stream_chat_flutter_core/test/stream_chat_flutter_core_test.dart @@ -1,5 +1,3 @@ import 'package:flutter_test/flutter_test.dart'; -import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; - void main() {} From 1bb6b0438142baf6084bed6121881454f6865190 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Fri, 22 Jan 2021 17:35:30 +0100 Subject: [PATCH 1015/1140] fix analyze --- .../stream_chat_flutter_core/lib/src/message_list_view.dart | 2 +- .../lib/src/message_search_list_view.dart | 1 - packages/stream_chat_flutter_core/lib/src/user_list_view.dart | 4 ++-- .../test/stream_chat_flutter_core_test.dart | 2 -- 4 files changed, 3 insertions(+), 6 deletions(-) diff --git a/packages/stream_chat_flutter_core/lib/src/message_list_view.dart b/packages/stream_chat_flutter_core/lib/src/message_list_view.dart index d0a59266..6e0c1b2b 100644 --- a/packages/stream_chat_flutter_core/lib/src/message_list_view.dart +++ b/packages/stream_chat_flutter_core/lib/src/message_list_view.dart @@ -58,7 +58,7 @@ class MessageListView extends StatefulWidget { this.messageListController, }) : super(key: key); - MessageListController messageListController; + final MessageListController messageListController; final Widget Function(BuildContext, List) messageListBuilder; diff --git a/packages/stream_chat_flutter_core/lib/src/message_search_list_view.dart b/packages/stream_chat_flutter_core/lib/src/message_search_list_view.dart index f27f7c8e..94aedeba 100644 --- a/packages/stream_chat_flutter_core/lib/src/message_search_list_view.dart +++ b/packages/stream_chat_flutter_core/lib/src/message_search_list_view.dart @@ -2,7 +2,6 @@ import 'dart:convert'; import 'package:flutter/material.dart'; import 'package:stream_chat/stream_chat.dart'; -import 'lazy_load_scroll_view.dart'; import 'message_search_bloc.dart'; /// Callback called when tapping on a user diff --git a/packages/stream_chat_flutter_core/lib/src/user_list_view.dart b/packages/stream_chat_flutter_core/lib/src/user_list_view.dart index 1b841333..6fe03577 100644 --- a/packages/stream_chat_flutter_core/lib/src/user_list_view.dart +++ b/packages/stream_chat_flutter_core/lib/src/user_list_view.dart @@ -154,12 +154,12 @@ class _UserListViewState extends State temp = users..sort((curr, next) => curr.name.compareTo(next.name)); } final groupedUsers = >{}; - for (var e in temp) { + for (final e in temp) { final alphabet = e.name[0]?.toUpperCase(); groupedUsers[alphabet] = [...groupedUsers[alphabet] ?? [], e]; } final items = []; - for (var key in groupedUsers.keys) { + for (final key in groupedUsers.keys) { items.add(ListHeaderItem(key)); items.addAll(groupedUsers[key].map((e) => ListUserItem(e))); } diff --git a/packages/stream_chat_flutter_core/test/stream_chat_flutter_core_test.dart b/packages/stream_chat_flutter_core/test/stream_chat_flutter_core_test.dart index ee9468ab..ab73b3a2 100644 --- a/packages/stream_chat_flutter_core/test/stream_chat_flutter_core_test.dart +++ b/packages/stream_chat_flutter_core/test/stream_chat_flutter_core_test.dart @@ -1,3 +1 @@ -import 'package:flutter_test/flutter_test.dart'; - void main() {} From 7935eb1ac5d8b8fab4381049e8b3a9688789a219 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Fri, 22 Jan 2021 22:49:59 +0100 Subject: [PATCH 1016/1140] enable persistence in sample app --- packages/flutter_widgets/example/lib/main.dart | 2 +- packages/flutter_widgets/example/pubspec.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/flutter_widgets/example/lib/main.dart b/packages/flutter_widgets/example/lib/main.dart index 86cfa52d..10d73997 100644 --- a/packages/flutter_widgets/example/lib/main.dart +++ b/packages/flutter_widgets/example/lib/main.dart @@ -29,7 +29,7 @@ void main() async { logLevel: Level.INFO, showLocalNotification: (!kIsWeb && Platform.isAndroid) ? showLocalNotification : null, - persistenceEnabled: false, + persistenceEnabled: true, ); if (userId != null) { diff --git a/packages/flutter_widgets/example/pubspec.yaml b/packages/flutter_widgets/example/pubspec.yaml index 8c11c0ee..9d6e79a3 100644 --- a/packages/flutter_widgets/example/pubspec.yaml +++ b/packages/flutter_widgets/example/pubspec.yaml @@ -1,7 +1,7 @@ name: example description: A new Flutter project. publish_to: 'none' -version: 1.1.3+3 +version: 1.1.3+4 environment: sdk: ">=2.2.2 <3.0.0" From 463dc96a2670e7f348b16dd469aeb6d8994b8672 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Sat, 23 Jan 2021 11:47:29 +0100 Subject: [PATCH 1017/1140] add nash iphone to certificates --- .../flutter_widgets/example/ios/fastlane/report.xml | 10 +++++----- packages/flutter_widgets/example/pubspec.yaml | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/flutter_widgets/example/ios/fastlane/report.xml b/packages/flutter_widgets/example/ios/fastlane/report.xml index 0010f637..69eca3e6 100644 --- a/packages/flutter_widgets/example/ios/fastlane/report.xml +++ b/packages/flutter_widgets/example/ios/fastlane/report.xml @@ -5,27 +5,27 @@ - + - + - + - + - + diff --git a/packages/flutter_widgets/example/pubspec.yaml b/packages/flutter_widgets/example/pubspec.yaml index 9d6e79a3..5344b852 100644 --- a/packages/flutter_widgets/example/pubspec.yaml +++ b/packages/flutter_widgets/example/pubspec.yaml @@ -1,7 +1,7 @@ name: example description: A new Flutter project. publish_to: 'none' -version: 1.1.3+4 +version: 1.1.3+5 environment: sdk: ">=2.2.2 <3.0.0" From c5caf5bfc36e7049cadb0a7955cbd344ff48370c Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Mon, 25 Jan 2021 12:54:55 +0530 Subject: [PATCH 1018/1140] rfac: Added core prefixes --- ..._view.dart => channel_list_view_core.dart} | 18 +++++++++--------- .../lib/src/channels_bloc.dart | 6 +++--- ..._view.dart => message_list_view_core.dart} | 10 +++++----- .../lib/src/message_search_bloc.dart | 4 ++-- ...art => message_search_list_view_core.dart} | 14 +++++++------- ...stream_chat.dart => stream_chat_core.dart} | 19 ++++++++++--------- ...ist_view.dart => user_list_view_core.dart} | 10 +++++----- .../lib/src/users_bloc.dart | 4 ++-- .../lib/stream_chat_flutter_core.dart | 10 +++++----- 9 files changed, 48 insertions(+), 47 deletions(-) rename packages/stream_chat_flutter_core/lib/src/{channel_list_view.dart => channel_list_view_core.dart} (92%) rename packages/stream_chat_flutter_core/lib/src/{message_list_view.dart => message_list_view_core.dart} (94%) rename packages/stream_chat_flutter_core/lib/src/{message_search_list_view.dart => message_search_list_view_core.dart} (93%) rename packages/stream_chat_flutter_core/lib/src/{stream_chat.dart => stream_chat_core.dart} (88%) rename packages/stream_chat_flutter_core/lib/src/{user_list_view.dart => user_list_view_core.dart} (96%) diff --git a/packages/stream_chat_flutter_core/lib/src/channel_list_view.dart b/packages/stream_chat_flutter_core/lib/src/channel_list_view_core.dart similarity index 92% rename from packages/stream_chat_flutter_core/lib/src/channel_list_view.dart rename to packages/stream_chat_flutter_core/lib/src/channel_list_view_core.dart index 38417190..f1b7d258 100644 --- a/packages/stream_chat_flutter_core/lib/src/channel_list_view.dart +++ b/packages/stream_chat_flutter_core/lib/src/channel_list_view_core.dart @@ -6,7 +6,7 @@ import 'package:flutter/material.dart'; import 'package:stream_chat/stream_chat.dart'; import 'package:stream_chat_flutter_core/src/channels_bloc.dart'; -import 'stream_chat.dart'; +import 'stream_chat_core.dart'; /// ![screenshot](https://raw.githubusercontent.com/GetStream/stream-chat-flutter/master/screenshots/channel_list_view.png) /// ![screenshot](https://raw.githubusercontent.com/GetStream/stream-chat-flutter/master/screenshots/channel_list_view_paint.png) @@ -36,14 +36,14 @@ import 'stream_chat.dart'; /// ``` /// /// -/// Make sure to have a [StreamChat] ancestor in order to provide the information about the channels. +/// Make sure to have a [StreamChatCore] ancestor in order to provide the information about the channels. /// The widget uses a [ListView.custom] to render the list of channels. /// /// The widget components render the ui based on the first ancestor of type [StreamChatTheme]. /// Modify it to change the widget appearance. -class ChannelListView extends StatefulWidget { +class ChannelListViewCore extends StatefulWidget { /// Instantiate a new ChannelListView - ChannelListView({ + ChannelListViewCore({ Key key, this.filter, this.options, @@ -96,10 +96,10 @@ class ChannelListView extends StatefulWidget { final bool pullToRefresh; @override - _ChannelListViewState createState() => _ChannelListViewState(); + _ChannelListViewCoreState createState() => _ChannelListViewCoreState(); } -class _ChannelListViewState extends State +class _ChannelListViewCoreState extends State with WidgetsBindingObserver { @override Widget build(BuildContext context) { @@ -197,7 +197,7 @@ class _ChannelListViewState extends State options: widget.options, ); - final client = StreamChat.of(context).client; + final client = StreamChatCore.of(context).client; _subscription = client .on( @@ -221,7 +221,7 @@ class _ChannelListViewState extends State } @override - void didUpdateWidget(ChannelListView oldWidget) { + void didUpdateWidget(ChannelListViewCore oldWidget) { super.didUpdateWidget(oldWidget); if (widget.filter?.toString() != oldWidget.filter?.toString() || @@ -247,7 +247,7 @@ class _ChannelListViewState extends State } } -/// Controller used for paginating data in [ChannelListView] +/// Controller used for paginating data in [ChannelListViewCore] class ChannelListController { VoidCallback paginateData; } diff --git a/packages/stream_chat_flutter_core/lib/src/channels_bloc.dart b/packages/stream_chat_flutter_core/lib/src/channels_bloc.dart index a9ab1682..2eef0f8a 100644 --- a/packages/stream_chat_flutter_core/lib/src/channels_bloc.dart +++ b/packages/stream_chat_flutter_core/lib/src/channels_bloc.dart @@ -3,7 +3,7 @@ import 'dart:async'; import 'package:flutter/material.dart'; import 'package:rxdart/rxdart.dart'; import 'package:stream_chat/stream_chat.dart'; -import 'package:stream_chat_flutter_core/src/stream_chat.dart'; +import 'package:stream_chat_flutter_core/src/stream_chat_core.dart'; /// Widget dedicated to the management of a channel list with pagination class ChannelsBloc extends StatefulWidget { @@ -79,7 +79,7 @@ class ChannelsBlocState extends State Map options, bool onlyOffline = false, }) async { - final client = StreamChat.of(context).client; + final client = StreamChatCore.of(context).client; if (client.state?.user == null || _queryChannelsLoadingController.value == true) { @@ -120,7 +120,7 @@ class ChannelsBlocState extends State void initState() { super.initState(); - final client = StreamChat.of(context).client; + final client = StreamChatCore.of(context).client; if (!widget.lockChannelsOrder) { _subscriptions.add(client.on(EventType.messageNew).listen((e) { diff --git a/packages/stream_chat_flutter_core/lib/src/message_list_view.dart b/packages/stream_chat_flutter_core/lib/src/message_list_view_core.dart similarity index 94% rename from packages/stream_chat_flutter_core/lib/src/message_list_view.dart rename to packages/stream_chat_flutter_core/lib/src/message_list_view_core.dart index d0a59266..859b3513 100644 --- a/packages/stream_chat_flutter_core/lib/src/message_list_view.dart +++ b/packages/stream_chat_flutter_core/lib/src/message_list_view_core.dart @@ -45,9 +45,9 @@ import 'stream_channel.dart'; /// /// The widget components render the ui based on the first ancestor of type [StreamChatTheme]. /// Modify it to change the widget appearance. -class MessageListView extends StatefulWidget { +class MessageListViewCore extends StatefulWidget { /// Instantiate a new MessageListView - MessageListView({ + MessageListViewCore({ Key key, this.showScrollToBottom = true, this.parentMessage, @@ -58,7 +58,7 @@ class MessageListView extends StatefulWidget { this.messageListController, }) : super(key: key); - MessageListController messageListController; + final MessageListController messageListController; final Widget Function(BuildContext, List) messageListBuilder; @@ -78,10 +78,10 @@ class MessageListView extends StatefulWidget { final Widget Function(DateTime) dateDividerBuilder; @override - _MessageListViewState createState() => _MessageListViewState(); + _MessageListViewCoreState createState() => _MessageListViewCoreState(); } -class _MessageListViewState extends State { +class _MessageListViewCoreState extends State { StreamChannelState streamChannel; bool get _upToDate => streamChannel.channel.state.isUpToDate; diff --git a/packages/stream_chat_flutter_core/lib/src/message_search_bloc.dart b/packages/stream_chat_flutter_core/lib/src/message_search_bloc.dart index 67b6455d..ca6a983d 100644 --- a/packages/stream_chat_flutter_core/lib/src/message_search_bloc.dart +++ b/packages/stream_chat_flutter_core/lib/src/message_search_bloc.dart @@ -2,7 +2,7 @@ import 'package:flutter/material.dart'; import 'package:rxdart/rxdart.dart'; import 'package:stream_chat/stream_chat.dart'; -import 'stream_chat.dart'; +import 'stream_chat_core.dart'; /// Widget dedicated to the management of a message list with pagination class MessageSearchBloc extends StatefulWidget { @@ -122,7 +122,7 @@ class MessageSearchBlocState extends State String query, PaginationParams pagination, }) { - final client = StreamChat.of(context).client; + final client = StreamChatCore.of(context).client; return client.search( filter, sort, diff --git a/packages/stream_chat_flutter_core/lib/src/message_search_list_view.dart b/packages/stream_chat_flutter_core/lib/src/message_search_list_view_core.dart similarity index 93% rename from packages/stream_chat_flutter_core/lib/src/message_search_list_view.dart rename to packages/stream_chat_flutter_core/lib/src/message_search_list_view_core.dart index f27f7c8e..4486c1f5 100644 --- a/packages/stream_chat_flutter_core/lib/src/message_search_list_view.dart +++ b/packages/stream_chat_flutter_core/lib/src/message_search_list_view_core.dart @@ -2,7 +2,6 @@ import 'dart:convert'; import 'package:flutter/material.dart'; import 'package:stream_chat/stream_chat.dart'; -import 'lazy_load_scroll_view.dart'; import 'message_search_bloc.dart'; /// Callback called when tapping on a user @@ -12,7 +11,7 @@ typedef MessageSearchItemTapCallback = void Function(GetMessageResponse); typedef MessageSearchItemBuilder = Widget Function( BuildContext, GetMessageResponse); -/// Builder used when [MessageSearchListView] is empty +/// Builder used when [MessageSearchListViewCore] is empty typedef EmptyMessageSearchBuilder = Widget Function( BuildContext context, String searchQuery); @@ -44,9 +43,9 @@ typedef EmptyMessageSearchBuilder = Widget Function( /// /// The widget components render the ui based on the first ancestor of type [StreamChatTheme]. /// Modify it to change the widget appearance. -class MessageSearchListView extends StatefulWidget { +class MessageSearchListViewCore extends StatefulWidget { /// Instantiate a new MessageSearchListView - const MessageSearchListView({ + const MessageSearchListViewCore({ Key key, this.messageQuery, this.filters, @@ -98,10 +97,11 @@ class MessageSearchListView extends StatefulWidget { final WidgetBuilder loadingBuilder; @override - _MessageSearchListViewState createState() => _MessageSearchListViewState(); + _MessageSearchListViewCoreState createState() => + _MessageSearchListViewCoreState(); } -class _MessageSearchListViewState extends State { +class _MessageSearchListViewCoreState extends State { @override void initState() { super.initState(); @@ -167,7 +167,7 @@ class _MessageSearchListViewState extends State { } @override - void didUpdateWidget(MessageSearchListView oldWidget) { + void didUpdateWidget(MessageSearchListViewCore oldWidget) { super.didUpdateWidget(oldWidget); if (widget.filters?.toString() != oldWidget.filters?.toString() || jsonEncode(widget.sortOptions) != jsonEncode(oldWidget.sortOptions) || diff --git a/packages/stream_chat_flutter_core/lib/src/stream_chat.dart b/packages/stream_chat_flutter_core/lib/src/stream_chat_core.dart similarity index 88% rename from packages/stream_chat_flutter_core/lib/src/stream_chat.dart rename to packages/stream_chat_flutter_core/lib/src/stream_chat_core.dart index 17ec62b6..e8312638 100644 --- a/packages/stream_chat_flutter_core/lib/src/stream_chat.dart +++ b/packages/stream_chat_flutter_core/lib/src/stream_chat_core.dart @@ -24,12 +24,12 @@ import 'package:stream_chat/stream_chat.dart'; /// } /// } /// -/// Use [StreamChat.of] to get the current [StreamChatState] instance. -class StreamChat extends StatefulWidget { +/// Use [StreamChatCore.of] to get the current [StreamChatCoreState] instance. +class StreamChatCore extends StatefulWidget { final Client client; final Widget child; - StreamChat({ + StreamChatCore({ Key key, @required this.client, @required this.child, @@ -38,13 +38,13 @@ class StreamChat extends StatefulWidget { ); @override - StreamChatState createState() => StreamChatState(); + StreamChatCoreState createState() => StreamChatCoreState(); - /// Use this method to get the current [StreamChatState] instance - static StreamChatState of(BuildContext context) { - StreamChatState streamChatState; + /// Use this method to get the current [StreamChatCoreState] instance + static StreamChatCoreState of(BuildContext context) { + StreamChatCoreState streamChatState; - streamChatState = context.findAncestorStateOfType(); + streamChatState = context.findAncestorStateOfType(); if (streamChatState == null) { throw Exception( @@ -56,7 +56,8 @@ class StreamChat extends StatefulWidget { } /// The current state of the StreamChat widget -class StreamChatState extends State with WidgetsBindingObserver { +class StreamChatCoreState extends State + with WidgetsBindingObserver { Client get client => widget.client; Timer _disconnectTimer; diff --git a/packages/stream_chat_flutter_core/lib/src/user_list_view.dart b/packages/stream_chat_flutter_core/lib/src/user_list_view_core.dart similarity index 96% rename from packages/stream_chat_flutter_core/lib/src/user_list_view.dart rename to packages/stream_chat_flutter_core/lib/src/user_list_view_core.dart index 1b841333..ae1cefdc 100644 --- a/packages/stream_chat_flutter_core/lib/src/user_list_view.dart +++ b/packages/stream_chat_flutter_core/lib/src/user_list_view_core.dart @@ -35,9 +35,9 @@ import 'package:stream_chat_flutter_core/src/users_bloc.dart'; /// /// The widget components render the ui based on the first ancestor of type [StreamChatTheme]. /// Modify it to change the widget appearance. -class UserListView extends StatefulWidget { +class UserListViewCore extends StatefulWidget { /// Instantiate a new UserListView - const UserListView({ + const UserListViewCore({ Key key, this.filter, this.options, @@ -98,10 +98,10 @@ class UserListView extends StatefulWidget { final bool groupAlphabetically; @override - _UserListViewState createState() => _UserListViewState(); + _UserListViewCoreState createState() => _UserListViewCoreState(); } -class _UserListViewState extends State +class _UserListViewCoreState extends State with WidgetsBindingObserver { @override void initState() { @@ -217,7 +217,7 @@ class _UserListViewState extends State } @override - void didUpdateWidget(UserListView oldWidget) { + void didUpdateWidget(UserListViewCore oldWidget) { super.didUpdateWidget(oldWidget); if (widget.filter?.toString() != oldWidget.filter?.toString() || jsonEncode(widget.sort) != jsonEncode(oldWidget.sort) || diff --git a/packages/stream_chat_flutter_core/lib/src/users_bloc.dart b/packages/stream_chat_flutter_core/lib/src/users_bloc.dart index 91cbaf80..489461ef 100644 --- a/packages/stream_chat_flutter_core/lib/src/users_bloc.dart +++ b/packages/stream_chat_flutter_core/lib/src/users_bloc.dart @@ -2,7 +2,7 @@ import 'package:flutter/material.dart'; import 'package:rxdart/rxdart.dart'; import 'package:stream_chat/stream_chat.dart'; -import 'stream_chat.dart'; +import 'stream_chat_core.dart'; /// Widget dedicated to the management of a users list with pagination class UsersBloc extends StatefulWidget { @@ -56,7 +56,7 @@ class UsersBlocState extends State Map options, PaginationParams pagination, }) async { - final client = StreamChat.of(context).client; + final client = StreamChatCore.of(context).client; if (client.state?.user == null || _queryUsersLoadingController.value == true) { diff --git a/packages/stream_chat_flutter_core/lib/stream_chat_flutter_core.dart b/packages/stream_chat_flutter_core/lib/stream_chat_flutter_core.dart index 638f71be..75424b4f 100644 --- a/packages/stream_chat_flutter_core/lib/stream_chat_flutter_core.dart +++ b/packages/stream_chat_flutter_core/lib/stream_chat_flutter_core.dart @@ -1,12 +1,12 @@ library stream_chat_flutter_core; -export 'src/channel_list_view.dart'; +export 'src/channel_list_view_core.dart'; export 'src/channels_bloc.dart'; export 'src/lazy_load_scroll_view.dart'; -export 'src/message_list_view.dart'; +export 'src/message_list_view_core.dart'; export 'src/message_search_bloc.dart'; -export 'src/message_search_list_view.dart'; +export 'src/message_search_list_view_core.dart'; export 'src/stream_channel.dart'; -export 'src/stream_chat.dart'; -export 'src/user_list_view.dart'; +export 'src/stream_chat_core.dart'; +export 'src/user_list_view_core.dart'; export 'src/users_bloc.dart'; From e9fd5c96f5a3f381666c8a80aa156e66f29559fc Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Mon, 25 Jan 2021 17:29:25 +0530 Subject: [PATCH 1019/1140] feat: Added load data to controllers --- .../lib/src/channel_list_view_core.dart | 13 +++++++++++++ .../lib/src/message_search_list_view_core.dart | 14 ++++++++++++++ .../lib/src/user_list_view_core.dart | 13 +++++++++++++ 3 files changed, 40 insertions(+) diff --git a/packages/stream_chat_flutter_core/lib/src/channel_list_view_core.dart b/packages/stream_chat_flutter_core/lib/src/channel_list_view_core.dart index f1b7d258..b03b523e 100644 --- a/packages/stream_chat_flutter_core/lib/src/channel_list_view_core.dart +++ b/packages/stream_chat_flutter_core/lib/src/channel_list_view_core.dart @@ -168,6 +168,17 @@ class _ChannelListViewCoreState extends State return widget.errorBuilder(snapshot.error); } + void loadData() { + final channelsBloc = ChannelsBloc.of(context); + + channelsBloc.queryChannels( + filter: widget.filter, + sortOptions: widget.sort, + paginationParams: widget.pagination, + options: widget.options, + ); + } + void paginateData() { final channelsBloc = ChannelsBloc.of(context); @@ -216,6 +227,7 @@ class _ChannelListViewCoreState extends State }); if (widget.channelListController != null) { + widget.channelListController.loadData = loadData; widget.channelListController.paginateData = paginateData; } } @@ -249,5 +261,6 @@ class _ChannelListViewCoreState extends State /// Controller used for paginating data in [ChannelListViewCore] class ChannelListController { + VoidCallback loadData; VoidCallback paginateData; } diff --git a/packages/stream_chat_flutter_core/lib/src/message_search_list_view_core.dart b/packages/stream_chat_flutter_core/lib/src/message_search_list_view_core.dart index 4486c1f5..99245d37 100644 --- a/packages/stream_chat_flutter_core/lib/src/message_search_list_view_core.dart +++ b/packages/stream_chat_flutter_core/lib/src/message_search_list_view_core.dart @@ -115,6 +115,7 @@ class _MessageSearchListViewCoreState extends State { ); if (widget.messageSearchListController != null) { + widget.messageSearchListController.loadData = loadData; widget.messageSearchListController.paginateData = paginateData; } } @@ -152,6 +153,18 @@ class _MessageSearchListViewCoreState extends State { ); } + void loadData() { + final messageSearchBloc = MessageSearchBloc.of(context); + + messageSearchBloc.search( + filter: widget.filters, + sort: widget.sortOptions, + query: widget.messageQuery, + pagination: widget.paginationParams, + messageFilter: widget.messageFilters, + ); + } + void paginateData() { final messageSearchBloc = MessageSearchBloc.of(context); @@ -190,5 +203,6 @@ class _MessageSearchListViewCoreState extends State { /// Controller used for paginating data in [ChannelListView] class MessageSearchListController { + VoidCallback loadData; VoidCallback paginateData; } diff --git a/packages/stream_chat_flutter_core/lib/src/user_list_view_core.dart b/packages/stream_chat_flutter_core/lib/src/user_list_view_core.dart index 41d5d668..b4e0b6c4 100644 --- a/packages/stream_chat_flutter_core/lib/src/user_list_view_core.dart +++ b/packages/stream_chat_flutter_core/lib/src/user_list_view_core.dart @@ -115,6 +115,7 @@ class _UserListViewCoreState extends State ); if (widget.userListController != null) { + widget.userListController.loadData = loadData; widget.userListController.paginateData = paginateData; } } @@ -203,6 +204,17 @@ class _UserListViewCoreState extends State ); } + void loadData() { + final usersBloc = UsersBloc.of(context); + + usersBloc.queryUsers( + filter: widget.filter, + sort: widget.sort, + pagination: widget.pagination, + options: widget.options, + ); + } + void paginateData() { final usersBloc = UsersBloc.of(context); @@ -276,5 +288,6 @@ class ListUserItem extends ListItem { /// Controller used for paginating data in [ChannelListView] class UserListController { + VoidCallback loadData; VoidCallback paginateData; } From 1cbdbf5d6fbbfd0bbd9c7bef32798737d07bcb8a Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Mon, 25 Jan 2021 18:39:06 +0530 Subject: [PATCH 1020/1140] rfac: Changed names according to convention --- ..._view_core.dart => channel_list_core.dart} | 12 ++++----- ..._view_core.dart => message_list_core.dart} | 8 +++--- ...ore.dart => message_search_list_core.dart} | 26 +++++-------------- ...ist_view_core.dart => user_list_core.dart} | 10 +++---- .../lib/stream_chat_flutter_core.dart | 8 +++--- 5 files changed, 26 insertions(+), 38 deletions(-) rename packages/stream_chat_flutter_core/lib/src/{channel_list_view_core.dart => channel_list_core.dart} (95%) rename packages/stream_chat_flutter_core/lib/src/{message_list_view_core.dart => message_list_core.dart} (95%) rename packages/stream_chat_flutter_core/lib/src/{message_search_list_view_core.dart => message_search_list_core.dart} (86%) rename packages/stream_chat_flutter_core/lib/src/{user_list_view_core.dart => user_list_core.dart} (96%) diff --git a/packages/stream_chat_flutter_core/lib/src/channel_list_view_core.dart b/packages/stream_chat_flutter_core/lib/src/channel_list_core.dart similarity index 95% rename from packages/stream_chat_flutter_core/lib/src/channel_list_view_core.dart rename to packages/stream_chat_flutter_core/lib/src/channel_list_core.dart index b03b523e..627c5131 100644 --- a/packages/stream_chat_flutter_core/lib/src/channel_list_view_core.dart +++ b/packages/stream_chat_flutter_core/lib/src/channel_list_core.dart @@ -41,9 +41,9 @@ import 'stream_chat_core.dart'; /// /// The widget components render the ui based on the first ancestor of type [StreamChatTheme]. /// Modify it to change the widget appearance. -class ChannelListViewCore extends StatefulWidget { +class ChannelListCore extends StatefulWidget { /// Instantiate a new ChannelListView - ChannelListViewCore({ + ChannelListCore({ Key key, this.filter, this.options, @@ -96,10 +96,10 @@ class ChannelListViewCore extends StatefulWidget { final bool pullToRefresh; @override - _ChannelListViewCoreState createState() => _ChannelListViewCoreState(); + _ChannelListCoreState createState() => _ChannelListCoreState(); } -class _ChannelListViewCoreState extends State +class _ChannelListCoreState extends State with WidgetsBindingObserver { @override Widget build(BuildContext context) { @@ -233,7 +233,7 @@ class _ChannelListViewCoreState extends State } @override - void didUpdateWidget(ChannelListViewCore oldWidget) { + void didUpdateWidget(ChannelListCore oldWidget) { super.didUpdateWidget(oldWidget); if (widget.filter?.toString() != oldWidget.filter?.toString() || @@ -259,7 +259,7 @@ class _ChannelListViewCoreState extends State } } -/// Controller used for paginating data in [ChannelListViewCore] +/// Controller used for paginating data in [ChannelListCore] class ChannelListController { VoidCallback loadData; VoidCallback paginateData; diff --git a/packages/stream_chat_flutter_core/lib/src/message_list_view_core.dart b/packages/stream_chat_flutter_core/lib/src/message_list_core.dart similarity index 95% rename from packages/stream_chat_flutter_core/lib/src/message_list_view_core.dart rename to packages/stream_chat_flutter_core/lib/src/message_list_core.dart index 859b3513..e04e1ea8 100644 --- a/packages/stream_chat_flutter_core/lib/src/message_list_view_core.dart +++ b/packages/stream_chat_flutter_core/lib/src/message_list_core.dart @@ -45,9 +45,9 @@ import 'stream_channel.dart'; /// /// The widget components render the ui based on the first ancestor of type [StreamChatTheme]. /// Modify it to change the widget appearance. -class MessageListViewCore extends StatefulWidget { +class MessageListCore extends StatefulWidget { /// Instantiate a new MessageListView - MessageListViewCore({ + MessageListCore({ Key key, this.showScrollToBottom = true, this.parentMessage, @@ -78,10 +78,10 @@ class MessageListViewCore extends StatefulWidget { final Widget Function(DateTime) dateDividerBuilder; @override - _MessageListViewCoreState createState() => _MessageListViewCoreState(); + _MessageListCoreState createState() => _MessageListCoreState(); } -class _MessageListViewCoreState extends State { +class _MessageListCoreState extends State { StreamChannelState streamChannel; bool get _upToDate => streamChannel.channel.state.isUpToDate; diff --git a/packages/stream_chat_flutter_core/lib/src/message_search_list_view_core.dart b/packages/stream_chat_flutter_core/lib/src/message_search_list_core.dart similarity index 86% rename from packages/stream_chat_flutter_core/lib/src/message_search_list_view_core.dart rename to packages/stream_chat_flutter_core/lib/src/message_search_list_core.dart index 99245d37..f011ee53 100644 --- a/packages/stream_chat_flutter_core/lib/src/message_search_list_view_core.dart +++ b/packages/stream_chat_flutter_core/lib/src/message_search_list_core.dart @@ -4,17 +4,6 @@ import 'package:flutter/material.dart'; import 'package:stream_chat/stream_chat.dart'; import 'message_search_bloc.dart'; -/// Callback called when tapping on a user -typedef MessageSearchItemTapCallback = void Function(GetMessageResponse); - -/// Builder used to create a custom [ListUserItem] from a [User] -typedef MessageSearchItemBuilder = Widget Function( - BuildContext, GetMessageResponse); - -/// Builder used when [MessageSearchListViewCore] is empty -typedef EmptyMessageSearchBuilder = Widget Function( - BuildContext context, String searchQuery); - /// /// It shows the list of searched messages. /// @@ -43,9 +32,9 @@ typedef EmptyMessageSearchBuilder = Widget Function( /// /// The widget components render the ui based on the first ancestor of type [StreamChatTheme]. /// Modify it to change the widget appearance. -class MessageSearchListViewCore extends StatefulWidget { +class MessageSearchListCore extends StatefulWidget { /// Instantiate a new MessageSearchListView - const MessageSearchListViewCore({ + const MessageSearchListCore({ Key key, this.messageQuery, this.filters, @@ -89,7 +78,7 @@ class MessageSearchListViewCore extends StatefulWidget { final Widget Function(List) childBuilder; /// The builder used when the channel list is empty. - final EmptyMessageSearchBuilder emptyBuilder; + final WidgetBuilder emptyBuilder; /// The builder that will be used in case of error final Widget Function(Error error) errorBuilder; @@ -97,11 +86,10 @@ class MessageSearchListViewCore extends StatefulWidget { final WidgetBuilder loadingBuilder; @override - _MessageSearchListViewCoreState createState() => - _MessageSearchListViewCoreState(); + _MessageSearchListCoreState createState() => _MessageSearchListCoreState(); } -class _MessageSearchListViewCoreState extends State { +class _MessageSearchListCoreState extends State { @override void initState() { super.initState(); @@ -145,7 +133,7 @@ class _MessageSearchListViewCoreState extends State { final items = snapshot.data; if (items.isEmpty) { - return widget.emptyBuilder(context, widget.messageQuery); + return widget.emptyBuilder(context); } return widget.childBuilder(snapshot.data); @@ -180,7 +168,7 @@ class _MessageSearchListViewCoreState extends State { } @override - void didUpdateWidget(MessageSearchListViewCore oldWidget) { + void didUpdateWidget(MessageSearchListCore oldWidget) { super.didUpdateWidget(oldWidget); if (widget.filters?.toString() != oldWidget.filters?.toString() || jsonEncode(widget.sortOptions) != jsonEncode(oldWidget.sortOptions) || diff --git a/packages/stream_chat_flutter_core/lib/src/user_list_view_core.dart b/packages/stream_chat_flutter_core/lib/src/user_list_core.dart similarity index 96% rename from packages/stream_chat_flutter_core/lib/src/user_list_view_core.dart rename to packages/stream_chat_flutter_core/lib/src/user_list_core.dart index b4e0b6c4..8edf8752 100644 --- a/packages/stream_chat_flutter_core/lib/src/user_list_view_core.dart +++ b/packages/stream_chat_flutter_core/lib/src/user_list_core.dart @@ -35,9 +35,9 @@ import 'package:stream_chat_flutter_core/src/users_bloc.dart'; /// /// The widget components render the ui based on the first ancestor of type [StreamChatTheme]. /// Modify it to change the widget appearance. -class UserListViewCore extends StatefulWidget { +class UserListCore extends StatefulWidget { /// Instantiate a new UserListView - const UserListViewCore({ + const UserListCore({ Key key, this.filter, this.options, @@ -98,10 +98,10 @@ class UserListViewCore extends StatefulWidget { final bool groupAlphabetically; @override - _UserListViewCoreState createState() => _UserListViewCoreState(); + _UserListCoreState createState() => _UserListCoreState(); } -class _UserListViewCoreState extends State +class _UserListCoreState extends State with WidgetsBindingObserver { @override void initState() { @@ -229,7 +229,7 @@ class _UserListViewCoreState extends State } @override - void didUpdateWidget(UserListViewCore oldWidget) { + void didUpdateWidget(UserListCore oldWidget) { super.didUpdateWidget(oldWidget); if (widget.filter?.toString() != oldWidget.filter?.toString() || jsonEncode(widget.sort) != jsonEncode(oldWidget.sort) || diff --git a/packages/stream_chat_flutter_core/lib/stream_chat_flutter_core.dart b/packages/stream_chat_flutter_core/lib/stream_chat_flutter_core.dart index 75424b4f..d82b57fd 100644 --- a/packages/stream_chat_flutter_core/lib/stream_chat_flutter_core.dart +++ b/packages/stream_chat_flutter_core/lib/stream_chat_flutter_core.dart @@ -1,12 +1,12 @@ library stream_chat_flutter_core; -export 'src/channel_list_view_core.dart'; +export 'src/channel_list_core.dart'; export 'src/channels_bloc.dart'; export 'src/lazy_load_scroll_view.dart'; -export 'src/message_list_view_core.dart'; +export 'src/message_list_core.dart'; export 'src/message_search_bloc.dart'; -export 'src/message_search_list_view_core.dart'; +export 'src/message_search_list_core.dart'; export 'src/stream_channel.dart'; export 'src/stream_chat_core.dart'; -export 'src/user_list_view_core.dart'; +export 'src/user_list_core.dart'; export 'src/users_bloc.dart'; From 1021814a75173d1efae47bc2f71ac5cabdc559c5 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Fri, 22 Jan 2021 17:37:57 +0530 Subject: [PATCH 1021/1140] [MessageSendingStatus] lowercase enum values --- packages/dart_client/lib/src/api/channel.dart | 4 +- .../dart_client/lib/src/api/retry_queue.dart | 42 +++++++++---------- packages/dart_client/lib/src/client.dart | 10 ++--- .../dart_client/lib/src/db/models.part.dart | 28 ++++++------- .../dart_client/lib/src/models/message.dart | 16 +++---- .../lib/src/message_actions_modal.dart | 12 +++--- .../lib/src/message_input.dart | 2 +- .../lib/src/message_reactions_modal.dart | 4 +- .../lib/src/message_widget.dart | 14 +++---- .../lib/src/sending_indicator.dart | 6 +-- 10 files changed, 69 insertions(+), 69 deletions(-) diff --git a/packages/dart_client/lib/src/api/channel.dart b/packages/dart_client/lib/src/api/channel.dart index d8ef1a03..01911b83 100644 --- a/packages/dart_client/lib/src/api/channel.dart +++ b/packages/dart_client/lib/src/api/channel.dart @@ -183,7 +183,7 @@ class Channel { user: _client.state.user, id: messageId, quotedMessage: quotedMessage, - status: MessageSendingStatus.SENDING, + status: MessageSendingStatus.sending, ); if (message.parentId != null && message.id == null) { @@ -978,7 +978,7 @@ class ChannelClientState { [...messages, ...threads.values.expand((v) => v)] .where((message) => message.status != null && - message.status != MessageSendingStatus.SENT && + message.status != MessageSendingStatus.sent && message.createdAt.isBefore(DateTime.now().subtract(Duration( seconds: 1, )))) diff --git a/packages/dart_client/lib/src/api/retry_queue.dart b/packages/dart_client/lib/src/api/retry_queue.dart index 12e8377a..376854af 100644 --- a/packages/dart_client/lib/src/api/retry_queue.dart +++ b/packages/dart_client/lib/src/api/retry_queue.dart @@ -113,30 +113,30 @@ class RetryQueue { } void _sendFailedEvent(Message message) { - final newStatus = message.status == MessageSendingStatus.SENDING - ? MessageSendingStatus.FAILED - : (message.status == MessageSendingStatus.UPDATING - ? MessageSendingStatus.FAILED_UPDATE - : MessageSendingStatus.FAILED_DELETE); + final newStatus = message.status == MessageSendingStatus.sending + ? MessageSendingStatus.failed + : (message.status == MessageSendingStatus.updating + ? MessageSendingStatus.failed_update + : MessageSendingStatus.failed_delete); channel.state.addMessage(message.copyWith( status: newStatus, )); } Future _sendMessage(Message message) async { - if (message.status == MessageSendingStatus.FAILED_UPDATE || - message.status == MessageSendingStatus.UPDATING) { + if (message.status == MessageSendingStatus.failed_update || + message.status == MessageSendingStatus.updating) { await channel.client.updateMessage( message, channel.cid, ); - } else if (message.status == MessageSendingStatus.FAILED || - message.status == MessageSendingStatus.SENDING) { + } else if (message.status == MessageSendingStatus.failed || + message.status == MessageSendingStatus.sending) { await channel.sendMessage( message, ); - } else if (message.status == MessageSendingStatus.FAILED_DELETE || - message.status == MessageSendingStatus.DELETING) { + } else if (message.status == MessageSendingStatus.failed_delete || + message.status == MessageSendingStatus.deleting) { await channel.client.deleteMessage( message, channel.cid, @@ -152,15 +152,15 @@ class RetryQueue { messageList.indexWhere((m) => m.id == event.message.id); if (messageIndex == -1 && [ - MessageSendingStatus.FAILED_UPDATE, - MessageSendingStatus.FAILED, - MessageSendingStatus.FAILED_DELETE, + MessageSendingStatus.failed_update, + MessageSendingStatus.failed, + MessageSendingStatus.failed_delete, ].contains(event.message.status)) { logger?.info('add message from events'); add([event.message]); } else if (messageIndex != -1 && [ - MessageSendingStatus.SENT, + MessageSendingStatus.sent, null, ].contains(event.message.status)) { _messageQueue.remove(messageList[messageIndex]); @@ -184,16 +184,16 @@ class RetryQueue { static DateTime _getMessageDate(Message m1) { switch (m1.status) { - case MessageSendingStatus.FAILED_DELETE: - case MessageSendingStatus.DELETING: + case MessageSendingStatus.failed_delete: + case MessageSendingStatus.deleting: return m1.deletedAt; - case MessageSendingStatus.FAILED: - case MessageSendingStatus.SENDING: + case MessageSendingStatus.failed: + case MessageSendingStatus.sending: return m1.createdAt; - case MessageSendingStatus.FAILED_UPDATE: - case MessageSendingStatus.UPDATING: + case MessageSendingStatus.failed_update: + case MessageSendingStatus.updating: return m1.updatedAt; default: return null; diff --git a/packages/dart_client/lib/src/client.dart b/packages/dart_client/lib/src/client.dart index 09ea4232..bb026ee7 100644 --- a/packages/dart_client/lib/src/client.dart +++ b/packages/dart_client/lib/src/client.dart @@ -1198,7 +1198,7 @@ class Client { String cid, ]) async { message = message.copyWith( - status: MessageSendingStatus.UPDATING, + status: MessageSendingStatus.updating, updatedAt: message.updatedAt ?? DateTime.now(), ); @@ -1229,10 +1229,10 @@ class Client { /// Deletes the given message Future deleteMessage(Message message, [String cid]) async { - if (message.status == MessageSendingStatus.FAILED) { + if (message.status == MessageSendingStatus.failed) { state.channels[cid].state.addMessage(message.copyWith( type: 'deleted', - status: MessageSendingStatus.SENT, + status: MessageSendingStatus.sent, )); return EmptyResponse(); } @@ -1240,7 +1240,7 @@ class Client { try { message = message.copyWith( type: 'deleted', - status: MessageSendingStatus.DELETING, + status: MessageSendingStatus.deleting, deletedAt: message.deletedAt ?? DateTime.now(), ); @@ -1252,7 +1252,7 @@ class Client { if (state?.channels != null) { state.channels[cid]?.state - ?.addMessage(message.copyWith(status: MessageSendingStatus.SENT)); + ?.addMessage(message.copyWith(status: MessageSendingStatus.sent)); } return decode(response.data, EmptyResponse.fromJson); diff --git a/packages/dart_client/lib/src/db/models.part.dart b/packages/dart_client/lib/src/db/models.part.dart index 98fced53..9a8c5e8e 100644 --- a/packages/dart_client/lib/src/db/models.part.dart +++ b/packages/dart_client/lib/src/db/models.part.dart @@ -216,19 +216,19 @@ class _MessageSendingStatusConverter MessageSendingStatus mapToDart(int fromDb) { switch (fromDb) { case 0: - return MessageSendingStatus.SENDING; + return MessageSendingStatus.sending; case 1: - return MessageSendingStatus.SENT; + return MessageSendingStatus.sent; case 2: - return MessageSendingStatus.FAILED; + return MessageSendingStatus.failed; case 3: - return MessageSendingStatus.UPDATING; + return MessageSendingStatus.updating; case 4: - return MessageSendingStatus.FAILED_UPDATE; + return MessageSendingStatus.failed_update; case 5: - return MessageSendingStatus.DELETING; + return MessageSendingStatus.deleting; case 6: - return MessageSendingStatus.FAILED_DELETE; + return MessageSendingStatus.failed_delete; default: return null; } @@ -237,19 +237,19 @@ class _MessageSendingStatusConverter @override int mapToSql(MessageSendingStatus value) { switch (value) { - case MessageSendingStatus.SENDING: + case MessageSendingStatus.sending: return 0; - case MessageSendingStatus.SENT: + case MessageSendingStatus.sent: return 1; - case MessageSendingStatus.FAILED: + case MessageSendingStatus.failed: return 2; - case MessageSendingStatus.UPDATING: + case MessageSendingStatus.updating: return 3; - case MessageSendingStatus.FAILED_UPDATE: + case MessageSendingStatus.failed_update: return 4; - case MessageSendingStatus.DELETING: + case MessageSendingStatus.deleting: return 5; - case MessageSendingStatus.FAILED_DELETE: + case MessageSendingStatus.failed_delete: return 6; default: return null; diff --git a/packages/dart_client/lib/src/models/message.dart b/packages/dart_client/lib/src/models/message.dart index e23eb51a..df188e35 100644 --- a/packages/dart_client/lib/src/models/message.dart +++ b/packages/dart_client/lib/src/models/message.dart @@ -10,25 +10,25 @@ part 'message.g.dart'; /// Enum defining the status of a sending message enum MessageSendingStatus { /// Message is being sent - SENDING, + sending, /// Message is being updated - UPDATING, + updating, /// Message is being deleted - DELETING, + deleting, /// Message failed to send - FAILED, + failed, /// Message failed to updated - FAILED_UPDATE, + failed_update, /// Message failed to delete - FAILED_DELETE, + failed_delete, /// Message correctly sent - SENT, + sent, } /// The class that contains the information about a message @@ -186,7 +186,7 @@ class Message { this.user, this.extraData, this.deletedAt, - this.status = MessageSendingStatus.SENT, + this.status = MessageSendingStatus.sent, }); /// Create a new instance from a json diff --git a/packages/flutter_widgets/lib/src/message_actions_modal.dart b/packages/flutter_widgets/lib/src/message_actions_modal.dart index 0cda4e9d..4aa2cde4 100644 --- a/packages/flutter_widgets/lib/src/message_actions_modal.dart +++ b/packages/flutter_widgets/lib/src/message_actions_modal.dart @@ -127,7 +127,7 @@ class _MessageActionsModalState extends State { children: [ if (widget.showReactions && (widget.message.status == - MessageSendingStatus.SENT || + MessageSendingStatus.sent || widget.message.status == null)) Align( alignment: Alignment( @@ -175,7 +175,7 @@ class _MessageActionsModalState extends State { showReactionPickerIndicator: widget.showReactions && (widget.message.status == - MessageSendingStatus.SENT || + MessageSendingStatus.sent || widget.message.status == null), showInChannelIndicator: false, showSendingIndicator: false, @@ -204,13 +204,13 @@ class _MessageActionsModalState extends State { children: [ if (widget.showReplyMessage && (widget.message.status == - MessageSendingStatus.SENT || + MessageSendingStatus.sent || widget.message.status == null) && widget.message.parentId == null) _buildReplyButton(context), if (widget.showThreadReplyMessage && (widget.message.status == - MessageSendingStatus.SENT || + MessageSendingStatus.sent || widget.message.status == null) && widget.message.parentId == null) _buildThreadReplyButton(context), @@ -487,7 +487,7 @@ class _MessageActionsModalState extends State { Widget _buildDeleteButton(BuildContext context) { final isDeleteFailed = - widget.message.status == MessageSendingStatus.FAILED_DELETE; + widget.message.status == MessageSendingStatus.failed_delete; return InkWell( onTap: () => _showDeleteDialog(), child: Padding( @@ -562,7 +562,7 @@ class _MessageActionsModalState extends State { Widget _buildResendMessage(BuildContext context) { final isUpdateFailed = - widget.message.status == MessageSendingStatus.FAILED_UPDATE; + widget.message.status == MessageSendingStatus.failed_update; return InkWell( onTap: () { Navigator.pop(context); diff --git a/packages/flutter_widgets/lib/src/message_input.dart b/packages/flutter_widgets/lib/src/message_input.dart index 01ae3d3a..70b8b46f 100644 --- a/packages/flutter_widgets/lib/src/message_input.dart +++ b/packages/flutter_widgets/lib/src/message_input.dart @@ -2211,7 +2211,7 @@ class MessageInputState extends State { _mentionedUsers.clear(); if (widget.editMessage == null || - widget.editMessage.status == MessageSendingStatus.FAILED) { + widget.editMessage.status == MessageSendingStatus.failed) { sendingFuture = channel.sendMessage(message); } else { sendingFuture = StreamChat.of(context).client.updateMessage( diff --git a/packages/flutter_widgets/lib/src/message_reactions_modal.dart b/packages/flutter_widgets/lib/src/message_reactions_modal.dart index 1ee3486d..2f117aca 100644 --- a/packages/flutter_widgets/lib/src/message_reactions_modal.dart +++ b/packages/flutter_widgets/lib/src/message_reactions_modal.dart @@ -93,7 +93,7 @@ class MessageReactionsModal extends StatelessWidget { crossAxisAlignment: CrossAxisAlignment.stretch, children: [ if (showReactions && - (message.status == MessageSendingStatus.SENT || + (message.status == MessageSendingStatus.sent || message.status == null)) Align( alignment: Alignment( @@ -141,7 +141,7 @@ class MessageReactionsModal extends StatelessWidget { ), showReactionPickerIndicator: showReactions && (message.status == - MessageSendingStatus.SENT || + MessageSendingStatus.sent || message.status == null), ), ), diff --git a/packages/flutter_widgets/lib/src/message_widget.dart b/packages/flutter_widgets/lib/src/message_widget.dart index 2a15f898..c2cbdc35 100644 --- a/packages/flutter_widgets/lib/src/message_widget.dart +++ b/packages/flutter_widgets/lib/src/message_widget.dart @@ -263,13 +263,13 @@ class _MessageWidgetState extends State { bool get hasQuotedMessage => widget.message?.quotedMessage != null; - bool get isSendFailed => widget.message.status == MessageSendingStatus.FAILED; + bool get isSendFailed => widget.message.status == MessageSendingStatus.failed; bool get isUpdateFailed => - widget.message.status == MessageSendingStatus.FAILED_UPDATE; + widget.message.status == MessageSendingStatus.failed_update; bool get isDeleteFailed => - widget.message.status == MessageSendingStatus.FAILED_DELETE; + widget.message.status == MessageSendingStatus.failed_delete; bool get isFailedState => isSendFailed || isUpdateFailed || isDeleteFailed; @@ -875,7 +875,7 @@ class _MessageWidgetState extends State { void onLongPress(BuildContext context) { if (widget.message.isEphemeral || - widget.message.status == MessageSendingStatus.SENDING) { + widget.message.status == MessageSendingStatus.sending) { return; } @@ -986,11 +986,11 @@ class _MessageWidgetState extends State { void retryMessage(BuildContext context) { final channel = StreamChannel.of(context).channel; - if (widget.message.status == MessageSendingStatus.FAILED) { + if (widget.message.status == MessageSendingStatus.failed) { channel.sendMessage(widget.message); return; } - if (widget.message.status == MessageSendingStatus.FAILED_UPDATE) { + if (widget.message.status == MessageSendingStatus.failed_update) { StreamChat.of(context).client.updateMessage( widget.message, channel.cid, @@ -998,7 +998,7 @@ class _MessageWidgetState extends State { return; } - if (widget.message.status == MessageSendingStatus.FAILED_DELETE) { + if (widget.message.status == MessageSendingStatus.failed_delete) { StreamChat.of(context).client.deleteMessage( widget.message, channel.cid, diff --git a/packages/flutter_widgets/lib/src/sending_indicator.dart b/packages/flutter_widgets/lib/src/sending_indicator.dart index 83e02bb3..3fca2fa9 100644 --- a/packages/flutter_widgets/lib/src/sending_indicator.dart +++ b/packages/flutter_widgets/lib/src/sending_indicator.dart @@ -22,14 +22,14 @@ class SendingIndicator extends StatelessWidget { color: StreamChatTheme.of(context).colorTheme.accentBlue, ); } - if (message.status == MessageSendingStatus.SENT || message.status == null) { + if (message.status == MessageSendingStatus.sent || message.status == null) { return StreamSvgIcon.check( size: size, color: IconTheme.of(context).color.withOpacity(0.5), ); } - if (message.status == MessageSendingStatus.SENDING || - message.status == MessageSendingStatus.UPDATING) { + if (message.status == MessageSendingStatus.sending || + message.status == MessageSendingStatus.updating) { return Icon( Icons.access_time, size: size, From 657b58af8b2888406ef224aa33e6e85e9c74e164 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Mon, 25 Jan 2021 19:14:55 +0530 Subject: [PATCH 1022/1140] [StreamChatPersistence] Add initial implementation Signed-off-by: Sahil Kumar --- .../lib/src/db/stream_chat_database.dart | 97 ++++++++ .../dart_client/lib/src/utils/result.dart | 45 ++++ packages/dart_client/lib/stream_chat.dart | 4 +- packages/dart_client/pubspec.yaml | 3 + packages/stream_chat_persistence/.gitignore | 74 ++++++ packages/stream_chat_persistence/.metadata | 10 + packages/stream_chat_persistence/CHANGELOG.md | 3 + packages/stream_chat_persistence/LICENSE | 1 + packages/stream_chat_persistence/README.md | 14 ++ packages/stream_chat_persistence/build.yaml | 6 + .../lib/src/converter/list_converter.dart | 22 ++ .../lib/src/converter/map_converter.dart | 22 ++ .../message_sending_status_converter.dart | 50 ++++ .../lib/src/dao/channel_dao.dart | 57 +++++ .../lib/src/dao/channel_query_dao.dart | 126 ++++++++++ .../lib/src/dao/connection_event_dao.dart | 58 +++++ .../lib/src/dao/dao.dart | 8 + .../lib/src/dao/member_dao.dart | 43 ++++ .../lib/src/dao/message_dao.dart | 143 +++++++++++ .../lib/src/dao/reaction_dao.dart | 50 ++++ .../lib/src/dao/read_dao.dart | 42 ++++ .../lib/src/dao/user_dao.dart | 25 ++ .../lib/src/db/moor_chat_database.dart | 83 +++++++ .../lib/src/db/shared/native_db.dart | 87 +++++++ .../lib/src/db/shared/shared_db.dart | 3 + .../lib/src/db/shared/unsupported_db.dart | 18 ++ .../lib/src/db/shared/web_db.dart | 21 ++ .../lib/src/db/stream_chat_database_impl.dart | 222 ++++++++++++++++++ .../lib/src/entity/channel_queries.dart | 14 ++ .../lib/src/entity/channels.dart | 32 +++ .../lib/src/entity/connection_events.dart | 19 ++ .../lib/src/entity/entity.dart | 8 + .../lib/src/entity/members.dart | 33 +++ .../lib/src/entity/messages.dart | 54 +++++ .../lib/src/entity/reactions.dart | 25 ++ .../lib/src/entity/reads.dart | 19 ++ .../lib/src/entity/users.dart | 24 ++ .../lib/src/mapper/channel_mapper.dart | 61 +++++ .../lib/src/mapper/event_mapper.dart | 15 ++ .../lib/src/mapper/mapper.dart | 7 + .../lib/src/mapper/member_mapper.dart | 43 ++++ .../lib/src/mapper/message_mapper.dart | 70 ++++++ .../lib/src/mapper/reaction_mapper.dart | 33 +++ .../lib/src/mapper/read_mapper.dart | 28 +++ .../lib/src/mapper/user_mapper.dart | 36 +++ .../lib/stream_chat_persistence.dart | 3 + packages/stream_chat_persistence/pubspec.yaml | 18 ++ 47 files changed, 1878 insertions(+), 1 deletion(-) create mode 100644 packages/dart_client/lib/src/db/stream_chat_database.dart create mode 100644 packages/dart_client/lib/src/utils/result.dart create mode 100644 packages/stream_chat_persistence/.gitignore create mode 100644 packages/stream_chat_persistence/.metadata create mode 100644 packages/stream_chat_persistence/CHANGELOG.md create mode 100644 packages/stream_chat_persistence/LICENSE create mode 100644 packages/stream_chat_persistence/README.md create mode 100644 packages/stream_chat_persistence/build.yaml create mode 100644 packages/stream_chat_persistence/lib/src/converter/list_converter.dart create mode 100644 packages/stream_chat_persistence/lib/src/converter/map_converter.dart create mode 100644 packages/stream_chat_persistence/lib/src/converter/message_sending_status_converter.dart create mode 100644 packages/stream_chat_persistence/lib/src/dao/channel_dao.dart create mode 100644 packages/stream_chat_persistence/lib/src/dao/channel_query_dao.dart create mode 100644 packages/stream_chat_persistence/lib/src/dao/connection_event_dao.dart create mode 100644 packages/stream_chat_persistence/lib/src/dao/dao.dart create mode 100644 packages/stream_chat_persistence/lib/src/dao/member_dao.dart create mode 100644 packages/stream_chat_persistence/lib/src/dao/message_dao.dart create mode 100644 packages/stream_chat_persistence/lib/src/dao/reaction_dao.dart create mode 100644 packages/stream_chat_persistence/lib/src/dao/read_dao.dart create mode 100644 packages/stream_chat_persistence/lib/src/dao/user_dao.dart create mode 100644 packages/stream_chat_persistence/lib/src/db/moor_chat_database.dart create mode 100644 packages/stream_chat_persistence/lib/src/db/shared/native_db.dart create mode 100644 packages/stream_chat_persistence/lib/src/db/shared/shared_db.dart create mode 100644 packages/stream_chat_persistence/lib/src/db/shared/unsupported_db.dart create mode 100644 packages/stream_chat_persistence/lib/src/db/shared/web_db.dart create mode 100644 packages/stream_chat_persistence/lib/src/db/stream_chat_database_impl.dart create mode 100644 packages/stream_chat_persistence/lib/src/entity/channel_queries.dart create mode 100644 packages/stream_chat_persistence/lib/src/entity/channels.dart create mode 100644 packages/stream_chat_persistence/lib/src/entity/connection_events.dart create mode 100644 packages/stream_chat_persistence/lib/src/entity/entity.dart create mode 100644 packages/stream_chat_persistence/lib/src/entity/members.dart create mode 100644 packages/stream_chat_persistence/lib/src/entity/messages.dart create mode 100644 packages/stream_chat_persistence/lib/src/entity/reactions.dart create mode 100644 packages/stream_chat_persistence/lib/src/entity/reads.dart create mode 100644 packages/stream_chat_persistence/lib/src/entity/users.dart create mode 100644 packages/stream_chat_persistence/lib/src/mapper/channel_mapper.dart create mode 100644 packages/stream_chat_persistence/lib/src/mapper/event_mapper.dart create mode 100644 packages/stream_chat_persistence/lib/src/mapper/mapper.dart create mode 100644 packages/stream_chat_persistence/lib/src/mapper/member_mapper.dart create mode 100644 packages/stream_chat_persistence/lib/src/mapper/message_mapper.dart create mode 100644 packages/stream_chat_persistence/lib/src/mapper/reaction_mapper.dart create mode 100644 packages/stream_chat_persistence/lib/src/mapper/read_mapper.dart create mode 100644 packages/stream_chat_persistence/lib/src/mapper/user_mapper.dart create mode 100644 packages/stream_chat_persistence/lib/stream_chat_persistence.dart create mode 100644 packages/stream_chat_persistence/pubspec.yaml diff --git a/packages/dart_client/lib/src/db/stream_chat_database.dart b/packages/dart_client/lib/src/db/stream_chat_database.dart new file mode 100644 index 00000000..87ab828e --- /dev/null +++ b/packages/dart_client/lib/src/db/stream_chat_database.dart @@ -0,0 +1,97 @@ +import 'package:stream_chat/src/api/requests.dart'; +import 'package:stream_chat/src/models/channel_model.dart'; +import 'package:stream_chat/src/models/channel_state.dart'; +import 'package:stream_chat/src/models/event.dart'; +import 'package:stream_chat/src/models/member.dart'; +import 'package:stream_chat/src/models/message.dart'; +import 'package:stream_chat/src/models/reaction.dart'; +import 'package:stream_chat/src/models/read.dart'; +import 'package:stream_chat/src/models/user.dart'; + +/// +abstract class StreamChatDatabase { + /// Creates a new connection to the database + Future connect({ + bool connectBackground = false, + bool logStatements = false, + }); + + /// Closes the database instance + /// If [flush] is true, the database data will be deleted + Future disconnect({bool flush = false}); + + /// Get stored replies by messageId + Future> getReplies( + String parentId, { + String lessThan, + }); + + /// Get stored connection event + Future getConnectionInfo(); + + /// Get stored lastSyncAt + Future getLastSyncAt(); + + /// Update stored connection event + Future updateConnectionInfo(Event event); + + /// Update stored lastSyncAt + Future updateLastSyncAt(DateTime lastSyncAt); + + /// Get the channel cids saved in the offline storage + Future> getChannelCids(); + + Future getChannelByCid(String cid); + + Future> getMembersByCid(String cid); + + Future> getReadsByCid(String cid); + + Future> getMessagesByCid( + String cid, { + int limit = 20, + String messageLessThan, + String messageGreaterThan, + }); + + /// Get list of channels by filter, sort and paginationParams + Future> getChannelStates({ + Map filter, + List sort = const [], + PaginationParams paginationParams, + }); + + /// Update list of channel queries + /// If [clearQueryCache] is true before the insert + /// the list of matching rows will be deleted + Future updateChannelQueries( + Map filter, + List cids, + bool clearQueryCache, + ); + + /// Remove a message by message id + Future deleteMessageByIds(List messageIds); + + /// Remove a message by message id + Future deleteMessageByCids(List cids); + + /// Remove a channel by cid + Future deleteChannelByCids(List cids); + + /// Update messages data from a list + Future updateMessages(String cid, List messages); + + /// Get the info about channel threads + Future>> getChannelThreads(String cid); + + Future updateChannels(List channels); + + Future updateMembers(String cid, List members); + + Future updateReads(String cid, List reads); + + Future updateUsers(List users); + + Future updateReactions(List reactions); +} diff --git a/packages/dart_client/lib/src/utils/result.dart b/packages/dart_client/lib/src/utils/result.dart new file mode 100644 index 00000000..a2961ec4 --- /dev/null +++ b/packages/dart_client/lib/src/utils/result.dart @@ -0,0 +1,45 @@ +import 'package:flutter/foundation.dart'; +import 'package:freezed_annotation/freezed_annotation.dart'; + +import '../exceptions.dart'; + +part 'result.freezed.dart'; + +/// +@freezed +abstract class Result with _$Result { + /// + const factory Result.success({@required T data}) = Success; + + /// + const factory Result.error({@required ApiError error}) = Error; +} + +/// +extension ResultX on Result { + /// + bool get isSuccess => this is Success; + + /// + bool get isError => this is Error; + + /// + T get data { + if (isError) { + throw Exception( + 'Result is not successful. Check result.isSuccess before reading the data.', + ); + } + return (this as Success).data; + } + + /// + ApiError get error { + if (isSuccess) { + throw Exception( + 'Result is successful, not an error. Check result.isError before reading the error.', + ); + } + return (this as Error).error; + } +} diff --git a/packages/dart_client/lib/stream_chat.dart b/packages/dart_client/lib/stream_chat.dart index 101e9440..8bac944f 100644 --- a/packages/dart_client/lib/stream_chat.dart +++ b/packages/dart_client/lib/stream_chat.dart @@ -2,7 +2,7 @@ library stream_chat; export 'package:dio/src/dio_error.dart'; export 'package:dio/src/multipart_file.dart'; -export 'package:logging/src/level.dart'; +export 'package:logging/logging.dart' show Logger, Level; export './src/api/channel.dart'; export './src/api/connection_status.dart'; @@ -27,3 +27,5 @@ export './src/models/reaction.dart'; export './src/models/read.dart'; export './src/models/user.dart'; export './src/notifications.dart'; +export './src/db/stream_chat_database.dart'; +export './src/utils/result.dart'; diff --git a/packages/dart_client/pubspec.yaml b/packages/dart_client/pubspec.yaml index 9fd0d9e0..d4734e44 100644 --- a/packages/dart_client/pubspec.yaml +++ b/packages/dart_client/pubspec.yaml @@ -26,6 +26,9 @@ dependencies: collection: ^1.14.12 sqlite3_flutter_libs: ^0.3.0 pedantic: ^1.9.2 + freezed: ^0.12.7 + stream_chat_persistence: + path: ../stream_chat_persistence dev_dependencies: build_runner: ^1.10.0 diff --git a/packages/stream_chat_persistence/.gitignore b/packages/stream_chat_persistence/.gitignore new file mode 100644 index 00000000..1985397a --- /dev/null +++ b/packages/stream_chat_persistence/.gitignore @@ -0,0 +1,74 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# IntelliJ related +*.iml +*.ipr +*.iws +.idea/ + +# The .vscode folder contains launch configuration and tasks you configure in +# VS Code which you may wish to be included in version control, so this line +# is commented out by default. +#.vscode/ + +# Flutter/Dart/Pub related +**/doc/api/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +build/ + +# Android related +**/android/**/gradle-wrapper.jar +**/android/.gradle +**/android/captures/ +**/android/gradlew +**/android/gradlew.bat +**/android/local.properties +**/android/**/GeneratedPluginRegistrant.java + +# iOS/XCode related +**/ios/**/*.mode1v3 +**/ios/**/*.mode2v3 +**/ios/**/*.moved-aside +**/ios/**/*.pbxuser +**/ios/**/*.perspectivev3 +**/ios/**/*sync/ +**/ios/**/.sconsign.dblite +**/ios/**/.tags* +**/ios/**/.vagrant/ +**/ios/**/DerivedData/ +**/ios/**/Icon? +**/ios/**/Pods/ +**/ios/**/.symlinks/ +**/ios/**/profile +**/ios/**/xcuserdata +**/ios/.generated/ +**/ios/Flutter/App.framework +**/ios/Flutter/Flutter.framework +**/ios/Flutter/Flutter.podspec +**/ios/Flutter/Generated.xcconfig +**/ios/Flutter/app.flx +**/ios/Flutter/app.zip +**/ios/Flutter/flutter_assets/ +**/ios/Flutter/flutter_export_environment.sh +**/ios/ServiceDefinitions.json +**/ios/Runner/GeneratedPluginRegistrant.* + +# Exceptions to above rules. +!**/ios/**/default.mode1v3 +!**/ios/**/default.mode2v3 +!**/ios/**/default.pbxuser +!**/ios/**/default.perspectivev3 diff --git a/packages/stream_chat_persistence/.metadata b/packages/stream_chat_persistence/.metadata new file mode 100644 index 00000000..5eb50347 --- /dev/null +++ b/packages/stream_chat_persistence/.metadata @@ -0,0 +1,10 @@ +# This file tracks properties of this Flutter project. +# Used by Flutter tool to assess capabilities and perform upgrades etc. +# +# This file should be version controlled and should not be manually edited. + +version: + revision: 78910062997c3a836feee883712c241a5fd22983 + channel: stable + +project_type: package diff --git a/packages/stream_chat_persistence/CHANGELOG.md b/packages/stream_chat_persistence/CHANGELOG.md new file mode 100644 index 00000000..ac071598 --- /dev/null +++ b/packages/stream_chat_persistence/CHANGELOG.md @@ -0,0 +1,3 @@ +## [0.0.1] - TODO: Add release date. + +* TODO: Describe initial release. diff --git a/packages/stream_chat_persistence/LICENSE b/packages/stream_chat_persistence/LICENSE new file mode 100644 index 00000000..ba75c69f --- /dev/null +++ b/packages/stream_chat_persistence/LICENSE @@ -0,0 +1 @@ +TODO: Add your license here. diff --git a/packages/stream_chat_persistence/README.md b/packages/stream_chat_persistence/README.md new file mode 100644 index 00000000..3e3f0c7c --- /dev/null +++ b/packages/stream_chat_persistence/README.md @@ -0,0 +1,14 @@ +# stream_chat_persistence + +A new Flutter package. + +## Getting Started + +This project is a starting point for a Dart +[package](https://flutter.dev/developing-packages/), +a library module containing code that can be shared easily across +multiple Flutter or Dart projects. + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/packages/stream_chat_persistence/build.yaml b/packages/stream_chat_persistence/build.yaml new file mode 100644 index 00000000..b07425b6 --- /dev/null +++ b/packages/stream_chat_persistence/build.yaml @@ -0,0 +1,6 @@ +targets: + $default: + builders: + moor_generator: + options: + generate_connect_constructor: true diff --git a/packages/stream_chat_persistence/lib/src/converter/list_converter.dart b/packages/stream_chat_persistence/lib/src/converter/list_converter.dart new file mode 100644 index 00000000..5d0a628f --- /dev/null +++ b/packages/stream_chat_persistence/lib/src/converter/list_converter.dart @@ -0,0 +1,22 @@ +import 'dart:convert'; + +import 'package:moor/moor.dart'; + +/// +class ListConverter extends TypeConverter, String> { + @override + List mapToDart(fromDb) { + if (fromDb == null) { + return null; + } + return List.from(jsonDecode(fromDb) ?? []); + } + + @override + String mapToSql(value) { + if (value == null) { + return null; + } + return jsonEncode(value); + } +} diff --git a/packages/stream_chat_persistence/lib/src/converter/map_converter.dart b/packages/stream_chat_persistence/lib/src/converter/map_converter.dart new file mode 100644 index 00000000..9fde0003 --- /dev/null +++ b/packages/stream_chat_persistence/lib/src/converter/map_converter.dart @@ -0,0 +1,22 @@ +import 'dart:convert'; + +import 'package:moor/moor.dart'; + +/// +class MapConverter extends TypeConverter, String> { + @override + Map mapToDart(fromDb) { + if (fromDb == null) { + return null; + } + return Map.from(jsonDecode(fromDb) ?? {}); + } + + @override + String mapToSql(value) { + if (value == null) { + return null; + } + return jsonEncode(value); + } +} diff --git a/packages/stream_chat_persistence/lib/src/converter/message_sending_status_converter.dart b/packages/stream_chat_persistence/lib/src/converter/message_sending_status_converter.dart new file mode 100644 index 00000000..b8d92b82 --- /dev/null +++ b/packages/stream_chat_persistence/lib/src/converter/message_sending_status_converter.dart @@ -0,0 +1,50 @@ +import 'package:moor/moor.dart'; +import 'package:stream_chat/stream_chat.dart'; + +/// +class MessageSendingStatusConverter + extends TypeConverter { + @override + MessageSendingStatus mapToDart(int fromDb) { + switch (fromDb) { + case 0: + return MessageSendingStatus.sending; + case 1: + return MessageSendingStatus.sent; + case 2: + return MessageSendingStatus.failed; + case 3: + return MessageSendingStatus.updating; + case 4: + return MessageSendingStatus.failed_update; + case 5: + return MessageSendingStatus.deleting; + case 6: + return MessageSendingStatus.failed_delete; + default: + return null; + } + } + + @override + int mapToSql(MessageSendingStatus value) { + switch (value) { + case MessageSendingStatus.sending: + return 0; + case MessageSendingStatus.sent: + return 1; + case MessageSendingStatus.failed: + return 2; + case MessageSendingStatus.updating: + return 3; + case MessageSendingStatus.failed_update: + return 4; + case MessageSendingStatus.deleting: + return 5; + case MessageSendingStatus.failed_delete: + return 6; + default: + return null; + } + } +} diff --git a/packages/stream_chat_persistence/lib/src/dao/channel_dao.dart b/packages/stream_chat_persistence/lib/src/dao/channel_dao.dart new file mode 100644 index 00000000..fa902f52 --- /dev/null +++ b/packages/stream_chat_persistence/lib/src/dao/channel_dao.dart @@ -0,0 +1,57 @@ +import 'package:moor/moor.dart'; +import 'package:stream_chat/stream_chat.dart'; +import 'package:stream_chat_persistence/src/db/moor_chat_database.dart'; +import 'package:stream_chat_persistence/src/entity/channels.dart'; +import 'package:stream_chat_persistence/src/entity/users.dart'; +import '../mapper/mapper.dart'; + +part 'channel_dao.g.dart'; + +/// +@UseDao(tables: [Channels, Users]) +class ChannelDao extends DatabaseAccessor + with _$ChannelDaoMixin { + /// + ChannelDao(MoorChatDatabase db) : super(db); + + /// Get channel by cid + Future getChannelByCid(String cid) async { + return (select(channels)..where((c) => c.cid.equals(cid))).join([ + leftOuterJoin(users, channels.createdById.equalsExp(users.id)), + ]).map((rows) { + final channel = rows.readTable(channels); + final createdBy = rows.readTable(users); + return channel.toChannelModel(createdBy: createdBy?.toUser()); + }).getSingle(); + } + + /// Delete all channels by matching cid in [cids] + /// + /// This will automatically delete the following linked records + /// 1. Channel Reads + /// 2. Channel Members + /// 3. Channel Messages -> Messages Reactions + Future deleteChannelByCids(List cids) async { + return (delete(channels)..where((tbl) => tbl.cid.isIn(cids))).go(); + } + + /// Get the channel cids saved in the storage + Future> get cids { + return (select(channels) + ..orderBy([(c) => OrderingTerm.desc(c.lastMessageAt)]) + ..limit(250)) + .map((c) => c.cid) + .get(); + } + + /// + Future updateChannels(List channelList) { + return batch( + (it) => it.insertAll( + channels, + channelList.map((c) => c.toEntity()).toList(), + mode: InsertMode.insertOrReplace, + ), + ); + } +} diff --git a/packages/stream_chat_persistence/lib/src/dao/channel_query_dao.dart b/packages/stream_chat_persistence/lib/src/dao/channel_query_dao.dart new file mode 100644 index 00000000..a42dd01e --- /dev/null +++ b/packages/stream_chat_persistence/lib/src/dao/channel_query_dao.dart @@ -0,0 +1,126 @@ +import 'dart:convert'; + +import 'package:moor/moor.dart'; +import 'package:stream_chat/stream_chat.dart'; +import 'package:stream_chat_persistence/src/db/moor_chat_database.dart'; +import 'package:stream_chat_persistence/src/entity/channel_queries.dart'; +import 'package:stream_chat_persistence/src/entity/channels.dart'; +import 'package:stream_chat_persistence/src/entity/users.dart'; +import '../mapper/mapper.dart'; + +part 'channel_query_dao.g.dart'; + +/// +@UseDao(tables: [ChannelQueries, Channels, Users]) +class ChannelQueryDao extends DatabaseAccessor + with _$ChannelQueryDaoMixin { + /// + ChannelQueryDao(this._db) : super(_db); + + final MoorChatDatabase _db; + + String _computeHash(Map filter) { + if (filter == null) { + return 'allchannels'; + } + final hash = base64Encode(utf8.encode('filter: ${jsonEncode(filter)}')); + return hash; + } + + /// Update list of channel queries + /// If [clearQueryCache] is true before the insert + /// the list of matching rows will be deleted + Future updateChannelQueries( + Map filter, + List cids, + bool clearQueryCache, + ) async { + final hash = _computeHash(filter); + if (clearQueryCache) { + await (delete(channelQueries) + ..where((query) => query.queryHash.equals(hash))) + .go(); + } + + return batch((batch) { + batch.insertAll( + channelQueries, + cids.map((cid) { + return ChannelQueryEntity( + queryHash: hash, + channelCid: cid, + ); + }).toList(), + mode: InsertMode.insertOrReplace, + ); + }); + } + + /// Get list of channels by filter, sort and paginationParams + Future> getChannelStates({ + Map filter, + List sort = const [], + PaginationParams paginationParams, + }) async { + final hash = _computeHash(filter); + final cachedChannels = await Future.wait(await (select(channelQueries) + ..where((c) => c.queryHash.equals(hash))) + .get() + .then((channelQueries) { + final cids = channelQueries.map((c) => c.channelCid).toList(); + final query = select(channels)..where((c) => c.cid.isIn(cids)); + + sort = sort + ?.where((s) => ChannelModel.topLevelFields.contains(s.field)) + ?.toList(); + + if (sort != null && sort.isNotEmpty) { + query.orderBy(sort.map((s) { + final orderExpression = CustomExpression('channels.${s.field}'); + return (c) => OrderingTerm( + expression: orderExpression, + mode: s.direction == 1 ? OrderingMode.asc : OrderingMode.desc, + ); + }).toList()); + } + + if (paginationParams != null) { + query.limit( + paginationParams.limit ?? 10, + offset: paginationParams.offset, + ); + } + + return query.join([ + leftOuterJoin(users, channels.createdById.equalsExp(users.id)), + ]).map((row) async { + final userEntity = row.readTable(users); + final channelEntity = row.readTable(channels); + + final cid = channelEntity.cid; + final members = await _db.memberDao.getMembersByCid(cid); + final reads = await _db.readDao.getReadsByCid(cid); + final messages = await _db.messageDao.getMessagesByCid(cid); + + return channelEntity.toChannelState( + createdBy: userEntity?.toUser(), + members: members, + reads: reads, + messages: messages, + ); + }).get(); + })); + + if (sort?.isEmpty != false && cachedChannels?.isNotEmpty == true) { + cachedChannels + .sort((a, b) => b.channel.updatedAt.compareTo(a.channel.updatedAt)); + cachedChannels.sort((a, b) { + final dateA = a.channel.lastMessageAt ?? a.channel.createdAt; + final dateB = b.channel.lastMessageAt ?? b.channel.createdAt; + return dateB.compareTo(dateA); + }); + } + + return cachedChannels; + } +} diff --git a/packages/stream_chat_persistence/lib/src/dao/connection_event_dao.dart b/packages/stream_chat_persistence/lib/src/dao/connection_event_dao.dart new file mode 100644 index 00000000..59d22010 --- /dev/null +++ b/packages/stream_chat_persistence/lib/src/dao/connection_event_dao.dart @@ -0,0 +1,58 @@ +import 'package:moor/moor.dart'; +import 'package:stream_chat/stream_chat.dart'; +import 'package:stream_chat_persistence/src/db/moor_chat_database.dart'; +import 'package:stream_chat_persistence/src/entity/connection_events.dart'; +import 'package:stream_chat_persistence/src/entity/users.dart'; +import '../mapper/mapper.dart'; + +part 'connection_event_dao.g.dart'; + +/// +@UseDao(tables: [ConnectionEvents, Users]) +class ConnectionEventDao extends DatabaseAccessor + with _$ConnectionEventDaoMixin { + /// + ConnectionEventDao(MoorChatDatabase db) : super(db); + + /// Get the latest stored connection event + Future get connectionEvent { + return select(connectionEvents).join([ + leftOuterJoin(users, connectionEvents.ownUserId.equalsExp(users.id)), + ]).map((rows) { + final event = rows.readTable(connectionEvents); + final user = rows.readTable(users); + return event.toEvent(user: user?.toUser()); + }).getSingle(); + } + + /// Get the latest stored lastSyncAt + Future get lastSyncAt { + return select(connectionEvents).getSingle().then((r) => r?.lastSyncAt); + } + + /// Update stored connection event with latest data + Future updateConnectionEvent(Event event) async { + final connectionInfo = await select(connectionEvents).getSingle(); + return into(connectionEvents).insert( + ConnectionEventEntity( + id: 1, + lastSyncAt: connectionInfo?.lastSyncAt, + lastEventAt: event.createdAt ?? connectionInfo?.lastEventAt, + totalUnreadCount: + event.totalUnreadCount ?? connectionInfo?.totalUnreadCount, + ownUserId: event.me?.id ?? connectionInfo?.ownUserId, + unreadChannels: event.unreadChannels ?? connectionInfo?.unreadChannels, + ), + mode: InsertMode.insertOrReplace, + ); + } + + /// Update stored lastSyncAt with latest data + Future updateLastSyncAt(DateTime lastSyncAt) async { + return (update(connectionEvents)..where((tbl) => tbl.id.equals(1))).write( + ConnectionEventsCompanion( + lastSyncAt: Value(lastSyncAt), + ), + ); + } +} diff --git a/packages/stream_chat_persistence/lib/src/dao/dao.dart b/packages/stream_chat_persistence/lib/src/dao/dao.dart new file mode 100644 index 00000000..6f1e8221 --- /dev/null +++ b/packages/stream_chat_persistence/lib/src/dao/dao.dart @@ -0,0 +1,8 @@ +export 'user_dao.dart'; +export 'channel_dao.dart'; +export 'message_dao.dart'; +export 'member_dao.dart'; +export 'connection_event_dao.dart'; +export 'reaction_dao.dart'; +export 'read_dao.dart'; +export 'channel_query_dao.dart'; diff --git a/packages/stream_chat_persistence/lib/src/dao/member_dao.dart b/packages/stream_chat_persistence/lib/src/dao/member_dao.dart new file mode 100644 index 00000000..f21ab334 --- /dev/null +++ b/packages/stream_chat_persistence/lib/src/dao/member_dao.dart @@ -0,0 +1,43 @@ +import 'package:moor/moor.dart'; +import 'package:stream_chat/stream_chat.dart'; +import 'package:stream_chat_persistence/src/db/moor_chat_database.dart'; + +import 'package:stream_chat_persistence/src/entity/members.dart'; +import 'package:stream_chat_persistence/src/entity/users.dart'; + +import '../mapper/mapper.dart'; + +part 'member_dao.g.dart'; + +/// +@UseDao(tables: [Members, Users]) +class MemberDao extends DatabaseAccessor + with _$MemberDaoMixin { + /// + MemberDao(MoorChatDatabase db) : super(db); + + /// Get all members where [members.channelCid] matches [cid] + Future> getMembersByCid(String cid) async { + return (select(members).join([ + leftOuterJoin(users, members.userId.equalsExp(users.id)), + ]) + ..where(members.channelCid.equals(cid)) + ..orderBy([OrderingTerm.asc(members.createdAt)])) + .map((row) { + final userEntity = row.readTable(users); + final memberEntity = row.readTable(members); + return memberEntity.toMember(user: userEntity?.toUser()); + }).get(); + } + + /// + Future updateMembers(String cid, List memberList) async { + return batch( + (it) => it.insertAll( + members, + memberList.map((m) => m.toEntity(cid: cid)).toList(), + mode: InsertMode.insertOrReplace, + ), + ); + } +} diff --git a/packages/stream_chat_persistence/lib/src/dao/message_dao.dart b/packages/stream_chat_persistence/lib/src/dao/message_dao.dart new file mode 100644 index 00000000..700f8bed --- /dev/null +++ b/packages/stream_chat_persistence/lib/src/dao/message_dao.dart @@ -0,0 +1,143 @@ +import 'package:moor/moor.dart'; +import 'package:stream_chat/stream_chat.dart'; +import 'package:stream_chat_persistence/src/db/moor_chat_database.dart'; +import 'package:stream_chat_persistence/src/entity/messages.dart'; +import 'package:stream_chat_persistence/src/entity/users.dart'; +import '../mapper/mapper.dart'; + +part 'message_dao.g.dart'; + +/// +@UseDao(tables: [Messages, Users]) +class MessageDao extends DatabaseAccessor + with _$MessageDaoMixin { + /// + MessageDao(this._db) : super(_db); + + final MoorChatDatabase _db; + + /// Removes all the messages by matching [messages.id] in [messageIds] + /// + /// This will automatically delete the following linked records + /// 1. Message Reactions + Future deleteMessageByIds(List messageIds) { + return (delete(messages)..where((tbl) => tbl.id.isIn(messageIds))).go(); + } + + /// Removes all the messages by matching [messages.channelCid] in [cids] + /// + /// This will automatically delete the following linked records + /// 1. Message Reactions + Future deleteMessageByCids(List cids) async { + return (delete(messages)..where((tbl) => tbl.channelCid.isIn(cids))).go(); + } + + Future _messageFromJoinRow(TypedResult rows) async { + final userEntity = rows.readTable(users); + final msgEntity = rows.readTable(messages); + final latestReactions = await _db.reactionDao.getReactions(msgEntity.id); + final ownReactions = await _db.reactionDao.getOwnReactions( + msgEntity.id, + userEntity.id, + ); + Message quotedMessage; + if (msgEntity.quotedMessageId != null) { + quotedMessage = await getMessageById(msgEntity.quotedMessageId); + } + return msgEntity.toMessage( + user: userEntity?.toUser(), + latestReactions: latestReactions, + ownReactions: ownReactions, + quotedMessage: quotedMessage, + ); + } + + /// + Future getMessageById(String id) async { + return await (select(messages).join([ + leftOuterJoin(users, messages.userId.equalsExp(users.id)), + ]) + ..where(messages.id.equals(id))) + .map(_messageFromJoinRow) + .getSingle(); + } + + /// + Future> getThreadMessages(String cid) async { + return Future.wait(await (select(messages).join([ + leftOuterJoin(users, messages.userId.equalsExp(users.id)), + ]) + ..where(messages.channelCid.equals(cid)) + ..where(isNotNull(messages.parentId)) + ..orderBy([OrderingTerm.asc(messages.createdAt)])) + .map(_messageFromJoinRow) + .get()); + } + + /// + Future> getThreadMessagesByParentId( + String parentId, { + String lessThan, + }) async { + final msgList = await Future.wait(await (select(messages).join([ + innerJoin(users, messages.userId.equalsExp(users.id)), + ]) + ..where(messages.parentId.equals(parentId)) + ..orderBy([OrderingTerm.asc(messages.createdAt)])) + .map(_messageFromJoinRow) + .get()); + + if (lessThan != null) { + final lessThanIndex = msgList.indexWhere((m) => m.id == lessThan); + msgList.removeRange(lessThanIndex, msgList.length); + } + return msgList; + } + + /// + Future> getMessagesByCid( + String cid, { + int limit = 20, + String messageLessThan, + String messageGreaterThan, + }) async { + final msgList = await Future.wait(await (select(messages).join([ + leftOuterJoin(users, messages.userId.equalsExp(users.id)), + ]) + ..where(messages.channelCid.equals(cid)) + ..where( + isNull(messages.parentId) | messages.showInChannel.equals(true)) + ..orderBy([OrderingTerm.asc(messages.createdAt)])) + .map(_messageFromJoinRow) + .get()); + + if (messageLessThan != null) { + final lessThanIndex = msgList.indexWhere((m) => m.id == messageLessThan); + if (lessThanIndex != -1) { + msgList.removeRange(lessThanIndex, msgList.length); + } + } + if (messageGreaterThan != null) { + final greaterThanIndex = + msgList.indexWhere((m) => m.id == messageGreaterThan); + if (greaterThanIndex != -1) { + msgList.removeRange(0, greaterThanIndex); + } + } + if (limit != null) { + return msgList.take(limit).toList(); + } + return msgList; + } + + /// + Future updateMessages(String cid, List messageList) { + return batch((batch) { + batch.insertAll( + messages, + messageList.map((it) => it.toEntity(cid: cid)).toList(), + mode: InsertMode.insertOrReplace, + ); + }); + } +} diff --git a/packages/stream_chat_persistence/lib/src/dao/reaction_dao.dart b/packages/stream_chat_persistence/lib/src/dao/reaction_dao.dart new file mode 100644 index 00000000..8df23d44 --- /dev/null +++ b/packages/stream_chat_persistence/lib/src/dao/reaction_dao.dart @@ -0,0 +1,50 @@ +import 'package:moor/moor.dart'; +import 'package:stream_chat/stream_chat.dart'; +import 'package:stream_chat_persistence/src/db/moor_chat_database.dart'; +import 'package:stream_chat_persistence/src/entity/reactions.dart'; +import 'package:stream_chat_persistence/src/entity/users.dart'; +import '../mapper/mapper.dart'; + +part 'reaction_dao.g.dart'; + +/// +@UseDao(tables: [Reactions, Users]) +class ReactionDao extends DatabaseAccessor + with _$ReactionDaoMixin { + /// + ReactionDao(MoorChatDatabase db) : super(db); + + /// + Future> getReactions(String messageId) { + return (select(reactions).join([ + leftOuterJoin(users, reactions.userId.equalsExp(users.id)), + ]) + ..where(reactions.messageId.equals(messageId)) + ..orderBy([OrderingTerm.asc(reactions.createdAt)])) + .map((rows) { + final userEntity = rows.readTable(users); + final reactionEntity = rows.readTable(reactions); + return reactionEntity.toReaction(user: userEntity?.toUser()); + }).get(); + } + + /// + Future> getOwnReactions( + String messageId, + String userId, + ) async { + final reactions = await getReactions(messageId); + return reactions.where((it) => it.userId == userId).toList(); + } + + /// + Future updateReactions(List reactionList) { + return batch((it) { + it.insertAll( + reactions, + reactionList.map((r) => r.toEntity()).toList(), + mode: InsertMode.insertOrReplace, + ); + }); + } +} diff --git a/packages/stream_chat_persistence/lib/src/dao/read_dao.dart b/packages/stream_chat_persistence/lib/src/dao/read_dao.dart new file mode 100644 index 00000000..cd4da0f6 --- /dev/null +++ b/packages/stream_chat_persistence/lib/src/dao/read_dao.dart @@ -0,0 +1,42 @@ +import 'package:moor/moor.dart'; +import 'package:stream_chat/stream_chat.dart'; +import 'package:stream_chat_persistence/src/db/moor_chat_database.dart'; +import 'package:stream_chat_persistence/src/entity/reads.dart'; +import 'package:stream_chat_persistence/src/entity/users.dart'; +import '../mapper/mapper.dart'; + +part 'read_dao.g.dart'; + +/// +@UseDao(tables: [Reads, Users]) +class ReadDao extends DatabaseAccessor with _$ReadDaoMixin { + /// + ReadDao(MoorChatDatabase db) : super(db); + + /// Get all reads where [reads.channelCid] matches [cid] + Future> getReadsByCid(String cid) async { + return (select(reads).join([ + leftOuterJoin(users, reads.userId.equalsExp(users.id)), + ]) + ..where(reads.channelCid.equals(cid)) + ..orderBy([ + OrderingTerm.asc(reads.lastRead), + ])) + .map((row) { + final userEntity = row.readTable(users); + final readEntity = row.readTable(reads); + return readEntity.toRead(user: userEntity?.toUser()); + }).get(); + } + + /// + Future updateReads(String cid, List readList) { + return batch( + (it) => it.insertAll( + reads, + readList.map((r) => r.toEntity(cid: cid)).toList(), + mode: InsertMode.insertOrReplace, + ), + ); + } +} diff --git a/packages/stream_chat_persistence/lib/src/dao/user_dao.dart b/packages/stream_chat_persistence/lib/src/dao/user_dao.dart new file mode 100644 index 00000000..630a8252 --- /dev/null +++ b/packages/stream_chat_persistence/lib/src/dao/user_dao.dart @@ -0,0 +1,25 @@ +import 'package:moor/moor.dart'; +import 'package:stream_chat/stream_chat.dart'; +import 'package:stream_chat_persistence/src/db/moor_chat_database.dart'; +import 'package:stream_chat_persistence/src/entity/users.dart'; +import '../mapper/user_mapper.dart'; + +part 'user_dao.g.dart'; + +/// +@UseDao(tables: [Users]) +class UserDao extends DatabaseAccessor with _$UserDaoMixin { + /// + UserDao(MoorChatDatabase db) : super(db); + + /// + Future updateUsers(List userList) { + return batch( + (it) => it.insertAll( + users, + userList.map((u) => u.toEntity()).toList(), + mode: InsertMode.insertOrReplace, + ), + ); + } +} diff --git a/packages/stream_chat_persistence/lib/src/db/moor_chat_database.dart b/packages/stream_chat_persistence/lib/src/db/moor_chat_database.dart new file mode 100644 index 00000000..21447981 --- /dev/null +++ b/packages/stream_chat_persistence/lib/src/db/moor_chat_database.dart @@ -0,0 +1,83 @@ +import 'package:moor/isolate.dart'; +import 'package:moor/moor.dart'; +import 'package:stream_chat/stream_chat.dart'; + +import '../entity/entity.dart'; +import '../dao/dao.dart'; +import 'shared/shared_db.dart'; + +part 'moor_chat_database.g.dart'; + +LazyDatabase _openConnection( + String dbName, { + logStatements = false, +}) { + return LazyDatabase(() async { + return await SharedDB.constructDatabase( + dbName, + logStatements: logStatements, + ); + }); +} + +/// +@UseMoor(tables: [ + Channels, + Messages, + Reactions, + Users, + Members, + Reads, + ChannelQueries, + ConnectionEvents, +], daos: [ + UserDao, + ChannelDao, + MessageDao, + MemberDao, + ReactionDao, + ReadDao, + ChannelQueryDao, + ConnectionEventDao, +]) +class MoorChatDatabase extends _$MoorChatDatabase { + /// Instantiate a new database instance + MoorChatDatabase( + String dbName, { + logStatements = false, + }) : super(_openConnection( + dbName, + logStatements: logStatements, + )); + + /// Instantiate a new database instance + MoorChatDatabase.connect( + this._isolate, + DatabaseConnection connection, + ) : super.connect(connection); + + MoorIsolate _isolate; + + // you should bump this number whenever you change or add a table definition. + @override + int get schemaVersion => 1; + + @override + MigrationStrategy get migration => MigrationStrategy( + onUpgrade: (openingDetails, before, after) async { + if (before != after) { + final m = createMigrator(); + for (final table in allTables) { + await m.deleteTable(table.actualTableName); + await m.createTable(table); + } + } + }, + ); + + /// Closes the database instance + Future disconnect() async { + await _isolate?.shutdownAll(); + await close(); + } +} diff --git a/packages/stream_chat_persistence/lib/src/db/shared/native_db.dart b/packages/stream_chat_persistence/lib/src/db/shared/native_db.dart new file mode 100644 index 00000000..198b9010 --- /dev/null +++ b/packages/stream_chat_persistence/lib/src/db/shared/native_db.dart @@ -0,0 +1,87 @@ +//ignore_for_file: public_member_api_docs + +import 'dart:io'; +import 'dart:isolate'; +import 'package:moor/ffi.dart'; +import 'package:moor/isolate.dart'; +import 'package:moor/moor.dart'; +import 'package:path/path.dart'; +import 'package:path_provider/path_provider.dart'; + +import '../moor_chat_database.dart'; + +class SharedDB { + static Future constructDatabase( + String dbName, { + bool logStatements = false, + }) async { + if (Platform.isIOS || Platform.isAndroid) { + final dir = await getApplicationDocumentsDirectory(); + final path = join(dir.path, '$dbName.sqlite'); + final file = File(path); + return VmDatabase(file, logStatements: logStatements); + } + if (Platform.isMacOS || Platform.isLinux) { + final file = File('$dbName.sqlite'); + return VmDatabase(file, logStatements: logStatements); + } + return VmDatabase.memory(logStatements: logStatements); + } + + static void _startBackground(_IsolateStartRequest request) { + final executor = LazyDatabase(() async { + return VmDatabase( + File(request.targetPath), + logStatements: request.logStatements, + ); + }); + final moorIsolate = MoorIsolate.inCurrent( + () => DatabaseConnection.fromExecutor(executor), + ); + request.sendMoorIsolate.send(moorIsolate); + } + + static Future _createMoorIsolate( + String dbName, { + bool logStatements = false, + }) async { + final dir = await getApplicationDocumentsDirectory(); + final path = join(dir.path, '$dbName.sqlite'); + + final receivePort = ReceivePort(); + await Isolate.spawn( + _startBackground, + _IsolateStartRequest( + receivePort.sendPort, + path, + logStatements: logStatements, + ), + ); + + return (await receivePort.first as MoorIsolate); + } + + static Future constructOfflineStorage( + String dbName, { + bool logStatements = false, + }) async { + final isolate = await _createMoorIsolate( + dbName, + logStatements: logStatements, + ); + final connection = await isolate.connect(); + return MoorChatDatabase.connect(isolate, connection); + } +} + +class _IsolateStartRequest { + final SendPort sendMoorIsolate; + final String targetPath; + final bool logStatements; + + const _IsolateStartRequest( + this.sendMoorIsolate, + this.targetPath, { + this.logStatements = false, + }); +} diff --git a/packages/stream_chat_persistence/lib/src/db/shared/shared_db.dart b/packages/stream_chat_persistence/lib/src/db/shared/shared_db.dart new file mode 100644 index 00000000..25120fcf --- /dev/null +++ b/packages/stream_chat_persistence/lib/src/db/shared/shared_db.dart @@ -0,0 +1,3 @@ +export 'unsupported_db.dart' + if (dart.library.io) 'native_db.dart' // implementation using dart:io + if (dart.library.html) 'web_db.dart'; diff --git a/packages/stream_chat_persistence/lib/src/db/shared/unsupported_db.dart b/packages/stream_chat_persistence/lib/src/db/shared/unsupported_db.dart new file mode 100644 index 00000000..7415fdba --- /dev/null +++ b/packages/stream_chat_persistence/lib/src/db/shared/unsupported_db.dart @@ -0,0 +1,18 @@ +//ignore_for_file: public_member_api_docs +//ignore_for_file: always_declare_return_types + +class SharedDB { + static constructDatabase( + String dbName, { + bool logStatements = false, + }) { + throw 'Unsupported Platform'; + } + + static constructOfflineStorage( + String dbName, { + logStatements = false, + }) { + throw 'Unsupported Platform'; + } +} diff --git a/packages/stream_chat_persistence/lib/src/db/shared/web_db.dart b/packages/stream_chat_persistence/lib/src/db/shared/web_db.dart new file mode 100644 index 00000000..31b4f4b6 --- /dev/null +++ b/packages/stream_chat_persistence/lib/src/db/shared/web_db.dart @@ -0,0 +1,21 @@ +//ignore_for_file: public_member_api_docs +//ignore_for_file: always_declare_return_types +import 'package:moor/moor_web.dart'; + +import '../moor_chat_database.dart'; + +class SharedDB { + static constructDatabase( + String dbName, { + bool logStatements = false, + }) async { + return WebDatabase(dbName, logStatements: logStatements); + } + + static Future constructOfflineStorage( + String dbName, { + bool logStatements = false, + }) async { + return MoorChatDatabase(dbName, logStatements: logStatements); + } +} diff --git a/packages/stream_chat_persistence/lib/src/db/stream_chat_database_impl.dart b/packages/stream_chat_persistence/lib/src/db/stream_chat_database_impl.dart new file mode 100644 index 00000000..de9bbe45 --- /dev/null +++ b/packages/stream_chat_persistence/lib/src/db/stream_chat_database_impl.dart @@ -0,0 +1,222 @@ +import 'package:stream_chat/stream_chat.dart'; + +import 'moor_chat_database.dart'; +import 'shared/shared_db.dart'; + +/// +class StreamChatDatabaseImpl implements StreamChatDatabase { + /// + StreamChatDatabaseImpl( + this._userId, { + Logger logger, + }) : _logger = logger, + assert(_userId != null); + + final String _userId; + final Logger _logger; + MoorChatDatabase _db; + + bool get _debugAssertConnected { + assert(() { + if (_db == null) { + throw Exception( + 'A $runtimeType was used after being disconnected.\n' + 'Once you have called disconnect() on a $runtimeType, it can no longer be used.', + ); + } + return true; + }()); + return true; + } + + @override + Future connect({ + bool connectBackground = false, + bool logStatements = false, + }) async { + if (_db != null) { + throw Exception( + 'An instance of StreamChatDatabase is already connected.\n' + 'disconnect the previous instance before connecting again.', + ); + } + + final dbName = 'db_$_userId'; + if (connectBackground) { + _logger?.info('Connecting on background isolate'); + _db = await SharedDB.constructOfflineStorage( + dbName, + logStatements: logStatements, + ); + } else { + _logger?.info('Connecting on a regular isolate'); + _db = MoorChatDatabase(dbName, logStatements: logStatements); + } + } + + @override + Future getConnectionInfo() { + return _db.connectionEventDao.connectionEvent; + } + + @override + Future updateConnectionInfo(Event event) { + return _db.connectionEventDao.updateConnectionEvent(event); + } + + @override + Future updateLastSyncAt(DateTime lastSyncAt) { + return _db.connectionEventDao.updateLastSyncAt(lastSyncAt); + } + + @override + Future getLastSyncAt() { + return _db.connectionEventDao.lastSyncAt; + } + + @override + Future deleteChannelByCids(List cids) { + return _db.channelDao.deleteChannelByCids(cids); + } + + @override + Future> getChannelCids() => _db.channelDao.cids; + + @override + Future deleteMessageByIds(List messageIds) { + return _db.messageDao.deleteMessageByIds(messageIds); + } + + @override + Future deleteMessageByCids(List cids) { + return _db.messageDao.deleteMessageByCids(cids); + } + + @override + Future> getMembersByCid(String cid) { + return _db.memberDao.getMembersByCid(cid); + } + + @override + Future getChannelByCid(String cid) { + return _db.channelDao.getChannelByCid(cid); + } + + @override + Future> getMessagesByCid( + String cid, { + int limit = 20, + String messageLessThan, + String messageGreaterThan, + }) { + return _db.messageDao.getMessagesByCid( + cid, + limit: limit, + messageLessThan: messageLessThan, + messageGreaterThan: messageGreaterThan, + ); + } + + @override + Future> getReadsByCid(String cid) { + return _db.readDao.getReadsByCid(cid); + } + + @override + Future>> getChannelThreads(String cid) async { + final messages = await _db.messageDao.getThreadMessages(cid); + final messageByParentIdDictionary = >{}; + for (final message in messages) { + final parentId = message.parentId; + messageByParentIdDictionary[parentId] = [ + ...messageByParentIdDictionary[parentId] ?? [], + message + ]; + } + return messageByParentIdDictionary; + } + + @override + Future> getReplies( + String parentId, { + String lessThan, + }) { + return _db.messageDao.getThreadMessagesByParentId( + parentId, + lessThan: lessThan, + ); + } + + @override + Future> getChannelStates({ + Map filter, + List sort = const [], + PaginationParams paginationParams, + }) { + return _db.channelQueryDao.getChannelStates( + filter: filter, + sort: sort, + paginationParams: paginationParams, + ); + } + + @override + Future updateChannelQueries( + Map filter, + List cids, + bool clearQueryCache, + ) { + return _db.channelQueryDao.updateChannelQueries( + filter, + cids, + clearQueryCache, + ); + } + + @override + Future updateChannels(List channels) { + return _db.channelDao.updateChannels(channels); + } + + @override + Future updateMembers(String cid, List members) { + return _db.memberDao.updateMembers(cid, members); + } + + @override + Future updateMessages(String cid, List messages) { + return _db.messageDao.updateMessages(cid, messages); + } + + @override + Future updateReactions(List reactions) { + return _db.reactionDao.updateReactions(reactions); + } + + @override + Future updateReads(String cid, List reads) { + return _db.readDao.updateReads(cid, reads); + } + + @override + Future updateUsers(List users) { + return _db.userDao.updateUsers(users); + } + + @override + Future disconnect({bool flush = false}) async { + if (_db != null) { + _logger?.info('Disconnecting'); + if (flush) { + _logger?.info('Flushing'); + await _db.batch((batch) { + _db.allTables.forEach((table) { + _db.delete(table).go(); + }); + }); + } + await _db.disconnect(); + _db = null; + } + } +} diff --git a/packages/stream_chat_persistence/lib/src/entity/channel_queries.dart b/packages/stream_chat_persistence/lib/src/entity/channel_queries.dart new file mode 100644 index 00000000..fefdc925 --- /dev/null +++ b/packages/stream_chat_persistence/lib/src/entity/channel_queries.dart @@ -0,0 +1,14 @@ +import 'package:moor/moor.dart'; + +@DataClassName('ChannelQueryEntity') +class ChannelQueries extends Table { + TextColumn get queryHash => text()(); + + TextColumn get channelCid => text()(); + + @override + Set get primaryKey => { + queryHash, + channelCid, + }; +} diff --git a/packages/stream_chat_persistence/lib/src/entity/channels.dart b/packages/stream_chat_persistence/lib/src/entity/channels.dart new file mode 100644 index 00000000..9f652ed1 --- /dev/null +++ b/packages/stream_chat_persistence/lib/src/entity/channels.dart @@ -0,0 +1,32 @@ +import 'package:moor/moor.dart'; +import 'package:stream_chat_persistence/src/converter/map_converter.dart'; + +@DataClassName('ChannelEntity') +class Channels extends Table { + TextColumn get id => text()(); + + TextColumn get type => text()(); + + TextColumn get cid => text()(); + + TextColumn get config => text().map(MapConverter())(); + + BoolColumn get frozen => boolean().withDefault(Constant(false))(); + + DateTimeColumn get lastMessageAt => dateTime().nullable()(); + + DateTimeColumn get createdAt => dateTime().nullable()(); + + DateTimeColumn get updatedAt => dateTime().nullable()(); + + DateTimeColumn get deletedAt => dateTime().nullable()(); + + IntColumn get memberCount => integer().nullable()(); + + TextColumn get createdById => text().nullable()(); + + TextColumn get extraData => text().nullable().map(MapConverter())(); + + @override + Set get primaryKey => {cid}; +} diff --git a/packages/stream_chat_persistence/lib/src/entity/connection_events.dart b/packages/stream_chat_persistence/lib/src/entity/connection_events.dart new file mode 100644 index 00000000..311f2da0 --- /dev/null +++ b/packages/stream_chat_persistence/lib/src/entity/connection_events.dart @@ -0,0 +1,19 @@ +import 'package:moor/moor.dart'; + +@DataClassName('ConnectionEventEntity') +class ConnectionEvents extends Table { + IntColumn get id => integer()(); + + TextColumn get ownUserId => text().nullable()(); + + IntColumn get totalUnreadCount => integer().nullable()(); + + IntColumn get unreadChannels => integer().nullable()(); + + DateTimeColumn get lastEventAt => dateTime().nullable()(); + + DateTimeColumn get lastSyncAt => dateTime().nullable()(); + + @override + Set get primaryKey => {id}; +} diff --git a/packages/stream_chat_persistence/lib/src/entity/entity.dart b/packages/stream_chat_persistence/lib/src/entity/entity.dart new file mode 100644 index 00000000..8751f538 --- /dev/null +++ b/packages/stream_chat_persistence/lib/src/entity/entity.dart @@ -0,0 +1,8 @@ +export 'channels.dart'; +export 'messages.dart'; +export 'reactions.dart'; +export 'users.dart'; +export 'members.dart'; +export 'reads.dart'; +export 'channel_queries.dart'; +export 'connection_events.dart'; diff --git a/packages/stream_chat_persistence/lib/src/entity/members.dart b/packages/stream_chat_persistence/lib/src/entity/members.dart new file mode 100644 index 00000000..39e224e0 --- /dev/null +++ b/packages/stream_chat_persistence/lib/src/entity/members.dart @@ -0,0 +1,33 @@ +import 'package:moor/moor.dart'; + +@DataClassName('MemberEntity') +class Members extends Table { + TextColumn get userId => text()(); + + TextColumn get channelCid => + text().customConstraint('REFERENCES channels(cid) ON DELETE CASCADE')(); + + TextColumn get role => text().nullable()(); + + DateTimeColumn get inviteAcceptedAt => dateTime().nullable()(); + + DateTimeColumn get inviteRejectedAt => dateTime().nullable()(); + + BoolColumn get invited => boolean().nullable()(); + + BoolColumn get banned => boolean().nullable()(); + + BoolColumn get shadowBanned => boolean().nullable()(); + + BoolColumn get isModerator => boolean().nullable()(); + + DateTimeColumn get createdAt => dateTime()(); + + DateTimeColumn get updatedAt => dateTime().nullable()(); + + @override + Set get primaryKey => { + userId, + channelCid, + }; +} diff --git a/packages/stream_chat_persistence/lib/src/entity/messages.dart b/packages/stream_chat_persistence/lib/src/entity/messages.dart new file mode 100644 index 00000000..10c98315 --- /dev/null +++ b/packages/stream_chat_persistence/lib/src/entity/messages.dart @@ -0,0 +1,54 @@ +import 'package:moor/moor.dart'; +import 'package:stream_chat_persistence/src/converter/list_converter.dart'; +import 'package:stream_chat_persistence/src/converter/map_converter.dart'; +import 'package:stream_chat_persistence/src/converter/message_sending_status_converter.dart'; + +@DataClassName('MessageEntity') +class Messages extends Table { + TextColumn get id => text()(); + + TextColumn get messageText => text().nullable()(); + + TextColumn get attachments => + text().nullable().map(ListConverter())(); + + IntColumn get status => + integer().nullable().map(MessageSendingStatusConverter())(); + + TextColumn get type => text().nullable()(); + + TextColumn get mentionedUsers => + text().nullable().map(ListConverter())(); + + TextColumn get reactionCounts => text().nullable().map(MapConverter())(); + + TextColumn get reactionScores => text().nullable().map(MapConverter())(); + + TextColumn get parentId => text().nullable()(); + + TextColumn get quotedMessageId => text().nullable()(); + + IntColumn get replyCount => integer().nullable()(); + + BoolColumn get showInChannel => boolean().nullable()(); + + BoolColumn get shadowed => boolean().nullable()(); + + TextColumn get command => text().nullable()(); + + DateTimeColumn get createdAt => dateTime()(); + + DateTimeColumn get updatedAt => dateTime().nullable()(); + + DateTimeColumn get deletedAt => dateTime().nullable()(); + + TextColumn get userId => text().nullable()(); + + TextColumn get channelCid => text().nullable().customConstraint( + 'NULLABLE REFERENCES channels(cid) ON DELETE CASCADE')(); + + TextColumn get extraData => text().nullable().map(MapConverter())(); + + @override + Set get primaryKey => {id}; +} diff --git a/packages/stream_chat_persistence/lib/src/entity/reactions.dart b/packages/stream_chat_persistence/lib/src/entity/reactions.dart new file mode 100644 index 00000000..a20ffbeb --- /dev/null +++ b/packages/stream_chat_persistence/lib/src/entity/reactions.dart @@ -0,0 +1,25 @@ +import 'package:moor/moor.dart'; +import 'package:stream_chat_persistence/src/converter/map_converter.dart'; + +@DataClassName('ReactionEntity') +class Reactions extends Table { + TextColumn get userId => text()(); + + TextColumn get messageId => + text().customConstraint('REFERENCES messages(id) ON DELETE CASCADE')(); + + TextColumn get type => text()(); + + DateTimeColumn get createdAt => dateTime()(); + + IntColumn get score => integer().nullable()(); + + TextColumn get extraData => text().nullable().map(MapConverter())(); + + @override + Set get primaryKey => { + messageId, + type, + userId, + }; +} diff --git a/packages/stream_chat_persistence/lib/src/entity/reads.dart b/packages/stream_chat_persistence/lib/src/entity/reads.dart new file mode 100644 index 00000000..c36dceef --- /dev/null +++ b/packages/stream_chat_persistence/lib/src/entity/reads.dart @@ -0,0 +1,19 @@ +import 'package:moor/moor.dart'; + +@DataClassName('ReadEntity') +class Reads extends Table { + DateTimeColumn get lastRead => dateTime()(); + + TextColumn get userId => text()(); + + TextColumn get channelCid => + text().customConstraint('REFERENCES channels(cid) ON DELETE CASCADE')(); + + IntColumn get unreadMessages => integer().nullable()(); + + @override + Set get primaryKey => { + userId, + channelCid, + }; +} diff --git a/packages/stream_chat_persistence/lib/src/entity/users.dart b/packages/stream_chat_persistence/lib/src/entity/users.dart new file mode 100644 index 00000000..4beee396 --- /dev/null +++ b/packages/stream_chat_persistence/lib/src/entity/users.dart @@ -0,0 +1,24 @@ +import 'package:moor/moor.dart'; +import 'package:stream_chat_persistence/src/converter/map_converter.dart'; + +@DataClassName('UserEntity') +class Users extends Table { + TextColumn get id => text()(); + + TextColumn get role => text().nullable()(); + + DateTimeColumn get createdAt => dateTime().nullable()(); + + DateTimeColumn get updatedAt => dateTime().nullable()(); + + DateTimeColumn get lastActive => dateTime().nullable()(); + + BoolColumn get online => boolean().nullable()(); + + BoolColumn get banned => boolean().nullable()(); + + TextColumn get extraData => text().nullable().map(MapConverter())(); + + @override + Set get primaryKey => {id}; +} diff --git a/packages/stream_chat_persistence/lib/src/mapper/channel_mapper.dart b/packages/stream_chat_persistence/lib/src/mapper/channel_mapper.dart new file mode 100644 index 00000000..cdabf17f --- /dev/null +++ b/packages/stream_chat_persistence/lib/src/mapper/channel_mapper.dart @@ -0,0 +1,61 @@ +import 'package:stream_chat/stream_chat.dart'; +import 'user_mapper.dart'; +import 'package:stream_chat_persistence/src/db/moor_chat_database.dart'; + +/// +extension ChannelEntityX on ChannelEntity { + /// + ChannelModel toChannelModel({User createdBy}) { + final config = ChannelConfig.fromJson(this.config ?? {}); + return ChannelModel( + id: id, + config: config, + type: type, + frozen: frozen, + createdAt: createdAt, + updatedAt: updatedAt, + memberCount: memberCount, + cid: cid, + lastMessageAt: lastMessageAt, + deletedAt: deletedAt, + extraData: extraData, + createdBy: createdBy, + ); + } + + /// + ChannelState toChannelState({ + User createdBy, + List members, + List reads, + List messages, + }) { + return ChannelState( + members: members, + read: reads, + messages: messages, + channel: toChannelModel(createdBy: createdBy), + ); + } +} + +/// +extension ChannelModelX on ChannelModel { + /// + ChannelEntity toEntity() { + return ChannelEntity( + id: id, + type: type, + cid: cid, + config: config.toJson(), + frozen: frozen, + lastMessageAt: lastMessageAt, + createdAt: createdAt, + updatedAt: updatedAt, + deletedAt: deletedAt, + memberCount: memberCount, + createdById: createdBy.id, + extraData: extraData, + ); + } +} diff --git a/packages/stream_chat_persistence/lib/src/mapper/event_mapper.dart b/packages/stream_chat_persistence/lib/src/mapper/event_mapper.dart new file mode 100644 index 00000000..41e90205 --- /dev/null +++ b/packages/stream_chat_persistence/lib/src/mapper/event_mapper.dart @@ -0,0 +1,15 @@ +import 'package:stream_chat/stream_chat.dart'; +import 'user_mapper.dart'; +import 'package:stream_chat_persistence/src/db/moor_chat_database.dart'; + +/// +extension ConnectionEventX on ConnectionEventEntity { + /// + Event toEvent({User user}) { + return Event( + me: user, + totalUnreadCount: totalUnreadCount, + unreadChannels: unreadChannels, + ); + } +} diff --git a/packages/stream_chat_persistence/lib/src/mapper/mapper.dart b/packages/stream_chat_persistence/lib/src/mapper/mapper.dart new file mode 100644 index 00000000..efedde22 --- /dev/null +++ b/packages/stream_chat_persistence/lib/src/mapper/mapper.dart @@ -0,0 +1,7 @@ +export 'user_mapper.dart'; +export 'reaction_mapper.dart'; +export 'channel_mapper.dart'; +export 'event_mapper.dart'; +export 'member_mapper.dart'; +export 'read_mapper.dart'; +export 'message_mapper.dart'; \ No newline at end of file diff --git a/packages/stream_chat_persistence/lib/src/mapper/member_mapper.dart b/packages/stream_chat_persistence/lib/src/mapper/member_mapper.dart new file mode 100644 index 00000000..42f463ba --- /dev/null +++ b/packages/stream_chat_persistence/lib/src/mapper/member_mapper.dart @@ -0,0 +1,43 @@ +import 'package:stream_chat/stream_chat.dart'; +import 'package:stream_chat_persistence/src/db/moor_chat_database.dart'; +import 'user_mapper.dart'; + +/// +extension MemberEntityX on MemberEntity { + /// + Member toMember({User user}) { + return Member( + user: user, + userId: userId, + banned: banned, + shadowBanned: shadowBanned, + updatedAt: updatedAt, + createdAt: createdAt, + role: role, + inviteAcceptedAt: inviteAcceptedAt, + invited: invited, + inviteRejectedAt: inviteRejectedAt, + isModerator: isModerator, + ); + } +} + +/// +extension MemberX on Member { + /// + MemberEntity toEntity({String cid}) { + return MemberEntity( + userId: user?.id, + banned: banned, + shadowBanned: shadowBanned, + channelCid: cid, + createdAt: createdAt, + isModerator: isModerator, + inviteRejectedAt: inviteRejectedAt, + invited: invited, + inviteAcceptedAt: inviteAcceptedAt, + role: role, + updatedAt: updatedAt, + ); + } +} diff --git a/packages/stream_chat_persistence/lib/src/mapper/message_mapper.dart b/packages/stream_chat_persistence/lib/src/mapper/message_mapper.dart new file mode 100644 index 00000000..4ea001a1 --- /dev/null +++ b/packages/stream_chat_persistence/lib/src/mapper/message_mapper.dart @@ -0,0 +1,70 @@ +import 'dart:convert'; + +import 'package:stream_chat/stream_chat.dart'; +import 'package:stream_chat_persistence/src/db/moor_chat_database.dart'; + +/// +extension MessageEntityX on MessageEntity { + /// + Message toMessage({ + User user, + List latestReactions, + List ownReactions, + Message quotedMessage, + }) { + return Message( + shadowed: shadowed, + latestReactions: latestReactions, + ownReactions: ownReactions, + attachments: attachments?.map((it) { + final json = jsonDecode(it); + return Attachment.fromJson(json); + })?.toList(), + createdAt: createdAt, + extraData: extraData, + updatedAt: updatedAt, + id: id, + type: type, + status: status, + command: command, + parentId: parentId, + quotedMessageId: quotedMessageId, + quotedMessage: quotedMessage, + reactionCounts: reactionCounts, + reactionScores: reactionScores, + replyCount: replyCount, + showInChannel: showInChannel, + text: messageText, + user: user, + deletedAt: deletedAt, + ); + } +} + +/// +extension MessageX on Message { + /// + MessageEntity toEntity({String cid}) { + return MessageEntity( + id: id, + attachments: attachments.map((it) => jsonEncode(it)).toList(), + channelCid: cid, + type: type, + parentId: parentId, + quotedMessageId: quotedMessageId, + command: command, + createdAt: createdAt, + shadowed: shadowed, + showInChannel: showInChannel, + replyCount: replyCount, + reactionScores: reactionScores, + reactionCounts: reactionCounts, + status: status, + updatedAt: updatedAt, + extraData: extraData, + userId: user?.id, + deletedAt: deletedAt, + messageText: text, + ); + } +} diff --git a/packages/stream_chat_persistence/lib/src/mapper/reaction_mapper.dart b/packages/stream_chat_persistence/lib/src/mapper/reaction_mapper.dart new file mode 100644 index 00000000..d468d11c --- /dev/null +++ b/packages/stream_chat_persistence/lib/src/mapper/reaction_mapper.dart @@ -0,0 +1,33 @@ +import 'package:stream_chat/stream_chat.dart'; +import 'package:stream_chat_persistence/src/db/moor_chat_database.dart'; + +/// +extension ReactionEntityX on ReactionEntity { + /// + Reaction toReaction({User user}) { + return Reaction( + extraData: extraData, + type: type, + createdAt: createdAt, + userId: userId, + user: user, + messageId: messageId, + score: score, + ); + } +} + +/// +extension ReactionX on Reaction { + /// + ReactionEntity toEntity() { + return ReactionEntity( + extraData: extraData, + type: type, + createdAt: createdAt, + userId: userId, + messageId: messageId, + score: score, + ); + } +} diff --git a/packages/stream_chat_persistence/lib/src/mapper/read_mapper.dart b/packages/stream_chat_persistence/lib/src/mapper/read_mapper.dart new file mode 100644 index 00000000..0f9ea560 --- /dev/null +++ b/packages/stream_chat_persistence/lib/src/mapper/read_mapper.dart @@ -0,0 +1,28 @@ +import 'package:stream_chat/stream_chat.dart'; +import 'package:stream_chat_persistence/src/db/moor_chat_database.dart'; +import 'user_mapper.dart'; + +/// +extension ReadEntityX on ReadEntity { + /// + Read toRead({User user}) { + return Read( + user: user, + lastRead: lastRead, + unreadMessages: unreadMessages, + ); + } +} + +/// +extension ReadX on Read { + /// + ReadEntity toEntity({String cid}) { + return ReadEntity( + lastRead: lastRead, + userId: user?.id, + channelCid: cid, + unreadMessages: unreadMessages, + ); + } +} diff --git a/packages/stream_chat_persistence/lib/src/mapper/user_mapper.dart b/packages/stream_chat_persistence/lib/src/mapper/user_mapper.dart new file mode 100644 index 00000000..cb775ab7 --- /dev/null +++ b/packages/stream_chat_persistence/lib/src/mapper/user_mapper.dart @@ -0,0 +1,36 @@ +import 'package:stream_chat/stream_chat.dart'; +import 'package:stream_chat_persistence/src/db/moor_chat_database.dart'; + +/// +extension UserEntityX on UserEntity { + /// + User toUser() { + return User( + id: id, + updatedAt: updatedAt, + role: role, + online: online, + lastActive: lastActive, + extraData: extraData, + banned: banned, + createdAt: createdAt, + ); + } +} + +/// +extension UserX on User { + /// + UserEntity toEntity() { + return UserEntity( + id: id, + role: role, + createdAt: createdAt, + updatedAt: updatedAt, + lastActive: lastActive, + online: online, + banned: banned, + extraData: extraData, + ); + } +} diff --git a/packages/stream_chat_persistence/lib/stream_chat_persistence.dart b/packages/stream_chat_persistence/lib/stream_chat_persistence.dart new file mode 100644 index 00000000..3388d36e --- /dev/null +++ b/packages/stream_chat_persistence/lib/stream_chat_persistence.dart @@ -0,0 +1,3 @@ +library stream_chat_persistence; + +export 'src/db/stream_chat_database_impl.dart'; diff --git a/packages/stream_chat_persistence/pubspec.yaml b/packages/stream_chat_persistence/pubspec.yaml new file mode 100644 index 00000000..9ba42d1a --- /dev/null +++ b/packages/stream_chat_persistence/pubspec.yaml @@ -0,0 +1,18 @@ +name: stream_chat_persistence +description: A new Flutter package. +version: 0.0.1 +author: +homepage: + +environment: + sdk: ">=2.7.0 <3.0.0" + +dependencies: + moor: ^3.4.0 + stream_chat: + path: ../dart_client + +dev_dependencies: + test: ^1.15.7 + build_runner: ^1.10.13 + moor_generator: ^3.4.1 From 82fee14f68ba537958d7d80f987b72589f46a69d Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Mon, 25 Jan 2021 19:23:38 +0530 Subject: [PATCH 1023/1140] [StreamChatPersistence] Ran formatter Signed-off-by: Sahil Kumar --- packages/stream_chat_persistence/lib/src/mapper/mapper.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/stream_chat_persistence/lib/src/mapper/mapper.dart b/packages/stream_chat_persistence/lib/src/mapper/mapper.dart index efedde22..8d19729d 100644 --- a/packages/stream_chat_persistence/lib/src/mapper/mapper.dart +++ b/packages/stream_chat_persistence/lib/src/mapper/mapper.dart @@ -4,4 +4,4 @@ export 'channel_mapper.dart'; export 'event_mapper.dart'; export 'member_mapper.dart'; export 'read_mapper.dart'; -export 'message_mapper.dart'; \ No newline at end of file +export 'message_mapper.dart'; From 0f7a16dc6d8dd5be8fb3e662406b641103a16894 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Mon, 25 Jan 2021 19:29:32 +0530 Subject: [PATCH 1024/1140] feat: Added channel_list new implementation, fixed upper repo --- .../lib/src/channel_file_display_screen.dart | 1 - .../lib/src/channel_header.dart | 1 - .../lib/src/channel_list_view.dart | 346 +++++++---------- .../lib/src/channel_media_display_screen.dart | 1 - .../flutter_widgets/lib/src/channel_name.dart | 1 - .../lib/src/channels_bloc.dart | 185 --------- .../lib/src/full_screen_media.dart | 1 - .../flutter_widgets/lib/src/image_header.dart | 2 +- .../lib/src/lazy_load_scroll_view.dart | 148 -------- .../lib/src/media_list_view.dart | 1 - .../lib/src/message_actions_modal.dart | 2 +- .../lib/src/message_input.dart | 1 - .../lib/src/message_list_view.dart | 2 - .../lib/src/message_search_bloc.dart | 150 -------- .../lib/src/message_search_list_view.dart | 3 +- .../lib/src/stream_channel.dart | 356 ------------------ .../flutter_widgets/lib/src/stream_chat.dart | 73 +--- .../lib/src/typing_indicator.dart | 2 +- .../lib/src/user_list_view.dart | 41 -- .../flutter_widgets/lib/src/users_bloc.dart | 108 ------ .../lib/stream_chat_flutter.dart | 8 +- packages/flutter_widgets/pubspec.yaml | 4 +- .../lib/src/channel_list_core.dart | 20 +- 23 files changed, 160 insertions(+), 1297 deletions(-) delete mode 100644 packages/flutter_widgets/lib/src/channels_bloc.dart delete mode 100644 packages/flutter_widgets/lib/src/lazy_load_scroll_view.dart delete mode 100644 packages/flutter_widgets/lib/src/message_search_bloc.dart delete mode 100644 packages/flutter_widgets/lib/src/stream_channel.dart delete mode 100644 packages/flutter_widgets/lib/src/users_bloc.dart diff --git a/packages/flutter_widgets/lib/src/channel_file_display_screen.dart b/packages/flutter_widgets/lib/src/channel_file_display_screen.dart index d5aef38c..244729a4 100644 --- a/packages/flutter_widgets/lib/src/channel_file_display_screen.dart +++ b/packages/flutter_widgets/lib/src/channel_file_display_screen.dart @@ -1,5 +1,4 @@ import 'package:flutter/material.dart'; -import 'package:stream_chat_flutter/src/lazy_load_scroll_view.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; class ChannelFileDisplayScreen extends StatefulWidget { diff --git a/packages/flutter_widgets/lib/src/channel_header.dart b/packages/flutter_widgets/lib/src/channel_header.dart index 8b920f23..73ee23a5 100644 --- a/packages/flutter_widgets/lib/src/channel_header.dart +++ b/packages/flutter_widgets/lib/src/channel_header.dart @@ -9,7 +9,6 @@ import 'package:stream_chat_flutter/src/stream_chat_theme.dart'; import '../stream_chat_flutter.dart'; import './channel_name.dart'; import 'channel_image.dart'; -import 'stream_channel.dart'; /// ![screenshot](https://raw.githubusercontent.com/GetStream/stream-chat-flutter/master/screenshots/channel_header.png) /// ![screenshot](https://raw.githubusercontent.com/GetStream/stream-chat-flutter/master/screenshots/channel_header_paint.png) diff --git a/packages/flutter_widgets/lib/src/channel_list_view.dart b/packages/flutter_widgets/lib/src/channel_list_view.dart index 0cc7634b..617b7ce9 100644 --- a/packages/flutter_widgets/lib/src/channel_list_view.dart +++ b/packages/flutter_widgets/lib/src/channel_list_view.dart @@ -5,16 +5,13 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_slidable/flutter_slidable.dart'; import 'package:shimmer/shimmer.dart'; -import 'package:stream_chat/stream_chat.dart'; -import 'package:stream_chat_flutter/src/channels_bloc.dart'; import 'package:stream_chat_flutter/src/stream_svg_icon.dart'; import 'package:stream_chat_flutter/src/utils.dart'; +import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; import '../stream_chat_flutter.dart'; import 'channel_bottom_sheet.dart'; import 'channel_preview.dart'; -import 'stream_channel.dart'; -import 'stream_chat.dart'; /// Callback called when tapping on a channel typedef ChannelTapCallback = void Function(Channel, Widget); @@ -158,168 +155,161 @@ class _ChannelListViewState extends State with WidgetsBindingObserver { final ScrollController _scrollController = ScrollController(); final SlidableController _slideController = SlidableController(); + final ChannelListController _channelListController = ChannelListController(); @override Widget build(BuildContext context) { - final channelsBloc = ChannelsBloc.of(context); - if (!widget.pullToRefresh) { - return _buildListView(channelsBloc); + _channelListController.loadData(); } return RefreshIndicator( onRefresh: () async { - return channelsBloc.queryChannels( - filter: widget.filter, - sortOptions: widget.sort, - paginationParams: widget.pagination, - options: widget.options, - ); + _channelListController.loadData(); }, - child: _buildListView(channelsBloc), + child: ChannelListCore( + channelListController: _channelListController, + listBuilder: (context, list) { + return _buildListView(list); + }, + emptyBuilder: (BuildContext context) { + return _buildEmptyWidget(); + }, + errorBuilder: (Error error) { + return _buildErrorWidget(context); + }, + loadingBuilder: (BuildContext context) { + return _buildLoadingWidget(); + }, + pagination: widget.pagination, + options: widget.options, + sort: widget.sort, + filter: widget.filter, + ), ); } - StreamBuilder> _buildListView( - ChannelsBlocState channelsBlocState, + Widget _buildListView( + List channels, ) { - return StreamBuilder>( - stream: channelsBlocState.channelsStream, - builder: (context, snapshot) { - var child; - if (snapshot.hasError) { - child = _buildErrorWidget( - snapshot, - context, - channelsBlocState, - ); - } else if (!snapshot.hasData) { - child = _buildLoadingWidget(); - } else { - final channels = snapshot.data; + var child; - if (channels.isEmpty && widget.emptyBuilder != null) { - child = widget.emptyBuilder(context); - } - - if (channels.isEmpty && widget.emptyBuilder == null) { - child = LayoutBuilder( - builder: (context, viewportConstraints) { - return SingleChildScrollView( - physics: AlwaysScrollableScrollPhysics(), - child: Stack( - children: [ - ConstrainedBox( - constraints: BoxConstraints( - minHeight: viewportConstraints.maxHeight, - ), - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Padding( - padding: const EdgeInsets.all(8.0), - child: StreamSvgIcon.message( - size: 136, - color: StreamChatTheme.of(context) - .colorTheme - .greyGainsboro, - ), - ), - Padding( - padding: const EdgeInsets.all(8.0), - child: Text( - 'Let’s start chatting!', - style: StreamChatTheme.of(context) - .textTheme - .headline, - ), - ), - Padding( - padding: const EdgeInsets.symmetric( - vertical: 8.0, - horizontal: 52, - ), - child: Text( - 'How about sending your first message to a friend?', - textAlign: TextAlign.center, - style: StreamChatTheme.of(context) - .textTheme - .body - .copyWith( - color: StreamChatTheme.of(context) - .colorTheme - .grey, - ), - ), - ), - ], - ), - ), - if (widget.onStartChatPressed != null) - Positioned( - right: 0, - left: 0, - bottom: 32, - child: Center( - child: FlatButton( - onPressed: widget.onStartChatPressed, - child: Text( - 'Start a chat', - style: StreamChatTheme.of(context) - .textTheme - .bodyBold - .copyWith( - color: StreamChatTheme.of(context) - .colorTheme - .accentBlue, - ), - ), - ), - ), - ), - ], - ), - ); - }, - ); - } - - if (channels.isNotEmpty) { - if (widget.crossAxisCount > 1) { - child = GridView.builder( - padding: widget.padding, - gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( - crossAxisCount: widget.crossAxisCount), - itemCount: channels.length, - physics: AlwaysScrollableScrollPhysics(), - controller: _scrollController, - itemBuilder: (context, index) { - return _gridItemBuilder(context, index, channels); - }, - ); - } else { - child = ListView.separated( - padding: widget.padding, - physics: AlwaysScrollableScrollPhysics(), - itemCount: - channels.isNotEmpty ? channels.length + 1 : channels.length, - separatorBuilder: (_, index) { - if (widget.separatorBuilder != null) { - return widget.separatorBuilder(context, index); - } - return _separatorBuilder(context, index); - }, - itemBuilder: (context, index) { - return _listItemBuilder(context, index, channels); - }, - ); + if (channels.isNotEmpty) { + if (widget.crossAxisCount > 1) { + child = GridView.builder( + padding: widget.padding, + gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: widget.crossAxisCount), + itemCount: channels.length, + physics: AlwaysScrollableScrollPhysics(), + controller: _scrollController, + itemBuilder: (context, index) { + return _gridItemBuilder(context, index, channels); + }, + ); + } else { + child = ListView.separated( + padding: widget.padding, + physics: AlwaysScrollableScrollPhysics(), + itemCount: + channels.isNotEmpty ? channels.length + 1 : channels.length, + separatorBuilder: (_, index) { + if (widget.separatorBuilder != null) { + return widget.separatorBuilder(context, index); } - } - } + return _separatorBuilder(context, index); + }, + itemBuilder: (context, index) { + return _listItemBuilder(context, index, channels); + }, + ); + } + } - return AnimatedSwitcher( - child: child, - duration: Duration(milliseconds: 500), + return AnimatedSwitcher( + child: child, + duration: Duration(milliseconds: 500), + ); + } + + Widget _buildEmptyWidget() { + if (widget.emptyBuilder != null) { + return widget.emptyBuilder(context); + } + + return LayoutBuilder( + builder: (context, viewportConstraints) { + return SingleChildScrollView( + physics: AlwaysScrollableScrollPhysics(), + child: Stack( + children: [ + ConstrainedBox( + constraints: BoxConstraints( + minHeight: viewportConstraints.maxHeight, + ), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Padding( + padding: const EdgeInsets.all(8.0), + child: StreamSvgIcon.message( + size: 136, + color: StreamChatTheme.of(context) + .colorTheme + .greyGainsboro, + ), + ), + Padding( + padding: const EdgeInsets.all(8.0), + child: Text( + 'Let’s start chatting!', + style: StreamChatTheme.of(context).textTheme.headline, + ), + ), + Padding( + padding: const EdgeInsets.symmetric( + vertical: 8.0, + horizontal: 52, + ), + child: Text( + 'How about sending your first message to a friend?', + textAlign: TextAlign.center, + style: StreamChatTheme.of(context) + .textTheme + .body + .copyWith( + color: + StreamChatTheme.of(context).colorTheme.grey, + ), + ), + ), + ], + ), + ), + if (widget.onStartChatPressed != null) + Positioned( + right: 0, + left: 0, + bottom: 32, + child: Center( + child: FlatButton( + onPressed: widget.onStartChatPressed, + child: Text( + 'Start a chat', + style: StreamChatTheme.of(context) + .textTheme + .bodyBold + .copyWith( + color: StreamChatTheme.of(context) + .colorTheme + .accentBlue, + ), + ), + ), + ), + ), + ], + ), ); }, ); @@ -443,27 +433,8 @@ class _ChannelListViewState extends State } Widget _buildErrorWidget( - AsyncSnapshot> snapshot, BuildContext context, - ChannelsBlocState channelsBlocState, ) { - if (snapshot.error is Error) { - print((snapshot.error as Error).stackTrace); - } - - if (widget.errorBuilder != null) { - return widget.errorBuilder(snapshot.error); - } - - var message = snapshot.error.toString(); - if (snapshot.error is DioError) { - final dioError = snapshot.error as DioError; - if (dioError.type == DioErrorType.RESPONSE) { - message = dioError.message; - } else { - message = 'Check your connection and retry'; - } - } return Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, @@ -484,20 +455,9 @@ class _ChannelListViewState extends State ), style: Theme.of(context).textTheme.headline6, ), - Padding( - padding: const EdgeInsets.only( - top: 16.0, - ), - child: Text(message), - ), FlatButton( onPressed: () { - channelsBlocState.queryChannels( - filter: widget.filter, - sortOptions: widget.sort, - paginationParams: widget.pagination, - options: widget.options, - ); + _channelListController.loadData(); }, child: Text('Retry'), ), @@ -714,14 +674,7 @@ class _ChannelListViewState extends State if (_scrollController.position.maxScrollExtent == _scrollController.offset && _scrollController.offset != 0) { - channelsProvider.queryChannels( - filter: widget.filter, - sortOptions: widget.sort, - paginationParams: widget.pagination.copyWith( - offset: channelsProvider.channels?.length ?? 0, - ), - options: widget.options, - ); + _channelListController.paginateData(); } } @@ -759,12 +712,7 @@ class _ChannelListViewState extends State EventType.channelVisible, ) .listen((event) { - channelsBloc.queryChannels( - filter: widget.filter, - sortOptions: widget.sort, - paginationParams: widget.pagination, - options: widget.options, - ); + _channelListController.loadData(); }); } @@ -777,13 +725,7 @@ class _ChannelListViewState extends State widget.pagination?.toJson()?.toString() != oldWidget.pagination?.toJson()?.toString() || widget.options?.toString() != oldWidget.options?.toString()) { - final channelsBloc = ChannelsBloc.of(context); - channelsBloc.queryChannels( - filter: widget.filter, - sortOptions: widget.sort, - paginationParams: widget.pagination, - options: widget.options, - ); + _channelListController.loadData(); } } diff --git a/packages/flutter_widgets/lib/src/channel_media_display_screen.dart b/packages/flutter_widgets/lib/src/channel_media_display_screen.dart index 8b69fac8..85b571bc 100644 --- a/packages/flutter_widgets/lib/src/channel_media_display_screen.dart +++ b/packages/flutter_widgets/lib/src/channel_media_display_screen.dart @@ -1,5 +1,4 @@ import 'package:flutter/material.dart'; -import 'package:stream_chat_flutter/src/lazy_load_scroll_view.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; import 'package:video_player/video_player.dart'; diff --git a/packages/flutter_widgets/lib/src/channel_name.dart b/packages/flutter_widgets/lib/src/channel_name.dart index bf3eff22..1d51f3fc 100644 --- a/packages/flutter_widgets/lib/src/channel_name.dart +++ b/packages/flutter_widgets/lib/src/channel_name.dart @@ -3,7 +3,6 @@ import 'package:flutter/rendering.dart'; import 'package:stream_chat/stream_chat.dart'; import '../stream_chat_flutter.dart'; -import 'stream_channel.dart'; /// It shows the current [Channel] name using a [Text] widget. /// diff --git a/packages/flutter_widgets/lib/src/channels_bloc.dart b/packages/flutter_widgets/lib/src/channels_bloc.dart deleted file mode 100644 index c3c5c6f1..00000000 --- a/packages/flutter_widgets/lib/src/channels_bloc.dart +++ /dev/null @@ -1,185 +0,0 @@ -import 'dart:async'; - -import 'package:flutter/material.dart'; -import 'package:rxdart/rxdart.dart'; -import 'package:stream_chat/stream_chat.dart'; -import 'package:stream_chat_flutter/src/stream_chat.dart'; -import 'package:stream_chat_flutter/stream_chat_flutter.dart'; - -/// Widget dedicated to the management of a channel list with pagination -class ChannelsBloc extends StatefulWidget { - /// The widget child - final Widget child; - - /// Set this to true to prevent channels to be brought to the top of the list when a new message arrives - final bool lockChannelsOrder; - - /// Comparator used to sort the channels when a message.new event is received - final Comparator channelsComparator; - - /// Function used to evaluate if a channel should be added to the list when a message.new event is received - final bool Function(Event) shouldAddChannel; - - /// Instantiate a new ChannelsBloc - const ChannelsBloc({ - Key key, - this.child, - this.lockChannelsOrder = false, - this.channelsComparator, - this.shouldAddChannel, - }) : super(key: key); - - @override - ChannelsBlocState createState() => ChannelsBlocState(); - - /// Use this method to get the current [ChannelsBlocState] instance - static ChannelsBlocState of(BuildContext context) { - ChannelsBlocState streamChatState; - - streamChatState = context.findAncestorStateOfType(); - - if (streamChatState == null) { - throw Exception('You must have a ChannelsBloc widget as ancestor'); - } - - return streamChatState; - } -} - -/// The current state of the [ChannelsBloc] -class ChannelsBlocState extends State - with AutomaticKeepAliveClientMixin { - @override - Widget build(BuildContext context) { - super.build(context); - return widget.child; - } - - /// The current channel list - List get channels => _channelsController.value; - - /// The current channel list as a stream - Stream> get channelsStream => _channelsController.stream; - - final BehaviorSubject _queryChannelsLoadingController = - BehaviorSubject.seeded(false); - - final BehaviorSubject> _channelsController = BehaviorSubject(); - - /// The stream notifying the state of queryChannel call - Stream get queryChannelsLoading => - _queryChannelsLoadingController.stream; - - final List _hiddenChannels = []; - - /// Calls [client.queryChannels] updating [queryChannelsLoading] stream - Future queryChannels({ - Map filter, - List sortOptions, - PaginationParams paginationParams, - Map options, - bool onlyOffline = false, - }) async { - final client = StreamChat.of(context).client; - - if (client.state?.user == null || - _queryChannelsLoadingController.value == true) { - return; - } - _queryChannelsLoadingController.sink.add(true); - - try { - final clear = paginationParams == null || - paginationParams.offset == null || - paginationParams.offset == 0; - final oldChannels = List.from(channels ?? []); - final _channels = await client.queryChannels( - filter: filter, - sort: sortOptions, - options: options, - paginationParams: paginationParams, - onlyOffline: onlyOffline, - ); - - if (clear) { - _channelsController.add(_channels); - } else { - final l = oldChannels + _channels; - _channelsController.add(l); - } - _queryChannelsLoadingController.sink.add(false); - } catch (err, stackTrace) { - print(err); - print(stackTrace); - _queryChannelsLoadingController.addError(err, stackTrace); - } - } - - final List _subscriptions = []; - - @override - void initState() { - super.initState(); - - final client = StreamChat.of(context).client; - - if (!widget.lockChannelsOrder) { - _subscriptions.add(client.on(EventType.messageNew).listen((e) { - final newChannels = List.from(channels ?? []); - final index = newChannels.indexWhere((c) => c.cid == e.cid); - if (index > -1) { - if (index > 0) { - final channel = newChannels.removeAt(index); - newChannels.insert(0, channel); - } - } else if (widget.shouldAddChannel != null && - widget.shouldAddChannel(e)) { - final hiddenIndex = _hiddenChannels.indexWhere((c) => c.cid == e.cid); - if (hiddenIndex > -1) { - newChannels.insert(0, _hiddenChannels[hiddenIndex]); - _hiddenChannels.removeAt(hiddenIndex); - } else { - if (client.state?.channels != null && - client.state?.channels[e.cid] != null) { - newChannels.insert(0, client.state.channels[e.cid]); - } - } - } - - if (widget.channelsComparator != null) { - newChannels.sort(widget.channelsComparator); - } - _channelsController.add(newChannels); - })); - } - - _subscriptions.add(client.on(EventType.channelHidden).listen((event) async { - final newChannels = List.from(channels ?? []); - final channelIndex = newChannels.indexWhere((c) => c.cid == event.cid); - if (channelIndex > -1) { - final channel = newChannels.removeAt(channelIndex); - _hiddenChannels.add(channel); - _channelsController.add(newChannels); - } - })); - - _subscriptions.add(client - .on(EventType.channelDeleted, EventType.notificationRemovedFromChannel) - .listen((e) { - final channel = e.channel; - _channelsController - .add(List.from(channels..removeWhere((c) => c.cid == channel.cid))); - })); - } - - @override - void dispose() { - _channelsController.close(); - _queryChannelsLoadingController.close(); - _subscriptions.forEach((s) => s.cancel()); - super.dispose(); - } - - @override - bool get wantKeepAlive => true; -} diff --git a/packages/flutter_widgets/lib/src/full_screen_media.dart b/packages/flutter_widgets/lib/src/full_screen_media.dart index 473c9a05..98ed3384 100644 --- a/packages/flutter_widgets/lib/src/full_screen_media.dart +++ b/packages/flutter_widgets/lib/src/full_screen_media.dart @@ -6,7 +6,6 @@ import 'package:photo_view/photo_view.dart'; import 'package:stream_chat_flutter/src/image_footer.dart'; import 'package:stream_chat_flutter/src/image_header.dart'; import 'package:video_player/video_player.dart'; -import 'stream_channel.dart'; import '../stream_chat_flutter.dart'; diff --git a/packages/flutter_widgets/lib/src/image_header.dart b/packages/flutter_widgets/lib/src/image_header.dart index 1694f0b7..f31ee3a6 100644 --- a/packages/flutter_widgets/lib/src/image_header.dart +++ b/packages/flutter_widgets/lib/src/image_header.dart @@ -2,8 +2,8 @@ import 'package:flutter/material.dart'; import 'package:stream_chat/stream_chat.dart'; import 'package:stream_chat_flutter/src/stream_chat_theme.dart'; import 'package:stream_chat_flutter/src/stream_svg_icon.dart'; +import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; import 'image_actions_modal.dart'; -import 'stream_channel.dart'; class ImageHeader extends StatelessWidget implements PreferredSizeWidget { /// True if this header shows the leading back button diff --git a/packages/flutter_widgets/lib/src/lazy_load_scroll_view.dart b/packages/flutter_widgets/lib/src/lazy_load_scroll_view.dart deleted file mode 100644 index bc1f4d1b..00000000 --- a/packages/flutter_widgets/lib/src/lazy_load_scroll_view.dart +++ /dev/null @@ -1,148 +0,0 @@ -import 'package:flutter/foundation.dart'; -import 'package:flutter/widgets.dart'; - -enum _LoadingStatus { LOADING, STABLE } - -/// A widget that wraps a [Widget] and will trigger [onEndOfPage]/[onStartOfPage] when it -/// reaches the bottom/start of the list -class LazyLoadScrollView extends StatefulWidget { - /// The [Widget] that this widget watches for changes on - final Widget child; - - /// Called when the [child] reaches the start of the list - final AsyncCallback onStartOfPage; - - /// Called when the [child] reaches the end of the list - final AsyncCallback onEndOfPage; - - /// Called when the list scrolling starts - final VoidCallback onPageScrollStart; - - /// Called when the list scrolling ends - final VoidCallback onPageScrollEnd; - - /// Called every time the [child] is in-between the list - final VoidCallback onInBetweenOfPage; - - /// The offset to take into account when triggering [onEndOfPage]/[onStartOfPage] in pixels - final double scrollOffset; - - /// Used to determine if loading of new data has finished. You should use set this if you aren't using a FutureBuilder or StreamBuilder - final bool isLoading; - - /// Initiates a LazyLoadScrollView widget - const LazyLoadScrollView({ - Key key, - @required this.child, - this.onStartOfPage, - this.onEndOfPage, - this.onPageScrollStart, - this.onPageScrollEnd, - this.onInBetweenOfPage, - this.isLoading = false, - this.scrollOffset = 100, - }) : assert(child != null), - super(key: key); - - @override - State createState() => _LazyLoadScrollViewState(); -} - -class _LazyLoadScrollViewState extends State { - _LoadingStatus _loadMoreStatus = _LoadingStatus.STABLE; - double _scrollPosition = 0.0; - - @override - Widget build(BuildContext context) { - return NotificationListener( - child: widget.child, - onNotification: _onNotification, - ); - } - - bool _onNotification(Notification notification) { - if (notification is ScrollStartNotification) { - if (widget.onPageScrollStart != null) { - widget.onPageScrollStart(); - return true; - } - } - if (notification is ScrollEndNotification) { - if (widget.onPageScrollEnd != null) { - widget.onPageScrollEnd(); - return true; - } - } - if (notification is ScrollUpdateNotification) { - final pixels = notification.metrics.pixels; - final maxScrollExtent = notification.metrics.maxScrollExtent; - final minScrollExtent = notification.metrics.minScrollExtent; - final scrollOffset = widget.scrollOffset; - - if (pixels > (minScrollExtent + scrollOffset) && - pixels < (maxScrollExtent - scrollOffset)) { - if (widget.onInBetweenOfPage != null) { - widget.onInBetweenOfPage(); - return true; - } - } - - final extentBefore = notification.metrics.extentBefore; - final extentAfter = notification.metrics.extentAfter; - final scrollingDown = _scrollPosition < pixels; - - if (scrollOffset == null || scrollOffset == 0) { - if (extentAfter == 0) { - _onEndOfPage(); - } - if (extentBefore == 0) { - _onStartOfPage(); - } - } else { - if (scrollingDown) { - if (extentAfter <= scrollOffset) { - _onEndOfPage(); - } - } else { - if (extentBefore <= scrollOffset) { - _onStartOfPage(); - } - } - } - _scrollPosition = pixels; - return true; - } - if (notification is OverscrollNotification) { - if (notification.overscroll > 0) { - _onEndOfPage(); - } - if (notification.overscroll < 0) { - _onStartOfPage(); - } - return true; - } - return false; - } - - void _onEndOfPage() { - if (_loadMoreStatus != null && _loadMoreStatus == _LoadingStatus.STABLE) { - _loadMoreStatus = _LoadingStatus.LOADING; - if (widget.onEndOfPage != null) { - widget.onEndOfPage().whenComplete(() { - _loadMoreStatus = _LoadingStatus.STABLE; - }); - } - } - } - - void _onStartOfPage() { - if (_loadMoreStatus != null && _loadMoreStatus == _LoadingStatus.STABLE) { - _loadMoreStatus = _LoadingStatus.LOADING; - if (widget.onStartOfPage != null) { - widget.onStartOfPage().whenComplete(() { - _loadMoreStatus = _LoadingStatus.STABLE; - }); - } - } - } -} diff --git a/packages/flutter_widgets/lib/src/media_list_view.dart b/packages/flutter_widgets/lib/src/media_list_view.dart index 249348c4..d84a2759 100644 --- a/packages/flutter_widgets/lib/src/media_list_view.dart +++ b/packages/flutter_widgets/lib/src/media_list_view.dart @@ -4,7 +4,6 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_svg/flutter_svg.dart'; import 'package:photo_manager/photo_manager.dart'; -import 'package:stream_chat_flutter/src/lazy_load_scroll_view.dart'; import 'package:stream_chat_flutter/src/stream_svg_icon.dart'; import '../stream_chat_flutter.dart'; diff --git a/packages/flutter_widgets/lib/src/message_actions_modal.dart b/packages/flutter_widgets/lib/src/message_actions_modal.dart index 0cda4e9d..3cee6ba4 100644 --- a/packages/flutter_widgets/lib/src/message_actions_modal.dart +++ b/packages/flutter_widgets/lib/src/message_actions_modal.dart @@ -6,9 +6,9 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:stream_chat/stream_chat.dart'; import 'package:stream_chat_flutter/src/reaction_picker.dart'; -import 'package:stream_chat_flutter/src/stream_channel.dart'; import 'package:stream_chat_flutter/src/stream_svg_icon.dart'; import 'package:stream_chat_flutter/src/utils.dart'; +import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; import 'message_input.dart'; import 'message_widget.dart'; diff --git a/packages/flutter_widgets/lib/src/message_input.dart b/packages/flutter_widgets/lib/src/message_input.dart index 01ae3d3a..35a9441e 100644 --- a/packages/flutter_widgets/lib/src/message_input.dart +++ b/packages/flutter_widgets/lib/src/message_input.dart @@ -26,7 +26,6 @@ import 'package:video_compress/video_compress.dart'; import '../stream_chat_flutter.dart'; import 'extension.dart'; import 'quoted_message_widget.dart'; -import 'stream_channel.dart'; typedef FileUploader = Future Function(PlatformFile, Channel); typedef AttachmentThumbnailBuilder = Widget Function( diff --git a/packages/flutter_widgets/lib/src/message_list_view.dart b/packages/flutter_widgets/lib/src/message_list_view.dart index 9a0fe955..f14c332a 100644 --- a/packages/flutter_widgets/lib/src/message_list_view.dart +++ b/packages/flutter_widgets/lib/src/message_list_view.dart @@ -8,7 +8,6 @@ import 'package:rxdart/rxdart.dart'; import 'package:scrollable_positioned_list/scrollable_positioned_list.dart'; import 'package:stream_chat/stream_chat.dart'; import 'package:stream_chat_flutter/src/info_tile.dart'; -import 'package:stream_chat_flutter/src/lazy_load_scroll_view.dart'; import 'package:stream_chat_flutter/src/message_widget.dart'; import 'package:stream_chat_flutter/src/stream_svg_icon.dart'; import 'package:stream_chat_flutter/src/system_message.dart'; @@ -16,7 +15,6 @@ import 'package:visibility_detector/visibility_detector.dart'; import '../stream_chat_flutter.dart'; import 'date_divider.dart'; -import 'stream_channel.dart'; import 'swipeable.dart'; import 'extension.dart'; diff --git a/packages/flutter_widgets/lib/src/message_search_bloc.dart b/packages/flutter_widgets/lib/src/message_search_bloc.dart deleted file mode 100644 index 67b6455d..00000000 --- a/packages/flutter_widgets/lib/src/message_search_bloc.dart +++ /dev/null @@ -1,150 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:rxdart/rxdart.dart'; -import 'package:stream_chat/stream_chat.dart'; - -import 'stream_chat.dart'; - -/// Widget dedicated to the management of a message list with pagination -class MessageSearchBloc extends StatefulWidget { - /// The widget child - final Widget child; - - /// Instantiate a new MessageSearchBloc - const MessageSearchBloc({ - Key key, - @required this.child, - }) : super(key: key); - - @override - MessageSearchBlocState createState() => MessageSearchBlocState(); - - /// Use this method to get the current [MessageSearchBlocState] instance - static MessageSearchBlocState of(BuildContext context) { - MessageSearchBlocState state; - - state = context.findAncestorStateOfType(); - - if (state == null) { - throw Exception('You must have a MessageSearchBloc widget as ancestor'); - } - - return state; - } -} - -/// The current state of the [MessageSearchBloc] -class MessageSearchBlocState extends State - with AutomaticKeepAliveClientMixin { - /// The current messages list - List get messageResponses => _messageResponses.value; - - /// The current messages list as a stream - Stream> get messagesStream => - _messageResponses.stream; - - final BehaviorSubject> _messageResponses = - BehaviorSubject(); - - final BehaviorSubject _queryMessagesLoadingController = - BehaviorSubject.seeded(false); - - /// The stream notifying the state of queryUsers call - Stream get queryMessagesLoading => - _queryMessagesLoadingController.stream; - - /// Calls [Client.search] updating [messageResponses] stream - Future search({ - Map filter, - Map messageFilter, - List sort, - String query, - PaginationParams pagination, - }) async { - _messageResponses.add(null); - try { - final messages = await _search( - filter: filter, - messageFilter: messageFilter, - sort: sort, - query: query, - pagination: pagination, - ); - _messageResponses.add(messages.results); - } catch (err, stk) { - _messageResponses.addError(err, stk); - } - } - - /// Calls [Client.search] updating [queryMessagesLoading] stream - Future loadMore({ - Map filter, - Map messageFilter, - List sort, - String query, - PaginationParams pagination, - }) async { - if (_queryMessagesLoadingController.value == true) { - return; - } - _queryMessagesLoadingController.add(true); - try { - final clear = pagination == null || - pagination.offset == null || - pagination.offset == 0; - - final oldMessages = List.from(messageResponses ?? []); - - final messages = await _search( - filter: filter, - messageFilter: messageFilter, - sort: sort, - query: query, - pagination: pagination, - ); - - if (clear) { - _messageResponses.add(messages.results); - } else { - final temp = oldMessages + messages.results; - _messageResponses.add(temp); - } - - _queryMessagesLoadingController.add(false); - } catch (err, stackTrace) { - _queryMessagesLoadingController.addError(err, stackTrace); - } - } - - Future _search({ - Map filter, - Map messageFilter, - List sort, - String query, - PaginationParams pagination, - }) { - final client = StreamChat.of(context).client; - return client.search( - filter, - sort, - query, - pagination, - messageFilters: messageFilter, - ); - } - - @override - Widget build(BuildContext context) { - super.build(context); - return widget.child; - } - - @override - void dispose() { - _messageResponses.close(); - _queryMessagesLoadingController.close(); - super.dispose(); - } - - @override - bool get wantKeepAlive => true; -} diff --git a/packages/flutter_widgets/lib/src/message_search_list_view.dart b/packages/flutter_widgets/lib/src/message_search_list_view.dart index b176e148..7897d2ec 100644 --- a/packages/flutter_widgets/lib/src/message_search_list_view.dart +++ b/packages/flutter_widgets/lib/src/message_search_list_view.dart @@ -4,10 +4,9 @@ import 'package:flutter/material.dart'; import 'package:stream_chat/stream_chat.dart'; import 'package:stream_chat_flutter/src/info_tile.dart'; import 'package:stream_chat_flutter/src/message_search_item.dart'; +import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; import '../stream_chat_flutter.dart'; -import 'lazy_load_scroll_view.dart'; -import 'message_search_bloc.dart'; /// Callback called when tapping on a user typedef MessageSearchItemTapCallback = void Function(GetMessageResponse); diff --git a/packages/flutter_widgets/lib/src/stream_channel.dart b/packages/flutter_widgets/lib/src/stream_channel.dart deleted file mode 100644 index 8b4b97ef..00000000 --- a/packages/flutter_widgets/lib/src/stream_channel.dart +++ /dev/null @@ -1,356 +0,0 @@ -import 'dart:async'; - -import 'package:flutter/material.dart'; -import 'package:rxdart/rxdart.dart'; -import 'package:stream_chat/stream_chat.dart'; - -enum QueryDirection { top, bottom } - -/// Widget used to provide information about the channel to the widget tree -/// -/// Use [StreamChannel.of] to get the current [StreamChannelState] instance. -class StreamChannel extends StatefulWidget { - const StreamChannel({ - Key key, - @required this.child, - @required this.channel, - this.showLoading = true, - this.initialMessageId, - }) : assert(child != null), - assert(channel != null), - super(key: key); - - final Widget child; - final Channel channel; - final bool showLoading; - - /// If passed the channel will load from this particular message. - final String initialMessageId; - - /// Use this method to get the current [StreamChannelState] instance - static StreamChannelState of(BuildContext context) { - StreamChannelState streamChannelState; - - streamChannelState = context.findAncestorStateOfType(); - - if (streamChannelState == null) { - throw Exception( - 'You must have a StreamChannel widget at the top of your widget tree'); - } - - return streamChannelState; - } - - @override - StreamChannelState createState() => StreamChannelState(); -} - -class StreamChannelState extends State { - /// Current channel - Channel get channel => widget.channel; - - /// InitialMessageId - String get initialMessageId => widget.initialMessageId; - - /// Current channel state stream - Stream get channelStateStream => - widget.channel.state.channelStateStream; - - final _queryTopMessagesController = BehaviorSubject.seeded(false); - final _queryBottomMessagesController = BehaviorSubject.seeded(false); - - /// The stream notifying the state of [_queryTopMessages] call - Stream get queryTopMessages => _queryTopMessagesController.stream; - - /// The stream notifying the state of [_queryBottomMessages] call - Stream get queryBottomMessages => _queryBottomMessagesController.stream; - - bool _topPaginationEnded = false; - bool _bottomPaginationEnded = false; - - Future _queryTopMessages({ - int limit = 20, - bool preferOffline = false, - }) async { - if (_topPaginationEnded || _queryTopMessagesController?.value == true) { - return; - } - _queryTopMessagesController.add(true); - - if (channel.state.messages.isEmpty) { - return _queryTopMessagesController.add(false); - } - - final oldestMessage = channel.state.messages.first; - - try { - final state = await queryBeforeMessage( - oldestMessage.id, - limit: limit, - preferOffline: preferOffline, - ); - if (state.messages.isEmpty || state.messages.length < limit) { - _topPaginationEnded = true; - } - _queryTopMessagesController.add(false); - } catch (e, stk) { - _queryTopMessagesController.addError(e, stk); - } - } - - Future _queryBottomMessages({ - int limit = 20, - bool preferOffline = false, - }) async { - if (_bottomPaginationEnded || - _queryBottomMessagesController?.value == true || - channel?.state?.isUpToDate == true) return; - _queryBottomMessagesController.add(true); - - if (channel.state.messages.isEmpty) { - return _queryBottomMessagesController.add(false); - } - - final recentMessage = channel.state.messages.last; - - try { - final state = await queryAfterMessage( - recentMessage.id, - limit: limit, - preferOffline: preferOffline, - ); - if (state.messages.isEmpty || state.messages.length < limit) { - _bottomPaginationEnded = true; - } - _queryBottomMessagesController.add(false); - } catch (e, stk) { - _queryBottomMessagesController.addError(e, stk); - } - } - - /// Calls [channel.query] updating [queryMessage] stream - Future queryMessages({QueryDirection direction = QueryDirection.top}) { - if (direction == QueryDirection.top) return _queryTopMessages(); - return _queryBottomMessages(); - } - - /// Calls [channel.getReplies] updating [queryMessage] stream - Future getReplies( - String parentId, { - int limit = 50, - bool preferOffline = false, - }) async { - if (_topPaginationEnded || _queryTopMessagesController.value) return; - _queryTopMessagesController.add(true); - - Message message; - if (channel.state.threads.containsKey(parentId)) { - final thread = channel.state.threads[parentId]; - if (thread.isNotEmpty) { - message = thread.first; - } - } - - try { - final response = await channel.getReplies( - parentId, - PaginationParams( - lessThan: message?.id, - limit: limit, - ), - preferOffline: preferOffline, - ); - if (response.messages.isEmpty || response.messages.length < limit) { - _topPaginationEnded = true; - } - _queryTopMessagesController.add(false); - } catch (e, stk) { - _queryTopMessagesController.addError(e, stk); - } - } - - /// Query the channel members and watchers - Future queryMembersAndWatchers() async { - await widget.channel.query( - membersPagination: PaginationParams( - offset: channel.state.members?.length, - limit: 100, - ), - watchersPagination: PaginationParams( - offset: channel.state.watchers?.length, - limit: 100, - ), - ); - } - - /// Loads channel at specific message - Future loadChannelAtMessage( - String messageId, { - int before = 20, - int after = 20, - bool preferOffline = false, - }) { - return queryAtMessage( - messageId: messageId, - before: before, - after: after, - preferOffline: preferOffline, - ); - } - - /// - Future queryAtMessage({ - String messageId, - int before = 20, - int after = 20, - bool preferOffline = false, - }) async { - if (channel.state == null) return; - channel.state.isUpToDate = false; - channel.state.truncate(); - - if (messageId == null) { - await channel.query( - messagesPagination: PaginationParams( - limit: before, - ), - preferOffline: preferOffline, - ); - channel.state.isUpToDate = true; - return; - } - - return Future.wait([ - queryBeforeMessage( - messageId, - limit: before, - preferOffline: preferOffline, - ), - queryAfterMessage( - messageId, - limit: after, - preferOffline: preferOffline, - ), - ]); - } - - /// - Future queryBeforeMessage( - String messageId, { - int limit = 20, - bool preferOffline = false, - }) { - return channel.query( - messagesPagination: PaginationParams( - lessThan: messageId, - limit: limit, - ), - preferOffline: preferOffline, - ); - } - - /// - Future queryAfterMessage( - String messageId, { - int limit = 20, - bool preferOffline = false, - }) async { - final state = await channel.query( - messagesPagination: PaginationParams( - greaterThanOrEqual: messageId, - limit: limit, - ), - preferOffline: preferOffline, - ); - if (state.messages.isEmpty || state.messages.length < limit) { - channel.state.isUpToDate = true; - } - return state; - } - - /// - Future getMessage(String messageId) async { - var message = channel.state.messages.firstWhere( - (it) => it.id == messageId, - orElse: () => null, - ); - if (message == null) { - final response = await channel.getMessagesById([messageId]); - message = response.messages.first; - } - return message; - } - - /// Reloads the channel with latest message - Future reloadChannel() => queryAtMessage(before: 30); - - List> _futures; - - Future get _loadChannelAtMessage async { - try { - await loadChannelAtMessage(initialMessageId); - return true; - } catch (e, stk) { - print('Error: $e\nStack: $stk'); - rethrow; - } - } - - @override - void initState() { - super.initState(); - _futures = [widget.channel.initialized]; - if (initialMessageId != null) { - _futures.add(_loadChannelAtMessage); - } - } - - @override - void dispose() { - _queryTopMessagesController.close(); - _queryBottomMessagesController.close(); - super.dispose(); - } - - @override - Widget build(BuildContext context) { - Widget child = FutureBuilder>( - future: Future.wait(_futures), - initialData: [ - channel.state != null, - if (initialMessageId != null) false, - ], - builder: (context, snapshot) { - if (snapshot.hasError) { - if (snapshot.error is Error) { - print((snapshot.error as Error).stackTrace); - } - var message = snapshot.error.toString(); - if (snapshot.error is DioError) { - final dioError = snapshot.error as DioError; - if (dioError.type == DioErrorType.RESPONSE) { - message = dioError.message; - } else { - message = 'Check your connection and retry'; - } - } - return Center( - child: Text(message), - ); - } - final initialized = snapshot.data[0]; - final dataLoaded = initialMessageId == null ? true : snapshot.data[1]; - if (widget.showLoading && (!initialized || !dataLoaded)) { - return Center( - child: CircularProgressIndicator(), - ); - } - return widget.child; - }, - ); - if (initialMessageId != null) { - child = Material(child: child); - } - return child; - } -} diff --git a/packages/flutter_widgets/lib/src/stream_chat.dart b/packages/flutter_widgets/lib/src/stream_chat.dart index 5d1b7484..ee7e049f 100644 --- a/packages/flutter_widgets/lib/src/stream_chat.dart +++ b/packages/flutter_widgets/lib/src/stream_chat.dart @@ -6,6 +6,7 @@ import 'package:flutter_app_badger/flutter_app_badger.dart'; import 'package:flutter_portal/flutter_portal.dart'; import 'package:stream_chat/stream_chat.dart'; import 'package:stream_chat_flutter/src/stream_chat_theme.dart'; +import 'package:stream_chat_flutter/stream_chat_flutter.dart'; /// Widget used to provide information about the chat to the widget tree /// @@ -61,9 +62,8 @@ class StreamChat extends StatefulWidget { } /// The current state of the StreamChat widget -class StreamChatState extends State with WidgetsBindingObserver { +class StreamChatState extends State { Client get client => widget.client; - Timer _disconnectTimer; @override Widget build(BuildContext context) { @@ -81,7 +81,10 @@ class StreamChatState extends State with WidgetsBindingObserver { accentColor: streamTheme.colorTheme.accentBlue, scaffoldBackgroundColor: streamTheme.colorTheme.white, ), - child: widget.child, + child: StreamChatCore( + child: widget.child, + client: client, + ), ); }, ), @@ -106,7 +109,6 @@ class StreamChatState extends State with WidgetsBindingObserver { @override void initState() { super.initState(); - WidgetsBinding.instance.addObserver(this); client.state?.totalUnreadCountStream?.listen((count) { if (count > 0) { FlutterAppBadger.updateBadgeCount(count); @@ -115,67 +117,4 @@ class StreamChatState extends State with WidgetsBindingObserver { } }); } - - StreamSubscription _newMessageSubscription; - - @override - void didChangeAppLifecycleState(AppLifecycleState state) { - if (client.state?.user != null) { - if (state == AppLifecycleState.paused) { - if (client.showLocalNotification != null) { - _newMessageSubscription = client - .on(EventType.messageNew) - .where((e) => e.user?.id != user.id) - .where((e) => e.message.silent != true) - .where((e) => e.message.shadowed != true) - .listen((event) async { - final channel = client.channel( - event.channelType, - id: event.channelId, - ); - - client.showLocalNotification( - event.message, - ChannelModel( - id: channel.id, - createdAt: channel.createdAt, - extraData: channel.extraData, - type: channel.type, - memberCount: channel.memberCount, - frozen: channel.frozen, - cid: channel.cid, - deletedAt: channel.deletedAt, - config: channel.config, - createdBy: channel.createdBy, - updatedAt: channel.updatedAt, - lastMessageAt: channel.lastMessageAt, - ), - ); - }); - _disconnectTimer = Timer(client.backgroundKeepAlive, () { - client.disconnect(); - }); - } else { - client.disconnect(); - } - } else if (state == AppLifecycleState.resumed) { - _newMessageSubscription?.cancel(); - if (_disconnectTimer?.isActive == true) { - _disconnectTimer.cancel(); - } else { - if (client.wsConnectionStatus.value == - ConnectionStatus.disconnected) { - NotificationService.handleIosMessageQueue(client); - client.connect(); - } - } - } - } - } - - @override - void dispose() { - WidgetsBinding.instance.removeObserver(this); - super.dispose(); - } } diff --git a/packages/flutter_widgets/lib/src/typing_indicator.dart b/packages/flutter_widgets/lib/src/typing_indicator.dart index 177e9e21..c9e579be 100644 --- a/packages/flutter_widgets/lib/src/typing_indicator.dart +++ b/packages/flutter_widgets/lib/src/typing_indicator.dart @@ -1,7 +1,7 @@ import 'package:flutter/material.dart'; import 'package:lottie/lottie.dart'; import 'package:stream_chat/stream_chat.dart'; -import 'package:stream_chat_flutter/src/stream_channel.dart'; +import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; /// Widget to show the current list of typing users class TypingIndicator extends StatelessWidget { diff --git a/packages/flutter_widgets/lib/src/user_list_view.dart b/packages/flutter_widgets/lib/src/user_list_view.dart index c5bac576..be34d3db 100644 --- a/packages/flutter_widgets/lib/src/user_list_view.dart +++ b/packages/flutter_widgets/lib/src/user_list_view.dart @@ -2,8 +2,6 @@ import 'dart:convert'; import 'package:flutter/material.dart'; import 'package:stream_chat/stream_chat.dart'; -import 'package:stream_chat_flutter/src/lazy_load_scroll_view.dart'; -import 'package:stream_chat_flutter/src/users_bloc.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; import 'user_item.dart'; @@ -513,42 +511,3 @@ class _UserListViewState extends State } } } - -abstract class ListItem { - String get key { - if (this is ListHeaderItem) { - final header = (this as ListHeaderItem).heading; - return 'HEADER-$header'; - } - if (this is ListUserItem) { - final user = (this as ListUserItem).user; - return 'USER-${user.id}'; - } - return null; - } - - Widget when({ - @required Widget Function(String heading) headerItem, - @required Widget Function(User user) userItem, - }) { - if (this is ListHeaderItem) { - return headerItem((this as ListHeaderItem).heading); - } - if (this is ListUserItem) { - return userItem((this as ListUserItem).user); - } - return SizedBox(); - } -} - -class ListHeaderItem extends ListItem { - final String heading; - - ListHeaderItem(this.heading); -} - -class ListUserItem extends ListItem { - final User user; - - ListUserItem(this.user); -} diff --git a/packages/flutter_widgets/lib/src/users_bloc.dart b/packages/flutter_widgets/lib/src/users_bloc.dart deleted file mode 100644 index 91cbaf80..00000000 --- a/packages/flutter_widgets/lib/src/users_bloc.dart +++ /dev/null @@ -1,108 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:rxdart/rxdart.dart'; -import 'package:stream_chat/stream_chat.dart'; - -import 'stream_chat.dart'; - -/// Widget dedicated to the management of a users list with pagination -class UsersBloc extends StatefulWidget { - /// The widget child - final Widget child; - - /// Instantiate a new UsersBloc - const UsersBloc({ - Key key, - @required this.child, - }) : super(key: key); - - @override - UsersBlocState createState() => UsersBlocState(); - - /// Use this method to get the current [UsersBlocState] instance - static UsersBlocState of(BuildContext context) { - UsersBlocState state; - - state = context.findAncestorStateOfType(); - - if (state == null) { - throw Exception('You must have a UsersBloc widget as ancestor'); - } - - return state; - } -} - -/// The current state of the [UsersBloc] -class UsersBlocState extends State - with AutomaticKeepAliveClientMixin { - /// The current users list - List get users => _usersController.value; - - /// The current users list as a stream - Stream> get usersStream => _usersController.stream; - - final BehaviorSubject> _usersController = BehaviorSubject(); - - final BehaviorSubject _queryUsersLoadingController = - BehaviorSubject.seeded(false); - - /// The stream notifying the state of queryUsers call - Stream get queryUsersLoading => _queryUsersLoadingController.stream; - - /// Calls [Client.queryUsers] updating [queryUsersLoading] stream - Future queryUsers({ - Map filter, - List sort, - Map options, - PaginationParams pagination, - }) async { - final client = StreamChat.of(context).client; - - if (client.state?.user == null || - _queryUsersLoadingController.value == true) { - return; - } - _queryUsersLoadingController.add(true); - try { - final clear = pagination == null || - pagination.offset == null || - pagination.offset == 0; - - final oldUsers = List.from(users ?? []); - - final usersResponse = await client.queryUsers( - filter: filter, - sort: sort, - options: options, - pagination: pagination, - ); - - if (clear) { - _usersController.add(usersResponse.users); - } else { - final temp = oldUsers + usersResponse.users; - _usersController.add(temp); - } - - _queryUsersLoadingController.add(false); - } catch (err, stackTrace) { - _queryUsersLoadingController.addError(err, stackTrace); - } - } - - @override - Widget build(BuildContext context) { - super.build(context); - return widget.child; - } - - @override - void dispose() { - _usersController.close(); - _queryUsersLoadingController.close(); - super.dispose(); - } - - @override - bool get wantKeepAlive => true; -} diff --git a/packages/flutter_widgets/lib/stream_chat_flutter.dart b/packages/flutter_widgets/lib/stream_chat_flutter.dart index df113234..c4e0e2e1 100644 --- a/packages/flutter_widgets/lib/stream_chat_flutter.dart +++ b/packages/flutter_widgets/lib/stream_chat_flutter.dart @@ -7,7 +7,6 @@ export 'src/channel_list_header.dart'; export 'src/channel_list_view.dart'; export 'src/channel_name.dart'; export 'src/channel_preview.dart'; -export 'src/channels_bloc.dart'; export 'src/date_divider.dart'; export 'src/deleted_message.dart'; export 'src/file_attachment.dart'; @@ -22,8 +21,6 @@ export 'src/message_text.dart'; export 'src/message_widget.dart'; export 'src/reaction_picker.dart'; export 'src/sending_indicator.dart'; -export 'src/stream_channel.dart'; -export 'src/stream_chat.dart'; export 'src/stream_chat_theme.dart'; export 'src/stream_neumorphic_button.dart'; export 'src/stream_svg_icon.dart'; @@ -35,11 +32,8 @@ export 'src/user_item.dart'; export 'src/user_item.dart'; export 'src/user_list_view.dart'; export 'src/user_list_view.dart'; -export 'src/users_bloc.dart'; -export 'src/users_bloc.dart'; export 'src/utils.dart'; export 'src/video_attachment.dart'; -export 'src/message_search_bloc.dart'; export 'src/message_search_item.dart'; export 'src/message_search_list_view.dart'; export 'src/unread_indicator.dart'; @@ -47,3 +41,5 @@ export 'src/option_list_tile.dart'; export 'src/channel_file_display_screen.dart'; export 'src/channel_media_display_screen.dart'; export 'src/info_tile.dart'; +export 'src/stream_chat.dart'; +export 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; diff --git a/packages/flutter_widgets/pubspec.yaml b/packages/flutter_widgets/pubspec.yaml index 2b82aca2..059d4fb2 100644 --- a/packages/flutter_widgets/pubspec.yaml +++ b/packages/flutter_widgets/pubspec.yaml @@ -11,6 +11,9 @@ environment: dependencies: flutter: sdk: flutter + # TODO: Change over to main dependency when deployed + stream_chat_flutter_core: + path: ../stream_chat_flutter_core flutter_app_badger: ^1.1.2 photo_view: ^0.10.3 rxdart: ^0.24.1 @@ -29,7 +32,6 @@ dependencies: image_picker: ^0.6.7+17 flutter_keyboard_visibility: ^4.0.2 mime: ^0.9.7 - stream_chat: ^0.2.24 video_compress: ^2.1.1 visibility_detector: ^0.1.5 http_parser: ^3.1.4 diff --git a/packages/stream_chat_flutter_core/lib/src/channel_list_core.dart b/packages/stream_chat_flutter_core/lib/src/channel_list_core.dart index 627c5131..972de62f 100644 --- a/packages/stream_chat_flutter_core/lib/src/channel_list_core.dart +++ b/packages/stream_chat_flutter_core/lib/src/channel_list_core.dart @@ -49,7 +49,6 @@ class ChannelListCore extends StatefulWidget { this.options, this.sort, this.pagination, - this.pullToRefresh = true, @required this.errorBuilder, @required this.emptyBuilder, @required this.loadingBuilder, @@ -92,9 +91,6 @@ class ChannelListCore extends StatefulWidget { /// message_limit: how many messages should be included to each channel final PaginationParams pagination; - /// Set it to false to disable the pull-to-refresh widget - final bool pullToRefresh; - @override _ChannelListCoreState createState() => _ChannelListCoreState(); } @@ -105,21 +101,7 @@ class _ChannelListCoreState extends State Widget build(BuildContext context) { final channelsBloc = ChannelsBloc.of(context); - if (!widget.pullToRefresh) { - return _buildListView(channelsBloc); - } - - return RefreshIndicator( - onRefresh: () async { - return channelsBloc.queryChannels( - filter: widget.filter, - sortOptions: widget.sort, - paginationParams: widget.pagination, - options: widget.options, - ); - }, - child: _buildListView(channelsBloc), - ); + return _buildListView(channelsBloc); } StreamBuilder> _buildListView( From 5594a9a116b1a2082fe3de4a4725181a06ec9236 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Mon, 25 Jan 2021 20:24:22 +0530 Subject: [PATCH 1025/1140] feat: Added fixes and user_list_view.dart --- .../example/lib/new_chat_screen.dart | 519 +++++++++--------- .../lib/src/channel_list_view.dart | 54 +- .../lib/src/user_list_view.dart | 352 +++++------- .../lib/src/user_list_core.dart | 20 +- 4 files changed, 429 insertions(+), 516 deletions(-) diff --git a/packages/flutter_widgets/example/lib/new_chat_screen.dart b/packages/flutter_widgets/example/lib/new_chat_screen.dart index 5772f5e2..baddd570 100644 --- a/packages/flutter_widgets/example/lib/new_chat_screen.dart +++ b/packages/flutter_widgets/example/lib/new_chat_screen.dart @@ -135,287 +135,284 @@ class _NewChatScreenState extends State { centerTitle: true, ), body: ValueListenableBuilder( - valueListenable: StreamChat.of(context).client.wsConnectionStatus, - builder: (context, status, _) { - String statusString = ''; - bool showStatus = true; + valueListenable: StreamChat.of(context).client.wsConnectionStatus, + builder: (context, status, _) { + String statusString = ''; + bool showStatus = true; - switch (status) { - case ConnectionStatus.connected: - statusString = 'Connected'; - showStatus = false; - break; - case ConnectionStatus.connecting: - statusString = 'Reconnecting...'; - break; - case ConnectionStatus.disconnected: - statusString = 'Disconnected'; - break; - } - return InfoTile( - showMessage: showStatus, - tileAnchor: Alignment.topCenter, - childAnchor: Alignment.topCenter, - message: statusString, - child: StreamChannel( - showLoading: false, - channel: channel, - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - ChipsInputTextField( - key: _chipInputTextFieldStateKey, - controller: _controller, - focusNode: _searchFocusNode, - chipBuilder: (context, user) { - return GestureDetector( - onTap: () { - _chipInputTextFieldState.removeItem(user); - _searchFocusNode.requestFocus(); - }, - child: Stack( - alignment: AlignmentDirectional.centerStart, + switch (status) { + case ConnectionStatus.connected: + statusString = 'Connected'; + showStatus = false; + break; + case ConnectionStatus.connecting: + statusString = 'Reconnecting...'; + break; + case ConnectionStatus.disconnected: + statusString = 'Disconnected'; + break; + } + return InfoTile( + showMessage: showStatus, + tileAnchor: Alignment.topCenter, + childAnchor: Alignment.topCenter, + message: statusString, + child: StreamChannel( + showLoading: false, + channel: channel, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + ChipsInputTextField( + key: _chipInputTextFieldStateKey, + controller: _controller, + focusNode: _searchFocusNode, + chipBuilder: (context, user) { + return GestureDetector( + onTap: () { + _chipInputTextFieldState.removeItem(user); + _searchFocusNode.requestFocus(); + }, + child: Stack( + alignment: AlignmentDirectional.centerStart, + children: [ + Container( + decoration: BoxDecoration( + color: StreamChatTheme.of(context) + .colorTheme + .greyGainsboro, + borderRadius: BorderRadius.circular(12), + ), + padding: const EdgeInsets.only(left: 24), + child: Padding( + padding: const EdgeInsets.fromLTRB(8, 4, 12, 4), + child: Text( + user.name, + maxLines: 1, + style: TextStyle( + color: StreamChatTheme.of(context) + .colorTheme + .black, + ), + ), + ), + ), + Container( + foregroundDecoration: BoxDecoration( + color: StreamChatTheme.of(context) + .colorTheme + .overlay, + shape: BoxShape.circle, + ), + child: UserAvatar( + showOnlineStatus: false, + user: user, + constraints: BoxConstraints.tightFor( + height: 24, + width: 24, + ), + ), + ), + StreamSvgIcon.close(), + ], + ), + ); + }, + onChipAdded: (user) { + setState(() => _selectedUsers.add(user)); + }, + onChipRemoved: (user) { + setState(() => _selectedUsers.remove(user)); + }, + ), + if (!_isSearchActive && !_selectedUsers.isNotEmpty) + Container( + child: InkWell( + onTap: () { + Navigator.pushNamed( + context, + Routes.NEW_GROUP_CHAT, + ); + }, + child: Padding( + padding: const EdgeInsets.symmetric(vertical: 8), + child: Row( children: [ - Container( - decoration: BoxDecoration( - color: StreamChatTheme.of(context) - .colorTheme - .greyGainsboro, - borderRadius: BorderRadius.circular(12), - ), - padding: const EdgeInsets.only(left: 24), - child: Padding( - padding: - const EdgeInsets.fromLTRB(8, 4, 12, 4), - child: Text( - user.name, - maxLines: 1, - style: TextStyle( - color: StreamChatTheme.of(context) - .colorTheme - .black, - ), + StreamNeumorphicButton( + child: Center( + child: StreamSvgIcon.contacts( + color: StreamChatTheme.of(context) + .colorTheme + .accentBlue, + size: 24, ), ), ), - Container( - foregroundDecoration: BoxDecoration( - color: StreamChatTheme.of(context) - .colorTheme - .overlay, - shape: BoxShape.circle, - ), - child: UserAvatar( - showOnlineStatus: false, - user: user, - constraints: BoxConstraints.tightFor( - height: 24, - width: 24, - ), - ), + SizedBox(width: 8), + Text( + 'Create a Group', + style: StreamChatTheme.of(context) + .textTheme + .bodyBold, ), - StreamSvgIcon.close(), ], ), - ); - }, - onChipAdded: (user) { - setState(() => _selectedUsers.add(user)); - }, - onChipRemoved: (user) { - setState(() => _selectedUsers.remove(user)); - }, + ), + ), ), - if (!_isSearchActive && !_selectedUsers.isNotEmpty) - Container( - child: InkWell( - onTap: () { - Navigator.pushNamed( - context, - Routes.NEW_GROUP_CHAT, - ); - }, - child: Padding( - padding: const EdgeInsets.symmetric(vertical: 8), - child: Row( - children: [ - StreamNeumorphicButton( - child: Center( - child: StreamSvgIcon.contacts( - color: StreamChatTheme.of(context) - .colorTheme - .accentBlue, - size: 24, - ), - ), - ), - SizedBox(width: 8), - Text( - 'Create a Group', - style: StreamChatTheme.of(context) - .textTheme - .bodyBold, - ), - ], - ), - ), - ), + if (_showUserList) + Container( + width: double.maxFinite, + decoration: BoxDecoration( + gradient: + StreamChatTheme.of(context).colorTheme.bgGradient, ), - if (_showUserList) - Container( - width: double.maxFinite, - decoration: BoxDecoration( - gradient: - StreamChatTheme.of(context).colorTheme.bgGradient, - ), - child: Padding( - padding: const EdgeInsets.symmetric( - vertical: 8, - horizontal: 8, - ), - child: Text( - _isSearchActive - ? "Matches for \"$_userNameQuery\"" - : 'On the platform', - style: StreamChatTheme.of(context) - .textTheme - .footnote - .copyWith( - color: StreamChatTheme.of(context) - .colorTheme - .black - .withOpacity(.5))), + child: Padding( + padding: const EdgeInsets.symmetric( + vertical: 8, + horizontal: 8, ), + child: Text( + _isSearchActive + ? "Matches for \"$_userNameQuery\"" + : 'On the platform', + style: StreamChatTheme.of(context) + .textTheme + .footnote + .copyWith( + color: StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(.5))), ), - Expanded( - child: _showUserList - ? GestureDetector( - behavior: HitTestBehavior.opaque, - onPanDown: (_) => - FocusScope.of(context).unfocus(), - child: UsersBloc( - child: UserListView( - selectedUsers: _selectedUsers, - groupAlphabetically: - _isSearchActive ? false : true, - onUserTap: (user, _) { - _controller.clear(); - if (!_selectedUsers.contains(user)) { - _chipInputTextFieldState - ..addItem(user) - ..pauseItemAddition(); - } else { - _chipInputTextFieldState.removeItem(user); - } - }, - pagination: PaginationParams( - limit: 25, - ), - filter: { - if (_userNameQuery.isNotEmpty) - 'name': { - r'$autocomplete': _userNameQuery, - }, - 'id': { - r'$ne': StreamChat.of(context).user.id, + ), + Expanded( + child: _showUserList + ? GestureDetector( + behavior: HitTestBehavior.opaque, + onPanDown: (_) => FocusScope.of(context).unfocus(), + child: UsersBloc( + child: UserListView( + selectedUsers: _selectedUsers, + groupAlphabetically: + _isSearchActive ? false : true, + onUserTap: (user, _) { + _controller.clear(); + if (!_selectedUsers.contains(user)) { + _chipInputTextFieldState + ..addItem(user) + ..pauseItemAddition(); + } else { + _chipInputTextFieldState.removeItem(user); + } + }, + pagination: PaginationParams( + limit: 25, + ), + filter: { + if (_userNameQuery.isNotEmpty) + 'name': { + r'$autocomplete': _userNameQuery, }, + 'id': { + r'$ne': StreamChat.of(context).user.id, }, - sort: [ - SortOption( - 'name', - direction: 1, - ), - ], - emptyBuilder: (_) { - return LayoutBuilder( - builder: (context, viewportConstraints) { - return SingleChildScrollView( - physics: - AlwaysScrollableScrollPhysics(), - child: ConstrainedBox( - constraints: BoxConstraints( - minHeight: - viewportConstraints.maxHeight, - ), - child: Center( - child: Column( - children: [ - Padding( - padding: - const EdgeInsets.all( - 24), - child: StreamSvgIcon.search( - size: 96, - color: Colors.grey, - ), + }, + sort: [ + SortOption( + 'name', + direction: 1, + ), + ], + emptyBuilder: (_) { + return LayoutBuilder( + builder: (context, viewportConstraints) { + return SingleChildScrollView( + physics: + AlwaysScrollableScrollPhysics(), + child: ConstrainedBox( + constraints: BoxConstraints( + minHeight: + viewportConstraints.maxHeight, + ), + child: Center( + child: Column( + children: [ + Padding( + padding: + const EdgeInsets.all(24), + child: StreamSvgIcon.search( + size: 96, + color: Colors.grey, ), - Text( - 'No user matches these keywords...', - style: StreamChatTheme.of( - context) - .textTheme - .footnote - .copyWith( - color: StreamChatTheme - .of(context) - .colorTheme - .black - .withOpacity( - .5)), - ), - ], - ), + ), + Text( + 'No user matches these keywords...', + style: StreamChatTheme.of( + context) + .textTheme + .footnote + .copyWith( + color: StreamChatTheme + .of(context) + .colorTheme + .black + .withOpacity(.5)), + ), + ], ), ), - ); - }, - ); - }, - ), + ), + ); + }, + ); + }, ), - ) - : FutureBuilder( - future: channel.initialized, - builder: (context, snapshot) { - if (snapshot.data == true) { - return MessageListView(); - } - - return Center( - child: Text( - 'No chats here yet...', - style: TextStyle( - fontSize: 12, - color: StreamChatTheme.of(context) - .colorTheme - .black - .withOpacity(.5), - ), - ), - ); - }, ), - ), - MessageInput( - focusNode: _messageInputFocusNode, - preMessageSending: (message) async { - await channel.watch(); - return message; - }, - onMessageSent: (m) { - Navigator.pushNamedAndRemoveUntil( - context, - Routes.CHANNEL_PAGE, - ModalRoute.withName(Routes.HOME), - arguments: ChannelPageArgs(channel: channel), - ); - }, - ), - ], - ), + ) + : FutureBuilder( + future: channel.initialized, + builder: (context, snapshot) { + if (snapshot.data == true) { + return MessageListView(); + } + + return Center( + child: Text( + 'No chats here yet...', + style: TextStyle( + fontSize: 12, + color: StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(.5), + ), + ), + ); + }, + ), + ), + MessageInput( + focusNode: _messageInputFocusNode, + preMessageSending: (message) async { + await channel.watch(); + return message; + }, + onMessageSent: (m) { + Navigator.pushNamedAndRemoveUntil( + context, + Routes.CHANNEL_PAGE, + ModalRoute.withName(Routes.HOME), + arguments: ChannelPageArgs(channel: channel), + ); + }, + ), + ], ), - ); - }), + ), + ); + }, + ), ); } } diff --git a/packages/flutter_widgets/lib/src/channel_list_view.dart b/packages/flutter_widgets/lib/src/channel_list_view.dart index 617b7ce9..84eb1298 100644 --- a/packages/flutter_widgets/lib/src/channel_list_view.dart +++ b/packages/flutter_widgets/lib/src/channel_list_view.dart @@ -159,34 +159,36 @@ class _ChannelListViewState extends State @override Widget build(BuildContext context) { - if (!widget.pullToRefresh) { - _channelListController.loadData(); - } - - return RefreshIndicator( - onRefresh: () async { - _channelListController.loadData(); + var child = ChannelListCore( + channelListController: _channelListController, + listBuilder: (context, list) { + return _buildListView(list); }, - child: ChannelListCore( - channelListController: _channelListController, - listBuilder: (context, list) { - return _buildListView(list); - }, - emptyBuilder: (BuildContext context) { - return _buildEmptyWidget(); - }, - errorBuilder: (Error error) { - return _buildErrorWidget(context); - }, - loadingBuilder: (BuildContext context) { - return _buildLoadingWidget(); - }, - pagination: widget.pagination, - options: widget.options, - sort: widget.sort, - filter: widget.filter, - ), + emptyBuilder: (BuildContext context) { + return _buildEmptyWidget(); + }, + errorBuilder: (Error error) { + return _buildErrorWidget(context); + }, + loadingBuilder: (BuildContext context) { + return _buildLoadingWidget(); + }, + pagination: widget.pagination, + options: widget.options, + sort: widget.sort, + filter: widget.filter, ); + + if (!widget.pullToRefresh) { + return child; + } else { + return RefreshIndicator( + onRefresh: () async { + _channelListController.loadData(); + }, + child: child, + ); + } } Widget _buildListView( diff --git a/packages/flutter_widgets/lib/src/user_list_view.dart b/packages/flutter_widgets/lib/src/user_list_view.dart index be34d3db..7027a875 100644 --- a/packages/flutter_widgets/lib/src/user_list_view.dart +++ b/packages/flutter_widgets/lib/src/user_list_view.dart @@ -140,209 +140,170 @@ class _UserListViewState extends State with WidgetsBindingObserver { bool get _isListView => widget.crossAxisCount == 1; - @override - void initState() { - super.initState(); - final usersBloc = UsersBloc.of(context); - usersBloc.queryUsers( - filter: widget.filter, - sort: widget.sort, - pagination: widget.pagination, - options: widget.options, - ); - } + UserListController _userListController = UserListController(); @override Widget build(BuildContext context) { - final usersBloc = UsersBloc.of(context); - - if (!widget.pullToRefresh) { - return _buildListView(usersBloc); - } - - return RefreshIndicator( - onRefresh: () async { - return usersBloc.queryUsers( - filter: widget.filter, - sort: widget.sort, - options: widget.options, - pagination: widget.pagination, + var child = UserListCore( + errorBuilder: (err) { + return _buildError(err); + }, + emptyBuilder: (context) { + return _buildEmpty(); + }, + loadingBuilder: (context) { + return LayoutBuilder( + builder: (context, viewportConstraints) { + return SingleChildScrollView( + physics: AlwaysScrollableScrollPhysics(), + child: ConstrainedBox( + constraints: BoxConstraints( + minHeight: viewportConstraints.maxHeight, + ), + child: Center( + child: CircularProgressIndicator(), + ), + ), + ); + }, ); }, - child: _buildListView(usersBloc), + listBuilder: (context, list) { + return _buildListView(list); + }, + pagination: widget.pagination, + options: widget.options, + sort: widget.sort, + filter: widget.filter, + groupAlphabetically: widget.groupAlphabetically, + userListController: _userListController, ); + + if (!widget.pullToRefresh) { + return child; + } else { + return RefreshIndicator( + onRefresh: () async { + _userListController.loadData(); + }, + child: child, + ); + } } bool get isListAlreadySorted => widget.sort?.any((e) => e.field == 'name' && e.direction == 1) ?? false; - Stream> _buildUserStream( - UsersBlocState usersBlocState, - ) { - return usersBlocState.usersStream.map( - (users) { - if (widget.groupAlphabetically) { - var temp = users; - if (!isListAlreadySorted) { - temp = users..sort((curr, next) => curr.name.compareTo(next.name)); - } - final groupedUsers = >{}; - for (var e in temp) { - final alphabet = e.name[0]?.toUpperCase(); - groupedUsers[alphabet] = [...groupedUsers[alphabet] ?? [], e]; - } - final items = []; - for (var key in groupedUsers.keys) { - items.add(ListHeaderItem(key)); - items.addAll(groupedUsers[key].map((e) => ListUserItem(e))); - } - return items; - } - return users.map((e) => ListUserItem(e)).toList(); - }, + Widget _buildError(Error error) { + print((error).stackTrace); + + if (widget.errorBuilder != null) { + return widget.errorBuilder(error); + } + + var message = error.toString(); + if (error is DioError) { + final dioError = error as DioError; + if (dioError.type == DioErrorType.RESPONSE) { + message = dioError.message; + } else { + message = 'Check your connection and retry'; + } + } + return Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text.rich( + TextSpan( + children: [ + WidgetSpan( + child: Padding( + padding: const EdgeInsets.only( + right: 2.0, + ), + child: Icon(Icons.error_outline), + ), + ), + TextSpan(text: 'Error loading channels'), + ], + ), + style: Theme.of(context).textTheme.headline6, + ), + Padding( + padding: const EdgeInsets.only( + top: 16.0, + ), + child: Text(message), + ), + FlatButton( + onPressed: () { + _userListController.loadData(); + }, + child: Text('Retry'), + ), + ], + ), ); } - StreamBuilder> _buildListView( - UsersBlocState usersBlocState, - ) { - return StreamBuilder( - stream: _buildUserStream(usersBlocState), - builder: (context, snapshot) { - if (snapshot.hasError) { - if (snapshot.error is Error) { - print((snapshot.error as Error).stackTrace); - } + Widget _buildEmpty() { + if (widget.emptyBuilder != null) { + return widget.emptyBuilder(context); + } - if (widget.errorBuilder != null) { - return widget.errorBuilder(snapshot.error); - } - - var message = snapshot.error.toString(); - if (snapshot.error is DioError) { - final dioError = snapshot.error as DioError; - if (dioError.type == DioErrorType.RESPONSE) { - message = dioError.message; - } else { - message = 'Check your connection and retry'; - } - } - return Center( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text.rich( - TextSpan( - children: [ - WidgetSpan( - child: Padding( - padding: const EdgeInsets.only( - right: 2.0, - ), - child: Icon(Icons.error_outline), - ), - ), - TextSpan(text: 'Error loading channels'), - ], - ), - style: Theme.of(context).textTheme.headline6, - ), - Padding( - padding: const EdgeInsets.only( - top: 16.0, - ), - child: Text(message), - ), - FlatButton( - onPressed: () { - usersBlocState.queryUsers( - filter: widget.filter, - sort: widget.sort, - pagination: widget.pagination, - options: widget.options, - ); - }, - child: Text('Retry'), - ), - ], + if (widget.emptyBuilder == null) { + return LayoutBuilder( + builder: (context, viewportConstraints) { + return SingleChildScrollView( + physics: AlwaysScrollableScrollPhysics(), + child: ConstrainedBox( + constraints: BoxConstraints( + minHeight: viewportConstraints.maxHeight, + ), + child: Center( + child: Text('There are no users currently'), + ), ), ); - } + }, + ); + } + } - if (!snapshot.hasData) { - return LayoutBuilder( - builder: (context, viewportConstraints) { - return SingleChildScrollView( - physics: AlwaysScrollableScrollPhysics(), - child: ConstrainedBox( - constraints: BoxConstraints( - minHeight: viewportConstraints.maxHeight, - ), - child: Center( - child: CircularProgressIndicator(), - ), - ), - ); + Widget _buildListView( + List items, + ) { + final child = _isListView + ? ListView.separated( + physics: AlwaysScrollableScrollPhysics(), + itemCount: items.isNotEmpty ? items.length + 1 : items.length, + separatorBuilder: (_, index) { + if (widget.separatorBuilder != null) { + return widget.separatorBuilder(context, index); + } + return _separatorBuilder(context, index); + }, + itemBuilder: (context, index) { + return _listItemBuilder(context, index, items); + }, + ) + : GridView.builder( + gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: widget.crossAxisCount, + ), + itemCount: items.isNotEmpty ? items.length + 1 : items.length, + physics: AlwaysScrollableScrollPhysics(), + itemBuilder: (context, index) { + return _gridItemBuilder(context, index, items); }, ); - } - final items = snapshot.data; - - if (items.isEmpty && widget.emptyBuilder != null) { - return widget.emptyBuilder(context); - } - - if (items.isEmpty && widget.emptyBuilder == null) { - return LayoutBuilder( - builder: (context, viewportConstraints) { - return SingleChildScrollView( - physics: AlwaysScrollableScrollPhysics(), - child: ConstrainedBox( - constraints: BoxConstraints( - minHeight: viewportConstraints.maxHeight, - ), - child: Center( - child: Text('There are no users currently'), - ), - ), - ); - }, - ); - } - - final child = _isListView - ? ListView.separated( - physics: AlwaysScrollableScrollPhysics(), - itemCount: items.isNotEmpty ? items.length + 1 : items.length, - separatorBuilder: (_, index) { - if (widget.separatorBuilder != null) { - return widget.separatorBuilder(context, index); - } - return _separatorBuilder(context, index); - }, - itemBuilder: (context, index) { - return _listItemBuilder(context, index, items); - }, - ) - : GridView.builder( - gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( - crossAxisCount: widget.crossAxisCount, - ), - itemCount: items.isNotEmpty ? items.length + 1 : items.length, - physics: AlwaysScrollableScrollPhysics(), - itemBuilder: (context, index) { - return _gridItemBuilder(context, index, items); - }, - ); - - return LazyLoadScrollView( - onEndOfPage: () async { - return _listenUserPagination(usersBlocState); - }, - child: child, - ); + return LazyLoadScrollView( + onEndOfPage: () async { + return _userListController.paginateData(); }, + child: child, ); } @@ -481,33 +442,4 @@ class _UserListViewState extends State color: StreamChatTheme.of(context).colorTheme.greyWhisper, ); } - - void _listenUserPagination(UsersBlocState usersProvider) { - usersProvider.queryUsers( - filter: widget.filter, - sort: widget.sort, - pagination: widget.pagination.copyWith( - offset: usersProvider.users?.length ?? 0, - ), - options: widget.options, - ); - } - - @override - void didUpdateWidget(UserListView oldWidget) { - super.didUpdateWidget(oldWidget); - if (widget.filter?.toString() != oldWidget.filter?.toString() || - jsonEncode(widget.sort) != jsonEncode(oldWidget.sort) || - widget.pagination?.toJson()?.toString() != - oldWidget.pagination?.toJson()?.toString() || - widget.options?.toString() != oldWidget.options?.toString()) { - final usersBloc = UsersBloc.of(context); - usersBloc.queryUsers( - filter: widget.filter, - sort: widget.sort, - pagination: widget.pagination, - options: widget.options, - ); - } - } } diff --git a/packages/stream_chat_flutter_core/lib/src/user_list_core.dart b/packages/stream_chat_flutter_core/lib/src/user_list_core.dart index 8edf8752..bb8f81fe 100644 --- a/packages/stream_chat_flutter_core/lib/src/user_list_core.dart +++ b/packages/stream_chat_flutter_core/lib/src/user_list_core.dart @@ -43,7 +43,6 @@ class UserListCore extends StatefulWidget { this.options, this.sort, this.pagination, - this.pullToRefresh = true, this.groupAlphabetically = false, @required this.errorBuilder, @required this.emptyBuilder, @@ -89,9 +88,6 @@ class UserListCore extends StatefulWidget { /// message_limit: how many messages should be included to each channel final PaginationParams pagination; - /// Set it to false to disable the pull-to-refresh widget - final bool pullToRefresh; - /// Set it to true to group users by their first character /// /// defaults to false @@ -124,21 +120,7 @@ class _UserListCoreState extends State Widget build(BuildContext context) { final usersBloc = UsersBloc.of(context); - if (!widget.pullToRefresh) { - return _buildListView(usersBloc); - } - - return RefreshIndicator( - onRefresh: () async { - return usersBloc.queryUsers( - filter: widget.filter, - sort: widget.sort, - options: widget.options, - pagination: widget.pagination, - ); - }, - child: _buildListView(usersBloc), - ); + return _buildListView(usersBloc); } bool get isListAlreadySorted => From a79f551332206265cdf5ecec0888acec884ab90e Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Mon, 25 Jan 2021 20:59:50 +0530 Subject: [PATCH 1026/1140] feat: Converted message_list_view.dart --- .../lib/src/message_list_view.dart | 551 +++++++++--------- .../lib/src/message_list_core.dart | 9 +- 2 files changed, 268 insertions(+), 292 deletions(-) diff --git a/packages/flutter_widgets/lib/src/message_list_view.dart b/packages/flutter_widgets/lib/src/message_list_view.dart index f14c332a..bb11a469 100644 --- a/packages/flutter_widgets/lib/src/message_list_view.dart +++ b/packages/flutter_widgets/lib/src/message_list_view.dart @@ -236,309 +236,288 @@ class _MessageListViewState extends State { bool _inBetweenList = false; + MessageListController _messageListController = MessageListController(); + @override Widget build(BuildContext context) { - final messagesStream = _isThreadConversation - ? streamChannel.channel.state.threadsStream - .where((threads) => threads.containsKey(widget.parentMessage.id)) - .map((threads) => threads[widget.parentMessage.id]) - : streamChannel.channel.state?.messagesStream; + return MessageListCore( + loadingBuilder: (context) { + return Center( + child: const CircularProgressIndicator(), + ); + }, + emptyBuilder: (context) { + return Center( + child: Text( + 'No chats here yet...', + style: StreamChatTheme.of(context).textTheme.footnote.copyWith( + color: StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(.5)), + ), + ); + }, + messageListBuilder: (context, list) { + return _buildListView(list); + }, + messageListController: _messageListController, + parentMessage: widget.parentMessage, + showScrollToBottom: widget.showScrollToBottom, + ); + } - return StreamBuilder>( - stream: messagesStream?.map((messages) => messages - ?.where((e) => - (!e.isDeleted && e.shadowed != true) || - (e.isDeleted && - e.user.id == streamChannel.channel.client.state.user.id)) - ?.toList()), - builder: (context, snapshot) { - if (!snapshot.hasData) { - return Center( - child: const CircularProgressIndicator(), - ); + Widget _buildListView(List data) { + messages = data; + final newMessagesListLength = messages.length; + + if (_messageListLength != null) { + if (_bottomPaginationActive || (_inBetweenList && _upToDate)) { + if (_itemPositionListener.itemPositions.value?.isNotEmpty == true) { + final first = _itemPositionListener.itemPositions.value.first; + final diff = newMessagesListLength - _messageListLength; + if (diff > 0) { + initialIndex = first.index + diff; + initialAlignment = first.itemLeadingEdge; } + } + } else if (!_topPaginationActive && _upToDate) { + // Reset the index in-case we send any new message + initialIndex = 0; + initialAlignment = 0; + } + } - final messageList = snapshot.data?.reversed?.toList() ?? []; - if (messageList.isEmpty) { - if (_upToDate) { - return Center( - child: Text( - 'No chats here yet...', - style: StreamChatTheme.of(context) - .textTheme - .footnote - .copyWith( - color: StreamChatTheme.of(context) - .colorTheme - .black - .withOpacity(.5)), + _messageListLength = newMessagesListLength; + final _client = StreamChat.of(context).client; + + return Stack( + alignment: Alignment.center, + children: [ + ValueListenableBuilder( + valueListenable: _client.wsConnectionStatus, + builder: (context, status, _) { + String statusString = ''; + bool showStatus = true; + + switch (status) { + case ConnectionStatus.connected: + statusString = 'Connected'; + showStatus = false; + break; + case ConnectionStatus.connecting: + statusString = 'Reconnecting...'; + break; + case ConnectionStatus.disconnected: + statusString = 'Disconnected'; + break; + } + + return InfoTile( + showMessage: + widget.showConnectionStateTile ? showStatus : false, + tileAnchor: Alignment.topCenter, + childAnchor: Alignment.topCenter, + message: statusString, + child: LazyLoadScrollView( + onStartOfPage: () async { + _inBetweenList = false; + if (!_upToDate) { + _topPaginationActive = false; + _bottomPaginationActive = true; + return _paginateData( + streamChannel, + QueryDirection.bottom, + ); + } + }, + onEndOfPage: () async { + _inBetweenList = false; + _topPaginationActive = true; + _bottomPaginationActive = false; + return _paginateData( + streamChannel, + QueryDirection.top, + ); + }, + onInBetweenOfPage: () { + _inBetweenList = true; + }, + child: ScrollablePositionedList.separated( + key: ValueKey(initialIndex + initialAlignment), + itemPositionsListener: _itemPositionListener, + addAutomaticKeepAlives: true, + initialScrollIndex: initialIndex ?? 0, + initialAlignment: initialAlignment ?? 0, + physics: widget.scrollPhysics, + itemScrollController: _scrollController, + reverse: true, + itemCount: + messages.length + 2 + (_isThreadConversation ? 1 : 0), + separatorBuilder: (context, i) { + if (i == messages.length) return Offstage(); + if (i == 0) return SizedBox(height: 30); + if (i == messages.length + 1) { + final replyCount = widget.parentMessage.replyCount; + return Container( + decoration: BoxDecoration( + gradient: StreamChatTheme.of(context) + .colorTheme + .bgGradient, + ), + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Text( + '$replyCount ${replyCount == 1 ? 'Reply' : 'Replies'}', + textAlign: TextAlign.center, + style: StreamChatTheme.of(context) + .channelTheme + .channelHeaderTheme + .lastMessageAt, + ), + ), + ); + } + + final message = messages[i]; + 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(), + ) + : DateDivider( + dateTime: nextMessage.createdAt.toLocal(), + ); + return Padding( + padding: const EdgeInsets.symmetric(vertical: 12.0), + child: divider, + ); + } + 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; + final isDeleted = message.isDeleted; + if (timeDiff >= 1 || + !isNextUserSame || + isThread || + isDeleted) { + return SizedBox(height: 8); + } + return SizedBox(height: 2); + }, + itemBuilder: (context, i) { + if (i == messages.length + 2) { + if (widget.parentMessageBuilder != null) { + return widget.parentMessageBuilder( + context, + widget.parentMessage, + ); + } else { + return buildParentMessage(widget.parentMessage); + } + } + if (i == messages.length + 1) { + return _buildLoadingIndicator( + streamChannel, + QueryDirection.top, + ); + } + if (i == 0) { + return _buildLoadingIndicator( + streamChannel, + QueryDirection.bottom, + ); + } + final message = messages[i - 1]; + + Widget messageWidget; + + if (i == 1) { + messageWidget = _buildBottomMessage( + context, + message, + messages, + streamChannel, + ); + } else if (i == messages.length - 1) { + messageWidget = _buildTopMessage( + context, + message, + messages, + streamChannel, + ); + } else { + if (widget.messageBuilder != null) { + messageWidget = Builder( + key: ValueKey('MESSAGE-${message.id}'), + builder: (context) => widget.messageBuilder( + context, + MessageDetails( + context, + message, + messages, + i, + ), + messages), + ); + } else { + messageWidget = buildMessage(message, messages, i); + } + } + return messageWidget; + }, + ), ), ); - } - } else { - messages = messageList; - } - - final newMessagesListLength = messages.length; - - if (_messageListLength != null) { - if (_bottomPaginationActive || (_inBetweenList && _upToDate)) { - if (_itemPositionListener.itemPositions.value?.isNotEmpty == - true) { - final first = _itemPositionListener.itemPositions.value.first; - final diff = newMessagesListLength - _messageListLength; - if (diff > 0) { - initialIndex = first.index + diff; - initialAlignment = first.itemLeadingEdge; - } + }), + if (widget.showScrollToBottom) _buildScrollToBottom(), + Positioned( + top: 20.0, + child: ValueListenableBuilder>( + valueListenable: _itemPositionListener.itemPositions, + builder: (context, values, _) { + final items = _itemPositionListener.itemPositions?.value; + if (items.isEmpty || messages.isEmpty) { + return SizedBox(); } - } else if (!_topPaginationActive && _upToDate) { - // Reset the index in-case we send any new message - initialIndex = 0; - initialAlignment = 0; - } - } - _messageListLength = newMessagesListLength; - final _client = StreamChat.of(context).client; + var index = _getTopElement(values).index; - return Stack( - alignment: Alignment.center, - children: [ - ValueListenableBuilder( - valueListenable: _client.wsConnectionStatus, - builder: (context, status, _) { - String statusString = ''; - bool showStatus = true; + if (index > messages.length) { + return SizedBox(); + } - switch (status) { - case ConnectionStatus.connected: - statusString = 'Connected'; - showStatus = false; - break; - case ConnectionStatus.connecting: - statusString = 'Reconnecting...'; - break; - case ConnectionStatus.disconnected: - statusString = 'Disconnected'; - break; - } + if (index == messages.length) { + index = max(index - 1, 0); + } - return InfoTile( - showMessage: - widget.showConnectionStateTile ? showStatus : false, - tileAnchor: Alignment.topCenter, - childAnchor: Alignment.topCenter, - message: statusString, - child: LazyLoadScrollView( - onStartOfPage: () async { - _inBetweenList = false; - if (!_upToDate) { - _topPaginationActive = false; - _bottomPaginationActive = true; - return _paginateData( - streamChannel, - QueryDirection.bottom, - ); - } - }, - onEndOfPage: () async { - _inBetweenList = false; - _topPaginationActive = true; - _bottomPaginationActive = false; - return _paginateData( - streamChannel, - QueryDirection.top, - ); - }, - onInBetweenOfPage: () { - _inBetweenList = true; - }, - child: ScrollablePositionedList.separated( - key: ValueKey(initialIndex + initialAlignment), - itemPositionsListener: _itemPositionListener, - addAutomaticKeepAlives: true, - initialScrollIndex: initialIndex ?? 0, - initialAlignment: initialAlignment ?? 0, - physics: widget.scrollPhysics, - itemScrollController: _scrollController, - reverse: true, - itemCount: messages.length + - 2 + - (_isThreadConversation ? 1 : 0), - separatorBuilder: (context, i) { - if (i == messages.length) return Offstage(); - if (i == 0) return SizedBox(height: 30); - if (i == messages.length + 1) { - final replyCount = - widget.parentMessage.replyCount; - return Container( - decoration: BoxDecoration( - gradient: StreamChatTheme.of(context) - .colorTheme - .bgGradient, - ), - child: Padding( - padding: const EdgeInsets.all(8.0), - child: Text( - '$replyCount ${replyCount == 1 ? 'Reply' : 'Replies'}', - textAlign: TextAlign.center, - style: StreamChatTheme.of(context) - .channelTheme - .channelHeaderTheme - .lastMessageAt, - ), - ), - ); - } - - final message = messages[i]; - 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(), - ) - : DateDivider( - dateTime: nextMessage.createdAt.toLocal(), - ); - return Padding( - padding: - const EdgeInsets.symmetric(vertical: 12.0), - child: divider, - ); - } - 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; - final isDeleted = message.isDeleted; - if (timeDiff >= 1 || - !isNextUserSame || - isThread || - isDeleted) { - return SizedBox(height: 8); - } - return SizedBox(height: 2); - }, - itemBuilder: (context, i) { - if (i == messages.length + 2) { - if (widget.parentMessageBuilder != null) { - return widget.parentMessageBuilder( - context, - widget.parentMessage, - ); - } else { - return buildParentMessage(widget.parentMessage); - } - } - if (i == messages.length + 1) { - return _buildLoadingIndicator( - streamChannel, - QueryDirection.top, - ); - } - if (i == 0) { - return _buildLoadingIndicator( - streamChannel, - QueryDirection.bottom, - ); - } - final message = messages[i - 1]; - - Widget messageWidget; - - if (i == 1) { - messageWidget = _buildBottomMessage( - context, - message, - messages, - streamChannel, - ); - } else if (i == messages.length - 1) { - messageWidget = _buildTopMessage( - context, - message, - messages, - streamChannel, - ); - } else { - if (widget.messageBuilder != null) { - messageWidget = Builder( - key: - ValueKey('MESSAGE-${message.id}'), - builder: (context) => widget.messageBuilder( - context, - MessageDetails( - context, - message, - messages, - i, - ), - messages), - ); - } else { - messageWidget = - buildMessage(message, messages, i); - } - } - return messageWidget; - }, - ), - ), + return widget.dateDividerBuilder != null + ? widget.dateDividerBuilder( + messages[index].createdAt.toLocal(), + ) + : DateDivider( + dateTime: messages[index].createdAt.toLocal(), ); - }), - if (widget.showScrollToBottom) _buildScrollToBottom(), - Positioned( - top: 20.0, - child: ValueListenableBuilder>( - valueListenable: _itemPositionListener.itemPositions, - builder: (context, values, _) { - final items = _itemPositionListener.itemPositions?.value; - if (items.isEmpty || messages.isEmpty) { - return SizedBox(); - } - - var index = _getTopElement(values).index; - - if (index > messages.length) { - return SizedBox(); - } - - if (index == messages.length) { - index = max(index - 1, 0); - } - - return widget.dateDividerBuilder != null - ? widget.dateDividerBuilder( - messages[index].createdAt.toLocal(), - ) - : DateDivider( - dateTime: messages[index].createdAt.toLocal(), - ); - }, - ), - ), - ], - ); - }); + }, + ), + ), + ], + ); } Future _paginateData( StreamChannelState channel, QueryDirection direction) { - if (!_isThreadConversation) { - return channel.queryMessages(direction: direction); - } else { - return channel.getReplies(widget.parentMessage.id); - } + return _messageListController.paginateData(direction: direction); } ItemPosition _getTopElement(Iterable values) { diff --git a/packages/stream_chat_flutter_core/lib/src/message_list_core.dart b/packages/stream_chat_flutter_core/lib/src/message_list_core.dart index e04e1ea8..a13c186c 100644 --- a/packages/stream_chat_flutter_core/lib/src/message_list_core.dart +++ b/packages/stream_chat_flutter_core/lib/src/message_list_core.dart @@ -51,7 +51,6 @@ class MessageListCore extends StatefulWidget { Key key, this.showScrollToBottom = true, this.parentMessage, - this.dateDividerBuilder, @required this.loadingBuilder, @required this.emptyBuilder, @required this.messageListBuilder, @@ -74,9 +73,6 @@ class MessageListCore extends StatefulWidget { /// Parent message in case of a thread final Message parentMessage; - /// Builder used to render date dividers - final Widget Function(DateTime) dateDividerBuilder; - @override _MessageListCoreState createState() => _MessageListCoreState(); } @@ -128,7 +124,8 @@ class _MessageListCoreState extends State { }); } - Future paginateData(QueryDirection direction) { + Future paginateData( + {QueryDirection direction = QueryDirection.bottom}) { if (!_isThreadConversation) { return streamChannel.queryMessages(direction: direction); } else { @@ -162,5 +159,5 @@ class _MessageListCoreState extends State { /// Controller used for paginating data in [ChannelListView] class MessageListController { - Function(QueryDirection direction) paginateData; + Function({QueryDirection direction}) paginateData; } From 016cff2c294919c61940b38f7a29ee945af52f4e Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Mon, 25 Jan 2021 21:17:17 +0530 Subject: [PATCH 1027/1140] feat: Converted message_search_list_view.dart --- .../lib/src/message_search_list_view.dart | 371 ++++++++---------- 1 file changed, 163 insertions(+), 208 deletions(-) diff --git a/packages/flutter_widgets/lib/src/message_search_list_view.dart b/packages/flutter_widgets/lib/src/message_search_list_view.dart index 7897d2ec..0e8f9223 100644 --- a/packages/flutter_widgets/lib/src/message_search_list_view.dart +++ b/packages/flutter_widgets/lib/src/message_search_list_view.dart @@ -119,23 +119,115 @@ class MessageSearchListView extends StatefulWidget { } class _MessageSearchListViewState extends State { - @override - void initState() { - super.initState(); - final messageSearchBloc = MessageSearchBloc.of(context); - messageSearchBloc.search( - filter: widget.filters, - sort: widget.sortOptions, - query: widget.messageQuery, - pagination: widget.paginationParams, - messageFilter: widget.messageFilters, - ); - } + MessageSearchListController _messageSearchListController = + MessageSearchListController(); @override Widget build(BuildContext context) { - final messageSearchBloc = MessageSearchBloc.of(context); - return _buildListView(messageSearchBloc); + return MessageSearchListCore( + filters: widget.filters, + sortOptions: widget.sortOptions, + messageQuery: widget.messageQuery, + paginationParams: widget.paginationParams, + messageFilters: widget.messageFilters, + messageSearchListController: _messageSearchListController, + emptyBuilder: (context) { + if (widget.emptyBuilder != null) { + return widget.emptyBuilder(context, widget.messageQuery); + } + return LayoutBuilder( + builder: (context, viewportConstraints) { + return SingleChildScrollView( + physics: AlwaysScrollableScrollPhysics(), + child: ConstrainedBox( + constraints: BoxConstraints( + minHeight: viewportConstraints.maxHeight, + ), + child: Center( + child: Text('There are no messages currently'), + ), + ), + ); + }, + ); + }, + errorBuilder: (error) { + if (error is Error) { + print((error).stackTrace); + } + + if (widget.errorBuilder != null) { + return widget.errorBuilder(error); + } + + var message = error.toString(); + if (error is DioError) { + final dioError = error as DioError; + if (dioError.type == DioErrorType.RESPONSE) { + message = dioError.message; + } else { + message = 'Check your connection and retry'; + } + } + return InfoTile( + showMessage: widget.showErrorTile, + tileAnchor: Alignment.topCenter, + childAnchor: Alignment.topCenter, + message: 'An error occurred.', + child: Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text.rich( + TextSpan( + children: [ + WidgetSpan( + child: Padding( + padding: const EdgeInsets.only(right: 2.0), + child: Icon(Icons.error_outline), + ), + ), + TextSpan(text: 'Error loading messages'), + ], + ), + style: Theme.of(context).textTheme.headline6, + ), + Padding( + padding: const EdgeInsets.only(top: 16.0), + child: Text(message), + ), + RaisedButton( + onPressed: () { + _messageSearchListController.loadData(); + }, + child: Text('Retry'), + ), + ], + ), + ), + ); + }, + loadingBuilder: (context) { + return LayoutBuilder( + builder: (context, viewportConstraints) { + return SingleChildScrollView( + physics: AlwaysScrollableScrollPhysics(), + child: ConstrainedBox( + constraints: BoxConstraints( + minHeight: viewportConstraints.maxHeight, + ), + child: Center( + child: CircularProgressIndicator(), + ), + ), + ); + }, + ); + }, + childBuilder: (list) { + return _buildListView(list); + }, + ); } Widget _separatorBuilder(BuildContext context, int index) { @@ -156,8 +248,9 @@ class _MessageSearchListViewState extends State { ); } - Widget _buildQueryProgressIndicator( - context, MessageSearchBlocState messageSearchBloc) { + Widget _buildQueryProgressIndicator(context) { + MessageSearchBlocState messageSearchBloc = MessageSearchBloc.of(context); + return StreamBuilder( stream: messageSearchBloc.queryMessagesLoading, initialData: false, @@ -186,204 +279,66 @@ class _MessageSearchListViewState extends State { }); } - Widget _buildListView(MessageSearchBlocState messageSearchBloc) { - return StreamBuilder>( - stream: messageSearchBloc.messagesStream, - builder: (context, snapshot) { - if (snapshot.hasError) { - if (snapshot.error is Error) { - print((snapshot.error as Error).stackTrace); - } + Widget _buildListView(List data) { + final items = data; - if (widget.errorBuilder != null) { - return widget.errorBuilder(snapshot.error); - } - - var message = snapshot.error.toString(); - if (snapshot.error is DioError) { - final dioError = snapshot.error as DioError; - if (dioError.type == DioErrorType.RESPONSE) { - message = dioError.message; - } else { - message = 'Check your connection and retry'; - } - } - return InfoTile( - showMessage: widget.showErrorTile, - tileAnchor: Alignment.topCenter, - childAnchor: Alignment.topCenter, - message: 'An error occurred.', - child: Center( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text.rich( - TextSpan( - children: [ - WidgetSpan( - child: Padding( - padding: const EdgeInsets.only(right: 2.0), - child: Icon(Icons.error_outline), - ), - ), - TextSpan(text: 'Error loading messages'), - ], - ), - style: Theme.of(context).textTheme.headline6, - ), - Padding( - padding: const EdgeInsets.only(top: 16.0), - child: Text(message), - ), - RaisedButton( - onPressed: () { - messageSearchBloc.search( - filter: widget.filters, - sort: widget.sortOptions, - query: widget.messageQuery, - pagination: widget.paginationParams, - messageFilter: widget.messageFilters, - ); - }, - child: Text('Retry'), - ), - ], - ), - ), - ); + Widget child = ListView.separated( + physics: AlwaysScrollableScrollPhysics(), + itemCount: items.isNotEmpty ? items.length + 1 : items.length, + separatorBuilder: (_, index) { + if (widget.separatorBuilder != null) { + return widget.separatorBuilder(context, index); } - - if (!snapshot.hasData) { - return LayoutBuilder( - builder: (context, viewportConstraints) { - return SingleChildScrollView( - physics: AlwaysScrollableScrollPhysics(), - child: ConstrainedBox( - constraints: BoxConstraints( - minHeight: viewportConstraints.maxHeight, - ), - child: Center( - child: CircularProgressIndicator(), - ), - ), - ); - }, - ); + return _separatorBuilder(context, index); + }, + itemBuilder: (context, index) { + if (index < items.length) { + return _listItemBuilder(context, items[index]); } - - final items = snapshot.data; - - if (items.isEmpty) { - if (widget.emptyBuilder != null) { - return widget.emptyBuilder(context, widget.messageQuery); - } - return LayoutBuilder( - builder: (context, viewportConstraints) { - return SingleChildScrollView( - physics: AlwaysScrollableScrollPhysics(), - child: ConstrainedBox( - constraints: BoxConstraints( - minHeight: viewportConstraints.maxHeight, - ), - child: Center( - child: Text('There are no messages currently'), - ), - ), - ); - }, - ); - } - - Widget child = ListView.separated( - physics: AlwaysScrollableScrollPhysics(), - itemCount: items.isNotEmpty ? items.length + 1 : items.length, - separatorBuilder: (_, index) { - if (widget.separatorBuilder != null) { - return widget.separatorBuilder(context, index); - } - return _separatorBuilder(context, index); - }, - itemBuilder: (context, index) { - if (index < items.length) { - return _listItemBuilder(context, items[index]); - } - return _buildQueryProgressIndicator(context, messageSearchBloc); - }, - ); - if (widget.pullToRefresh) { - child = RefreshIndicator( - onRefresh: () async => messageSearchBloc.search( - filter: widget.filters, - sort: widget.sortOptions, - query: widget.messageQuery, - pagination: widget.paginationParams, - messageFilter: widget.messageFilters, - ), - child: child, - ); - } - - child = LazyLoadScrollView( - onEndOfPage: () => messageSearchBloc.loadMore( - filter: widget.filters, - sort: widget.sortOptions, - pagination: widget.paginationParams.copyWith( - offset: messageSearchBloc.messageResponses?.length ?? 0, - ), - query: widget.messageQuery, - messageFilter: widget.messageFilters, - ), - child: child, - ); - - if (widget.showResultCount) { - child = Column( - children: [ - Container( - width: double.maxFinite, - decoration: BoxDecoration( - gradient: StreamChatTheme.of(context).colorTheme.bgGradient, - ), - child: Padding( - padding: const EdgeInsets.symmetric( - vertical: 8, - horizontal: 8, - ), - child: Text( - '${items.length} results', - style: TextStyle( - color: StreamChatTheme.of(context).colorTheme.grey, - ), - ), - ), - ), - Expanded(child: child), - ], - ); - } - return child; + return _buildQueryProgressIndicator(context); }, ); - } - - @override - void didUpdateWidget(MessageSearchListView oldWidget) { - super.didUpdateWidget(oldWidget); - if (widget.filters?.toString() != oldWidget.filters?.toString() || - jsonEncode(widget.sortOptions) != jsonEncode(oldWidget.sortOptions) || - widget.paginationParams?.toJson()?.toString() != - oldWidget.paginationParams?.toJson()?.toString() || - widget.messageQuery?.toString() != oldWidget.messageQuery?.toString() || - widget.messageFilters?.toString() != - oldWidget.messageFilters?.toString()) { - final messageSearchBloc = MessageSearchBloc.of(context); - messageSearchBloc.search( - filter: widget.filters, - sort: widget.sortOptions, - query: widget.messageQuery, - pagination: widget.paginationParams, - messageFilter: widget.messageFilters, + if (widget.pullToRefresh) { + child = RefreshIndicator( + onRefresh: () async { + _messageSearchListController.loadData(); + }, + child: child, ); } + + child = LazyLoadScrollView( + onEndOfPage: () async { + return _messageSearchListController.paginateData(); + }, + child: child, + ); + + if (widget.showResultCount) { + child = Column( + children: [ + Container( + width: double.maxFinite, + decoration: BoxDecoration( + gradient: StreamChatTheme.of(context).colorTheme.bgGradient, + ), + child: Padding( + padding: const EdgeInsets.symmetric( + vertical: 8, + horizontal: 8, + ), + child: Text( + '${items.length} results', + style: TextStyle( + color: StreamChatTheme.of(context).colorTheme.grey, + ), + ), + ), + ), + Expanded(child: child), + ], + ); + } + return child; } } From 773b8d5579c066a8064625ebf5c231bcb9f94960 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Tue, 26 Jan 2021 10:12:13 +0100 Subject: [PATCH 1028/1140] stop ws reconnection after calling disconnect --- packages/dart_client/lib/src/api/websocket.dart | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/dart_client/lib/src/api/websocket.dart b/packages/dart_client/lib/src/api/websocket.dart index a8288573..e3194078 100644 --- a/packages/dart_client/lib/src/api/websocket.dart +++ b/packages/dart_client/lib/src/api/websocket.dart @@ -293,6 +293,7 @@ class WebSocket { logger.info('disconnecting'); _connectionCompleter = Completer(); _cancelTimers(); + _reconnecting = false; _manuallyClosed = true; connectionStatus.value = ConnectionStatus.disconnected; connectionStatus.dispose(); From e39daa0d6ec8d006e26f64f8b1bd4629dc5d1828 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Tue, 26 Jan 2021 10:13:21 +0100 Subject: [PATCH 1029/1140] llc version bump --- packages/dart_client/CHANGELOG.md | 4 ++++ packages/dart_client/lib/version.dart | 2 +- packages/dart_client/pubspec.yaml | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/packages/dart_client/CHANGELOG.md b/packages/dart_client/CHANGELOG.md index 5c799a17..4019cf06 100644 --- a/packages/dart_client/CHANGELOG.md +++ b/packages/dart_client/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.2.24+1 + +- Stop ws reconnection after calling disconnect + ## 0.2.24 - Create enum for push providers diff --git a/packages/dart_client/lib/version.dart b/packages/dart_client/lib/version.dart index bc746ab0..cf6b0a93 100644 --- a/packages/dart_client/lib/version.dart +++ b/packages/dart_client/lib/version.dart @@ -2,4 +2,4 @@ import 'package:stream_chat/src/client.dart'; /// Current package version /// Used in [Client] to build the `x-stream-client` header -const PACKAGE_VERSION = '0.2.24'; +const PACKAGE_VERSION = '0.2.24+1'; diff --git a/packages/dart_client/pubspec.yaml b/packages/dart_client/pubspec.yaml index 9fd0d9e0..f9c22db0 100644 --- a/packages/dart_client/pubspec.yaml +++ b/packages/dart_client/pubspec.yaml @@ -1,7 +1,7 @@ name: stream_chat homepage: https://getstream.io/ description: The official Dart client for Stream Chat, a service for building chat applications. -version: 0.2.24 +version: 0.2.24+1 repository: https://github.com/GetStream/stream-chat-dart issue_tracker: https://github.com/GetStream/stream-chat-dart/issues From a8c44829b4223702e42f2169cdbd67b55634ce90 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Tue, 26 Jan 2021 10:26:39 +0100 Subject: [PATCH 1030/1140] return if calling disconnect more than once in websocket --- packages/dart_client/lib/src/api/websocket.dart | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/dart_client/lib/src/api/websocket.dart b/packages/dart_client/lib/src/api/websocket.dart index e3194078..ebe19868 100644 --- a/packages/dart_client/lib/src/api/websocket.dart +++ b/packages/dart_client/lib/src/api/websocket.dart @@ -290,6 +290,9 @@ class WebSocket { /// Disconnects the WS and releases eventual resources Future disconnect() { + if (_manuallyClosed) { + return Future.value(); + } logger.info('disconnecting'); _connectionCompleter = Completer(); _cancelTimers(); From 20f37a6ff0b86523dbb664f3ff52b308fd6e3ca6 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Tue, 26 Jan 2021 10:27:35 +0100 Subject: [PATCH 1031/1140] fix --- packages/dart_client/lib/src/api/websocket.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/dart_client/lib/src/api/websocket.dart b/packages/dart_client/lib/src/api/websocket.dart index ebe19868..48e7b0ee 100644 --- a/packages/dart_client/lib/src/api/websocket.dart +++ b/packages/dart_client/lib/src/api/websocket.dart @@ -289,9 +289,9 @@ class WebSocket { } /// Disconnects the WS and releases eventual resources - Future disconnect() { + Future disconnect() async { if (_manuallyClosed) { - return Future.value(); + return; } logger.info('disconnecting'); _connectionCompleter = Completer(); From 388829e32d0df4dfef1dce155322c4efd64f051f Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Tue, 26 Jan 2021 10:51:26 +0100 Subject: [PATCH 1032/1140] rename _manuallyClosed to _manuallyDisconnected --- packages/dart_client/lib/src/api/websocket.dart | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/packages/dart_client/lib/src/api/websocket.dart b/packages/dart_client/lib/src/api/websocket.dart index 48e7b0ee..bdd14a1e 100644 --- a/packages/dart_client/lib/src/api/websocket.dart +++ b/packages/dart_client/lib/src/api/websocket.dart @@ -108,7 +108,9 @@ class WebSocket { WebSocketChannel _channel; Timer _healthCheck, _reconnectionMonitor; DateTime _lastEventAt; - bool _manuallyClosed = false, _connecting = false, _reconnecting = false; + bool _manuallyDisconnected = false, + _connecting = false, + _reconnecting = false; Event _decodeEvent(String source) { return Event.fromJson(json.decode(source)); @@ -118,7 +120,7 @@ class WebSocket { /// Connect the WS using the parameters passed in the constructor Future connect() { - _manuallyClosed = false; + _manuallyDisconnected = false; if (_connecting) { logger.severe('already connecting'); @@ -151,7 +153,7 @@ class WebSocket { void _onDone() { _connecting = false; - if (_manuallyClosed) { + if (_manuallyDisconnected) { return; } @@ -290,14 +292,14 @@ class WebSocket { /// Disconnects the WS and releases eventual resources Future disconnect() async { - if (_manuallyClosed) { + if (_manuallyDisconnected) { return; } logger.info('disconnecting'); _connectionCompleter = Completer(); _cancelTimers(); _reconnecting = false; - _manuallyClosed = true; + _manuallyDisconnected = true; connectionStatus.value = ConnectionStatus.disconnected; connectionStatus.dispose(); return _channel.sink.close(); From 849f9c2c4a6e45a999bfa3ede0afd96149e6abba Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Tue, 26 Jan 2021 11:00:05 +0100 Subject: [PATCH 1033/1140] update melos --- .github/workflows/scripts/install-tools.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/scripts/install-tools.sh b/.github/workflows/scripts/install-tools.sh index b83f55f0..1f77f519 100755 --- a/.github/workflows/scripts/install-tools.sh +++ b/.github/workflows/scripts/install-tools.sh @@ -1,6 +1,6 @@ #!/bin/bash -flutter pub global activate melos 0.4.0-dev.2 +flutter pub global activate melos 0.4.0+1 echo "::add-path::$HOME/.pub-cache/bin" echo "::add-path::$GITHUB_WORKSPACE/_flutter/.pub-cache/bin" echo "::add-path::$GITHUB_WORKSPACE/_flutter/bin/cache/dart-sdk/bin" \ No newline at end of file From b5285ff332dbe55f20a48e4e00a7187cc4663d89 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Tue, 26 Jan 2021 11:18:27 +0100 Subject: [PATCH 1034/1140] update llc dependency in stream_chat_flutter --- packages/flutter_widgets/pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/flutter_widgets/pubspec.yaml b/packages/flutter_widgets/pubspec.yaml index 2b82aca2..8db4860d 100644 --- a/packages/flutter_widgets/pubspec.yaml +++ b/packages/flutter_widgets/pubspec.yaml @@ -29,7 +29,7 @@ dependencies: image_picker: ^0.6.7+17 flutter_keyboard_visibility: ^4.0.2 mime: ^0.9.7 - stream_chat: ^0.2.24 + stream_chat: ^0.2.24+1 video_compress: ^2.1.1 visibility_detector: ^0.1.5 http_parser: ^3.1.4 From 02cb4749579b2569c332c239a6c8dbb34b377f4f Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Tue, 26 Jan 2021 11:18:44 +0100 Subject: [PATCH 1035/1140] update sample app version --- packages/flutter_widgets/example/pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/flutter_widgets/example/pubspec.yaml b/packages/flutter_widgets/example/pubspec.yaml index 5344b852..fea15136 100644 --- a/packages/flutter_widgets/example/pubspec.yaml +++ b/packages/flutter_widgets/example/pubspec.yaml @@ -1,7 +1,7 @@ name: example description: A new Flutter project. publish_to: 'none' -version: 1.1.3+5 +version: 1.1.3+6 environment: sdk: ">=2.2.2 <3.0.0" From a168d3695d9e164a5ca5fcfad40a39b49917a394 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Tue, 26 Jan 2021 15:58:11 +0530 Subject: [PATCH 1036/1140] [StreamChatPersistence] Fix connectionEventEntity, MessageDao Signed-off-by: Sahil Kumar --- .../lib/src/converter/converter.dart | 3 +++ .../lib/src/dao/connection_event_dao.dart | 10 +++----- .../lib/src/dao/message_dao.dart | 23 ++++++++++--------- .../lib/src/db/moor_chat_database.dart | 1 + .../lib/src/entity/connection_events.dart | 3 ++- .../lib/src/mapper/event_mapper.dart | 4 ++-- ...dart => stream_chat_persistence_impl.dart} | 18 ++++++--------- .../lib/stream_chat_persistence.dart | 2 +- packages/stream_chat_persistence/pubspec.yaml | 5 +++- 9 files changed, 35 insertions(+), 34 deletions(-) create mode 100644 packages/stream_chat_persistence/lib/src/converter/converter.dart rename packages/stream_chat_persistence/lib/src/{db/stream_chat_database_impl.dart => stream_chat_persistence_impl.dart} (92%) diff --git a/packages/stream_chat_persistence/lib/src/converter/converter.dart b/packages/stream_chat_persistence/lib/src/converter/converter.dart new file mode 100644 index 00000000..f32f4b54 --- /dev/null +++ b/packages/stream_chat_persistence/lib/src/converter/converter.dart @@ -0,0 +1,3 @@ +export 'list_converter.dart'; +export 'map_converter.dart'; +export 'message_sending_status_converter.dart'; \ No newline at end of file diff --git a/packages/stream_chat_persistence/lib/src/dao/connection_event_dao.dart b/packages/stream_chat_persistence/lib/src/dao/connection_event_dao.dart index 59d22010..baf91095 100644 --- a/packages/stream_chat_persistence/lib/src/dao/connection_event_dao.dart +++ b/packages/stream_chat_persistence/lib/src/dao/connection_event_dao.dart @@ -16,12 +16,8 @@ class ConnectionEventDao extends DatabaseAccessor /// Get the latest stored connection event Future get connectionEvent { - return select(connectionEvents).join([ - leftOuterJoin(users, connectionEvents.ownUserId.equalsExp(users.id)), - ]).map((rows) { - final event = rows.readTable(connectionEvents); - final user = rows.readTable(users); - return event.toEvent(user: user?.toUser()); + return select(connectionEvents).map((eventEntity) { + return eventEntity.toEvent(); }).getSingle(); } @@ -40,7 +36,7 @@ class ConnectionEventDao extends DatabaseAccessor lastEventAt: event.createdAt ?? connectionInfo?.lastEventAt, totalUnreadCount: event.totalUnreadCount ?? connectionInfo?.totalUnreadCount, - ownUserId: event.me?.id ?? connectionInfo?.ownUserId, + ownUser: event.me?.toJson() ?? connectionInfo?.ownUser, unreadChannels: event.unreadChannels ?? connectionInfo?.unreadChannels, ), mode: InsertMode.insertOrReplace, diff --git a/packages/stream_chat_persistence/lib/src/dao/message_dao.dart b/packages/stream_chat_persistence/lib/src/dao/message_dao.dart index 700f8bed..320cb022 100644 --- a/packages/stream_chat_persistence/lib/src/dao/message_dao.dart +++ b/packages/stream_chat_persistence/lib/src/dao/message_dao.dart @@ -97,9 +97,7 @@ class MessageDao extends DatabaseAccessor /// Future> getMessagesByCid( String cid, { - int limit = 20, - String messageLessThan, - String messageGreaterThan, + PaginationParams messagePagination, }) async { final msgList = await Future.wait(await (select(messages).join([ leftOuterJoin(users, messages.userId.equalsExp(users.id)), @@ -111,27 +109,30 @@ class MessageDao extends DatabaseAccessor .map(_messageFromJoinRow) .get()); - if (messageLessThan != null) { - final lessThanIndex = msgList.indexWhere((m) => m.id == messageLessThan); + if (messagePagination.lessThan != null) { + final lessThanIndex = msgList.indexWhere( + (m) => m.id == messagePagination.lessThan, + ); if (lessThanIndex != -1) { msgList.removeRange(lessThanIndex, msgList.length); } } - if (messageGreaterThan != null) { - final greaterThanIndex = - msgList.indexWhere((m) => m.id == messageGreaterThan); + if (messagePagination.greaterThanOrEqual != null) { + final greaterThanIndex = msgList.indexWhere( + (m) => m.id == messagePagination.greaterThanOrEqual, + ); if (greaterThanIndex != -1) { msgList.removeRange(0, greaterThanIndex); } } - if (limit != null) { - return msgList.take(limit).toList(); + if (messagePagination.limit != null) { + return msgList.take(messagePagination.limit).toList(); } return msgList; } /// - Future updateMessages(String cid, List messageList) { + Future updateMessages(String cid, List messageList) { return batch((batch) { batch.insertAll( messages, diff --git a/packages/stream_chat_persistence/lib/src/db/moor_chat_database.dart b/packages/stream_chat_persistence/lib/src/db/moor_chat_database.dart index 21447981..e32c3e3c 100644 --- a/packages/stream_chat_persistence/lib/src/db/moor_chat_database.dart +++ b/packages/stream_chat_persistence/lib/src/db/moor_chat_database.dart @@ -4,6 +4,7 @@ import 'package:stream_chat/stream_chat.dart'; import '../entity/entity.dart'; import '../dao/dao.dart'; +import '../converter/converter.dart'; import 'shared/shared_db.dart'; part 'moor_chat_database.g.dart'; diff --git a/packages/stream_chat_persistence/lib/src/entity/connection_events.dart b/packages/stream_chat_persistence/lib/src/entity/connection_events.dart index 311f2da0..3ca4592e 100644 --- a/packages/stream_chat_persistence/lib/src/entity/connection_events.dart +++ b/packages/stream_chat_persistence/lib/src/entity/connection_events.dart @@ -1,10 +1,11 @@ import 'package:moor/moor.dart'; +import 'package:stream_chat_persistence/src/converter/map_converter.dart'; @DataClassName('ConnectionEventEntity') class ConnectionEvents extends Table { IntColumn get id => integer()(); - TextColumn get ownUserId => text().nullable()(); + TextColumn get ownUser => text().nullable().map(MapConverter())(); IntColumn get totalUnreadCount => integer().nullable()(); diff --git a/packages/stream_chat_persistence/lib/src/mapper/event_mapper.dart b/packages/stream_chat_persistence/lib/src/mapper/event_mapper.dart index 41e90205..9746dc20 100644 --- a/packages/stream_chat_persistence/lib/src/mapper/event_mapper.dart +++ b/packages/stream_chat_persistence/lib/src/mapper/event_mapper.dart @@ -5,9 +5,9 @@ import 'package:stream_chat_persistence/src/db/moor_chat_database.dart'; /// extension ConnectionEventX on ConnectionEventEntity { /// - Event toEvent({User user}) { + Event toEvent() { return Event( - me: user, + me: ownUser != null ? OwnUser.fromJson(ownUser) : null, totalUnreadCount: totalUnreadCount, unreadChannels: unreadChannels, ); diff --git a/packages/stream_chat_persistence/lib/src/db/stream_chat_database_impl.dart b/packages/stream_chat_persistence/lib/src/stream_chat_persistence_impl.dart similarity index 92% rename from packages/stream_chat_persistence/lib/src/db/stream_chat_database_impl.dart rename to packages/stream_chat_persistence/lib/src/stream_chat_persistence_impl.dart index de9bbe45..2d4caae8 100644 --- a/packages/stream_chat_persistence/lib/src/db/stream_chat_database_impl.dart +++ b/packages/stream_chat_persistence/lib/src/stream_chat_persistence_impl.dart @@ -1,12 +1,12 @@ import 'package:stream_chat/stream_chat.dart'; -import 'moor_chat_database.dart'; -import 'shared/shared_db.dart'; +import 'db/moor_chat_database.dart'; +import 'db/shared/shared_db.dart'; /// -class StreamChatDatabaseImpl implements StreamChatDatabase { +class StreamChatPersistenceImpl extends StreamChatPersistence { /// - StreamChatDatabaseImpl( + StreamChatPersistenceImpl( this._userId, { Logger logger, }) : _logger = logger, @@ -75,7 +75,7 @@ class StreamChatDatabaseImpl implements StreamChatDatabase { } @override - Future deleteChannelByCids(List cids) { + Future deleteChannels(List cids) { return _db.channelDao.deleteChannelByCids(cids); } @@ -105,15 +105,11 @@ class StreamChatDatabaseImpl implements StreamChatDatabase { @override Future> getMessagesByCid( String cid, { - int limit = 20, - String messageLessThan, - String messageGreaterThan, + PaginationParams messagePagination, }) { return _db.messageDao.getMessagesByCid( cid, - limit: limit, - messageLessThan: messageLessThan, - messageGreaterThan: messageGreaterThan, + messagePagination: messagePagination, ); } diff --git a/packages/stream_chat_persistence/lib/stream_chat_persistence.dart b/packages/stream_chat_persistence/lib/stream_chat_persistence.dart index 3388d36e..3d58cb17 100644 --- a/packages/stream_chat_persistence/lib/stream_chat_persistence.dart +++ b/packages/stream_chat_persistence/lib/stream_chat_persistence.dart @@ -1,3 +1,3 @@ library stream_chat_persistence; -export 'src/db/stream_chat_database_impl.dart'; +export 'src/stream_chat_persistence_impl.dart'; diff --git a/packages/stream_chat_persistence/pubspec.yaml b/packages/stream_chat_persistence/pubspec.yaml index 9ba42d1a..a0c97c89 100644 --- a/packages/stream_chat_persistence/pubspec.yaml +++ b/packages/stream_chat_persistence/pubspec.yaml @@ -9,10 +9,13 @@ environment: dependencies: moor: ^3.4.0 + path: ^1.7.0 + path_provider: ^1.6.27 + sqlite3_flutter_libs: ^0.3.0 stream_chat: path: ../dart_client dev_dependencies: test: ^1.15.7 - build_runner: ^1.10.13 + build_runner: ^1.11.0 moor_generator: ^3.4.1 From b08506062e383512c28730a7f5b36eded3c9085f Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Tue, 26 Jan 2021 15:59:05 +0530 Subject: [PATCH 1037/1140] [StreamChat] Migrate to use `streamChatPersistence` instead of `OfflineStorage` Signed-off-by: Sahil Kumar --- packages/dart_client/lib/src/api/channel.dart | 23 +- packages/dart_client/lib/src/client.dart | 54 +- .../dart_client/lib/src/db/models.part.dart | 258 - .../lib/src/db/offline_storage.dart | 841 ---- .../lib/src/db/offline_storage.g.dart | 4160 ----------------- .../lib/src/db/shared/native_db.dart | 65 - .../lib/src/db/shared/shared_db.dart | 3 - .../lib/src/db/shared/unsupported_db.dart | 14 - .../dart_client/lib/src/db/shared/web_db.dart | 20 - .../lib/src/db/stream_chat_database.dart | 97 - .../lib/src/db/stream_chat_persistence.dart | 196 + .../dart_client/lib/src/notifications.dart | 22 +- packages/dart_client/lib/stream_chat.dart | 4 +- packages/dart_client/pubspec.yaml | 5 - packages/flutter_widgets/pubspec.yaml | 3 +- 15 files changed, 253 insertions(+), 5512 deletions(-) delete mode 100644 packages/dart_client/lib/src/db/models.part.dart delete mode 100644 packages/dart_client/lib/src/db/offline_storage.dart delete mode 100644 packages/dart_client/lib/src/db/offline_storage.g.dart delete mode 100644 packages/dart_client/lib/src/db/shared/native_db.dart delete mode 100644 packages/dart_client/lib/src/db/shared/shared_db.dart delete mode 100644 packages/dart_client/lib/src/db/shared/unsupported_db.dart delete mode 100644 packages/dart_client/lib/src/db/shared/web_db.dart delete mode 100644 packages/dart_client/lib/src/db/stream_chat_database.dart create mode 100644 packages/dart_client/lib/src/db/stream_chat_persistence.dart diff --git a/packages/dart_client/lib/src/api/channel.dart b/packages/dart_client/lib/src/api/channel.dart index 01911b83..a8952e34 100644 --- a/packages/dart_client/lib/src/api/channel.dart +++ b/packages/dart_client/lib/src/api/channel.dart @@ -419,7 +419,7 @@ class Channel { } } - await _client.offlineStorage?.deleteMessages([messageId]); + await _client.chatPersistence?.deleteMessageById(messageId); } return res; @@ -487,7 +487,7 @@ class Channel { PaginationParams options, { bool preferOffline = false, }) async { - final cachedReplies = await _client.offlineStorage?.getReplies( + final cachedReplies = await _client.chatPersistence?.getReplies( parentId, lessThan: options?.lessThan, ); @@ -603,11 +603,9 @@ class Channel { } if (preferOffline && cid != null) { - final updatedState = await _client.offlineStorage?.getChannel( + final updatedState = await _client.chatPersistence?.getChannelStateByCid( cid, - limit: messagesPagination?.limit, - messageLessThan: messagesPagination?.lessThan, - messageGreaterThan: messagesPagination?.greaterThan, + messagePagination: messagesPagination, ); if (updatedState != null && updatedState.messages.isNotEmpty) { if (state == null) { @@ -732,7 +730,7 @@ class Channel { if (clearHistory == true) { state.truncate(); - await _client.offlineStorage?.deleteChannelsMessages([_cid]); + await _client.chatPersistence?.deleteMessageByCid(_cid); } return _client.decode(response.data, EmptyResponse.fromJson); @@ -871,7 +869,7 @@ class ChannelClientState { _computeInitialUnread(); - _channel._client.offlineStorage + _channel._client.chatPersistence ?.getChannelThreads(_channel.cid) ?.then((threads) { _threads = threads; @@ -949,8 +947,7 @@ class ChannelClientState { .on(EventType.channelTruncated, EventType.notificationChannelTruncated) .listen((event) async { final channel = event.channel; - await _channel._client.offlineStorage - ?.deleteChannelsMessages([channel.cid]); + await _channel._client.chatPersistence?.deleteMessageByCid(channel.cid); truncate(); })); } @@ -1404,7 +1401,7 @@ class ChannelClientState { set _channelState(ChannelState v) { _channelStateController.add(v); - _channel._client.offlineStorage?.updateChannelState(v); + _channel._client.chatPersistence?.updateChannelState(v); } /// The channel threads related to this channel @@ -1417,9 +1414,9 @@ class ChannelClientState { BehaviorSubject.seeded({}); set _threads(Map> v) { - _channel._client.offlineStorage?.updateMessages( - v.values.expand((v) => v).toList(), + _channel._client.chatPersistence?.updateMessages( _channel.cid, + v.values.expand((v) => v).toList(), ); _threadsController.add(v); } diff --git a/packages/dart_client/lib/src/client.dart b/packages/dart_client/lib/src/client.dart index bb026ee7..99350636 100644 --- a/packages/dart_client/lib/src/client.dart +++ b/packages/dart_client/lib/src/client.dart @@ -6,6 +6,7 @@ import 'package:dio/dio.dart'; import 'package:flutter/cupertino.dart'; import 'package:logging/logging.dart'; import 'package:rxdart/rxdart.dart'; +import 'package:stream_chat_persistence/stream_chat_persistence.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:stream_chat/src/api/retry_policy.dart'; import 'package:stream_chat/src/event_type.dart'; @@ -20,7 +21,7 @@ import 'api/connection_status.dart'; import 'api/requests.dart'; import 'api/responses.dart'; import 'api/websocket.dart'; -import 'db/offline_storage.dart'; +import 'db/stream_chat_persistence.dart'; import 'exceptions.dart'; import 'models/event.dart'; import 'models/message.dart'; @@ -110,7 +111,7 @@ class Client { logger.info('instantiating new client'); } - OfflineStorage _offlineStorage; + StreamChatPersistence _chatPersistence; /// If true chat data will persist on disk final bool persistenceEnabled; @@ -131,7 +132,7 @@ class Client { final Duration backgroundKeepAlive; /// Client offline database - OfflineStorage get offlineStorage => _offlineStorage; + StreamChatPersistence get chatPersistence => _chatPersistence; /// This client state ClientState state; @@ -344,7 +345,7 @@ class Client { /// Call this function to dispose the client void dispose() async { - await _offlineStorage?.disconnect(); + await _chatPersistence?.disconnect(); await _disconnect(); httpClient.close(); await _controller.close(); @@ -426,8 +427,8 @@ class Client { if (!event.isLocal) { if (_synced && event.createdAt != null) { - await _offlineStorage?.updateConnectionInfo(event); - await _offlineStorage?.updateLastSyncAt(event.createdAt); + await _chatPersistence?.updateConnectionInfo(event); + await _chatPersistence?.updateLastSyncAt(event.createdAt); } } @@ -458,9 +459,12 @@ class Client { wsConnectionStatus.value = ConnectionStatus.connecting; - if (persistenceEnabled && _offlineStorage == null) { - _offlineStorage = - await connectDatabase(state.user, _detachedLogger('💽')); + if (persistenceEnabled && _chatPersistence == null) { + _chatPersistence = StreamChatPersistenceImpl( + state.user.id, + logger: _detachedLogger('💽'), + ); + await _chatPersistence.connect(); } _ws = WebSocket( @@ -510,10 +514,10 @@ class Client { _ws.connectionStatus.addListener(_connectionStatusListener); - var event = await _offlineStorage?.getConnectionInfo(); + var event = await _chatPersistence?.getConnectionInfo(); await _ws.connect().then((e) async { - await _offlineStorage?.updateConnectionInfo(e); + await _chatPersistence?.updateConnectionInfo(e); event = e; await resync(); }).catchError((err, stacktrace) { @@ -528,14 +532,14 @@ class Client { /// Get the events missed while offline to sync the offline storage Future resync([List cids]) async { - final lastSyncAt = await offlineStorage?.getLastSyncAt(); + final lastSyncAt = await chatPersistence?.getLastSyncAt(); if (lastSyncAt == null) { _synced = true; return; } - cids ??= await offlineStorage?.getChannelCids(); + cids ??= await chatPersistence?.getChannelCids(); if (cids?.isEmpty == true) { return; @@ -564,7 +568,7 @@ class Client { handleEvent(event); }); - await _offlineStorage?.updateLastSyncAt(DateTime.now()); + await _chatPersistence?.updateLastSyncAt(DateTime.now()); _synced = true; } catch (error) { logger.severe('Error during resync $error'); @@ -710,7 +714,7 @@ class Client { channels.add(channel); } else { final newChannel = Channel.fromState(this, channelState); - await _offlineStorage + await _chatPersistence ?.updateChannelState(newChannel.state.channelState); newChannel.state?.updateChannelState(channelState); newChannels[newChannel.cid] = newChannel; @@ -721,7 +725,7 @@ class Client { state.channels = newChannels; - await _offlineStorage?.updateChannelQueries( + await _chatPersistence?.updateChannelQueries( filter, res.channels.map((c) => c.channel.cid).toList(), paginationParams?.offset == null || paginationParams.offset == 0, @@ -756,7 +760,7 @@ class Client { @required List sort, PaginationParams paginationParams = const PaginationParams(limit: 10), }) async { - final offlineChannels = await _offlineStorage?.getChannelStates( + final offlineChannels = await _chatPersistence?.getChannelStates( filter: filter, sort: sort, paginationParams: paginationParams, @@ -771,7 +775,7 @@ class Client { return channel; } else { final newChannel = Channel.fromState(this, channelState); - _offlineStorage?.updateChannelState(newChannel.state.channelState); + _chatPersistence?.updateChannelState(newChannel.state.channelState); newChannels[newChannel.cid] = newChannel; return newChannel; } @@ -925,17 +929,17 @@ class Client { } /// Closes the websocket connection and resets the client - /// If [flushOfflineStorage] is true the client deletes all offline user's data + /// If [flushChatPersistence] is true the client deletes all offline user's data /// If [clearUser] is true the client unsets the current user Future disconnect({ - bool flushOfflineStorage = false, + bool flushChatPersistence = false, bool clearUser = false, }) async { logger.info( - 'Disconnecting flushOfflineStorage: $flushOfflineStorage; clearUser: $clearUser'); + 'Disconnecting flushOfflineStorage: $flushChatPersistence; clearUser: $clearUser'); - await _offlineStorage?.disconnect(flush: flushOfflineStorage); - _offlineStorage = null; + await _chatPersistence?.disconnect(flush: flushChatPersistence); + _chatPersistence = null; if (clearUser == true) { state.dispose(); @@ -1324,7 +1328,7 @@ class ClientState { void _listenChannelHidden() { _subscriptions.add(_client.on(EventType.channelHidden).listen((event) { - _client._offlineStorage?.deleteChannels([event.cid]); + _client._chatPersistence?.deleteChannels([event.cid]); if (channels != null) { channels = channels..removeWhere((cid, ch) => cid == event.cid); } @@ -1349,7 +1353,7 @@ class ClientState { ) .listen((Event event) async { final eventChannel = event.channel; - await _client._offlineStorage?.deleteChannels([eventChannel.cid]); + await _client._chatPersistence?.deleteChannels([eventChannel.cid]); if (channels != null) { channels = channels..remove(eventChannel.cid); } diff --git a/packages/dart_client/lib/src/db/models.part.dart b/packages/dart_client/lib/src/db/models.part.dart deleted file mode 100644 index 9a8c5e8e..00000000 --- a/packages/dart_client/lib/src/db/models.part.dart +++ /dev/null @@ -1,258 +0,0 @@ -part of 'offline_storage.dart'; - -@DataClassName('ChannelQuery') -class _ChannelQueries extends Table { - TextColumn get queryHash => text()(); - - TextColumn get channelCid => text()(); - - @override - Set get primaryKey => { - queryHash, - channelCid, - }; -} - -class _Channels extends Table { - TextColumn get id => text()(); - - TextColumn get type => text()(); - - TextColumn get cid => text()(); - - TextColumn get config => text()(); - - BoolColumn get frozen => boolean().withDefault(Constant(false))(); - - DateTimeColumn get lastMessageAt => dateTime().nullable()(); - - DateTimeColumn get createdAt => dateTime().nullable()(); - - DateTimeColumn get updatedAt => dateTime().nullable()(); - - DateTimeColumn get deletedAt => dateTime().nullable()(); - - IntColumn get memberCount => integer().nullable()(); - - TextColumn get extraData => text().nullable().map(_ExtraDataConverter())(); - - TextColumn get createdBy => text().nullable()(); - - @override - Set get primaryKey => {cid}; -} - -class _ConnectionEvent extends Table { - IntColumn get id => integer()(); - - TextColumn get ownUser => text().nullable().map(_ExtraDataConverter())(); - - IntColumn get totalUnreadCount => integer().nullable()(); - - IntColumn get unreadChannels => integer().nullable()(); - - DateTimeColumn get lastEventAt => dateTime().nullable()(); - - DateTimeColumn get lastSyncAt => dateTime().nullable()(); - - @override - Set get primaryKey => {id}; -} - -class _Users extends Table { - TextColumn get id => text()(); - - TextColumn get role => text().nullable()(); - - DateTimeColumn get createdAt => dateTime().nullable()(); - - DateTimeColumn get updatedAt => dateTime().nullable()(); - - DateTimeColumn get lastActive => dateTime().nullable()(); - - BoolColumn get online => boolean().nullable()(); - - BoolColumn get banned => boolean().nullable()(); - - TextColumn get extraData => text().nullable().map(_ExtraDataConverter())(); - - @override - Set get primaryKey => {id}; -} - -class _Reads extends Table { - DateTimeColumn get lastRead => dateTime()(); - - TextColumn get userId => text()(); - - TextColumn get channelCid => text()(); - - IntColumn get unreadMessages => integer().nullable()(); - - @override - Set get primaryKey => { - userId, - channelCid, - }; -} - -class _Reactions extends Table { - TextColumn get messageId => text()(); - - TextColumn get type => text()(); - - DateTimeColumn get createdAt => dateTime()(); - - IntColumn get score => integer().nullable()(); - - TextColumn get userId => text()(); - - TextColumn get extraData => text().nullable().map(_ExtraDataConverter())(); - - @override - Set get primaryKey => { - messageId, - type, - userId, - }; -} - -class _Messages extends Table { - TextColumn get id => text()(); - - TextColumn get messageText => text().nullable()(); - - TextColumn get attachmentJson => text().nullable()(); - - IntColumn get status => - integer().map(_MessageSendingStatusConverter()).nullable()(); - - TextColumn get type => text().nullable()(); - - List mentionedUsers; - - TextColumn get reactionCounts => - text().nullable().map(_ExtraDataConverter())(); - - TextColumn get reactionScores => - text().nullable().map(_ExtraDataConverter())(); - - TextColumn get parentId => text().nullable()(); - - TextColumn get quotedMessageId => text().nullable()(); - - IntColumn get replyCount => integer().nullable()(); - - BoolColumn get showInChannel => boolean().nullable()(); - - BoolColumn get shadowed => boolean().nullable()(); - - TextColumn get command => text().nullable()(); - - DateTimeColumn get createdAt => dateTime()(); - - DateTimeColumn get updatedAt => dateTime().nullable()(); - - DateTimeColumn get deletedAt => dateTime().nullable()(); - - TextColumn get userId => text().nullable()(); - - TextColumn get channelCid => text().nullable()(); - - TextColumn get extraData => text().nullable().map(_ExtraDataConverter())(); - - @override - Set get primaryKey => {id}; -} - -class _Members extends Table { - TextColumn get userId => text()(); - - TextColumn get channelCid => text()(); - - TextColumn get role => text().nullable()(); - - DateTimeColumn get inviteAcceptedAt => dateTime().nullable()(); - - DateTimeColumn get inviteRejectedAt => dateTime().nullable()(); - - BoolColumn get invited => boolean().nullable()(); - - BoolColumn get banned => boolean().nullable()(); - - BoolColumn get shadowBanned => boolean().nullable()(); - - BoolColumn get isModerator => boolean().nullable()(); - - DateTimeColumn get createdAt => dateTime()(); - - DateTimeColumn get updatedAt => dateTime().nullable()(); - - @override - Set get primaryKey => { - userId, - channelCid, - }; -} - -class _ExtraDataConverter extends TypeConverter, String> { - @override - Map mapToDart(fromDb) { - if (fromDb == null) { - return null; - } - return Map.from(jsonDecode(fromDb) ?? {}); - } - - @override - String mapToSql(value) { - return jsonEncode(value); - } -} - -class _MessageSendingStatusConverter - extends TypeConverter { - @override - MessageSendingStatus mapToDart(int fromDb) { - switch (fromDb) { - case 0: - return MessageSendingStatus.sending; - case 1: - return MessageSendingStatus.sent; - case 2: - return MessageSendingStatus.failed; - case 3: - return MessageSendingStatus.updating; - case 4: - return MessageSendingStatus.failed_update; - case 5: - return MessageSendingStatus.deleting; - case 6: - return MessageSendingStatus.failed_delete; - default: - return null; - } - } - - @override - int mapToSql(MessageSendingStatus value) { - switch (value) { - case MessageSendingStatus.sending: - return 0; - case MessageSendingStatus.sent: - return 1; - case MessageSendingStatus.failed: - return 2; - case MessageSendingStatus.updating: - return 3; - case MessageSendingStatus.failed_update: - return 4; - case MessageSendingStatus.deleting: - return 5; - case MessageSendingStatus.failed_delete: - return 6; - default: - return null; - } - } -} diff --git a/packages/dart_client/lib/src/db/offline_storage.dart b/packages/dart_client/lib/src/db/offline_storage.dart deleted file mode 100644 index b132ae02..00000000 --- a/packages/dart_client/lib/src/db/offline_storage.dart +++ /dev/null @@ -1,841 +0,0 @@ -import 'dart:convert'; - -import 'package:flutter/material.dart' show WidgetsFlutterBinding; -import 'package:logging/logging.dart'; -import 'package:moor/isolate.dart'; -import 'package:moor/moor.dart'; -import 'package:stream_chat/src/db/shared/shared_db.dart'; -import 'package:stream_chat/src/models/event.dart'; -import 'package:stream_chat/src/models/own_user.dart'; - -import '../api/requests.dart'; -import '../models/attachment.dart'; -import '../models/channel_config.dart'; -import '../models/channel_model.dart'; -import '../models/channel_state.dart'; -import '../models/member.dart'; -import '../models/message.dart'; -import '../models/reaction.dart'; -import '../models/read.dart'; -import '../models/user.dart'; - -part 'models.part.dart'; - -part 'offline_storage.g.dart'; - -/// Gets a new instance of the database running on a background isolate -Future connectDatabase(User user, Logger logger) async { - logger.info('Connecting on background isolate'); - WidgetsFlutterBinding.ensureInitialized(); - return SharedDB.constructOfflineStorage( - userId: user.id, - logger: logger, - ); -} - -LazyDatabase _openConnection(String userId) { - moorRuntimeOptions.dontWarnAboutMultipleDatabases = true; - return LazyDatabase(() async { - return await SharedDB.constructDatabase('db_$userId.sqlite'); - }); -} - -/// Offline database used for caching channel queries and state -@UseMoor(tables: [ - _ConnectionEvent, - _Channels, - _Users, - _Messages, - _Reads, - _Members, - _ChannelQueries, - _Reactions, -]) -class OfflineStorage extends _$OfflineStorage { - /// Creates a new database instance - OfflineStorage.connect( - DatabaseConnection connection, - this._userId, - this._isolate, - this._logger, - ) : super.connect(connection); - - /// Instantiate a new OfflineStorage - OfflineStorage( - this._userId, - this._logger, - ) : _isolate = null, - super(_openConnection(_userId)) { - _logger.info('Connecting on standard isolate'); - } - - final String _userId; - final MoorIsolate _isolate; - final Logger _logger; - - // you should bump this number whenever you change or add a table definition. Migrations - // are covered later in this readme. - @override - int get schemaVersion => 8; - - @override - MigrationStrategy get migration => MigrationStrategy( - onUpgrade: (openingDetails, before, after) async { - if (before != after) { - final m = createMigrator(); - for (final table in allTables) { - await m.deleteTable(table.actualTableName); - await m.createTable(table); - } - } - }, - ); - - /// Closes the database instance - /// If [flush] is true, the database data will be deleted - Future disconnect({bool flush = false}) async { - _logger.info('Disconnecting'); - if (flush) { - _logger.info('Flushing'); - await batch((batch) { - allTables.forEach((table) { - delete(table).go(); - }); - }); - } - - await _isolate?.shutdownAll(); - - await close(); - } - - /// Get stored replies by messageId - Future> getReplies( - String parentId, { - String lessThan, - }) async { - final offlineList = await Future.wait(await (select(messages).join([ - innerJoin(users, messages.userId.equalsExp(users.id)), - ]) - ..where(messages.parentId.equals(parentId)) - ..orderBy([ - OrderingTerm.asc(messages.createdAt), - ])) - .map(_messageFromJoinRow) - .get()); - if (lessThan != null) { - final lessThanIndex = offlineList.indexWhere((m) => m.id == lessThan); - offlineList.removeRange(lessThanIndex, offlineList.length); - } - - return offlineList; - } - - /// Get stored connection event - Future getConnectionInfo() async { - return select(connectionEvent).map((row) { - return Event( - me: row.ownUser != null ? OwnUser.fromJson(row.ownUser) : null, - totalUnreadCount: row.totalUnreadCount, - unreadChannels: row.unreadChannels, - ); - }).getSingle(); - } - - /// Get stored lastSyncAt - Future getLastSyncAt() async { - return select(connectionEvent).getSingle().then((r) => r?.lastSyncAt); - } - - /// Update stored connection event - Future updateConnectionInfo(Event event) async { - final connectionInfo = await select(connectionEvent).getSingle(); - - return into(connectionEvent).insert( - _ConnectionEventData( - id: 1, - lastSyncAt: connectionInfo?.lastSyncAt, - lastEventAt: event.createdAt ?? connectionInfo?.lastEventAt, - totalUnreadCount: - event.totalUnreadCount ?? connectionInfo?.totalUnreadCount, - ownUser: event.me?.toJson() ?? connectionInfo?.ownUser, - unreadChannels: event.unreadChannels ?? connectionInfo?.unreadChannels, - ), - mode: InsertMode.insertOrReplace, - ); - } - - /// Update stored lastSyncAt - Future updateLastSyncAt(DateTime lastSyncAt) async { - return await (update(connectionEvent)..where((r) => r.id.equals(1))).write( - _ConnectionEventCompanion( - id: Value(1), - lastSyncAt: Value(lastSyncAt), - ), - ); - } - - /// Get the channel cids saved in the offline storage - Future> getChannelCids() async { - return (select(channels) - ..orderBy([(c) => OrderingTerm.desc(c.lastMessageAt)]) - ..limit(250)) - .map((c) => c.cid) - .get(); - } - - /// Get channel data by cid - Future getChannel( - String cid, { - int limit, - String messageLessThan, - String messageGreaterThan, - }) async { - return await (select(channels)..where((c) => c.cid.equals(cid))).join([ - leftOuterJoin(users, channels.createdBy.equalsExp(users.id)), - ]).map((row) { - return _channelFromRow( - row.readTable(channels), - row.readTable(users), - limit: limit, - messageLessThan: messageLessThan, - messageGreaterThan: messageGreaterThan, - ); - }).getSingle(); - } - - /// Get list of channels by filter, sort and paginationParams - Future> getChannelStates({ - Map filter, - List sort = const [], - PaginationParams paginationParams, - }) async { - _logger.info('Get channel states'); - final hash = _computeHash(filter); - final cachedChannels = await Future.wait(await (select(channelQueries) - ..where((c) => c.queryHash.equals(hash))) - .get() - .then((channelQueries) { - final cids = channelQueries.map((c) => c.channelCid).toList(); - final query = select(channels)..where((c) => c.cid.isIn(cids)); - - sort = sort - ?.where((s) => ChannelModel.topLevelFields.contains(s.field)) - ?.toList(); - - if (sort != null && sort.isNotEmpty) { - query.orderBy(sort.map((s) { - final orderExpression = CustomExpression('channels.${s.field}'); - return (c) => OrderingTerm( - expression: orderExpression, - mode: s.direction == 1 ? OrderingMode.asc : OrderingMode.desc, - ); - }).toList()); - } - - if (paginationParams != null) { - query.limit( - paginationParams.limit ?? 10, - offset: paginationParams.offset, - ); - } - - return query.join([ - leftOuterJoin(users, channels.createdBy.equalsExp(users.id)), - ]).map((row) async { - final userRow = row.readTable(users); - final channelRow = row.readTable(channels); - - return _channelFromRow(channelRow, userRow); - }).get(); - })); - - _logger.info('Got ${cachedChannels.length} channels'); - - if (sort?.isEmpty != false && cachedChannels?.isNotEmpty == true) { - cachedChannels - .sort((a, b) => b.channel.updatedAt.compareTo(a.channel.updatedAt)); - cachedChannels.sort((a, b) { - final dateA = a.channel.lastMessageAt ?? a.channel.createdAt; - final dateB = b.channel.lastMessageAt ?? b.channel.createdAt; - return dateB.compareTo(dateA); - }); - } - - return cachedChannels; - } - - /// Update list of channel queries - /// If [clearQueryCache] is true before the insert - /// the list of matching rows will be deleted - Future updateChannelQueries( - Map filter, - List cids, - bool clearQueryCache, - ) async { - final hash = _computeHash(filter); - if (clearQueryCache) { - await (delete(channelQueries) - ..where( - (_ChannelQueries query) => query.queryHash.equals(hash), - )) - .go(); - } - - return batch((batch) { - batch.insertAll( - channelQueries, - cids.map((cid) { - return ChannelQuery( - queryHash: hash, - channelCid: cid, - ); - }).toList(), - mode: InsertMode.insertOrReplace, - ); - }); - } - - /// Remove a message by message id - Future deleteMessages(List messageIds) { - return batch((batch) { - batch.deleteWhere<_Reactions, _Reaction>( - reactions, - (r) => r.messageId.isIn(messageIds), - ); - batch.deleteWhere<_Messages, _Message>( - messages, - (m) => m.id.isIn(messageIds), - ); - }); - } - - /// Remove a message by message id - Future deleteChannelsMessages(List cids) async { - final messageIds = await (select(messages) - ..where((m) => m.channelCid.isIn(cids))) - .map((m) => m.id) - .get(); - return batch((batch) { - batch.deleteWhere<_Reactions, _Reaction>( - reactions, - (r) => r.messageId.isIn(messageIds), - ); - batch.deleteWhere<_Messages, _Message>( - messages, - (m) => m.id.isIn(messageIds), - ); - }); - } - - /// Remove a channel by cid - Future deleteChannels(List cids) async { - await deleteChannelsMessages(cids); - return batch((batch) { - batch.deleteWhere<_Members, _Member>( - members, - (m) => m.channelCid.isIn(cids), - ); - batch.deleteWhere<_Reads, _Read>( - reads, - (r) => r.channelCid.isIn(cids), - ); - batch.deleteWhere<_Channels, _Channel>( - channels, - (c) => c.cid.isIn(cids), - ); - }); - } - - /// Update messages data from a list - Future updateMessages( - List newMessages, - String cid, - ) { - return batch((batch) { - batch.insertAll( - messages, - newMessages.map( - (m) { - return _Message( - id: m.id, - attachmentJson: m.attachments != null - ? jsonEncode(m.attachments.map((a) => a.toJson()).toList()) - : null, - channelCid: cid, - type: m.type, - parentId: m.parentId, - quotedMessageId: m.quotedMessageId, - command: m.command, - createdAt: m.createdAt, - shadowed: m.shadowed, - showInChannel: m.showInChannel, - replyCount: m.replyCount, - reactionScores: m.reactionScores, - reactionCounts: m.reactionCounts, - status: m.status, - updatedAt: m.updatedAt, - extraData: m.extraData, - userId: m.user.id, - deletedAt: m.deletedAt, - messageText: m.text, - ); - }, - ).toList(), - mode: InsertMode.insertOrReplace, - ); - }); - } - - /// Update single channel state - Future updateChannelState(ChannelState channelState) async { - await updateChannelStates([channelState]); - } - - /// Update list of channel states - Future updateChannelStates(List channelStates) async { - channelStates.forEach((cs) { - updateMessages( - cs.messages, - cs.channel.cid, - ); - }); - - await batch((batch) { - _updateReactions(batch, channelStates); - - _updateUsers(batch, channelStates); - - _updateReads(channelStates, batch); - - _updateMembers(channelStates, batch); - - _updateChannels(batch, channelStates); - }); - } - - /// Get the info about channel threads - Future>> getChannelThreads(String cid) async { - final rowMessages = await Future.wait(await (select(messages).join([ - leftOuterJoin(users, messages.userId.equalsExp(users.id)), - ]) - ..where(messages.channelCid.equals(cid)) - ..where(isNotNull(messages.parentId)) - ..orderBy([ - OrderingTerm.asc(messages.createdAt), - ])) - .map(_messageFromJoinRow) - .get()); - - final threads = >{}; - rowMessages.forEach((message) { - if (threads.containsKey(message.parentId)) { - threads[message.parentId].add(message); - } else { - threads[message.parentId] = [message]; - } - }); - - return threads; - } - - Future _channelFromRow( - _Channel channelRow, - _User userRow, { - int limit, - String messageLessThan, - String messageGreaterThan, - }) async { - final rowMessages = await _getChannelMessages( - channelRow, - limit: limit, - lessThan: messageLessThan, - greaterThan: messageGreaterThan, - ); - final rowReads = await _getChannelReads(channelRow); - final rowMembers = await _getChannelMembers(channelRow); - - return ChannelState( - members: rowMembers, - read: rowReads, - messages: rowMessages, - channel: ChannelModel( - id: channelRow.id, - type: channelRow.type, - frozen: channelRow.frozen, - createdAt: channelRow.createdAt, - updatedAt: channelRow.updatedAt, - memberCount: channelRow.memberCount, - cid: channelRow.cid, - lastMessageAt: channelRow.lastMessageAt, - deletedAt: channelRow.deletedAt, - extraData: channelRow.extraData, - config: ChannelConfig.fromJson(jsonDecode(channelRow.config)), - createdBy: userRow != null ? _userFromUserRow(userRow) : null, - ), - ); - } - - String _computeHash(Map filter) { - if (filter == null) { - return 'allchannels'; - } - final hash = base64Encode(utf8.encode('filter: ${jsonEncode(filter)}')); - return hash; - } - - Future _getMessageById(String id) async { - if (id == null || id.isEmpty) return null; - final message = await Future.wait(await (select(messages).join([ - leftOuterJoin(users, messages.userId.equalsExp(users.id)), - ]) - ..where(messages.id.equals(id))) - .map(_messageFromJoinRow) - .get()); - return message.first; - } - - Future> _getChannelMessages( - _Channel channelRow, { - int limit, - String lessThan, - String greaterThan, - }) async { - final rowMessages = await Future.wait(await (select(messages).join([ - leftOuterJoin(users, messages.userId.equalsExp(users.id)), - ]) - ..where(messages.channelCid.equals(channelRow.cid)) - ..where( - isNull(messages.parentId) | messages.showInChannel.equals(true)) - ..orderBy([ - OrderingTerm.asc(messages.createdAt), - ])) - .map(_messageFromJoinRow) - .get()); - - if (lessThan != null) { - final lessThanIndex = rowMessages.indexWhere((m) => m.id == lessThan); - if (lessThanIndex != -1) { - rowMessages.removeRange(lessThanIndex, rowMessages.length); - } - } - if (greaterThan != null) { - final greaterThanIndex = - rowMessages.indexWhere((m) => m.id == greaterThan); - if (greaterThanIndex != -1) { - rowMessages.removeRange(0, greaterThanIndex); - } - } - if (limit != null) { - return rowMessages.take(limit).toList(); - } - return rowMessages; - } - - Future _messageFromJoinRow(row) async { - final messageRow = row.readTable(messages); - final userRow = row.readTable(users); - - final latestReactions = await _getLatestReactions(messageRow); - final ownReactions = await _getOwnReactions(messageRow); - final quotedMessage = await _getMessageById(messageRow.quotedMessageId); - - return Message( - shadowed: messageRow.shadowed, - latestReactions: latestReactions, - ownReactions: ownReactions, - attachments: messageRow.attachmentJson != null - ? List>.from( - jsonDecode(messageRow.attachmentJson)) - .map((j) => Attachment.fromJson(j)) - .toList() - : null, - createdAt: messageRow.createdAt, - extraData: messageRow.extraData, - updatedAt: messageRow.updatedAt, - id: messageRow.id, - type: messageRow.type, - status: messageRow.status, - command: messageRow.command, - parentId: messageRow.parentId, - quotedMessageId: messageRow.quotedMessageId, - quotedMessage: quotedMessage, - reactionCounts: messageRow.reactionCounts, - reactionScores: messageRow.reactionScores, - replyCount: messageRow.replyCount, - showInChannel: messageRow.showInChannel, - text: messageRow.messageText, - user: _userFromUserRow(userRow), - deletedAt: messageRow.deletedAt, - ); - } - - Future> _getLatestReactions(_Message messageRow) async { - return await (select(reactions).join([ - leftOuterJoin(users, reactions.userId.equalsExp(users.id)), - ]) - ..where(reactions.messageId.equals(messageRow.id)) - ..orderBy([OrderingTerm.asc(reactions.createdAt)])) - .map((row) { - final r = row.readTable(reactions); - final u = row.readTable(users); - return _reactionFromRow(r, u); - }).get(); - } - - Reaction _reactionFromRow(_Reaction r, _User u) { - return Reaction( - extraData: r.extraData, - type: r.type, - createdAt: r.createdAt, - userId: r.userId, - user: _userFromUserRow(u), - messageId: r.messageId, - score: r.score, - ); - } - - Future> _getOwnReactions(_Message messageRow) async { - return await (select(reactions).join([ - leftOuterJoin(users, reactions.userId.equalsExp(users.id)), - ]) - ..where(reactions.userId.equals(_userId)) - ..where(reactions.messageId.equals(messageRow.id)) - ..orderBy([OrderingTerm.asc(reactions.createdAt)])) - .map((row) { - final r = row.readTable(reactions); - final u = row.readTable(users); - return _reactionFromRow(r, u); - }).get(); - } - - Future> _getChannelReads(_Channel channelRow) async { - final rowReads = await (select(reads).join([ - leftOuterJoin(users, reads.userId.equalsExp(users.id)), - ]) - ..where(reads.channelCid.equals(channelRow.cid)) - ..orderBy([ - OrderingTerm.asc(reads.lastRead), - ])) - .map((row) { - final userRow = row.readTable(users); - final readRow = row.readTable(reads); - return Read( - user: _userFromUserRow(userRow), - lastRead: readRow.lastRead, - unreadMessages: readRow.unreadMessages, - ); - }).get(); - return rowReads; - } - - Future> _getChannelMembers(_Channel channelRow) async { - final rowMembers = await (select(members).join([ - leftOuterJoin(users, members.userId.equalsExp(users.id)), - ]) - ..where(members.channelCid.equals(channelRow.cid)) - ..orderBy([ - OrderingTerm.asc(members.createdAt), - ])) - .map((row) { - final userRow = row.readTable(users); - final memberRow = row.readTable(members); - return Member( - user: _userFromUserRow(userRow), - userId: userRow.id, - banned: memberRow.banned, - shadowBanned: memberRow.shadowBanned, - updatedAt: memberRow.updatedAt, - createdAt: memberRow.createdAt, - role: memberRow.role, - inviteAcceptedAt: memberRow.inviteAcceptedAt, - invited: memberRow.invited, - inviteRejectedAt: memberRow.inviteRejectedAt, - isModerator: memberRow.isModerator, - ); - }).get(); - return rowMembers; - } - - User _userFromUserRow(_User userRow) { - return User( - updatedAt: userRow.updatedAt, - role: userRow.role, - online: userRow.online, - lastActive: userRow.lastActive, - extraData: userRow.extraData, - banned: userRow.banned, - createdAt: userRow.createdAt, - id: userRow.id, - ); - } - - void _updateChannels(Batch batch, List channelStates) { - batch.insertAll( - channels, - channelStates.map((cs) { - final channel = cs.channel; - return _channelDataFromChannelModel(channel); - }).toList(), - mode: InsertMode.insertOrReplace, - ); - } - - void _updateMembers(List channelStates, Batch batch) async { - await (delete(members) - ..where((tbl) => - tbl.channelCid.isIn(channelStates.map((e) => e.channel.cid)))) - .go(); - final newMembers = channelStates - .map((cs) => cs.members.map((m) => _Member( - userId: m.user.id, - banned: m.banned, - shadowBanned: m.shadowBanned, - channelCid: cs.channel.cid, - createdAt: m.createdAt, - isModerator: m.isModerator, - inviteRejectedAt: m.inviteRejectedAt, - invited: m.invited, - inviteAcceptedAt: m.inviteAcceptedAt, - role: m.role, - updatedAt: m.updatedAt, - ))) - .where((v) => v != null) - .expand((v) => v); - if (newMembers != null && newMembers.isNotEmpty) { - batch.insertAll( - members, - newMembers.toList(), - mode: InsertMode.insertOrReplace, - ); - } - } - - void _updateReads(List channelStates, Batch batch) { - final newReads = channelStates - .map((cs) => cs.read?.map((r) => _Read( - lastRead: r.lastRead, - userId: r.user.id, - channelCid: cs.channel.cid, - unreadMessages: r.unreadMessages, - ))) - .where((v) => v != null) - .expand((v) => v); - - if (newReads != null && newReads.isNotEmpty) { - batch.insertAll( - reads, - newReads.toList(), - mode: InsertMode.insertOrReplace, - ); - } - } - - void _updateUsers(Batch batch, List channelStates) { - batch.insertAll( - users, - channelStates - .map((cs) => [ - if (cs.channel.createdBy != null) - _userDataFromUser(cs.channel.createdBy), - if (cs.messages != null) - ...cs.messages - .map((m) => [ - _userDataFromUser(m.user), - if (m.latestReactions != null) - ...m.latestReactions - .where((r) => r.user != null) - .map((r) => _userDataFromUser(r.user)), - if (m.ownReactions != null) - ...m.ownReactions - .where((r) => r.user != null) - .map((r) => _userDataFromUser(r.user)), - ]) - .expand((v) => v), - if (cs.read != null) - ...cs.read.map((r) => _userDataFromUser(r.user)), - if (cs.members != null) - ...cs.members.map((m) => _userDataFromUser(m.user)), - ]) - .expand((v) => v) - .toList(), - mode: InsertMode.insertOrReplace, - ); - } - - void _updateReactions(Batch batch, List channelStates) { - batch.deleteWhere<_Reactions, _Reaction>( - reactions, - (r) => r.messageId.isIn(channelStates - .map((cs) => cs.messages.map((m) => m.id)) - .expand((v) => v)), - ); - final newReactions = channelStates - .map((cs) => cs.messages.map((m) { - final ownReactions = - m.ownReactions?.where((e) => e.userId != null)?.map( - (r) => _reactionDataFromReaction(m, r), - ) ?? - []; - final latestReactions = - m.latestReactions?.where((e) => e.userId != null)?.map( - (r) => _reactionDataFromReaction(m, r), - ) ?? - []; - return [ - ...ownReactions, - ...latestReactions, - ]; - }).expand((v) => v)) - .expand((v) => v); - - if (newReactions.isNotEmpty) { - batch.insertAll( - reactions, - newReactions.toList(), - mode: InsertMode.insertOrReplace, - ); - } - } - - _Reaction _reactionDataFromReaction(Message m, Reaction r) { - return _Reaction( - messageId: m.id, - type: r.type, - extraData: r.extraData, - score: r.score, - createdAt: r.createdAt, - userId: r.userId, - ); - } - - _User _userDataFromUser(User user) { - return _User( - id: user.id, - createdAt: user.createdAt, - banned: user.banned, - extraData: user.extraData, - lastActive: user.lastActive, - online: user.online, - role: user.role, - updatedAt: user.updatedAt, - ); - } - - _Channel _channelDataFromChannelModel(ChannelModel channel) { - return _Channel( - id: channel.id, - config: jsonEncode(channel.config?.toJson() ?? {}), - type: channel.type, - frozen: channel.frozen, - createdAt: channel.createdAt, - updatedAt: channel.updatedAt, - memberCount: channel.memberCount, - cid: channel.cid, - lastMessageAt: channel.lastMessageAt, - deletedAt: channel.deletedAt, - extraData: channel.extraData, - createdBy: channel.createdBy?.id, - ); - } -} diff --git a/packages/dart_client/lib/src/db/offline_storage.g.dart b/packages/dart_client/lib/src/db/offline_storage.g.dart deleted file mode 100644 index a87ecb92..00000000 --- a/packages/dart_client/lib/src/db/offline_storage.g.dart +++ /dev/null @@ -1,4160 +0,0 @@ -// GENERATED CODE - DO NOT MODIFY BY HAND - -part of 'offline_storage.dart'; - -// ************************************************************************** -// MoorGenerator -// ************************************************************************** - -// ignore_for_file: unnecessary_brace_in_string_interps, unnecessary_this -class _ConnectionEventData extends DataClass - implements Insertable<_ConnectionEventData> { - final int id; - final Map ownUser; - final int totalUnreadCount; - final int unreadChannels; - final DateTime lastEventAt; - final DateTime lastSyncAt; - _ConnectionEventData( - {@required this.id, - this.ownUser, - this.totalUnreadCount, - this.unreadChannels, - this.lastEventAt, - this.lastSyncAt}); - factory _ConnectionEventData.fromData( - Map data, GeneratedDatabase db, - {String prefix}) { - final effectivePrefix = prefix ?? ''; - final intType = db.typeSystem.forDartType(); - final stringType = db.typeSystem.forDartType(); - final dateTimeType = db.typeSystem.forDartType(); - return _ConnectionEventData( - id: intType.mapFromDatabaseResponse(data['${effectivePrefix}id']), - ownUser: $_ConnectionEventTable.$converter0.mapToDart(stringType - .mapFromDatabaseResponse(data['${effectivePrefix}own_user'])), - totalUnreadCount: intType.mapFromDatabaseResponse( - data['${effectivePrefix}total_unread_count']), - unreadChannels: intType - .mapFromDatabaseResponse(data['${effectivePrefix}unread_channels']), - lastEventAt: dateTimeType - .mapFromDatabaseResponse(data['${effectivePrefix}last_event_at']), - lastSyncAt: dateTimeType - .mapFromDatabaseResponse(data['${effectivePrefix}last_sync_at']), - ); - } - @override - Map toColumns(bool nullToAbsent) { - final map = {}; - if (!nullToAbsent || id != null) { - map['id'] = Variable(id); - } - if (!nullToAbsent || ownUser != null) { - final converter = $_ConnectionEventTable.$converter0; - map['own_user'] = Variable(converter.mapToSql(ownUser)); - } - if (!nullToAbsent || totalUnreadCount != null) { - map['total_unread_count'] = Variable(totalUnreadCount); - } - if (!nullToAbsent || unreadChannels != null) { - map['unread_channels'] = Variable(unreadChannels); - } - if (!nullToAbsent || lastEventAt != null) { - map['last_event_at'] = Variable(lastEventAt); - } - if (!nullToAbsent || lastSyncAt != null) { - map['last_sync_at'] = Variable(lastSyncAt); - } - return map; - } - - _ConnectionEventCompanion toCompanion(bool nullToAbsent) { - return _ConnectionEventCompanion( - id: id == null && nullToAbsent ? const Value.absent() : Value(id), - ownUser: ownUser == null && nullToAbsent - ? const Value.absent() - : Value(ownUser), - totalUnreadCount: totalUnreadCount == null && nullToAbsent - ? const Value.absent() - : Value(totalUnreadCount), - unreadChannels: unreadChannels == null && nullToAbsent - ? const Value.absent() - : Value(unreadChannels), - lastEventAt: lastEventAt == null && nullToAbsent - ? const Value.absent() - : Value(lastEventAt), - lastSyncAt: lastSyncAt == null && nullToAbsent - ? const Value.absent() - : Value(lastSyncAt), - ); - } - - factory _ConnectionEventData.fromJson(Map json, - {ValueSerializer serializer}) { - serializer ??= moorRuntimeOptions.defaultSerializer; - return _ConnectionEventData( - id: serializer.fromJson(json['id']), - ownUser: serializer.fromJson>(json['ownUser']), - totalUnreadCount: serializer.fromJson(json['totalUnreadCount']), - unreadChannels: serializer.fromJson(json['unreadChannels']), - lastEventAt: serializer.fromJson(json['lastEventAt']), - lastSyncAt: serializer.fromJson(json['lastSyncAt']), - ); - } - @override - Map toJson({ValueSerializer serializer}) { - serializer ??= moorRuntimeOptions.defaultSerializer; - return { - 'id': serializer.toJson(id), - 'ownUser': serializer.toJson>(ownUser), - 'totalUnreadCount': serializer.toJson(totalUnreadCount), - 'unreadChannels': serializer.toJson(unreadChannels), - 'lastEventAt': serializer.toJson(lastEventAt), - 'lastSyncAt': serializer.toJson(lastSyncAt), - }; - } - - _ConnectionEventData copyWith( - {int id, - Map ownUser, - int totalUnreadCount, - int unreadChannels, - DateTime lastEventAt, - DateTime lastSyncAt}) => - _ConnectionEventData( - id: id ?? this.id, - ownUser: ownUser ?? this.ownUser, - totalUnreadCount: totalUnreadCount ?? this.totalUnreadCount, - unreadChannels: unreadChannels ?? this.unreadChannels, - lastEventAt: lastEventAt ?? this.lastEventAt, - lastSyncAt: lastSyncAt ?? this.lastSyncAt, - ); - @override - String toString() { - return (StringBuffer('_ConnectionEventData(') - ..write('id: $id, ') - ..write('ownUser: $ownUser, ') - ..write('totalUnreadCount: $totalUnreadCount, ') - ..write('unreadChannels: $unreadChannels, ') - ..write('lastEventAt: $lastEventAt, ') - ..write('lastSyncAt: $lastSyncAt') - ..write(')')) - .toString(); - } - - @override - int get hashCode => $mrjf($mrjc( - id.hashCode, - $mrjc( - ownUser.hashCode, - $mrjc( - totalUnreadCount.hashCode, - $mrjc(unreadChannels.hashCode, - $mrjc(lastEventAt.hashCode, lastSyncAt.hashCode)))))); - @override - bool operator ==(dynamic other) => - identical(this, other) || - (other is _ConnectionEventData && - other.id == this.id && - other.ownUser == this.ownUser && - other.totalUnreadCount == this.totalUnreadCount && - other.unreadChannels == this.unreadChannels && - other.lastEventAt == this.lastEventAt && - other.lastSyncAt == this.lastSyncAt); -} - -class _ConnectionEventCompanion extends UpdateCompanion<_ConnectionEventData> { - final Value id; - final Value> ownUser; - final Value totalUnreadCount; - final Value unreadChannels; - final Value lastEventAt; - final Value lastSyncAt; - const _ConnectionEventCompanion({ - this.id = const Value.absent(), - this.ownUser = const Value.absent(), - this.totalUnreadCount = const Value.absent(), - this.unreadChannels = const Value.absent(), - this.lastEventAt = const Value.absent(), - this.lastSyncAt = const Value.absent(), - }); - _ConnectionEventCompanion.insert({ - this.id = const Value.absent(), - this.ownUser = const Value.absent(), - this.totalUnreadCount = const Value.absent(), - this.unreadChannels = const Value.absent(), - this.lastEventAt = const Value.absent(), - this.lastSyncAt = const Value.absent(), - }); - static Insertable<_ConnectionEventData> custom({ - Expression id, - Expression ownUser, - Expression totalUnreadCount, - Expression unreadChannels, - Expression lastEventAt, - Expression lastSyncAt, - }) { - return RawValuesInsertable({ - if (id != null) 'id': id, - if (ownUser != null) 'own_user': ownUser, - if (totalUnreadCount != null) 'total_unread_count': totalUnreadCount, - if (unreadChannels != null) 'unread_channels': unreadChannels, - if (lastEventAt != null) 'last_event_at': lastEventAt, - if (lastSyncAt != null) 'last_sync_at': lastSyncAt, - }); - } - - _ConnectionEventCompanion copyWith( - {Value id, - Value> ownUser, - Value totalUnreadCount, - Value unreadChannels, - Value lastEventAt, - Value lastSyncAt}) { - return _ConnectionEventCompanion( - id: id ?? this.id, - ownUser: ownUser ?? this.ownUser, - totalUnreadCount: totalUnreadCount ?? this.totalUnreadCount, - unreadChannels: unreadChannels ?? this.unreadChannels, - lastEventAt: lastEventAt ?? this.lastEventAt, - lastSyncAt: lastSyncAt ?? this.lastSyncAt, - ); - } - - @override - Map toColumns(bool nullToAbsent) { - final map = {}; - if (id.present) { - map['id'] = Variable(id.value); - } - if (ownUser.present) { - final converter = $_ConnectionEventTable.$converter0; - map['own_user'] = Variable(converter.mapToSql(ownUser.value)); - } - if (totalUnreadCount.present) { - map['total_unread_count'] = Variable(totalUnreadCount.value); - } - if (unreadChannels.present) { - map['unread_channels'] = Variable(unreadChannels.value); - } - if (lastEventAt.present) { - map['last_event_at'] = Variable(lastEventAt.value); - } - if (lastSyncAt.present) { - map['last_sync_at'] = Variable(lastSyncAt.value); - } - return map; - } - - @override - String toString() { - return (StringBuffer('_ConnectionEventCompanion(') - ..write('id: $id, ') - ..write('ownUser: $ownUser, ') - ..write('totalUnreadCount: $totalUnreadCount, ') - ..write('unreadChannels: $unreadChannels, ') - ..write('lastEventAt: $lastEventAt, ') - ..write('lastSyncAt: $lastSyncAt') - ..write(')')) - .toString(); - } -} - -class $_ConnectionEventTable extends _ConnectionEvent - with TableInfo<$_ConnectionEventTable, _ConnectionEventData> { - final GeneratedDatabase _db; - final String _alias; - $_ConnectionEventTable(this._db, [this._alias]); - final VerificationMeta _idMeta = const VerificationMeta('id'); - GeneratedIntColumn _id; - @override - GeneratedIntColumn get id => _id ??= _constructId(); - GeneratedIntColumn _constructId() { - return GeneratedIntColumn( - 'id', - $tableName, - false, - ); - } - - final VerificationMeta _ownUserMeta = const VerificationMeta('ownUser'); - GeneratedTextColumn _ownUser; - @override - GeneratedTextColumn get ownUser => _ownUser ??= _constructOwnUser(); - GeneratedTextColumn _constructOwnUser() { - return GeneratedTextColumn( - 'own_user', - $tableName, - true, - ); - } - - final VerificationMeta _totalUnreadCountMeta = - const VerificationMeta('totalUnreadCount'); - GeneratedIntColumn _totalUnreadCount; - @override - GeneratedIntColumn get totalUnreadCount => - _totalUnreadCount ??= _constructTotalUnreadCount(); - GeneratedIntColumn _constructTotalUnreadCount() { - return GeneratedIntColumn( - 'total_unread_count', - $tableName, - true, - ); - } - - final VerificationMeta _unreadChannelsMeta = - const VerificationMeta('unreadChannels'); - GeneratedIntColumn _unreadChannels; - @override - GeneratedIntColumn get unreadChannels => - _unreadChannels ??= _constructUnreadChannels(); - GeneratedIntColumn _constructUnreadChannels() { - return GeneratedIntColumn( - 'unread_channels', - $tableName, - true, - ); - } - - final VerificationMeta _lastEventAtMeta = - const VerificationMeta('lastEventAt'); - GeneratedDateTimeColumn _lastEventAt; - @override - GeneratedDateTimeColumn get lastEventAt => - _lastEventAt ??= _constructLastEventAt(); - GeneratedDateTimeColumn _constructLastEventAt() { - return GeneratedDateTimeColumn( - 'last_event_at', - $tableName, - true, - ); - } - - final VerificationMeta _lastSyncAtMeta = const VerificationMeta('lastSyncAt'); - GeneratedDateTimeColumn _lastSyncAt; - @override - GeneratedDateTimeColumn get lastSyncAt => - _lastSyncAt ??= _constructLastSyncAt(); - GeneratedDateTimeColumn _constructLastSyncAt() { - return GeneratedDateTimeColumn( - 'last_sync_at', - $tableName, - true, - ); - } - - @override - List get $columns => - [id, ownUser, totalUnreadCount, unreadChannels, lastEventAt, lastSyncAt]; - @override - $_ConnectionEventTable get asDslTable => this; - @override - String get $tableName => _alias ?? 'connection_event'; - @override - final String actualTableName = 'connection_event'; - @override - VerificationContext validateIntegrity( - Insertable<_ConnectionEventData> instance, - {bool isInserting = false}) { - final context = VerificationContext(); - final data = instance.toColumns(true); - if (data.containsKey('id')) { - context.handle(_idMeta, id.isAcceptableOrUnknown(data['id'], _idMeta)); - } - context.handle(_ownUserMeta, const VerificationResult.success()); - if (data.containsKey('total_unread_count')) { - context.handle( - _totalUnreadCountMeta, - totalUnreadCount.isAcceptableOrUnknown( - data['total_unread_count'], _totalUnreadCountMeta)); - } - if (data.containsKey('unread_channels')) { - context.handle( - _unreadChannelsMeta, - unreadChannels.isAcceptableOrUnknown( - data['unread_channels'], _unreadChannelsMeta)); - } - if (data.containsKey('last_event_at')) { - context.handle( - _lastEventAtMeta, - lastEventAt.isAcceptableOrUnknown( - data['last_event_at'], _lastEventAtMeta)); - } - if (data.containsKey('last_sync_at')) { - context.handle( - _lastSyncAtMeta, - lastSyncAt.isAcceptableOrUnknown( - data['last_sync_at'], _lastSyncAtMeta)); - } - return context; - } - - @override - Set get $primaryKey => {id}; - @override - _ConnectionEventData map(Map data, {String tablePrefix}) { - final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : null; - return _ConnectionEventData.fromData(data, _db, prefix: effectivePrefix); - } - - @override - $_ConnectionEventTable createAlias(String alias) { - return $_ConnectionEventTable(_db, alias); - } - - static TypeConverter, String> $converter0 = - _ExtraDataConverter(); -} - -class _Channel extends DataClass implements Insertable<_Channel> { - final String id; - final String type; - final String cid; - final String config; - final bool frozen; - final DateTime lastMessageAt; - final DateTime createdAt; - final DateTime updatedAt; - final DateTime deletedAt; - final int memberCount; - final Map extraData; - final String createdBy; - _Channel( - {@required this.id, - @required this.type, - @required this.cid, - @required this.config, - @required this.frozen, - this.lastMessageAt, - this.createdAt, - this.updatedAt, - this.deletedAt, - this.memberCount, - this.extraData, - this.createdBy}); - factory _Channel.fromData(Map data, GeneratedDatabase db, - {String prefix}) { - final effectivePrefix = prefix ?? ''; - final stringType = db.typeSystem.forDartType(); - final boolType = db.typeSystem.forDartType(); - final dateTimeType = db.typeSystem.forDartType(); - final intType = db.typeSystem.forDartType(); - return _Channel( - id: stringType.mapFromDatabaseResponse(data['${effectivePrefix}id']), - type: stringType.mapFromDatabaseResponse(data['${effectivePrefix}type']), - cid: stringType.mapFromDatabaseResponse(data['${effectivePrefix}cid']), - config: - stringType.mapFromDatabaseResponse(data['${effectivePrefix}config']), - frozen: - boolType.mapFromDatabaseResponse(data['${effectivePrefix}frozen']), - lastMessageAt: dateTimeType - .mapFromDatabaseResponse(data['${effectivePrefix}last_message_at']), - createdAt: dateTimeType - .mapFromDatabaseResponse(data['${effectivePrefix}created_at']), - updatedAt: dateTimeType - .mapFromDatabaseResponse(data['${effectivePrefix}updated_at']), - deletedAt: dateTimeType - .mapFromDatabaseResponse(data['${effectivePrefix}deleted_at']), - memberCount: intType - .mapFromDatabaseResponse(data['${effectivePrefix}member_count']), - extraData: $_ChannelsTable.$converter0.mapToDart(stringType - .mapFromDatabaseResponse(data['${effectivePrefix}extra_data'])), - createdBy: stringType - .mapFromDatabaseResponse(data['${effectivePrefix}created_by']), - ); - } - @override - Map toColumns(bool nullToAbsent) { - final map = {}; - if (!nullToAbsent || id != null) { - map['id'] = Variable(id); - } - if (!nullToAbsent || type != null) { - map['type'] = Variable(type); - } - if (!nullToAbsent || cid != null) { - map['cid'] = Variable(cid); - } - if (!nullToAbsent || config != null) { - map['config'] = Variable(config); - } - if (!nullToAbsent || frozen != null) { - map['frozen'] = Variable(frozen); - } - if (!nullToAbsent || lastMessageAt != null) { - map['last_message_at'] = Variable(lastMessageAt); - } - if (!nullToAbsent || createdAt != null) { - map['created_at'] = Variable(createdAt); - } - if (!nullToAbsent || updatedAt != null) { - map['updated_at'] = Variable(updatedAt); - } - if (!nullToAbsent || deletedAt != null) { - map['deleted_at'] = Variable(deletedAt); - } - if (!nullToAbsent || memberCount != null) { - map['member_count'] = Variable(memberCount); - } - if (!nullToAbsent || extraData != null) { - final converter = $_ChannelsTable.$converter0; - map['extra_data'] = Variable(converter.mapToSql(extraData)); - } - if (!nullToAbsent || createdBy != null) { - map['created_by'] = Variable(createdBy); - } - return map; - } - - _ChannelsCompanion toCompanion(bool nullToAbsent) { - return _ChannelsCompanion( - id: id == null && nullToAbsent ? const Value.absent() : Value(id), - type: type == null && nullToAbsent ? const Value.absent() : Value(type), - cid: cid == null && nullToAbsent ? const Value.absent() : Value(cid), - config: - config == null && nullToAbsent ? const Value.absent() : Value(config), - frozen: - frozen == null && nullToAbsent ? const Value.absent() : Value(frozen), - lastMessageAt: lastMessageAt == null && nullToAbsent - ? const Value.absent() - : Value(lastMessageAt), - createdAt: createdAt == null && nullToAbsent - ? const Value.absent() - : Value(createdAt), - updatedAt: updatedAt == null && nullToAbsent - ? const Value.absent() - : Value(updatedAt), - deletedAt: deletedAt == null && nullToAbsent - ? const Value.absent() - : Value(deletedAt), - memberCount: memberCount == null && nullToAbsent - ? const Value.absent() - : Value(memberCount), - extraData: extraData == null && nullToAbsent - ? const Value.absent() - : Value(extraData), - createdBy: createdBy == null && nullToAbsent - ? const Value.absent() - : Value(createdBy), - ); - } - - factory _Channel.fromJson(Map json, - {ValueSerializer serializer}) { - serializer ??= moorRuntimeOptions.defaultSerializer; - return _Channel( - id: serializer.fromJson(json['id']), - type: serializer.fromJson(json['type']), - cid: serializer.fromJson(json['cid']), - config: serializer.fromJson(json['config']), - frozen: serializer.fromJson(json['frozen']), - lastMessageAt: serializer.fromJson(json['lastMessageAt']), - createdAt: serializer.fromJson(json['createdAt']), - updatedAt: serializer.fromJson(json['updatedAt']), - deletedAt: serializer.fromJson(json['deletedAt']), - memberCount: serializer.fromJson(json['memberCount']), - extraData: serializer.fromJson>(json['extraData']), - createdBy: serializer.fromJson(json['createdBy']), - ); - } - @override - Map toJson({ValueSerializer serializer}) { - serializer ??= moorRuntimeOptions.defaultSerializer; - return { - 'id': serializer.toJson(id), - 'type': serializer.toJson(type), - 'cid': serializer.toJson(cid), - 'config': serializer.toJson(config), - 'frozen': serializer.toJson(frozen), - 'lastMessageAt': serializer.toJson(lastMessageAt), - 'createdAt': serializer.toJson(createdAt), - 'updatedAt': serializer.toJson(updatedAt), - 'deletedAt': serializer.toJson(deletedAt), - 'memberCount': serializer.toJson(memberCount), - 'extraData': serializer.toJson>(extraData), - 'createdBy': serializer.toJson(createdBy), - }; - } - - _Channel copyWith( - {String id, - String type, - String cid, - String config, - bool frozen, - DateTime lastMessageAt, - DateTime createdAt, - DateTime updatedAt, - DateTime deletedAt, - int memberCount, - Map extraData, - String createdBy}) => - _Channel( - id: id ?? this.id, - type: type ?? this.type, - cid: cid ?? this.cid, - config: config ?? this.config, - frozen: frozen ?? this.frozen, - lastMessageAt: lastMessageAt ?? this.lastMessageAt, - createdAt: createdAt ?? this.createdAt, - updatedAt: updatedAt ?? this.updatedAt, - deletedAt: deletedAt ?? this.deletedAt, - memberCount: memberCount ?? this.memberCount, - extraData: extraData ?? this.extraData, - createdBy: createdBy ?? this.createdBy, - ); - @override - String toString() { - return (StringBuffer('_Channel(') - ..write('id: $id, ') - ..write('type: $type, ') - ..write('cid: $cid, ') - ..write('config: $config, ') - ..write('frozen: $frozen, ') - ..write('lastMessageAt: $lastMessageAt, ') - ..write('createdAt: $createdAt, ') - ..write('updatedAt: $updatedAt, ') - ..write('deletedAt: $deletedAt, ') - ..write('memberCount: $memberCount, ') - ..write('extraData: $extraData, ') - ..write('createdBy: $createdBy') - ..write(')')) - .toString(); - } - - @override - int get hashCode => $mrjf($mrjc( - id.hashCode, - $mrjc( - type.hashCode, - $mrjc( - cid.hashCode, - $mrjc( - config.hashCode, - $mrjc( - frozen.hashCode, - $mrjc( - lastMessageAt.hashCode, - $mrjc( - createdAt.hashCode, - $mrjc( - updatedAt.hashCode, - $mrjc( - deletedAt.hashCode, - $mrjc( - memberCount.hashCode, - $mrjc(extraData.hashCode, - createdBy.hashCode)))))))))))); - @override - bool operator ==(dynamic other) => - identical(this, other) || - (other is _Channel && - other.id == this.id && - other.type == this.type && - other.cid == this.cid && - other.config == this.config && - other.frozen == this.frozen && - other.lastMessageAt == this.lastMessageAt && - other.createdAt == this.createdAt && - other.updatedAt == this.updatedAt && - other.deletedAt == this.deletedAt && - other.memberCount == this.memberCount && - other.extraData == this.extraData && - other.createdBy == this.createdBy); -} - -class _ChannelsCompanion extends UpdateCompanion<_Channel> { - final Value id; - final Value type; - final Value cid; - final Value config; - final Value frozen; - final Value lastMessageAt; - final Value createdAt; - final Value updatedAt; - final Value deletedAt; - final Value memberCount; - final Value> extraData; - final Value createdBy; - const _ChannelsCompanion({ - this.id = const Value.absent(), - this.type = const Value.absent(), - this.cid = const Value.absent(), - this.config = const Value.absent(), - this.frozen = const Value.absent(), - this.lastMessageAt = const Value.absent(), - this.createdAt = const Value.absent(), - this.updatedAt = const Value.absent(), - this.deletedAt = const Value.absent(), - this.memberCount = const Value.absent(), - this.extraData = const Value.absent(), - this.createdBy = const Value.absent(), - }); - _ChannelsCompanion.insert({ - @required String id, - @required String type, - @required String cid, - @required String config, - this.frozen = const Value.absent(), - this.lastMessageAt = const Value.absent(), - this.createdAt = const Value.absent(), - this.updatedAt = const Value.absent(), - this.deletedAt = const Value.absent(), - this.memberCount = const Value.absent(), - this.extraData = const Value.absent(), - this.createdBy = const Value.absent(), - }) : id = Value(id), - type = Value(type), - cid = Value(cid), - config = Value(config); - static Insertable<_Channel> custom({ - Expression id, - Expression type, - Expression cid, - Expression config, - Expression frozen, - Expression lastMessageAt, - Expression createdAt, - Expression updatedAt, - Expression deletedAt, - Expression memberCount, - Expression extraData, - Expression createdBy, - }) { - return RawValuesInsertable({ - if (id != null) 'id': id, - if (type != null) 'type': type, - if (cid != null) 'cid': cid, - if (config != null) 'config': config, - if (frozen != null) 'frozen': frozen, - if (lastMessageAt != null) 'last_message_at': lastMessageAt, - if (createdAt != null) 'created_at': createdAt, - if (updatedAt != null) 'updated_at': updatedAt, - if (deletedAt != null) 'deleted_at': deletedAt, - if (memberCount != null) 'member_count': memberCount, - if (extraData != null) 'extra_data': extraData, - if (createdBy != null) 'created_by': createdBy, - }); - } - - _ChannelsCompanion copyWith( - {Value id, - Value type, - Value cid, - Value config, - Value frozen, - Value lastMessageAt, - Value createdAt, - Value updatedAt, - Value deletedAt, - Value memberCount, - Value> extraData, - Value createdBy}) { - return _ChannelsCompanion( - id: id ?? this.id, - type: type ?? this.type, - cid: cid ?? this.cid, - config: config ?? this.config, - frozen: frozen ?? this.frozen, - lastMessageAt: lastMessageAt ?? this.lastMessageAt, - createdAt: createdAt ?? this.createdAt, - updatedAt: updatedAt ?? this.updatedAt, - deletedAt: deletedAt ?? this.deletedAt, - memberCount: memberCount ?? this.memberCount, - extraData: extraData ?? this.extraData, - createdBy: createdBy ?? this.createdBy, - ); - } - - @override - Map toColumns(bool nullToAbsent) { - final map = {}; - if (id.present) { - map['id'] = Variable(id.value); - } - if (type.present) { - map['type'] = Variable(type.value); - } - if (cid.present) { - map['cid'] = Variable(cid.value); - } - if (config.present) { - map['config'] = Variable(config.value); - } - if (frozen.present) { - map['frozen'] = Variable(frozen.value); - } - if (lastMessageAt.present) { - map['last_message_at'] = Variable(lastMessageAt.value); - } - if (createdAt.present) { - map['created_at'] = Variable(createdAt.value); - } - if (updatedAt.present) { - map['updated_at'] = Variable(updatedAt.value); - } - if (deletedAt.present) { - map['deleted_at'] = Variable(deletedAt.value); - } - if (memberCount.present) { - map['member_count'] = Variable(memberCount.value); - } - if (extraData.present) { - final converter = $_ChannelsTable.$converter0; - map['extra_data'] = Variable(converter.mapToSql(extraData.value)); - } - if (createdBy.present) { - map['created_by'] = Variable(createdBy.value); - } - return map; - } - - @override - String toString() { - return (StringBuffer('_ChannelsCompanion(') - ..write('id: $id, ') - ..write('type: $type, ') - ..write('cid: $cid, ') - ..write('config: $config, ') - ..write('frozen: $frozen, ') - ..write('lastMessageAt: $lastMessageAt, ') - ..write('createdAt: $createdAt, ') - ..write('updatedAt: $updatedAt, ') - ..write('deletedAt: $deletedAt, ') - ..write('memberCount: $memberCount, ') - ..write('extraData: $extraData, ') - ..write('createdBy: $createdBy') - ..write(')')) - .toString(); - } -} - -class $_ChannelsTable extends _Channels - with TableInfo<$_ChannelsTable, _Channel> { - final GeneratedDatabase _db; - final String _alias; - $_ChannelsTable(this._db, [this._alias]); - final VerificationMeta _idMeta = const VerificationMeta('id'); - GeneratedTextColumn _id; - @override - GeneratedTextColumn get id => _id ??= _constructId(); - GeneratedTextColumn _constructId() { - return GeneratedTextColumn( - 'id', - $tableName, - false, - ); - } - - final VerificationMeta _typeMeta = const VerificationMeta('type'); - GeneratedTextColumn _type; - @override - GeneratedTextColumn get type => _type ??= _constructType(); - GeneratedTextColumn _constructType() { - return GeneratedTextColumn( - 'type', - $tableName, - false, - ); - } - - final VerificationMeta _cidMeta = const VerificationMeta('cid'); - GeneratedTextColumn _cid; - @override - GeneratedTextColumn get cid => _cid ??= _constructCid(); - GeneratedTextColumn _constructCid() { - return GeneratedTextColumn( - 'cid', - $tableName, - false, - ); - } - - final VerificationMeta _configMeta = const VerificationMeta('config'); - GeneratedTextColumn _config; - @override - GeneratedTextColumn get config => _config ??= _constructConfig(); - GeneratedTextColumn _constructConfig() { - return GeneratedTextColumn( - 'config', - $tableName, - false, - ); - } - - final VerificationMeta _frozenMeta = const VerificationMeta('frozen'); - GeneratedBoolColumn _frozen; - @override - GeneratedBoolColumn get frozen => _frozen ??= _constructFrozen(); - GeneratedBoolColumn _constructFrozen() { - return GeneratedBoolColumn('frozen', $tableName, false, - defaultValue: Constant(false)); - } - - final VerificationMeta _lastMessageAtMeta = - const VerificationMeta('lastMessageAt'); - GeneratedDateTimeColumn _lastMessageAt; - @override - GeneratedDateTimeColumn get lastMessageAt => - _lastMessageAt ??= _constructLastMessageAt(); - GeneratedDateTimeColumn _constructLastMessageAt() { - return GeneratedDateTimeColumn( - 'last_message_at', - $tableName, - true, - ); - } - - final VerificationMeta _createdAtMeta = const VerificationMeta('createdAt'); - GeneratedDateTimeColumn _createdAt; - @override - GeneratedDateTimeColumn get createdAt => _createdAt ??= _constructCreatedAt(); - GeneratedDateTimeColumn _constructCreatedAt() { - return GeneratedDateTimeColumn( - 'created_at', - $tableName, - true, - ); - } - - final VerificationMeta _updatedAtMeta = const VerificationMeta('updatedAt'); - GeneratedDateTimeColumn _updatedAt; - @override - GeneratedDateTimeColumn get updatedAt => _updatedAt ??= _constructUpdatedAt(); - GeneratedDateTimeColumn _constructUpdatedAt() { - return GeneratedDateTimeColumn( - 'updated_at', - $tableName, - true, - ); - } - - final VerificationMeta _deletedAtMeta = const VerificationMeta('deletedAt'); - GeneratedDateTimeColumn _deletedAt; - @override - GeneratedDateTimeColumn get deletedAt => _deletedAt ??= _constructDeletedAt(); - GeneratedDateTimeColumn _constructDeletedAt() { - return GeneratedDateTimeColumn( - 'deleted_at', - $tableName, - true, - ); - } - - final VerificationMeta _memberCountMeta = - const VerificationMeta('memberCount'); - GeneratedIntColumn _memberCount; - @override - GeneratedIntColumn get memberCount => - _memberCount ??= _constructMemberCount(); - GeneratedIntColumn _constructMemberCount() { - return GeneratedIntColumn( - 'member_count', - $tableName, - true, - ); - } - - final VerificationMeta _extraDataMeta = const VerificationMeta('extraData'); - GeneratedTextColumn _extraData; - @override - GeneratedTextColumn get extraData => _extraData ??= _constructExtraData(); - GeneratedTextColumn _constructExtraData() { - return GeneratedTextColumn( - 'extra_data', - $tableName, - true, - ); - } - - final VerificationMeta _createdByMeta = const VerificationMeta('createdBy'); - GeneratedTextColumn _createdBy; - @override - GeneratedTextColumn get createdBy => _createdBy ??= _constructCreatedBy(); - GeneratedTextColumn _constructCreatedBy() { - return GeneratedTextColumn( - 'created_by', - $tableName, - true, - ); - } - - @override - List get $columns => [ - id, - type, - cid, - config, - frozen, - lastMessageAt, - createdAt, - updatedAt, - deletedAt, - memberCount, - extraData, - createdBy - ]; - @override - $_ChannelsTable get asDslTable => this; - @override - String get $tableName => _alias ?? 'channels'; - @override - final String actualTableName = 'channels'; - @override - VerificationContext validateIntegrity(Insertable<_Channel> instance, - {bool isInserting = false}) { - final context = VerificationContext(); - final data = instance.toColumns(true); - if (data.containsKey('id')) { - context.handle(_idMeta, id.isAcceptableOrUnknown(data['id'], _idMeta)); - } else if (isInserting) { - context.missing(_idMeta); - } - if (data.containsKey('type')) { - context.handle( - _typeMeta, type.isAcceptableOrUnknown(data['type'], _typeMeta)); - } else if (isInserting) { - context.missing(_typeMeta); - } - if (data.containsKey('cid')) { - context.handle( - _cidMeta, cid.isAcceptableOrUnknown(data['cid'], _cidMeta)); - } else if (isInserting) { - context.missing(_cidMeta); - } - if (data.containsKey('config')) { - context.handle(_configMeta, - config.isAcceptableOrUnknown(data['config'], _configMeta)); - } else if (isInserting) { - context.missing(_configMeta); - } - if (data.containsKey('frozen')) { - context.handle(_frozenMeta, - frozen.isAcceptableOrUnknown(data['frozen'], _frozenMeta)); - } - if (data.containsKey('last_message_at')) { - context.handle( - _lastMessageAtMeta, - lastMessageAt.isAcceptableOrUnknown( - data['last_message_at'], _lastMessageAtMeta)); - } - if (data.containsKey('created_at')) { - context.handle(_createdAtMeta, - createdAt.isAcceptableOrUnknown(data['created_at'], _createdAtMeta)); - } - if (data.containsKey('updated_at')) { - context.handle(_updatedAtMeta, - updatedAt.isAcceptableOrUnknown(data['updated_at'], _updatedAtMeta)); - } - if (data.containsKey('deleted_at')) { - context.handle(_deletedAtMeta, - deletedAt.isAcceptableOrUnknown(data['deleted_at'], _deletedAtMeta)); - } - if (data.containsKey('member_count')) { - context.handle( - _memberCountMeta, - memberCount.isAcceptableOrUnknown( - data['member_count'], _memberCountMeta)); - } - context.handle(_extraDataMeta, const VerificationResult.success()); - if (data.containsKey('created_by')) { - context.handle(_createdByMeta, - createdBy.isAcceptableOrUnknown(data['created_by'], _createdByMeta)); - } - return context; - } - - @override - Set get $primaryKey => {cid}; - @override - _Channel map(Map data, {String tablePrefix}) { - final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : null; - return _Channel.fromData(data, _db, prefix: effectivePrefix); - } - - @override - $_ChannelsTable createAlias(String alias) { - return $_ChannelsTable(_db, alias); - } - - static TypeConverter, String> $converter0 = - _ExtraDataConverter(); -} - -class _User extends DataClass implements Insertable<_User> { - final String id; - final String role; - final DateTime createdAt; - final DateTime updatedAt; - final DateTime lastActive; - final bool online; - final bool banned; - final Map extraData; - _User( - {@required this.id, - this.role, - this.createdAt, - this.updatedAt, - this.lastActive, - this.online, - this.banned, - this.extraData}); - factory _User.fromData(Map data, GeneratedDatabase db, - {String prefix}) { - final effectivePrefix = prefix ?? ''; - final stringType = db.typeSystem.forDartType(); - final dateTimeType = db.typeSystem.forDartType(); - final boolType = db.typeSystem.forDartType(); - return _User( - id: stringType.mapFromDatabaseResponse(data['${effectivePrefix}id']), - role: stringType.mapFromDatabaseResponse(data['${effectivePrefix}role']), - createdAt: dateTimeType - .mapFromDatabaseResponse(data['${effectivePrefix}created_at']), - updatedAt: dateTimeType - .mapFromDatabaseResponse(data['${effectivePrefix}updated_at']), - lastActive: dateTimeType - .mapFromDatabaseResponse(data['${effectivePrefix}last_active']), - online: - boolType.mapFromDatabaseResponse(data['${effectivePrefix}online']), - banned: - boolType.mapFromDatabaseResponse(data['${effectivePrefix}banned']), - extraData: $_UsersTable.$converter0.mapToDart(stringType - .mapFromDatabaseResponse(data['${effectivePrefix}extra_data'])), - ); - } - @override - Map toColumns(bool nullToAbsent) { - final map = {}; - if (!nullToAbsent || id != null) { - map['id'] = Variable(id); - } - if (!nullToAbsent || role != null) { - map['role'] = Variable(role); - } - if (!nullToAbsent || createdAt != null) { - map['created_at'] = Variable(createdAt); - } - if (!nullToAbsent || updatedAt != null) { - map['updated_at'] = Variable(updatedAt); - } - if (!nullToAbsent || lastActive != null) { - map['last_active'] = Variable(lastActive); - } - if (!nullToAbsent || online != null) { - map['online'] = Variable(online); - } - if (!nullToAbsent || banned != null) { - map['banned'] = Variable(banned); - } - if (!nullToAbsent || extraData != null) { - final converter = $_UsersTable.$converter0; - map['extra_data'] = Variable(converter.mapToSql(extraData)); - } - return map; - } - - _UsersCompanion toCompanion(bool nullToAbsent) { - return _UsersCompanion( - id: id == null && nullToAbsent ? const Value.absent() : Value(id), - role: role == null && nullToAbsent ? const Value.absent() : Value(role), - createdAt: createdAt == null && nullToAbsent - ? const Value.absent() - : Value(createdAt), - updatedAt: updatedAt == null && nullToAbsent - ? const Value.absent() - : Value(updatedAt), - lastActive: lastActive == null && nullToAbsent - ? const Value.absent() - : Value(lastActive), - online: - online == null && nullToAbsent ? const Value.absent() : Value(online), - banned: - banned == null && nullToAbsent ? const Value.absent() : Value(banned), - extraData: extraData == null && nullToAbsent - ? const Value.absent() - : Value(extraData), - ); - } - - factory _User.fromJson(Map json, - {ValueSerializer serializer}) { - serializer ??= moorRuntimeOptions.defaultSerializer; - return _User( - id: serializer.fromJson(json['id']), - role: serializer.fromJson(json['role']), - createdAt: serializer.fromJson(json['createdAt']), - updatedAt: serializer.fromJson(json['updatedAt']), - lastActive: serializer.fromJson(json['lastActive']), - online: serializer.fromJson(json['online']), - banned: serializer.fromJson(json['banned']), - extraData: serializer.fromJson>(json['extraData']), - ); - } - @override - Map toJson({ValueSerializer serializer}) { - serializer ??= moorRuntimeOptions.defaultSerializer; - return { - 'id': serializer.toJson(id), - 'role': serializer.toJson(role), - 'createdAt': serializer.toJson(createdAt), - 'updatedAt': serializer.toJson(updatedAt), - 'lastActive': serializer.toJson(lastActive), - 'online': serializer.toJson(online), - 'banned': serializer.toJson(banned), - 'extraData': serializer.toJson>(extraData), - }; - } - - _User copyWith( - {String id, - String role, - DateTime createdAt, - DateTime updatedAt, - DateTime lastActive, - bool online, - bool banned, - Map extraData}) => - _User( - id: id ?? this.id, - role: role ?? this.role, - createdAt: createdAt ?? this.createdAt, - updatedAt: updatedAt ?? this.updatedAt, - lastActive: lastActive ?? this.lastActive, - online: online ?? this.online, - banned: banned ?? this.banned, - extraData: extraData ?? this.extraData, - ); - @override - String toString() { - return (StringBuffer('_User(') - ..write('id: $id, ') - ..write('role: $role, ') - ..write('createdAt: $createdAt, ') - ..write('updatedAt: $updatedAt, ') - ..write('lastActive: $lastActive, ') - ..write('online: $online, ') - ..write('banned: $banned, ') - ..write('extraData: $extraData') - ..write(')')) - .toString(); - } - - @override - int get hashCode => $mrjf($mrjc( - id.hashCode, - $mrjc( - role.hashCode, - $mrjc( - createdAt.hashCode, - $mrjc( - updatedAt.hashCode, - $mrjc( - lastActive.hashCode, - $mrjc(online.hashCode, - $mrjc(banned.hashCode, extraData.hashCode)))))))); - @override - bool operator ==(dynamic other) => - identical(this, other) || - (other is _User && - other.id == this.id && - other.role == this.role && - other.createdAt == this.createdAt && - other.updatedAt == this.updatedAt && - other.lastActive == this.lastActive && - other.online == this.online && - other.banned == this.banned && - other.extraData == this.extraData); -} - -class _UsersCompanion extends UpdateCompanion<_User> { - final Value id; - final Value role; - final Value createdAt; - final Value updatedAt; - final Value lastActive; - final Value online; - final Value banned; - final Value> extraData; - const _UsersCompanion({ - this.id = const Value.absent(), - this.role = const Value.absent(), - this.createdAt = const Value.absent(), - this.updatedAt = const Value.absent(), - this.lastActive = const Value.absent(), - this.online = const Value.absent(), - this.banned = const Value.absent(), - this.extraData = const Value.absent(), - }); - _UsersCompanion.insert({ - @required String id, - this.role = const Value.absent(), - this.createdAt = const Value.absent(), - this.updatedAt = const Value.absent(), - this.lastActive = const Value.absent(), - this.online = const Value.absent(), - this.banned = const Value.absent(), - this.extraData = const Value.absent(), - }) : id = Value(id); - static Insertable<_User> custom({ - Expression id, - Expression role, - Expression createdAt, - Expression updatedAt, - Expression lastActive, - Expression online, - Expression banned, - Expression extraData, - }) { - return RawValuesInsertable({ - if (id != null) 'id': id, - if (role != null) 'role': role, - if (createdAt != null) 'created_at': createdAt, - if (updatedAt != null) 'updated_at': updatedAt, - if (lastActive != null) 'last_active': lastActive, - if (online != null) 'online': online, - if (banned != null) 'banned': banned, - if (extraData != null) 'extra_data': extraData, - }); - } - - _UsersCompanion copyWith( - {Value id, - Value role, - Value createdAt, - Value updatedAt, - Value lastActive, - Value online, - Value banned, - Value> extraData}) { - return _UsersCompanion( - id: id ?? this.id, - role: role ?? this.role, - createdAt: createdAt ?? this.createdAt, - updatedAt: updatedAt ?? this.updatedAt, - lastActive: lastActive ?? this.lastActive, - online: online ?? this.online, - banned: banned ?? this.banned, - extraData: extraData ?? this.extraData, - ); - } - - @override - Map toColumns(bool nullToAbsent) { - final map = {}; - if (id.present) { - map['id'] = Variable(id.value); - } - if (role.present) { - map['role'] = Variable(role.value); - } - if (createdAt.present) { - map['created_at'] = Variable(createdAt.value); - } - if (updatedAt.present) { - map['updated_at'] = Variable(updatedAt.value); - } - if (lastActive.present) { - map['last_active'] = Variable(lastActive.value); - } - if (online.present) { - map['online'] = Variable(online.value); - } - if (banned.present) { - map['banned'] = Variable(banned.value); - } - if (extraData.present) { - final converter = $_UsersTable.$converter0; - map['extra_data'] = Variable(converter.mapToSql(extraData.value)); - } - return map; - } - - @override - String toString() { - return (StringBuffer('_UsersCompanion(') - ..write('id: $id, ') - ..write('role: $role, ') - ..write('createdAt: $createdAt, ') - ..write('updatedAt: $updatedAt, ') - ..write('lastActive: $lastActive, ') - ..write('online: $online, ') - ..write('banned: $banned, ') - ..write('extraData: $extraData') - ..write(')')) - .toString(); - } -} - -class $_UsersTable extends _Users with TableInfo<$_UsersTable, _User> { - final GeneratedDatabase _db; - final String _alias; - $_UsersTable(this._db, [this._alias]); - final VerificationMeta _idMeta = const VerificationMeta('id'); - GeneratedTextColumn _id; - @override - GeneratedTextColumn get id => _id ??= _constructId(); - GeneratedTextColumn _constructId() { - return GeneratedTextColumn( - 'id', - $tableName, - false, - ); - } - - final VerificationMeta _roleMeta = const VerificationMeta('role'); - GeneratedTextColumn _role; - @override - GeneratedTextColumn get role => _role ??= _constructRole(); - GeneratedTextColumn _constructRole() { - return GeneratedTextColumn( - 'role', - $tableName, - true, - ); - } - - final VerificationMeta _createdAtMeta = const VerificationMeta('createdAt'); - GeneratedDateTimeColumn _createdAt; - @override - GeneratedDateTimeColumn get createdAt => _createdAt ??= _constructCreatedAt(); - GeneratedDateTimeColumn _constructCreatedAt() { - return GeneratedDateTimeColumn( - 'created_at', - $tableName, - true, - ); - } - - final VerificationMeta _updatedAtMeta = const VerificationMeta('updatedAt'); - GeneratedDateTimeColumn _updatedAt; - @override - GeneratedDateTimeColumn get updatedAt => _updatedAt ??= _constructUpdatedAt(); - GeneratedDateTimeColumn _constructUpdatedAt() { - return GeneratedDateTimeColumn( - 'updated_at', - $tableName, - true, - ); - } - - final VerificationMeta _lastActiveMeta = const VerificationMeta('lastActive'); - GeneratedDateTimeColumn _lastActive; - @override - GeneratedDateTimeColumn get lastActive => - _lastActive ??= _constructLastActive(); - GeneratedDateTimeColumn _constructLastActive() { - return GeneratedDateTimeColumn( - 'last_active', - $tableName, - true, - ); - } - - final VerificationMeta _onlineMeta = const VerificationMeta('online'); - GeneratedBoolColumn _online; - @override - GeneratedBoolColumn get online => _online ??= _constructOnline(); - GeneratedBoolColumn _constructOnline() { - return GeneratedBoolColumn( - 'online', - $tableName, - true, - ); - } - - final VerificationMeta _bannedMeta = const VerificationMeta('banned'); - GeneratedBoolColumn _banned; - @override - GeneratedBoolColumn get banned => _banned ??= _constructBanned(); - GeneratedBoolColumn _constructBanned() { - return GeneratedBoolColumn( - 'banned', - $tableName, - true, - ); - } - - final VerificationMeta _extraDataMeta = const VerificationMeta('extraData'); - GeneratedTextColumn _extraData; - @override - GeneratedTextColumn get extraData => _extraData ??= _constructExtraData(); - GeneratedTextColumn _constructExtraData() { - return GeneratedTextColumn( - 'extra_data', - $tableName, - true, - ); - } - - @override - List get $columns => - [id, role, createdAt, updatedAt, lastActive, online, banned, extraData]; - @override - $_UsersTable get asDslTable => this; - @override - String get $tableName => _alias ?? 'users'; - @override - final String actualTableName = 'users'; - @override - VerificationContext validateIntegrity(Insertable<_User> instance, - {bool isInserting = false}) { - final context = VerificationContext(); - final data = instance.toColumns(true); - if (data.containsKey('id')) { - context.handle(_idMeta, id.isAcceptableOrUnknown(data['id'], _idMeta)); - } else if (isInserting) { - context.missing(_idMeta); - } - if (data.containsKey('role')) { - context.handle( - _roleMeta, role.isAcceptableOrUnknown(data['role'], _roleMeta)); - } - if (data.containsKey('created_at')) { - context.handle(_createdAtMeta, - createdAt.isAcceptableOrUnknown(data['created_at'], _createdAtMeta)); - } - if (data.containsKey('updated_at')) { - context.handle(_updatedAtMeta, - updatedAt.isAcceptableOrUnknown(data['updated_at'], _updatedAtMeta)); - } - if (data.containsKey('last_active')) { - context.handle( - _lastActiveMeta, - lastActive.isAcceptableOrUnknown( - data['last_active'], _lastActiveMeta)); - } - if (data.containsKey('online')) { - context.handle(_onlineMeta, - online.isAcceptableOrUnknown(data['online'], _onlineMeta)); - } - if (data.containsKey('banned')) { - context.handle(_bannedMeta, - banned.isAcceptableOrUnknown(data['banned'], _bannedMeta)); - } - context.handle(_extraDataMeta, const VerificationResult.success()); - return context; - } - - @override - Set get $primaryKey => {id}; - @override - _User map(Map data, {String tablePrefix}) { - final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : null; - return _User.fromData(data, _db, prefix: effectivePrefix); - } - - @override - $_UsersTable createAlias(String alias) { - return $_UsersTable(_db, alias); - } - - static TypeConverter, String> $converter0 = - _ExtraDataConverter(); -} - -class _Message extends DataClass implements Insertable<_Message> { - final String id; - final String messageText; - final String attachmentJson; - final MessageSendingStatus status; - final String type; - final Map reactionCounts; - final Map reactionScores; - final String parentId; - final String quotedMessageId; - final int replyCount; - final bool showInChannel; - final bool shadowed; - final String command; - final DateTime createdAt; - final DateTime updatedAt; - final DateTime deletedAt; - final String userId; - final String channelCid; - final Map extraData; - _Message( - {@required this.id, - this.messageText, - this.attachmentJson, - this.status, - this.type, - this.reactionCounts, - this.reactionScores, - this.parentId, - this.quotedMessageId, - this.replyCount, - this.showInChannel, - this.shadowed, - this.command, - @required this.createdAt, - this.updatedAt, - this.deletedAt, - this.userId, - this.channelCid, - this.extraData}); - factory _Message.fromData(Map data, GeneratedDatabase db, - {String prefix}) { - final effectivePrefix = prefix ?? ''; - final stringType = db.typeSystem.forDartType(); - final intType = db.typeSystem.forDartType(); - final boolType = db.typeSystem.forDartType(); - final dateTimeType = db.typeSystem.forDartType(); - return _Message( - id: stringType.mapFromDatabaseResponse(data['${effectivePrefix}id']), - messageText: stringType - .mapFromDatabaseResponse(data['${effectivePrefix}message_text']), - attachmentJson: stringType - .mapFromDatabaseResponse(data['${effectivePrefix}attachment_json']), - status: $_MessagesTable.$converter0.mapToDart( - intType.mapFromDatabaseResponse(data['${effectivePrefix}status'])), - type: stringType.mapFromDatabaseResponse(data['${effectivePrefix}type']), - reactionCounts: $_MessagesTable.$converter1.mapToDart(stringType - .mapFromDatabaseResponse(data['${effectivePrefix}reaction_counts'])), - reactionScores: $_MessagesTable.$converter2.mapToDart(stringType - .mapFromDatabaseResponse(data['${effectivePrefix}reaction_scores'])), - parentId: stringType - .mapFromDatabaseResponse(data['${effectivePrefix}parent_id']), - quotedMessageId: stringType - .mapFromDatabaseResponse(data['${effectivePrefix}quoted_message_id']), - replyCount: intType - .mapFromDatabaseResponse(data['${effectivePrefix}reply_count']), - showInChannel: boolType - .mapFromDatabaseResponse(data['${effectivePrefix}show_in_channel']), - shadowed: - boolType.mapFromDatabaseResponse(data['${effectivePrefix}shadowed']), - command: - stringType.mapFromDatabaseResponse(data['${effectivePrefix}command']), - createdAt: dateTimeType - .mapFromDatabaseResponse(data['${effectivePrefix}created_at']), - updatedAt: dateTimeType - .mapFromDatabaseResponse(data['${effectivePrefix}updated_at']), - deletedAt: dateTimeType - .mapFromDatabaseResponse(data['${effectivePrefix}deleted_at']), - userId: - stringType.mapFromDatabaseResponse(data['${effectivePrefix}user_id']), - channelCid: stringType - .mapFromDatabaseResponse(data['${effectivePrefix}channel_cid']), - extraData: $_MessagesTable.$converter3.mapToDart(stringType - .mapFromDatabaseResponse(data['${effectivePrefix}extra_data'])), - ); - } - @override - Map toColumns(bool nullToAbsent) { - final map = {}; - if (!nullToAbsent || id != null) { - map['id'] = Variable(id); - } - if (!nullToAbsent || messageText != null) { - map['message_text'] = Variable(messageText); - } - if (!nullToAbsent || attachmentJson != null) { - map['attachment_json'] = Variable(attachmentJson); - } - if (!nullToAbsent || status != null) { - final converter = $_MessagesTable.$converter0; - map['status'] = Variable(converter.mapToSql(status)); - } - if (!nullToAbsent || type != null) { - map['type'] = Variable(type); - } - if (!nullToAbsent || reactionCounts != null) { - final converter = $_MessagesTable.$converter1; - map['reaction_counts'] = - Variable(converter.mapToSql(reactionCounts)); - } - if (!nullToAbsent || reactionScores != null) { - final converter = $_MessagesTable.$converter2; - map['reaction_scores'] = - Variable(converter.mapToSql(reactionScores)); - } - if (!nullToAbsent || parentId != null) { - map['parent_id'] = Variable(parentId); - } - if (!nullToAbsent || quotedMessageId != null) { - map['quoted_message_id'] = Variable(quotedMessageId); - } - if (!nullToAbsent || replyCount != null) { - map['reply_count'] = Variable(replyCount); - } - if (!nullToAbsent || showInChannel != null) { - map['show_in_channel'] = Variable(showInChannel); - } - if (!nullToAbsent || shadowed != null) { - map['shadowed'] = Variable(shadowed); - } - if (!nullToAbsent || command != null) { - map['command'] = Variable(command); - } - if (!nullToAbsent || createdAt != null) { - map['created_at'] = Variable(createdAt); - } - if (!nullToAbsent || updatedAt != null) { - map['updated_at'] = Variable(updatedAt); - } - if (!nullToAbsent || deletedAt != null) { - map['deleted_at'] = Variable(deletedAt); - } - if (!nullToAbsent || userId != null) { - map['user_id'] = Variable(userId); - } - if (!nullToAbsent || channelCid != null) { - map['channel_cid'] = Variable(channelCid); - } - if (!nullToAbsent || extraData != null) { - final converter = $_MessagesTable.$converter3; - map['extra_data'] = Variable(converter.mapToSql(extraData)); - } - return map; - } - - _MessagesCompanion toCompanion(bool nullToAbsent) { - return _MessagesCompanion( - id: id == null && nullToAbsent ? const Value.absent() : Value(id), - messageText: messageText == null && nullToAbsent - ? const Value.absent() - : Value(messageText), - attachmentJson: attachmentJson == null && nullToAbsent - ? const Value.absent() - : Value(attachmentJson), - status: - status == null && nullToAbsent ? const Value.absent() : Value(status), - type: type == null && nullToAbsent ? const Value.absent() : Value(type), - reactionCounts: reactionCounts == null && nullToAbsent - ? const Value.absent() - : Value(reactionCounts), - reactionScores: reactionScores == null && nullToAbsent - ? const Value.absent() - : Value(reactionScores), - parentId: parentId == null && nullToAbsent - ? const Value.absent() - : Value(parentId), - quotedMessageId: quotedMessageId == null && nullToAbsent - ? const Value.absent() - : Value(quotedMessageId), - replyCount: replyCount == null && nullToAbsent - ? const Value.absent() - : Value(replyCount), - showInChannel: showInChannel == null && nullToAbsent - ? const Value.absent() - : Value(showInChannel), - shadowed: shadowed == null && nullToAbsent - ? const Value.absent() - : Value(shadowed), - command: command == null && nullToAbsent - ? const Value.absent() - : Value(command), - createdAt: createdAt == null && nullToAbsent - ? const Value.absent() - : Value(createdAt), - updatedAt: updatedAt == null && nullToAbsent - ? const Value.absent() - : Value(updatedAt), - deletedAt: deletedAt == null && nullToAbsent - ? const Value.absent() - : Value(deletedAt), - userId: - userId == null && nullToAbsent ? const Value.absent() : Value(userId), - channelCid: channelCid == null && nullToAbsent - ? const Value.absent() - : Value(channelCid), - extraData: extraData == null && nullToAbsent - ? const Value.absent() - : Value(extraData), - ); - } - - factory _Message.fromJson(Map json, - {ValueSerializer serializer}) { - serializer ??= moorRuntimeOptions.defaultSerializer; - return _Message( - id: serializer.fromJson(json['id']), - messageText: serializer.fromJson(json['messageText']), - attachmentJson: serializer.fromJson(json['attachmentJson']), - status: serializer.fromJson(json['status']), - type: serializer.fromJson(json['type']), - reactionCounts: - serializer.fromJson>(json['reactionCounts']), - reactionScores: - serializer.fromJson>(json['reactionScores']), - parentId: serializer.fromJson(json['parentId']), - quotedMessageId: serializer.fromJson(json['quotedMessageId']), - replyCount: serializer.fromJson(json['replyCount']), - showInChannel: serializer.fromJson(json['showInChannel']), - shadowed: serializer.fromJson(json['shadowed']), - command: serializer.fromJson(json['command']), - createdAt: serializer.fromJson(json['createdAt']), - updatedAt: serializer.fromJson(json['updatedAt']), - deletedAt: serializer.fromJson(json['deletedAt']), - userId: serializer.fromJson(json['userId']), - channelCid: serializer.fromJson(json['channelCid']), - extraData: serializer.fromJson>(json['extraData']), - ); - } - @override - Map toJson({ValueSerializer serializer}) { - serializer ??= moorRuntimeOptions.defaultSerializer; - return { - 'id': serializer.toJson(id), - 'messageText': serializer.toJson(messageText), - 'attachmentJson': serializer.toJson(attachmentJson), - 'status': serializer.toJson(status), - 'type': serializer.toJson(type), - 'reactionCounts': serializer.toJson>(reactionCounts), - 'reactionScores': serializer.toJson>(reactionScores), - 'parentId': serializer.toJson(parentId), - 'quotedMessageId': serializer.toJson(quotedMessageId), - 'replyCount': serializer.toJson(replyCount), - 'showInChannel': serializer.toJson(showInChannel), - 'shadowed': serializer.toJson(shadowed), - 'command': serializer.toJson(command), - 'createdAt': serializer.toJson(createdAt), - 'updatedAt': serializer.toJson(updatedAt), - 'deletedAt': serializer.toJson(deletedAt), - 'userId': serializer.toJson(userId), - 'channelCid': serializer.toJson(channelCid), - 'extraData': serializer.toJson>(extraData), - }; - } - - _Message copyWith( - {String id, - String messageText, - String attachmentJson, - MessageSendingStatus status, - String type, - Map reactionCounts, - Map reactionScores, - String parentId, - String quotedMessageId, - int replyCount, - bool showInChannel, - bool shadowed, - String command, - DateTime createdAt, - DateTime updatedAt, - DateTime deletedAt, - String userId, - String channelCid, - Map extraData}) => - _Message( - id: id ?? this.id, - messageText: messageText ?? this.messageText, - attachmentJson: attachmentJson ?? this.attachmentJson, - status: status ?? this.status, - type: type ?? this.type, - reactionCounts: reactionCounts ?? this.reactionCounts, - reactionScores: reactionScores ?? this.reactionScores, - parentId: parentId ?? this.parentId, - quotedMessageId: quotedMessageId ?? this.quotedMessageId, - replyCount: replyCount ?? this.replyCount, - showInChannel: showInChannel ?? this.showInChannel, - shadowed: shadowed ?? this.shadowed, - command: command ?? this.command, - createdAt: createdAt ?? this.createdAt, - updatedAt: updatedAt ?? this.updatedAt, - deletedAt: deletedAt ?? this.deletedAt, - userId: userId ?? this.userId, - channelCid: channelCid ?? this.channelCid, - extraData: extraData ?? this.extraData, - ); - @override - String toString() { - return (StringBuffer('_Message(') - ..write('id: $id, ') - ..write('messageText: $messageText, ') - ..write('attachmentJson: $attachmentJson, ') - ..write('status: $status, ') - ..write('type: $type, ') - ..write('reactionCounts: $reactionCounts, ') - ..write('reactionScores: $reactionScores, ') - ..write('parentId: $parentId, ') - ..write('quotedMessageId: $quotedMessageId, ') - ..write('replyCount: $replyCount, ') - ..write('showInChannel: $showInChannel, ') - ..write('shadowed: $shadowed, ') - ..write('command: $command, ') - ..write('createdAt: $createdAt, ') - ..write('updatedAt: $updatedAt, ') - ..write('deletedAt: $deletedAt, ') - ..write('userId: $userId, ') - ..write('channelCid: $channelCid, ') - ..write('extraData: $extraData') - ..write(')')) - .toString(); - } - - @override - int get hashCode => $mrjf($mrjc( - id.hashCode, - $mrjc( - messageText.hashCode, - $mrjc( - attachmentJson.hashCode, - $mrjc( - status.hashCode, - $mrjc( - type.hashCode, - $mrjc( - reactionCounts.hashCode, - $mrjc( - reactionScores.hashCode, - $mrjc( - parentId.hashCode, - $mrjc( - quotedMessageId.hashCode, - $mrjc( - replyCount.hashCode, - $mrjc( - showInChannel.hashCode, - $mrjc( - shadowed.hashCode, - $mrjc( - command.hashCode, - $mrjc( - createdAt.hashCode, - $mrjc( - updatedAt - .hashCode, - $mrjc( - deletedAt - .hashCode, - $mrjc( - userId - .hashCode, - $mrjc( - channelCid - .hashCode, - extraData - .hashCode))))))))))))))))))); - @override - bool operator ==(dynamic other) => - identical(this, other) || - (other is _Message && - other.id == this.id && - other.messageText == this.messageText && - other.attachmentJson == this.attachmentJson && - other.status == this.status && - other.type == this.type && - other.reactionCounts == this.reactionCounts && - other.reactionScores == this.reactionScores && - other.parentId == this.parentId && - other.quotedMessageId == this.quotedMessageId && - other.replyCount == this.replyCount && - other.showInChannel == this.showInChannel && - other.shadowed == this.shadowed && - other.command == this.command && - other.createdAt == this.createdAt && - other.updatedAt == this.updatedAt && - other.deletedAt == this.deletedAt && - other.userId == this.userId && - other.channelCid == this.channelCid && - other.extraData == this.extraData); -} - -class _MessagesCompanion extends UpdateCompanion<_Message> { - final Value id; - final Value messageText; - final Value attachmentJson; - final Value status; - final Value type; - final Value> reactionCounts; - final Value> reactionScores; - final Value parentId; - final Value quotedMessageId; - final Value replyCount; - final Value showInChannel; - final Value shadowed; - final Value command; - final Value createdAt; - final Value updatedAt; - final Value deletedAt; - final Value userId; - final Value channelCid; - final Value> extraData; - const _MessagesCompanion({ - this.id = const Value.absent(), - this.messageText = const Value.absent(), - this.attachmentJson = const Value.absent(), - this.status = const Value.absent(), - this.type = const Value.absent(), - this.reactionCounts = const Value.absent(), - this.reactionScores = const Value.absent(), - this.parentId = const Value.absent(), - this.quotedMessageId = const Value.absent(), - this.replyCount = const Value.absent(), - this.showInChannel = const Value.absent(), - this.shadowed = const Value.absent(), - this.command = const Value.absent(), - this.createdAt = const Value.absent(), - this.updatedAt = const Value.absent(), - this.deletedAt = const Value.absent(), - this.userId = const Value.absent(), - this.channelCid = const Value.absent(), - this.extraData = const Value.absent(), - }); - _MessagesCompanion.insert({ - @required String id, - this.messageText = const Value.absent(), - this.attachmentJson = const Value.absent(), - this.status = const Value.absent(), - this.type = const Value.absent(), - this.reactionCounts = const Value.absent(), - this.reactionScores = const Value.absent(), - this.parentId = const Value.absent(), - this.quotedMessageId = const Value.absent(), - this.replyCount = const Value.absent(), - this.showInChannel = const Value.absent(), - this.shadowed = const Value.absent(), - this.command = const Value.absent(), - @required DateTime createdAt, - this.updatedAt = const Value.absent(), - this.deletedAt = const Value.absent(), - this.userId = const Value.absent(), - this.channelCid = const Value.absent(), - this.extraData = const Value.absent(), - }) : id = Value(id), - createdAt = Value(createdAt); - static Insertable<_Message> custom({ - Expression id, - Expression messageText, - Expression attachmentJson, - Expression status, - Expression type, - Expression reactionCounts, - Expression reactionScores, - Expression parentId, - Expression quotedMessageId, - Expression replyCount, - Expression showInChannel, - Expression shadowed, - Expression command, - Expression createdAt, - Expression updatedAt, - Expression deletedAt, - Expression userId, - Expression channelCid, - Expression extraData, - }) { - return RawValuesInsertable({ - if (id != null) 'id': id, - if (messageText != null) 'message_text': messageText, - if (attachmentJson != null) 'attachment_json': attachmentJson, - if (status != null) 'status': status, - if (type != null) 'type': type, - if (reactionCounts != null) 'reaction_counts': reactionCounts, - if (reactionScores != null) 'reaction_scores': reactionScores, - if (parentId != null) 'parent_id': parentId, - if (quotedMessageId != null) 'quoted_message_id': quotedMessageId, - if (replyCount != null) 'reply_count': replyCount, - if (showInChannel != null) 'show_in_channel': showInChannel, - if (shadowed != null) 'shadowed': shadowed, - if (command != null) 'command': command, - if (createdAt != null) 'created_at': createdAt, - if (updatedAt != null) 'updated_at': updatedAt, - if (deletedAt != null) 'deleted_at': deletedAt, - if (userId != null) 'user_id': userId, - if (channelCid != null) 'channel_cid': channelCid, - if (extraData != null) 'extra_data': extraData, - }); - } - - _MessagesCompanion copyWith( - {Value id, - Value messageText, - Value attachmentJson, - Value status, - Value type, - Value> reactionCounts, - Value> reactionScores, - Value parentId, - Value quotedMessageId, - Value replyCount, - Value showInChannel, - Value shadowed, - Value command, - Value createdAt, - Value updatedAt, - Value deletedAt, - Value userId, - Value channelCid, - Value> extraData}) { - return _MessagesCompanion( - id: id ?? this.id, - messageText: messageText ?? this.messageText, - attachmentJson: attachmentJson ?? this.attachmentJson, - status: status ?? this.status, - type: type ?? this.type, - reactionCounts: reactionCounts ?? this.reactionCounts, - reactionScores: reactionScores ?? this.reactionScores, - parentId: parentId ?? this.parentId, - quotedMessageId: quotedMessageId ?? this.quotedMessageId, - replyCount: replyCount ?? this.replyCount, - showInChannel: showInChannel ?? this.showInChannel, - shadowed: shadowed ?? this.shadowed, - command: command ?? this.command, - createdAt: createdAt ?? this.createdAt, - updatedAt: updatedAt ?? this.updatedAt, - deletedAt: deletedAt ?? this.deletedAt, - userId: userId ?? this.userId, - channelCid: channelCid ?? this.channelCid, - extraData: extraData ?? this.extraData, - ); - } - - @override - Map toColumns(bool nullToAbsent) { - final map = {}; - if (id.present) { - map['id'] = Variable(id.value); - } - if (messageText.present) { - map['message_text'] = Variable(messageText.value); - } - if (attachmentJson.present) { - map['attachment_json'] = Variable(attachmentJson.value); - } - if (status.present) { - final converter = $_MessagesTable.$converter0; - map['status'] = Variable(converter.mapToSql(status.value)); - } - if (type.present) { - map['type'] = Variable(type.value); - } - if (reactionCounts.present) { - final converter = $_MessagesTable.$converter1; - map['reaction_counts'] = - Variable(converter.mapToSql(reactionCounts.value)); - } - if (reactionScores.present) { - final converter = $_MessagesTable.$converter2; - map['reaction_scores'] = - Variable(converter.mapToSql(reactionScores.value)); - } - if (parentId.present) { - map['parent_id'] = Variable(parentId.value); - } - if (quotedMessageId.present) { - map['quoted_message_id'] = Variable(quotedMessageId.value); - } - if (replyCount.present) { - map['reply_count'] = Variable(replyCount.value); - } - if (showInChannel.present) { - map['show_in_channel'] = Variable(showInChannel.value); - } - if (shadowed.present) { - map['shadowed'] = Variable(shadowed.value); - } - if (command.present) { - map['command'] = Variable(command.value); - } - if (createdAt.present) { - map['created_at'] = Variable(createdAt.value); - } - if (updatedAt.present) { - map['updated_at'] = Variable(updatedAt.value); - } - if (deletedAt.present) { - map['deleted_at'] = Variable(deletedAt.value); - } - if (userId.present) { - map['user_id'] = Variable(userId.value); - } - if (channelCid.present) { - map['channel_cid'] = Variable(channelCid.value); - } - if (extraData.present) { - final converter = $_MessagesTable.$converter3; - map['extra_data'] = Variable(converter.mapToSql(extraData.value)); - } - return map; - } - - @override - String toString() { - return (StringBuffer('_MessagesCompanion(') - ..write('id: $id, ') - ..write('messageText: $messageText, ') - ..write('attachmentJson: $attachmentJson, ') - ..write('status: $status, ') - ..write('type: $type, ') - ..write('reactionCounts: $reactionCounts, ') - ..write('reactionScores: $reactionScores, ') - ..write('parentId: $parentId, ') - ..write('quotedMessageId: $quotedMessageId, ') - ..write('replyCount: $replyCount, ') - ..write('showInChannel: $showInChannel, ') - ..write('shadowed: $shadowed, ') - ..write('command: $command, ') - ..write('createdAt: $createdAt, ') - ..write('updatedAt: $updatedAt, ') - ..write('deletedAt: $deletedAt, ') - ..write('userId: $userId, ') - ..write('channelCid: $channelCid, ') - ..write('extraData: $extraData') - ..write(')')) - .toString(); - } -} - -class $_MessagesTable extends _Messages - with TableInfo<$_MessagesTable, _Message> { - final GeneratedDatabase _db; - final String _alias; - $_MessagesTable(this._db, [this._alias]); - final VerificationMeta _idMeta = const VerificationMeta('id'); - GeneratedTextColumn _id; - @override - GeneratedTextColumn get id => _id ??= _constructId(); - GeneratedTextColumn _constructId() { - return GeneratedTextColumn( - 'id', - $tableName, - false, - ); - } - - final VerificationMeta _messageTextMeta = - const VerificationMeta('messageText'); - GeneratedTextColumn _messageText; - @override - GeneratedTextColumn get messageText => - _messageText ??= _constructMessageText(); - GeneratedTextColumn _constructMessageText() { - return GeneratedTextColumn( - 'message_text', - $tableName, - true, - ); - } - - final VerificationMeta _attachmentJsonMeta = - const VerificationMeta('attachmentJson'); - GeneratedTextColumn _attachmentJson; - @override - GeneratedTextColumn get attachmentJson => - _attachmentJson ??= _constructAttachmentJson(); - GeneratedTextColumn _constructAttachmentJson() { - return GeneratedTextColumn( - 'attachment_json', - $tableName, - true, - ); - } - - final VerificationMeta _statusMeta = const VerificationMeta('status'); - GeneratedIntColumn _status; - @override - GeneratedIntColumn get status => _status ??= _constructStatus(); - GeneratedIntColumn _constructStatus() { - return GeneratedIntColumn( - 'status', - $tableName, - true, - ); - } - - final VerificationMeta _typeMeta = const VerificationMeta('type'); - GeneratedTextColumn _type; - @override - GeneratedTextColumn get type => _type ??= _constructType(); - GeneratedTextColumn _constructType() { - return GeneratedTextColumn( - 'type', - $tableName, - true, - ); - } - - final VerificationMeta _reactionCountsMeta = - const VerificationMeta('reactionCounts'); - GeneratedTextColumn _reactionCounts; - @override - GeneratedTextColumn get reactionCounts => - _reactionCounts ??= _constructReactionCounts(); - GeneratedTextColumn _constructReactionCounts() { - return GeneratedTextColumn( - 'reaction_counts', - $tableName, - true, - ); - } - - final VerificationMeta _reactionScoresMeta = - const VerificationMeta('reactionScores'); - GeneratedTextColumn _reactionScores; - @override - GeneratedTextColumn get reactionScores => - _reactionScores ??= _constructReactionScores(); - GeneratedTextColumn _constructReactionScores() { - return GeneratedTextColumn( - 'reaction_scores', - $tableName, - true, - ); - } - - final VerificationMeta _parentIdMeta = const VerificationMeta('parentId'); - GeneratedTextColumn _parentId; - @override - GeneratedTextColumn get parentId => _parentId ??= _constructParentId(); - GeneratedTextColumn _constructParentId() { - return GeneratedTextColumn( - 'parent_id', - $tableName, - true, - ); - } - - final VerificationMeta _quotedMessageIdMeta = - const VerificationMeta('quotedMessageId'); - GeneratedTextColumn _quotedMessageId; - @override - GeneratedTextColumn get quotedMessageId => - _quotedMessageId ??= _constructQuotedMessageId(); - GeneratedTextColumn _constructQuotedMessageId() { - return GeneratedTextColumn( - 'quoted_message_id', - $tableName, - true, - ); - } - - final VerificationMeta _replyCountMeta = const VerificationMeta('replyCount'); - GeneratedIntColumn _replyCount; - @override - GeneratedIntColumn get replyCount => _replyCount ??= _constructReplyCount(); - GeneratedIntColumn _constructReplyCount() { - return GeneratedIntColumn( - 'reply_count', - $tableName, - true, - ); - } - - final VerificationMeta _showInChannelMeta = - const VerificationMeta('showInChannel'); - GeneratedBoolColumn _showInChannel; - @override - GeneratedBoolColumn get showInChannel => - _showInChannel ??= _constructShowInChannel(); - GeneratedBoolColumn _constructShowInChannel() { - return GeneratedBoolColumn( - 'show_in_channel', - $tableName, - true, - ); - } - - final VerificationMeta _shadowedMeta = const VerificationMeta('shadowed'); - GeneratedBoolColumn _shadowed; - @override - GeneratedBoolColumn get shadowed => _shadowed ??= _constructShadowed(); - GeneratedBoolColumn _constructShadowed() { - return GeneratedBoolColumn( - 'shadowed', - $tableName, - true, - ); - } - - final VerificationMeta _commandMeta = const VerificationMeta('command'); - GeneratedTextColumn _command; - @override - GeneratedTextColumn get command => _command ??= _constructCommand(); - GeneratedTextColumn _constructCommand() { - return GeneratedTextColumn( - 'command', - $tableName, - true, - ); - } - - final VerificationMeta _createdAtMeta = const VerificationMeta('createdAt'); - GeneratedDateTimeColumn _createdAt; - @override - GeneratedDateTimeColumn get createdAt => _createdAt ??= _constructCreatedAt(); - GeneratedDateTimeColumn _constructCreatedAt() { - return GeneratedDateTimeColumn( - 'created_at', - $tableName, - false, - ); - } - - final VerificationMeta _updatedAtMeta = const VerificationMeta('updatedAt'); - GeneratedDateTimeColumn _updatedAt; - @override - GeneratedDateTimeColumn get updatedAt => _updatedAt ??= _constructUpdatedAt(); - GeneratedDateTimeColumn _constructUpdatedAt() { - return GeneratedDateTimeColumn( - 'updated_at', - $tableName, - true, - ); - } - - final VerificationMeta _deletedAtMeta = const VerificationMeta('deletedAt'); - GeneratedDateTimeColumn _deletedAt; - @override - GeneratedDateTimeColumn get deletedAt => _deletedAt ??= _constructDeletedAt(); - GeneratedDateTimeColumn _constructDeletedAt() { - return GeneratedDateTimeColumn( - 'deleted_at', - $tableName, - true, - ); - } - - final VerificationMeta _userIdMeta = const VerificationMeta('userId'); - GeneratedTextColumn _userId; - @override - GeneratedTextColumn get userId => _userId ??= _constructUserId(); - GeneratedTextColumn _constructUserId() { - return GeneratedTextColumn( - 'user_id', - $tableName, - true, - ); - } - - final VerificationMeta _channelCidMeta = const VerificationMeta('channelCid'); - GeneratedTextColumn _channelCid; - @override - GeneratedTextColumn get channelCid => _channelCid ??= _constructChannelCid(); - GeneratedTextColumn _constructChannelCid() { - return GeneratedTextColumn( - 'channel_cid', - $tableName, - true, - ); - } - - final VerificationMeta _extraDataMeta = const VerificationMeta('extraData'); - GeneratedTextColumn _extraData; - @override - GeneratedTextColumn get extraData => _extraData ??= _constructExtraData(); - GeneratedTextColumn _constructExtraData() { - return GeneratedTextColumn( - 'extra_data', - $tableName, - true, - ); - } - - @override - List get $columns => [ - id, - messageText, - attachmentJson, - status, - type, - reactionCounts, - reactionScores, - parentId, - quotedMessageId, - replyCount, - showInChannel, - shadowed, - command, - createdAt, - updatedAt, - deletedAt, - userId, - channelCid, - extraData - ]; - @override - $_MessagesTable get asDslTable => this; - @override - String get $tableName => _alias ?? 'messages'; - @override - final String actualTableName = 'messages'; - @override - VerificationContext validateIntegrity(Insertable<_Message> instance, - {bool isInserting = false}) { - final context = VerificationContext(); - final data = instance.toColumns(true); - if (data.containsKey('id')) { - context.handle(_idMeta, id.isAcceptableOrUnknown(data['id'], _idMeta)); - } else if (isInserting) { - context.missing(_idMeta); - } - if (data.containsKey('message_text')) { - context.handle( - _messageTextMeta, - messageText.isAcceptableOrUnknown( - data['message_text'], _messageTextMeta)); - } - if (data.containsKey('attachment_json')) { - context.handle( - _attachmentJsonMeta, - attachmentJson.isAcceptableOrUnknown( - data['attachment_json'], _attachmentJsonMeta)); - } - context.handle(_statusMeta, const VerificationResult.success()); - if (data.containsKey('type')) { - context.handle( - _typeMeta, type.isAcceptableOrUnknown(data['type'], _typeMeta)); - } - context.handle(_reactionCountsMeta, const VerificationResult.success()); - context.handle(_reactionScoresMeta, const VerificationResult.success()); - if (data.containsKey('parent_id')) { - context.handle(_parentIdMeta, - parentId.isAcceptableOrUnknown(data['parent_id'], _parentIdMeta)); - } - if (data.containsKey('quoted_message_id')) { - context.handle( - _quotedMessageIdMeta, - quotedMessageId.isAcceptableOrUnknown( - data['quoted_message_id'], _quotedMessageIdMeta)); - } - if (data.containsKey('reply_count')) { - context.handle( - _replyCountMeta, - replyCount.isAcceptableOrUnknown( - data['reply_count'], _replyCountMeta)); - } - if (data.containsKey('show_in_channel')) { - context.handle( - _showInChannelMeta, - showInChannel.isAcceptableOrUnknown( - data['show_in_channel'], _showInChannelMeta)); - } - if (data.containsKey('shadowed')) { - context.handle(_shadowedMeta, - shadowed.isAcceptableOrUnknown(data['shadowed'], _shadowedMeta)); - } - if (data.containsKey('command')) { - context.handle(_commandMeta, - command.isAcceptableOrUnknown(data['command'], _commandMeta)); - } - if (data.containsKey('created_at')) { - context.handle(_createdAtMeta, - createdAt.isAcceptableOrUnknown(data['created_at'], _createdAtMeta)); - } else if (isInserting) { - context.missing(_createdAtMeta); - } - if (data.containsKey('updated_at')) { - context.handle(_updatedAtMeta, - updatedAt.isAcceptableOrUnknown(data['updated_at'], _updatedAtMeta)); - } - if (data.containsKey('deleted_at')) { - context.handle(_deletedAtMeta, - deletedAt.isAcceptableOrUnknown(data['deleted_at'], _deletedAtMeta)); - } - if (data.containsKey('user_id')) { - context.handle(_userIdMeta, - userId.isAcceptableOrUnknown(data['user_id'], _userIdMeta)); - } - if (data.containsKey('channel_cid')) { - context.handle( - _channelCidMeta, - channelCid.isAcceptableOrUnknown( - data['channel_cid'], _channelCidMeta)); - } - context.handle(_extraDataMeta, const VerificationResult.success()); - return context; - } - - @override - Set get $primaryKey => {id}; - @override - _Message map(Map data, {String tablePrefix}) { - final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : null; - return _Message.fromData(data, _db, prefix: effectivePrefix); - } - - @override - $_MessagesTable createAlias(String alias) { - return $_MessagesTable(_db, alias); - } - - static TypeConverter $converter0 = - _MessageSendingStatusConverter(); - static TypeConverter, String> $converter1 = - _ExtraDataConverter(); - static TypeConverter, String> $converter2 = - _ExtraDataConverter(); - static TypeConverter, String> $converter3 = - _ExtraDataConverter(); -} - -class _Read extends DataClass implements Insertable<_Read> { - final DateTime lastRead; - final String userId; - final String channelCid; - final int unreadMessages; - _Read( - {@required this.lastRead, - @required this.userId, - @required this.channelCid, - this.unreadMessages}); - factory _Read.fromData(Map data, GeneratedDatabase db, - {String prefix}) { - final effectivePrefix = prefix ?? ''; - final dateTimeType = db.typeSystem.forDartType(); - final stringType = db.typeSystem.forDartType(); - final intType = db.typeSystem.forDartType(); - return _Read( - lastRead: dateTimeType - .mapFromDatabaseResponse(data['${effectivePrefix}last_read']), - userId: - stringType.mapFromDatabaseResponse(data['${effectivePrefix}user_id']), - channelCid: stringType - .mapFromDatabaseResponse(data['${effectivePrefix}channel_cid']), - unreadMessages: intType - .mapFromDatabaseResponse(data['${effectivePrefix}unread_messages']), - ); - } - @override - Map toColumns(bool nullToAbsent) { - final map = {}; - if (!nullToAbsent || lastRead != null) { - map['last_read'] = Variable(lastRead); - } - if (!nullToAbsent || userId != null) { - map['user_id'] = Variable(userId); - } - if (!nullToAbsent || channelCid != null) { - map['channel_cid'] = Variable(channelCid); - } - if (!nullToAbsent || unreadMessages != null) { - map['unread_messages'] = Variable(unreadMessages); - } - return map; - } - - _ReadsCompanion toCompanion(bool nullToAbsent) { - return _ReadsCompanion( - lastRead: lastRead == null && nullToAbsent - ? const Value.absent() - : Value(lastRead), - userId: - userId == null && nullToAbsent ? const Value.absent() : Value(userId), - channelCid: channelCid == null && nullToAbsent - ? const Value.absent() - : Value(channelCid), - unreadMessages: unreadMessages == null && nullToAbsent - ? const Value.absent() - : Value(unreadMessages), - ); - } - - factory _Read.fromJson(Map json, - {ValueSerializer serializer}) { - serializer ??= moorRuntimeOptions.defaultSerializer; - return _Read( - lastRead: serializer.fromJson(json['lastRead']), - userId: serializer.fromJson(json['userId']), - channelCid: serializer.fromJson(json['channelCid']), - unreadMessages: serializer.fromJson(json['unreadMessages']), - ); - } - @override - Map toJson({ValueSerializer serializer}) { - serializer ??= moorRuntimeOptions.defaultSerializer; - return { - 'lastRead': serializer.toJson(lastRead), - 'userId': serializer.toJson(userId), - 'channelCid': serializer.toJson(channelCid), - 'unreadMessages': serializer.toJson(unreadMessages), - }; - } - - _Read copyWith( - {DateTime lastRead, - String userId, - String channelCid, - int unreadMessages}) => - _Read( - lastRead: lastRead ?? this.lastRead, - userId: userId ?? this.userId, - channelCid: channelCid ?? this.channelCid, - unreadMessages: unreadMessages ?? this.unreadMessages, - ); - @override - String toString() { - return (StringBuffer('_Read(') - ..write('lastRead: $lastRead, ') - ..write('userId: $userId, ') - ..write('channelCid: $channelCid, ') - ..write('unreadMessages: $unreadMessages') - ..write(')')) - .toString(); - } - - @override - int get hashCode => $mrjf($mrjc( - lastRead.hashCode, - $mrjc(userId.hashCode, - $mrjc(channelCid.hashCode, unreadMessages.hashCode)))); - @override - bool operator ==(dynamic other) => - identical(this, other) || - (other is _Read && - other.lastRead == this.lastRead && - other.userId == this.userId && - other.channelCid == this.channelCid && - other.unreadMessages == this.unreadMessages); -} - -class _ReadsCompanion extends UpdateCompanion<_Read> { - final Value lastRead; - final Value userId; - final Value channelCid; - final Value unreadMessages; - const _ReadsCompanion({ - this.lastRead = const Value.absent(), - this.userId = const Value.absent(), - this.channelCid = const Value.absent(), - this.unreadMessages = const Value.absent(), - }); - _ReadsCompanion.insert({ - @required DateTime lastRead, - @required String userId, - @required String channelCid, - this.unreadMessages = const Value.absent(), - }) : lastRead = Value(lastRead), - userId = Value(userId), - channelCid = Value(channelCid); - static Insertable<_Read> custom({ - Expression lastRead, - Expression userId, - Expression channelCid, - Expression unreadMessages, - }) { - return RawValuesInsertable({ - if (lastRead != null) 'last_read': lastRead, - if (userId != null) 'user_id': userId, - if (channelCid != null) 'channel_cid': channelCid, - if (unreadMessages != null) 'unread_messages': unreadMessages, - }); - } - - _ReadsCompanion copyWith( - {Value lastRead, - Value userId, - Value channelCid, - Value unreadMessages}) { - return _ReadsCompanion( - lastRead: lastRead ?? this.lastRead, - userId: userId ?? this.userId, - channelCid: channelCid ?? this.channelCid, - unreadMessages: unreadMessages ?? this.unreadMessages, - ); - } - - @override - Map toColumns(bool nullToAbsent) { - final map = {}; - if (lastRead.present) { - map['last_read'] = Variable(lastRead.value); - } - if (userId.present) { - map['user_id'] = Variable(userId.value); - } - if (channelCid.present) { - map['channel_cid'] = Variable(channelCid.value); - } - if (unreadMessages.present) { - map['unread_messages'] = Variable(unreadMessages.value); - } - return map; - } - - @override - String toString() { - return (StringBuffer('_ReadsCompanion(') - ..write('lastRead: $lastRead, ') - ..write('userId: $userId, ') - ..write('channelCid: $channelCid, ') - ..write('unreadMessages: $unreadMessages') - ..write(')')) - .toString(); - } -} - -class $_ReadsTable extends _Reads with TableInfo<$_ReadsTable, _Read> { - final GeneratedDatabase _db; - final String _alias; - $_ReadsTable(this._db, [this._alias]); - final VerificationMeta _lastReadMeta = const VerificationMeta('lastRead'); - GeneratedDateTimeColumn _lastRead; - @override - GeneratedDateTimeColumn get lastRead => _lastRead ??= _constructLastRead(); - GeneratedDateTimeColumn _constructLastRead() { - return GeneratedDateTimeColumn( - 'last_read', - $tableName, - false, - ); - } - - final VerificationMeta _userIdMeta = const VerificationMeta('userId'); - GeneratedTextColumn _userId; - @override - GeneratedTextColumn get userId => _userId ??= _constructUserId(); - GeneratedTextColumn _constructUserId() { - return GeneratedTextColumn( - 'user_id', - $tableName, - false, - ); - } - - final VerificationMeta _channelCidMeta = const VerificationMeta('channelCid'); - GeneratedTextColumn _channelCid; - @override - GeneratedTextColumn get channelCid => _channelCid ??= _constructChannelCid(); - GeneratedTextColumn _constructChannelCid() { - return GeneratedTextColumn( - 'channel_cid', - $tableName, - false, - ); - } - - final VerificationMeta _unreadMessagesMeta = - const VerificationMeta('unreadMessages'); - GeneratedIntColumn _unreadMessages; - @override - GeneratedIntColumn get unreadMessages => - _unreadMessages ??= _constructUnreadMessages(); - GeneratedIntColumn _constructUnreadMessages() { - return GeneratedIntColumn( - 'unread_messages', - $tableName, - true, - ); - } - - @override - List get $columns => - [lastRead, userId, channelCid, unreadMessages]; - @override - $_ReadsTable get asDslTable => this; - @override - String get $tableName => _alias ?? 'reads'; - @override - final String actualTableName = 'reads'; - @override - VerificationContext validateIntegrity(Insertable<_Read> instance, - {bool isInserting = false}) { - final context = VerificationContext(); - final data = instance.toColumns(true); - if (data.containsKey('last_read')) { - context.handle(_lastReadMeta, - lastRead.isAcceptableOrUnknown(data['last_read'], _lastReadMeta)); - } else if (isInserting) { - context.missing(_lastReadMeta); - } - if (data.containsKey('user_id')) { - context.handle(_userIdMeta, - userId.isAcceptableOrUnknown(data['user_id'], _userIdMeta)); - } else if (isInserting) { - context.missing(_userIdMeta); - } - if (data.containsKey('channel_cid')) { - context.handle( - _channelCidMeta, - channelCid.isAcceptableOrUnknown( - data['channel_cid'], _channelCidMeta)); - } else if (isInserting) { - context.missing(_channelCidMeta); - } - if (data.containsKey('unread_messages')) { - context.handle( - _unreadMessagesMeta, - unreadMessages.isAcceptableOrUnknown( - data['unread_messages'], _unreadMessagesMeta)); - } - return context; - } - - @override - Set get $primaryKey => {userId, channelCid}; - @override - _Read map(Map data, {String tablePrefix}) { - final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : null; - return _Read.fromData(data, _db, prefix: effectivePrefix); - } - - @override - $_ReadsTable createAlias(String alias) { - return $_ReadsTable(_db, alias); - } -} - -class _Member extends DataClass implements Insertable<_Member> { - final String userId; - final String channelCid; - final String role; - final DateTime inviteAcceptedAt; - final DateTime inviteRejectedAt; - final bool invited; - final bool banned; - final bool shadowBanned; - final bool isModerator; - final DateTime createdAt; - final DateTime updatedAt; - _Member( - {@required this.userId, - @required this.channelCid, - this.role, - this.inviteAcceptedAt, - this.inviteRejectedAt, - this.invited, - this.banned, - this.shadowBanned, - this.isModerator, - @required this.createdAt, - this.updatedAt}); - factory _Member.fromData(Map data, GeneratedDatabase db, - {String prefix}) { - final effectivePrefix = prefix ?? ''; - final stringType = db.typeSystem.forDartType(); - final dateTimeType = db.typeSystem.forDartType(); - final boolType = db.typeSystem.forDartType(); - return _Member( - userId: - stringType.mapFromDatabaseResponse(data['${effectivePrefix}user_id']), - channelCid: stringType - .mapFromDatabaseResponse(data['${effectivePrefix}channel_cid']), - role: stringType.mapFromDatabaseResponse(data['${effectivePrefix}role']), - inviteAcceptedAt: dateTimeType.mapFromDatabaseResponse( - data['${effectivePrefix}invite_accepted_at']), - inviteRejectedAt: dateTimeType.mapFromDatabaseResponse( - data['${effectivePrefix}invite_rejected_at']), - invited: - boolType.mapFromDatabaseResponse(data['${effectivePrefix}invited']), - banned: - boolType.mapFromDatabaseResponse(data['${effectivePrefix}banned']), - shadowBanned: boolType - .mapFromDatabaseResponse(data['${effectivePrefix}shadow_banned']), - isModerator: boolType - .mapFromDatabaseResponse(data['${effectivePrefix}is_moderator']), - createdAt: dateTimeType - .mapFromDatabaseResponse(data['${effectivePrefix}created_at']), - updatedAt: dateTimeType - .mapFromDatabaseResponse(data['${effectivePrefix}updated_at']), - ); - } - @override - Map toColumns(bool nullToAbsent) { - final map = {}; - if (!nullToAbsent || userId != null) { - map['user_id'] = Variable(userId); - } - if (!nullToAbsent || channelCid != null) { - map['channel_cid'] = Variable(channelCid); - } - if (!nullToAbsent || role != null) { - map['role'] = Variable(role); - } - if (!nullToAbsent || inviteAcceptedAt != null) { - map['invite_accepted_at'] = Variable(inviteAcceptedAt); - } - if (!nullToAbsent || inviteRejectedAt != null) { - map['invite_rejected_at'] = Variable(inviteRejectedAt); - } - if (!nullToAbsent || invited != null) { - map['invited'] = Variable(invited); - } - if (!nullToAbsent || banned != null) { - map['banned'] = Variable(banned); - } - if (!nullToAbsent || shadowBanned != null) { - map['shadow_banned'] = Variable(shadowBanned); - } - if (!nullToAbsent || isModerator != null) { - map['is_moderator'] = Variable(isModerator); - } - if (!nullToAbsent || createdAt != null) { - map['created_at'] = Variable(createdAt); - } - if (!nullToAbsent || updatedAt != null) { - map['updated_at'] = Variable(updatedAt); - } - return map; - } - - _MembersCompanion toCompanion(bool nullToAbsent) { - return _MembersCompanion( - userId: - userId == null && nullToAbsent ? const Value.absent() : Value(userId), - channelCid: channelCid == null && nullToAbsent - ? const Value.absent() - : Value(channelCid), - role: role == null && nullToAbsent ? const Value.absent() : Value(role), - inviteAcceptedAt: inviteAcceptedAt == null && nullToAbsent - ? const Value.absent() - : Value(inviteAcceptedAt), - inviteRejectedAt: inviteRejectedAt == null && nullToAbsent - ? const Value.absent() - : Value(inviteRejectedAt), - invited: invited == null && nullToAbsent - ? const Value.absent() - : Value(invited), - banned: - banned == null && nullToAbsent ? const Value.absent() : Value(banned), - shadowBanned: shadowBanned == null && nullToAbsent - ? const Value.absent() - : Value(shadowBanned), - isModerator: isModerator == null && nullToAbsent - ? const Value.absent() - : Value(isModerator), - createdAt: createdAt == null && nullToAbsent - ? const Value.absent() - : Value(createdAt), - updatedAt: updatedAt == null && nullToAbsent - ? const Value.absent() - : Value(updatedAt), - ); - } - - factory _Member.fromJson(Map json, - {ValueSerializer serializer}) { - serializer ??= moorRuntimeOptions.defaultSerializer; - return _Member( - userId: serializer.fromJson(json['userId']), - channelCid: serializer.fromJson(json['channelCid']), - role: serializer.fromJson(json['role']), - inviteAcceptedAt: serializer.fromJson(json['inviteAcceptedAt']), - inviteRejectedAt: serializer.fromJson(json['inviteRejectedAt']), - invited: serializer.fromJson(json['invited']), - banned: serializer.fromJson(json['banned']), - shadowBanned: serializer.fromJson(json['shadowBanned']), - isModerator: serializer.fromJson(json['isModerator']), - createdAt: serializer.fromJson(json['createdAt']), - updatedAt: serializer.fromJson(json['updatedAt']), - ); - } - @override - Map toJson({ValueSerializer serializer}) { - serializer ??= moorRuntimeOptions.defaultSerializer; - return { - 'userId': serializer.toJson(userId), - 'channelCid': serializer.toJson(channelCid), - 'role': serializer.toJson(role), - 'inviteAcceptedAt': serializer.toJson(inviteAcceptedAt), - 'inviteRejectedAt': serializer.toJson(inviteRejectedAt), - 'invited': serializer.toJson(invited), - 'banned': serializer.toJson(banned), - 'shadowBanned': serializer.toJson(shadowBanned), - 'isModerator': serializer.toJson(isModerator), - 'createdAt': serializer.toJson(createdAt), - 'updatedAt': serializer.toJson(updatedAt), - }; - } - - _Member copyWith( - {String userId, - String channelCid, - String role, - DateTime inviteAcceptedAt, - DateTime inviteRejectedAt, - bool invited, - bool banned, - bool shadowBanned, - bool isModerator, - DateTime createdAt, - DateTime updatedAt}) => - _Member( - userId: userId ?? this.userId, - channelCid: channelCid ?? this.channelCid, - role: role ?? this.role, - inviteAcceptedAt: inviteAcceptedAt ?? this.inviteAcceptedAt, - inviteRejectedAt: inviteRejectedAt ?? this.inviteRejectedAt, - invited: invited ?? this.invited, - banned: banned ?? this.banned, - shadowBanned: shadowBanned ?? this.shadowBanned, - isModerator: isModerator ?? this.isModerator, - createdAt: createdAt ?? this.createdAt, - updatedAt: updatedAt ?? this.updatedAt, - ); - @override - String toString() { - return (StringBuffer('_Member(') - ..write('userId: $userId, ') - ..write('channelCid: $channelCid, ') - ..write('role: $role, ') - ..write('inviteAcceptedAt: $inviteAcceptedAt, ') - ..write('inviteRejectedAt: $inviteRejectedAt, ') - ..write('invited: $invited, ') - ..write('banned: $banned, ') - ..write('shadowBanned: $shadowBanned, ') - ..write('isModerator: $isModerator, ') - ..write('createdAt: $createdAt, ') - ..write('updatedAt: $updatedAt') - ..write(')')) - .toString(); - } - - @override - int get hashCode => $mrjf($mrjc( - userId.hashCode, - $mrjc( - channelCid.hashCode, - $mrjc( - role.hashCode, - $mrjc( - inviteAcceptedAt.hashCode, - $mrjc( - inviteRejectedAt.hashCode, - $mrjc( - invited.hashCode, - $mrjc( - banned.hashCode, - $mrjc( - shadowBanned.hashCode, - $mrjc( - isModerator.hashCode, - $mrjc(createdAt.hashCode, - updatedAt.hashCode))))))))))); - @override - bool operator ==(dynamic other) => - identical(this, other) || - (other is _Member && - other.userId == this.userId && - other.channelCid == this.channelCid && - other.role == this.role && - other.inviteAcceptedAt == this.inviteAcceptedAt && - other.inviteRejectedAt == this.inviteRejectedAt && - other.invited == this.invited && - other.banned == this.banned && - other.shadowBanned == this.shadowBanned && - other.isModerator == this.isModerator && - other.createdAt == this.createdAt && - other.updatedAt == this.updatedAt); -} - -class _MembersCompanion extends UpdateCompanion<_Member> { - final Value userId; - final Value channelCid; - final Value role; - final Value inviteAcceptedAt; - final Value inviteRejectedAt; - final Value invited; - final Value banned; - final Value shadowBanned; - final Value isModerator; - final Value createdAt; - final Value updatedAt; - const _MembersCompanion({ - this.userId = const Value.absent(), - this.channelCid = const Value.absent(), - this.role = const Value.absent(), - this.inviteAcceptedAt = const Value.absent(), - this.inviteRejectedAt = const Value.absent(), - this.invited = const Value.absent(), - this.banned = const Value.absent(), - this.shadowBanned = const Value.absent(), - this.isModerator = const Value.absent(), - this.createdAt = const Value.absent(), - this.updatedAt = const Value.absent(), - }); - _MembersCompanion.insert({ - @required String userId, - @required String channelCid, - this.role = const Value.absent(), - this.inviteAcceptedAt = const Value.absent(), - this.inviteRejectedAt = const Value.absent(), - this.invited = const Value.absent(), - this.banned = const Value.absent(), - this.shadowBanned = const Value.absent(), - this.isModerator = const Value.absent(), - @required DateTime createdAt, - this.updatedAt = const Value.absent(), - }) : userId = Value(userId), - channelCid = Value(channelCid), - createdAt = Value(createdAt); - static Insertable<_Member> custom({ - Expression userId, - Expression channelCid, - Expression role, - Expression inviteAcceptedAt, - Expression inviteRejectedAt, - Expression invited, - Expression banned, - Expression shadowBanned, - Expression isModerator, - Expression createdAt, - Expression updatedAt, - }) { - return RawValuesInsertable({ - if (userId != null) 'user_id': userId, - if (channelCid != null) 'channel_cid': channelCid, - if (role != null) 'role': role, - if (inviteAcceptedAt != null) 'invite_accepted_at': inviteAcceptedAt, - if (inviteRejectedAt != null) 'invite_rejected_at': inviteRejectedAt, - if (invited != null) 'invited': invited, - if (banned != null) 'banned': banned, - if (shadowBanned != null) 'shadow_banned': shadowBanned, - if (isModerator != null) 'is_moderator': isModerator, - if (createdAt != null) 'created_at': createdAt, - if (updatedAt != null) 'updated_at': updatedAt, - }); - } - - _MembersCompanion copyWith( - {Value userId, - Value channelCid, - Value role, - Value inviteAcceptedAt, - Value inviteRejectedAt, - Value invited, - Value banned, - Value shadowBanned, - Value isModerator, - Value createdAt, - Value updatedAt}) { - return _MembersCompanion( - userId: userId ?? this.userId, - channelCid: channelCid ?? this.channelCid, - role: role ?? this.role, - inviteAcceptedAt: inviteAcceptedAt ?? this.inviteAcceptedAt, - inviteRejectedAt: inviteRejectedAt ?? this.inviteRejectedAt, - invited: invited ?? this.invited, - banned: banned ?? this.banned, - shadowBanned: shadowBanned ?? this.shadowBanned, - isModerator: isModerator ?? this.isModerator, - createdAt: createdAt ?? this.createdAt, - updatedAt: updatedAt ?? this.updatedAt, - ); - } - - @override - Map toColumns(bool nullToAbsent) { - final map = {}; - if (userId.present) { - map['user_id'] = Variable(userId.value); - } - if (channelCid.present) { - map['channel_cid'] = Variable(channelCid.value); - } - if (role.present) { - map['role'] = Variable(role.value); - } - if (inviteAcceptedAt.present) { - map['invite_accepted_at'] = Variable(inviteAcceptedAt.value); - } - if (inviteRejectedAt.present) { - map['invite_rejected_at'] = Variable(inviteRejectedAt.value); - } - if (invited.present) { - map['invited'] = Variable(invited.value); - } - if (banned.present) { - map['banned'] = Variable(banned.value); - } - if (shadowBanned.present) { - map['shadow_banned'] = Variable(shadowBanned.value); - } - if (isModerator.present) { - map['is_moderator'] = Variable(isModerator.value); - } - if (createdAt.present) { - map['created_at'] = Variable(createdAt.value); - } - if (updatedAt.present) { - map['updated_at'] = Variable(updatedAt.value); - } - return map; - } - - @override - String toString() { - return (StringBuffer('_MembersCompanion(') - ..write('userId: $userId, ') - ..write('channelCid: $channelCid, ') - ..write('role: $role, ') - ..write('inviteAcceptedAt: $inviteAcceptedAt, ') - ..write('inviteRejectedAt: $inviteRejectedAt, ') - ..write('invited: $invited, ') - ..write('banned: $banned, ') - ..write('shadowBanned: $shadowBanned, ') - ..write('isModerator: $isModerator, ') - ..write('createdAt: $createdAt, ') - ..write('updatedAt: $updatedAt') - ..write(')')) - .toString(); - } -} - -class $_MembersTable extends _Members with TableInfo<$_MembersTable, _Member> { - final GeneratedDatabase _db; - final String _alias; - $_MembersTable(this._db, [this._alias]); - final VerificationMeta _userIdMeta = const VerificationMeta('userId'); - GeneratedTextColumn _userId; - @override - GeneratedTextColumn get userId => _userId ??= _constructUserId(); - GeneratedTextColumn _constructUserId() { - return GeneratedTextColumn( - 'user_id', - $tableName, - false, - ); - } - - final VerificationMeta _channelCidMeta = const VerificationMeta('channelCid'); - GeneratedTextColumn _channelCid; - @override - GeneratedTextColumn get channelCid => _channelCid ??= _constructChannelCid(); - GeneratedTextColumn _constructChannelCid() { - return GeneratedTextColumn( - 'channel_cid', - $tableName, - false, - ); - } - - final VerificationMeta _roleMeta = const VerificationMeta('role'); - GeneratedTextColumn _role; - @override - GeneratedTextColumn get role => _role ??= _constructRole(); - GeneratedTextColumn _constructRole() { - return GeneratedTextColumn( - 'role', - $tableName, - true, - ); - } - - final VerificationMeta _inviteAcceptedAtMeta = - const VerificationMeta('inviteAcceptedAt'); - GeneratedDateTimeColumn _inviteAcceptedAt; - @override - GeneratedDateTimeColumn get inviteAcceptedAt => - _inviteAcceptedAt ??= _constructInviteAcceptedAt(); - GeneratedDateTimeColumn _constructInviteAcceptedAt() { - return GeneratedDateTimeColumn( - 'invite_accepted_at', - $tableName, - true, - ); - } - - final VerificationMeta _inviteRejectedAtMeta = - const VerificationMeta('inviteRejectedAt'); - GeneratedDateTimeColumn _inviteRejectedAt; - @override - GeneratedDateTimeColumn get inviteRejectedAt => - _inviteRejectedAt ??= _constructInviteRejectedAt(); - GeneratedDateTimeColumn _constructInviteRejectedAt() { - return GeneratedDateTimeColumn( - 'invite_rejected_at', - $tableName, - true, - ); - } - - final VerificationMeta _invitedMeta = const VerificationMeta('invited'); - GeneratedBoolColumn _invited; - @override - GeneratedBoolColumn get invited => _invited ??= _constructInvited(); - GeneratedBoolColumn _constructInvited() { - return GeneratedBoolColumn( - 'invited', - $tableName, - true, - ); - } - - final VerificationMeta _bannedMeta = const VerificationMeta('banned'); - GeneratedBoolColumn _banned; - @override - GeneratedBoolColumn get banned => _banned ??= _constructBanned(); - GeneratedBoolColumn _constructBanned() { - return GeneratedBoolColumn( - 'banned', - $tableName, - true, - ); - } - - final VerificationMeta _shadowBannedMeta = - const VerificationMeta('shadowBanned'); - GeneratedBoolColumn _shadowBanned; - @override - GeneratedBoolColumn get shadowBanned => - _shadowBanned ??= _constructShadowBanned(); - GeneratedBoolColumn _constructShadowBanned() { - return GeneratedBoolColumn( - 'shadow_banned', - $tableName, - true, - ); - } - - final VerificationMeta _isModeratorMeta = - const VerificationMeta('isModerator'); - GeneratedBoolColumn _isModerator; - @override - GeneratedBoolColumn get isModerator => - _isModerator ??= _constructIsModerator(); - GeneratedBoolColumn _constructIsModerator() { - return GeneratedBoolColumn( - 'is_moderator', - $tableName, - true, - ); - } - - final VerificationMeta _createdAtMeta = const VerificationMeta('createdAt'); - GeneratedDateTimeColumn _createdAt; - @override - GeneratedDateTimeColumn get createdAt => _createdAt ??= _constructCreatedAt(); - GeneratedDateTimeColumn _constructCreatedAt() { - return GeneratedDateTimeColumn( - 'created_at', - $tableName, - false, - ); - } - - final VerificationMeta _updatedAtMeta = const VerificationMeta('updatedAt'); - GeneratedDateTimeColumn _updatedAt; - @override - GeneratedDateTimeColumn get updatedAt => _updatedAt ??= _constructUpdatedAt(); - GeneratedDateTimeColumn _constructUpdatedAt() { - return GeneratedDateTimeColumn( - 'updated_at', - $tableName, - true, - ); - } - - @override - List get $columns => [ - userId, - channelCid, - role, - inviteAcceptedAt, - inviteRejectedAt, - invited, - banned, - shadowBanned, - isModerator, - createdAt, - updatedAt - ]; - @override - $_MembersTable get asDslTable => this; - @override - String get $tableName => _alias ?? 'members'; - @override - final String actualTableName = 'members'; - @override - VerificationContext validateIntegrity(Insertable<_Member> instance, - {bool isInserting = false}) { - final context = VerificationContext(); - final data = instance.toColumns(true); - if (data.containsKey('user_id')) { - context.handle(_userIdMeta, - userId.isAcceptableOrUnknown(data['user_id'], _userIdMeta)); - } else if (isInserting) { - context.missing(_userIdMeta); - } - if (data.containsKey('channel_cid')) { - context.handle( - _channelCidMeta, - channelCid.isAcceptableOrUnknown( - data['channel_cid'], _channelCidMeta)); - } else if (isInserting) { - context.missing(_channelCidMeta); - } - if (data.containsKey('role')) { - context.handle( - _roleMeta, role.isAcceptableOrUnknown(data['role'], _roleMeta)); - } - if (data.containsKey('invite_accepted_at')) { - context.handle( - _inviteAcceptedAtMeta, - inviteAcceptedAt.isAcceptableOrUnknown( - data['invite_accepted_at'], _inviteAcceptedAtMeta)); - } - if (data.containsKey('invite_rejected_at')) { - context.handle( - _inviteRejectedAtMeta, - inviteRejectedAt.isAcceptableOrUnknown( - data['invite_rejected_at'], _inviteRejectedAtMeta)); - } - if (data.containsKey('invited')) { - context.handle(_invitedMeta, - invited.isAcceptableOrUnknown(data['invited'], _invitedMeta)); - } - if (data.containsKey('banned')) { - context.handle(_bannedMeta, - banned.isAcceptableOrUnknown(data['banned'], _bannedMeta)); - } - if (data.containsKey('shadow_banned')) { - context.handle( - _shadowBannedMeta, - shadowBanned.isAcceptableOrUnknown( - data['shadow_banned'], _shadowBannedMeta)); - } - if (data.containsKey('is_moderator')) { - context.handle( - _isModeratorMeta, - isModerator.isAcceptableOrUnknown( - data['is_moderator'], _isModeratorMeta)); - } - if (data.containsKey('created_at')) { - context.handle(_createdAtMeta, - createdAt.isAcceptableOrUnknown(data['created_at'], _createdAtMeta)); - } else if (isInserting) { - context.missing(_createdAtMeta); - } - if (data.containsKey('updated_at')) { - context.handle(_updatedAtMeta, - updatedAt.isAcceptableOrUnknown(data['updated_at'], _updatedAtMeta)); - } - return context; - } - - @override - Set get $primaryKey => {userId, channelCid}; - @override - _Member map(Map data, {String tablePrefix}) { - final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : null; - return _Member.fromData(data, _db, prefix: effectivePrefix); - } - - @override - $_MembersTable createAlias(String alias) { - return $_MembersTable(_db, alias); - } -} - -class ChannelQuery extends DataClass implements Insertable { - final String queryHash; - final String channelCid; - ChannelQuery({@required this.queryHash, @required this.channelCid}); - factory ChannelQuery.fromData(Map data, GeneratedDatabase db, - {String prefix}) { - final effectivePrefix = prefix ?? ''; - final stringType = db.typeSystem.forDartType(); - return ChannelQuery( - queryHash: stringType - .mapFromDatabaseResponse(data['${effectivePrefix}query_hash']), - channelCid: stringType - .mapFromDatabaseResponse(data['${effectivePrefix}channel_cid']), - ); - } - @override - Map toColumns(bool nullToAbsent) { - final map = {}; - if (!nullToAbsent || queryHash != null) { - map['query_hash'] = Variable(queryHash); - } - if (!nullToAbsent || channelCid != null) { - map['channel_cid'] = Variable(channelCid); - } - return map; - } - - _ChannelQueriesCompanion toCompanion(bool nullToAbsent) { - return _ChannelQueriesCompanion( - queryHash: queryHash == null && nullToAbsent - ? const Value.absent() - : Value(queryHash), - channelCid: channelCid == null && nullToAbsent - ? const Value.absent() - : Value(channelCid), - ); - } - - factory ChannelQuery.fromJson(Map json, - {ValueSerializer serializer}) { - serializer ??= moorRuntimeOptions.defaultSerializer; - return ChannelQuery( - queryHash: serializer.fromJson(json['queryHash']), - channelCid: serializer.fromJson(json['channelCid']), - ); - } - @override - Map toJson({ValueSerializer serializer}) { - serializer ??= moorRuntimeOptions.defaultSerializer; - return { - 'queryHash': serializer.toJson(queryHash), - 'channelCid': serializer.toJson(channelCid), - }; - } - - ChannelQuery copyWith({String queryHash, String channelCid}) => ChannelQuery( - queryHash: queryHash ?? this.queryHash, - channelCid: channelCid ?? this.channelCid, - ); - @override - String toString() { - return (StringBuffer('ChannelQuery(') - ..write('queryHash: $queryHash, ') - ..write('channelCid: $channelCid') - ..write(')')) - .toString(); - } - - @override - int get hashCode => $mrjf($mrjc(queryHash.hashCode, channelCid.hashCode)); - @override - bool operator ==(dynamic other) => - identical(this, other) || - (other is ChannelQuery && - other.queryHash == this.queryHash && - other.channelCid == this.channelCid); -} - -class _ChannelQueriesCompanion extends UpdateCompanion { - final Value queryHash; - final Value channelCid; - const _ChannelQueriesCompanion({ - this.queryHash = const Value.absent(), - this.channelCid = const Value.absent(), - }); - _ChannelQueriesCompanion.insert({ - @required String queryHash, - @required String channelCid, - }) : queryHash = Value(queryHash), - channelCid = Value(channelCid); - static Insertable custom({ - Expression queryHash, - Expression channelCid, - }) { - return RawValuesInsertable({ - if (queryHash != null) 'query_hash': queryHash, - if (channelCid != null) 'channel_cid': channelCid, - }); - } - - _ChannelQueriesCompanion copyWith( - {Value queryHash, Value channelCid}) { - return _ChannelQueriesCompanion( - queryHash: queryHash ?? this.queryHash, - channelCid: channelCid ?? this.channelCid, - ); - } - - @override - Map toColumns(bool nullToAbsent) { - final map = {}; - if (queryHash.present) { - map['query_hash'] = Variable(queryHash.value); - } - if (channelCid.present) { - map['channel_cid'] = Variable(channelCid.value); - } - return map; - } - - @override - String toString() { - return (StringBuffer('_ChannelQueriesCompanion(') - ..write('queryHash: $queryHash, ') - ..write('channelCid: $channelCid') - ..write(')')) - .toString(); - } -} - -class $_ChannelQueriesTable extends _ChannelQueries - with TableInfo<$_ChannelQueriesTable, ChannelQuery> { - final GeneratedDatabase _db; - final String _alias; - $_ChannelQueriesTable(this._db, [this._alias]); - final VerificationMeta _queryHashMeta = const VerificationMeta('queryHash'); - GeneratedTextColumn _queryHash; - @override - GeneratedTextColumn get queryHash => _queryHash ??= _constructQueryHash(); - GeneratedTextColumn _constructQueryHash() { - return GeneratedTextColumn( - 'query_hash', - $tableName, - false, - ); - } - - final VerificationMeta _channelCidMeta = const VerificationMeta('channelCid'); - GeneratedTextColumn _channelCid; - @override - GeneratedTextColumn get channelCid => _channelCid ??= _constructChannelCid(); - GeneratedTextColumn _constructChannelCid() { - return GeneratedTextColumn( - 'channel_cid', - $tableName, - false, - ); - } - - @override - List get $columns => [queryHash, channelCid]; - @override - $_ChannelQueriesTable get asDslTable => this; - @override - String get $tableName => _alias ?? 'channel_queries'; - @override - final String actualTableName = 'channel_queries'; - @override - VerificationContext validateIntegrity(Insertable instance, - {bool isInserting = false}) { - final context = VerificationContext(); - final data = instance.toColumns(true); - if (data.containsKey('query_hash')) { - context.handle(_queryHashMeta, - queryHash.isAcceptableOrUnknown(data['query_hash'], _queryHashMeta)); - } else if (isInserting) { - context.missing(_queryHashMeta); - } - if (data.containsKey('channel_cid')) { - context.handle( - _channelCidMeta, - channelCid.isAcceptableOrUnknown( - data['channel_cid'], _channelCidMeta)); - } else if (isInserting) { - context.missing(_channelCidMeta); - } - return context; - } - - @override - Set get $primaryKey => {queryHash, channelCid}; - @override - ChannelQuery map(Map data, {String tablePrefix}) { - final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : null; - return ChannelQuery.fromData(data, _db, prefix: effectivePrefix); - } - - @override - $_ChannelQueriesTable createAlias(String alias) { - return $_ChannelQueriesTable(_db, alias); - } -} - -class _Reaction extends DataClass implements Insertable<_Reaction> { - final String messageId; - final String type; - final DateTime createdAt; - final int score; - final String userId; - final Map extraData; - _Reaction( - {@required this.messageId, - @required this.type, - @required this.createdAt, - this.score, - @required this.userId, - this.extraData}); - factory _Reaction.fromData(Map data, GeneratedDatabase db, - {String prefix}) { - final effectivePrefix = prefix ?? ''; - final stringType = db.typeSystem.forDartType(); - final dateTimeType = db.typeSystem.forDartType(); - final intType = db.typeSystem.forDartType(); - return _Reaction( - messageId: stringType - .mapFromDatabaseResponse(data['${effectivePrefix}message_id']), - type: stringType.mapFromDatabaseResponse(data['${effectivePrefix}type']), - createdAt: dateTimeType - .mapFromDatabaseResponse(data['${effectivePrefix}created_at']), - score: intType.mapFromDatabaseResponse(data['${effectivePrefix}score']), - userId: - stringType.mapFromDatabaseResponse(data['${effectivePrefix}user_id']), - extraData: $_ReactionsTable.$converter0.mapToDart(stringType - .mapFromDatabaseResponse(data['${effectivePrefix}extra_data'])), - ); - } - @override - Map toColumns(bool nullToAbsent) { - final map = {}; - if (!nullToAbsent || messageId != null) { - map['message_id'] = Variable(messageId); - } - if (!nullToAbsent || type != null) { - map['type'] = Variable(type); - } - if (!nullToAbsent || createdAt != null) { - map['created_at'] = Variable(createdAt); - } - if (!nullToAbsent || score != null) { - map['score'] = Variable(score); - } - if (!nullToAbsent || userId != null) { - map['user_id'] = Variable(userId); - } - if (!nullToAbsent || extraData != null) { - final converter = $_ReactionsTable.$converter0; - map['extra_data'] = Variable(converter.mapToSql(extraData)); - } - return map; - } - - _ReactionsCompanion toCompanion(bool nullToAbsent) { - return _ReactionsCompanion( - messageId: messageId == null && nullToAbsent - ? const Value.absent() - : Value(messageId), - type: type == null && nullToAbsent ? const Value.absent() : Value(type), - createdAt: createdAt == null && nullToAbsent - ? const Value.absent() - : Value(createdAt), - score: - score == null && nullToAbsent ? const Value.absent() : Value(score), - userId: - userId == null && nullToAbsent ? const Value.absent() : Value(userId), - extraData: extraData == null && nullToAbsent - ? const Value.absent() - : Value(extraData), - ); - } - - factory _Reaction.fromJson(Map json, - {ValueSerializer serializer}) { - serializer ??= moorRuntimeOptions.defaultSerializer; - return _Reaction( - messageId: serializer.fromJson(json['messageId']), - type: serializer.fromJson(json['type']), - createdAt: serializer.fromJson(json['createdAt']), - score: serializer.fromJson(json['score']), - userId: serializer.fromJson(json['userId']), - extraData: serializer.fromJson>(json['extraData']), - ); - } - @override - Map toJson({ValueSerializer serializer}) { - serializer ??= moorRuntimeOptions.defaultSerializer; - return { - 'messageId': serializer.toJson(messageId), - 'type': serializer.toJson(type), - 'createdAt': serializer.toJson(createdAt), - 'score': serializer.toJson(score), - 'userId': serializer.toJson(userId), - 'extraData': serializer.toJson>(extraData), - }; - } - - _Reaction copyWith( - {String messageId, - String type, - DateTime createdAt, - int score, - String userId, - Map extraData}) => - _Reaction( - messageId: messageId ?? this.messageId, - type: type ?? this.type, - createdAt: createdAt ?? this.createdAt, - score: score ?? this.score, - userId: userId ?? this.userId, - extraData: extraData ?? this.extraData, - ); - @override - String toString() { - return (StringBuffer('_Reaction(') - ..write('messageId: $messageId, ') - ..write('type: $type, ') - ..write('createdAt: $createdAt, ') - ..write('score: $score, ') - ..write('userId: $userId, ') - ..write('extraData: $extraData') - ..write(')')) - .toString(); - } - - @override - int get hashCode => $mrjf($mrjc( - messageId.hashCode, - $mrjc( - type.hashCode, - $mrjc( - createdAt.hashCode, - $mrjc(score.hashCode, - $mrjc(userId.hashCode, extraData.hashCode)))))); - @override - bool operator ==(dynamic other) => - identical(this, other) || - (other is _Reaction && - other.messageId == this.messageId && - other.type == this.type && - other.createdAt == this.createdAt && - other.score == this.score && - other.userId == this.userId && - other.extraData == this.extraData); -} - -class _ReactionsCompanion extends UpdateCompanion<_Reaction> { - final Value messageId; - final Value type; - final Value createdAt; - final Value score; - final Value userId; - final Value> extraData; - const _ReactionsCompanion({ - this.messageId = const Value.absent(), - this.type = const Value.absent(), - this.createdAt = const Value.absent(), - this.score = const Value.absent(), - this.userId = const Value.absent(), - this.extraData = const Value.absent(), - }); - _ReactionsCompanion.insert({ - @required String messageId, - @required String type, - @required DateTime createdAt, - this.score = const Value.absent(), - @required String userId, - this.extraData = const Value.absent(), - }) : messageId = Value(messageId), - type = Value(type), - createdAt = Value(createdAt), - userId = Value(userId); - static Insertable<_Reaction> custom({ - Expression messageId, - Expression type, - Expression createdAt, - Expression score, - Expression userId, - Expression extraData, - }) { - return RawValuesInsertable({ - if (messageId != null) 'message_id': messageId, - if (type != null) 'type': type, - if (createdAt != null) 'created_at': createdAt, - if (score != null) 'score': score, - if (userId != null) 'user_id': userId, - if (extraData != null) 'extra_data': extraData, - }); - } - - _ReactionsCompanion copyWith( - {Value messageId, - Value type, - Value createdAt, - Value score, - Value userId, - Value> extraData}) { - return _ReactionsCompanion( - messageId: messageId ?? this.messageId, - type: type ?? this.type, - createdAt: createdAt ?? this.createdAt, - score: score ?? this.score, - userId: userId ?? this.userId, - extraData: extraData ?? this.extraData, - ); - } - - @override - Map toColumns(bool nullToAbsent) { - final map = {}; - if (messageId.present) { - map['message_id'] = Variable(messageId.value); - } - if (type.present) { - map['type'] = Variable(type.value); - } - if (createdAt.present) { - map['created_at'] = Variable(createdAt.value); - } - if (score.present) { - map['score'] = Variable(score.value); - } - if (userId.present) { - map['user_id'] = Variable(userId.value); - } - if (extraData.present) { - final converter = $_ReactionsTable.$converter0; - map['extra_data'] = Variable(converter.mapToSql(extraData.value)); - } - return map; - } - - @override - String toString() { - return (StringBuffer('_ReactionsCompanion(') - ..write('messageId: $messageId, ') - ..write('type: $type, ') - ..write('createdAt: $createdAt, ') - ..write('score: $score, ') - ..write('userId: $userId, ') - ..write('extraData: $extraData') - ..write(')')) - .toString(); - } -} - -class $_ReactionsTable extends _Reactions - with TableInfo<$_ReactionsTable, _Reaction> { - final GeneratedDatabase _db; - final String _alias; - $_ReactionsTable(this._db, [this._alias]); - final VerificationMeta _messageIdMeta = const VerificationMeta('messageId'); - GeneratedTextColumn _messageId; - @override - GeneratedTextColumn get messageId => _messageId ??= _constructMessageId(); - GeneratedTextColumn _constructMessageId() { - return GeneratedTextColumn( - 'message_id', - $tableName, - false, - ); - } - - final VerificationMeta _typeMeta = const VerificationMeta('type'); - GeneratedTextColumn _type; - @override - GeneratedTextColumn get type => _type ??= _constructType(); - GeneratedTextColumn _constructType() { - return GeneratedTextColumn( - 'type', - $tableName, - false, - ); - } - - final VerificationMeta _createdAtMeta = const VerificationMeta('createdAt'); - GeneratedDateTimeColumn _createdAt; - @override - GeneratedDateTimeColumn get createdAt => _createdAt ??= _constructCreatedAt(); - GeneratedDateTimeColumn _constructCreatedAt() { - return GeneratedDateTimeColumn( - 'created_at', - $tableName, - false, - ); - } - - final VerificationMeta _scoreMeta = const VerificationMeta('score'); - GeneratedIntColumn _score; - @override - GeneratedIntColumn get score => _score ??= _constructScore(); - GeneratedIntColumn _constructScore() { - return GeneratedIntColumn( - 'score', - $tableName, - true, - ); - } - - final VerificationMeta _userIdMeta = const VerificationMeta('userId'); - GeneratedTextColumn _userId; - @override - GeneratedTextColumn get userId => _userId ??= _constructUserId(); - GeneratedTextColumn _constructUserId() { - return GeneratedTextColumn( - 'user_id', - $tableName, - false, - ); - } - - final VerificationMeta _extraDataMeta = const VerificationMeta('extraData'); - GeneratedTextColumn _extraData; - @override - GeneratedTextColumn get extraData => _extraData ??= _constructExtraData(); - GeneratedTextColumn _constructExtraData() { - return GeneratedTextColumn( - 'extra_data', - $tableName, - true, - ); - } - - @override - List get $columns => - [messageId, type, createdAt, score, userId, extraData]; - @override - $_ReactionsTable get asDslTable => this; - @override - String get $tableName => _alias ?? 'reactions'; - @override - final String actualTableName = 'reactions'; - @override - VerificationContext validateIntegrity(Insertable<_Reaction> instance, - {bool isInserting = false}) { - final context = VerificationContext(); - final data = instance.toColumns(true); - if (data.containsKey('message_id')) { - context.handle(_messageIdMeta, - messageId.isAcceptableOrUnknown(data['message_id'], _messageIdMeta)); - } else if (isInserting) { - context.missing(_messageIdMeta); - } - if (data.containsKey('type')) { - context.handle( - _typeMeta, type.isAcceptableOrUnknown(data['type'], _typeMeta)); - } else if (isInserting) { - context.missing(_typeMeta); - } - if (data.containsKey('created_at')) { - context.handle(_createdAtMeta, - createdAt.isAcceptableOrUnknown(data['created_at'], _createdAtMeta)); - } else if (isInserting) { - context.missing(_createdAtMeta); - } - if (data.containsKey('score')) { - context.handle( - _scoreMeta, score.isAcceptableOrUnknown(data['score'], _scoreMeta)); - } - if (data.containsKey('user_id')) { - context.handle(_userIdMeta, - userId.isAcceptableOrUnknown(data['user_id'], _userIdMeta)); - } else if (isInserting) { - context.missing(_userIdMeta); - } - context.handle(_extraDataMeta, const VerificationResult.success()); - return context; - } - - @override - Set get $primaryKey => {messageId, type, userId}; - @override - _Reaction map(Map data, {String tablePrefix}) { - final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : null; - return _Reaction.fromData(data, _db, prefix: effectivePrefix); - } - - @override - $_ReactionsTable createAlias(String alias) { - return $_ReactionsTable(_db, alias); - } - - static TypeConverter, String> $converter0 = - _ExtraDataConverter(); -} - -abstract class _$OfflineStorage extends GeneratedDatabase { - _$OfflineStorage(QueryExecutor e) : super(SqlTypeSystem.defaultInstance, e); - _$OfflineStorage.connect(DatabaseConnection c) : super.connect(c); - $_ConnectionEventTable _connectionEvent; - $_ConnectionEventTable get connectionEvent => - _connectionEvent ??= $_ConnectionEventTable(this); - $_ChannelsTable _channels; - $_ChannelsTable get channels => _channels ??= $_ChannelsTable(this); - $_UsersTable _users; - $_UsersTable get users => _users ??= $_UsersTable(this); - $_MessagesTable _messages; - $_MessagesTable get messages => _messages ??= $_MessagesTable(this); - $_ReadsTable _reads; - $_ReadsTable get reads => _reads ??= $_ReadsTable(this); - $_MembersTable _members; - $_MembersTable get members => _members ??= $_MembersTable(this); - $_ChannelQueriesTable _channelQueries; - $_ChannelQueriesTable get channelQueries => - _channelQueries ??= $_ChannelQueriesTable(this); - $_ReactionsTable _reactions; - $_ReactionsTable get reactions => _reactions ??= $_ReactionsTable(this); - @override - Iterable get allTables => allSchemaEntities.whereType(); - @override - List get allSchemaEntities => [ - connectionEvent, - channels, - users, - messages, - reads, - members, - channelQueries, - reactions - ]; -} diff --git a/packages/dart_client/lib/src/db/shared/native_db.dart b/packages/dart_client/lib/src/db/shared/native_db.dart deleted file mode 100644 index deee5b08..00000000 --- a/packages/dart_client/lib/src/db/shared/native_db.dart +++ /dev/null @@ -1,65 +0,0 @@ -//ignore_for_file: public_member_api_docs -import 'dart:io'; -import 'dart:isolate'; -import 'package:flutter/material.dart'; -import 'package:moor/ffi.dart'; -import 'package:moor/isolate.dart'; -import 'package:moor/moor.dart'; -import 'package:path/path.dart'; -import 'package:path_provider/path_provider.dart'; -import 'package:stream_chat/src/db/offline_storage.dart'; - -class SharedDB { - static Future constructDatabase(dbName) async { - final dir = await getApplicationDocumentsDirectory(); - final path = join(dir.path, dbName); - final file = File(path); - return VmDatabase(file); - } - - static Future createMoorIsolate(String userId) async { - WidgetsFlutterBinding.ensureInitialized(); - final dir = await getApplicationDocumentsDirectory(); - final path = join(dir.path, 'db_$userId.sqlite'); - - final receivePort = ReceivePort(); - await Isolate.spawn( - startBackground, - _IsolateStartRequest(receivePort.sendPort, path), - ); - - return (await receivePort.first as MoorIsolate); - } - - static void startBackground(_IsolateStartRequest request) { - final executor = LazyDatabase(() async { - return VmDatabase(File(request.targetPath)); - }); - final moorIsolate = MoorIsolate.inCurrent( - () => DatabaseConnection.fromExecutor(executor), - ); - request.sendMoorIsolate.send(moorIsolate); - } - - static Future constructOfflineStorage({ - userId, - logger, - }) async { - logger.info('Connecting on background isolate'); - final isolate = await createMoorIsolate(userId); - final connection = await isolate.connect(); - return OfflineStorage.connect( - connection, - userId, - isolate, - logger, - ); - } -} - -class _IsolateStartRequest { - final SendPort sendMoorIsolate; - final String targetPath; - - _IsolateStartRequest(this.sendMoorIsolate, this.targetPath); -} diff --git a/packages/dart_client/lib/src/db/shared/shared_db.dart b/packages/dart_client/lib/src/db/shared/shared_db.dart deleted file mode 100644 index 25120fcf..00000000 --- a/packages/dart_client/lib/src/db/shared/shared_db.dart +++ /dev/null @@ -1,3 +0,0 @@ -export 'unsupported_db.dart' - if (dart.library.io) 'native_db.dart' // implementation using dart:io - if (dart.library.html) 'web_db.dart'; diff --git a/packages/dart_client/lib/src/db/shared/unsupported_db.dart b/packages/dart_client/lib/src/db/shared/unsupported_db.dart deleted file mode 100644 index bbb4ccb7..00000000 --- a/packages/dart_client/lib/src/db/shared/unsupported_db.dart +++ /dev/null @@ -1,14 +0,0 @@ -//ignore_for_file: public_member_api_docs -//ignore_for_file: always_declare_return_types -class SharedDB { - static constructDatabase(dbName) async { - print('Unsupported Platform'); - return null; - } - - static createMoorIsolate(userId) {} - - static startBackground(request) {} - - static constructOfflineStorage({userId, logger}) {} -} diff --git a/packages/dart_client/lib/src/db/shared/web_db.dart b/packages/dart_client/lib/src/db/shared/web_db.dart deleted file mode 100644 index f79c224a..00000000 --- a/packages/dart_client/lib/src/db/shared/web_db.dart +++ /dev/null @@ -1,20 +0,0 @@ -//ignore_for_file: public_member_api_docs -//ignore_for_file: always_declare_return_types -import 'package:moor/moor_web.dart'; -import 'package:stream_chat/src/db/offline_storage.dart'; - -class SharedDB { - static constructDatabase(dbName) async { - return WebDatabase(dbName); - } - - static Future constructOfflineStorage({ - userId, - logger, - }) async { - return OfflineStorage( - userId, - logger, - ); - } -} diff --git a/packages/dart_client/lib/src/db/stream_chat_database.dart b/packages/dart_client/lib/src/db/stream_chat_database.dart deleted file mode 100644 index 87ab828e..00000000 --- a/packages/dart_client/lib/src/db/stream_chat_database.dart +++ /dev/null @@ -1,97 +0,0 @@ -import 'package:stream_chat/src/api/requests.dart'; -import 'package:stream_chat/src/models/channel_model.dart'; -import 'package:stream_chat/src/models/channel_state.dart'; -import 'package:stream_chat/src/models/event.dart'; -import 'package:stream_chat/src/models/member.dart'; -import 'package:stream_chat/src/models/message.dart'; -import 'package:stream_chat/src/models/reaction.dart'; -import 'package:stream_chat/src/models/read.dart'; -import 'package:stream_chat/src/models/user.dart'; - -/// -abstract class StreamChatDatabase { - /// Creates a new connection to the database - Future connect({ - bool connectBackground = false, - bool logStatements = false, - }); - - /// Closes the database instance - /// If [flush] is true, the database data will be deleted - Future disconnect({bool flush = false}); - - /// Get stored replies by messageId - Future> getReplies( - String parentId, { - String lessThan, - }); - - /// Get stored connection event - Future getConnectionInfo(); - - /// Get stored lastSyncAt - Future getLastSyncAt(); - - /// Update stored connection event - Future updateConnectionInfo(Event event); - - /// Update stored lastSyncAt - Future updateLastSyncAt(DateTime lastSyncAt); - - /// Get the channel cids saved in the offline storage - Future> getChannelCids(); - - Future getChannelByCid(String cid); - - Future> getMembersByCid(String cid); - - Future> getReadsByCid(String cid); - - Future> getMessagesByCid( - String cid, { - int limit = 20, - String messageLessThan, - String messageGreaterThan, - }); - - /// Get list of channels by filter, sort and paginationParams - Future> getChannelStates({ - Map filter, - List sort = const [], - PaginationParams paginationParams, - }); - - /// Update list of channel queries - /// If [clearQueryCache] is true before the insert - /// the list of matching rows will be deleted - Future updateChannelQueries( - Map filter, - List cids, - bool clearQueryCache, - ); - - /// Remove a message by message id - Future deleteMessageByIds(List messageIds); - - /// Remove a message by message id - Future deleteMessageByCids(List cids); - - /// Remove a channel by cid - Future deleteChannelByCids(List cids); - - /// Update messages data from a list - Future updateMessages(String cid, List messages); - - /// Get the info about channel threads - Future>> getChannelThreads(String cid); - - Future updateChannels(List channels); - - Future updateMembers(String cid, List members); - - Future updateReads(String cid, List reads); - - Future updateUsers(List users); - - Future updateReactions(List reactions); -} diff --git a/packages/dart_client/lib/src/db/stream_chat_persistence.dart b/packages/dart_client/lib/src/db/stream_chat_persistence.dart new file mode 100644 index 00000000..40004825 --- /dev/null +++ b/packages/dart_client/lib/src/db/stream_chat_persistence.dart @@ -0,0 +1,196 @@ +import 'package:stream_chat/src/api/requests.dart'; +import 'package:stream_chat/src/models/channel_model.dart'; +import 'package:stream_chat/src/models/channel_state.dart'; +import 'package:stream_chat/src/models/event.dart'; +import 'package:stream_chat/src/models/member.dart'; +import 'package:stream_chat/src/models/message.dart'; +import 'package:stream_chat/src/models/reaction.dart'; +import 'package:stream_chat/src/models/read.dart'; +import 'package:stream_chat/src/models/user.dart'; + +/// +abstract class StreamChatPersistence { + /// Creates a new connection to the database + Future connect({ + bool connectBackground = false, + bool logStatements = false, + }); + + /// Closes the database instance + /// If [flush] is true, the database data will be deleted + Future disconnect({bool flush = false}); + + /// Get stored replies by messageId + Future> getReplies( + String parentId, { + String lessThan, + }); + + /// Get stored connection event + Future getConnectionInfo(); + + /// Get stored lastSyncAt + Future getLastSyncAt(); + + /// Update stored connection event + Future updateConnectionInfo(Event event); + + /// Update stored lastSyncAt + Future updateLastSyncAt(DateTime lastSyncAt); + + /// Get the channel cids saved in the offline storage + Future> getChannelCids(); + + /// + Future getChannelByCid(String cid); + + /// + Future> getMembersByCid(String cid); + + /// + Future> getReadsByCid(String cid); + + /// + Future> getMessagesByCid( + String cid, { + PaginationParams messagePagination, + }); + + /// Get channel data by cid + Future getChannelStateByCid( + String cid, { + PaginationParams messagePagination, + }) async { + final members = await getMembersByCid(cid); + final reads = await getReadsByCid(cid); + final channel = await getChannelByCid(cid); + final messages = await getMessagesByCid( + cid, + messagePagination: messagePagination, + ); + return ChannelState( + members: members, + read: reads, + messages: messages, + channel: channel, + ); + } + + /// Get list of channels by filter, sort and paginationParams + Future> getChannelStates({ + Map filter, + List sort = const [], + PaginationParams paginationParams, + }); + + /// Update list of channel queries + /// If [clearQueryCache] is true before the insert + /// the list of matching rows will be deleted + Future updateChannelQueries( + Map filter, + List cids, + bool clearQueryCache, + ); + + /// Remove a message by message id + Future deleteMessageById(String messageId) { + return deleteMessageByIds([messageId]); + } + + /// Remove a message by message ids + Future deleteMessageByIds(List messageIds); + + /// Remove a message by channel cid + Future deleteMessageByCid(String cid) { + return deleteMessageByCids([cid]); + } + + /// Remove a message by message cids + Future deleteMessageByCids(List cids); + + /// Remove a channel by cid + Future deleteChannels(List cids); + + /// Update messages data from a list + Future updateMessages(String cid, List messages); + + /// Get the info about channel threads + Future>> getChannelThreads(String cid); + + /// + Future updateChannels(List channels); + + /// + Future updateMembers(String cid, List members); + + /// + Future updateReads(String cid, List reads); + + /// + Future updateUsers(List users); + + /// + Future updateReactions(List reactions); + + /// + Future updateChannelState(ChannelState channelState) { + return updateChannelStates([channelState]); + } + + /// Update list of channel states + Future updateChannelStates(List channelStates) async { + final channels = channelStates.map((it) { + return it.channel; + }).where((it) => it != null); + + final reactions = channelStates.expand((it) => it.messages).expand((it) { + return [ + ...it.ownReactions.where((r) => r.userId != null), + ...it.latestReactions.where((r) => r.userId != null) + ]; + }).where((it) => it != null); + + final users = channelStates + .map((cs) => [ + cs.channel?.createdBy, + ...cs.messages?.map((m) { + return [ + m.user, + ...m.latestReactions?.map((r) => r.user), + ...m.ownReactions?.map((r) => r.user), + ]; + })?.expand((v) => v), + ...cs.read?.map((r) => r.user), + ...cs.members?.map((m) => m.user), + ]) + .expand((it) => it) + .where((it) => it != null); + + final updateMessagesFuture = channelStates.map((it) { + final cid = it.channel.cid; + final messages = it.messages.where((it) => it != null); + return updateMessages(cid, messages.toList(growable: false)); + }).toList(growable: false); + + final updateReadsFuture = channelStates.map((it) { + final cid = it.channel.cid; + final reads = it.read.where((it) => it != null); + return updateReads(cid, reads.toList(growable: false)); + }).toList(growable: false); + + final updateMembersFuture = channelStates.map((it) { + final cid = it.channel.cid; + final members = it.members.where((it) => it != null); + return updateMembers(cid, members.toList(growable: false)); + }).toList(growable: false); + + await Future.wait([ + ...updateMessagesFuture, + ...updateReadsFuture, + ...updateMembersFuture, + updateChannels(channels.toList(growable: false)), + updateReactions(reactions.toList(growable: false)), + updateUsers(users.toList(growable: false)), + ]); + } +} diff --git a/packages/dart_client/lib/src/notifications.dart b/packages/dart_client/lib/src/notifications.dart index 2fc500cf..e4cef9b5 100644 --- a/packages/dart_client/lib/src/notifications.dart +++ b/packages/dart_client/lib/src/notifications.dart @@ -3,10 +3,10 @@ import 'dart:convert'; import 'package:logging/logging.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:stream_chat/src/api/responses.dart'; -import 'package:stream_chat/src/db/offline_storage.dart'; import 'package:stream_chat/src/models/channel_model.dart'; import 'package:stream_chat/src/models/channel_state.dart'; import 'package:stream_chat/src/models/message.dart'; +import 'package:stream_chat_persistence/stream_chat_persistence.dart'; import 'client.dart'; import 'models/own_user.dart'; @@ -23,14 +23,18 @@ class NotificationService { final sharedPreferences = await _getSharedPreferences(); final userId = sharedPreferences.getString(KEY_USER_ID); - final offlineStorage = OfflineStorage(userId, Logger('💽')); - await offlineStorage.updateChannelState( + final chatPersistence = StreamChatPersistenceImpl( + userId, + logger: Logger('💽'), + ); + await chatPersistence.connect(); + await chatPersistence.updateChannelState( ChannelState( channel: channelModel, messages: [message], ), ); - await offlineStorage.disconnect(); + await chatPersistence.disconnect(); } else { final channel = client.state.channels[channelModel.cid]; channel.state.updateChannelState( @@ -44,6 +48,7 @@ class NotificationService { } static SharedPreferences _sharedPreferences; + static Future _getSharedPreferences() async { _sharedPreferences ??= await SharedPreferences.getInstance(); return _sharedPreferences; @@ -74,17 +79,18 @@ class NotificationService { final sharedPreferences = await _getSharedPreferences(); final userId = sharedPreferences.getString(KEY_USER_ID); - final offlineStorage = OfflineStorage( + final chatPersistence = StreamChatPersistenceImpl( userId, - Logger('💽'), + logger: Logger('💽'), ); + await chatPersistence.connect(); - await offlineStorage.updateChannelState(ChannelState( + await chatPersistence.updateChannelState(ChannelState( messages: [messageResponse.message], channel: messageResponse.channel, )); - await offlineStorage.disconnect(); + await chatPersistence.disconnect(); } /// Gets the message using the client and stores it in the offline storage diff --git a/packages/dart_client/lib/stream_chat.dart b/packages/dart_client/lib/stream_chat.dart index 8bac944f..f9a366c3 100644 --- a/packages/dart_client/lib/stream_chat.dart +++ b/packages/dart_client/lib/stream_chat.dart @@ -27,5 +27,5 @@ export './src/models/reaction.dart'; export './src/models/read.dart'; export './src/models/user.dart'; export './src/notifications.dart'; -export './src/db/stream_chat_database.dart'; -export './src/utils/result.dart'; +export './src/db/stream_chat_persistence.dart'; +export './src/utils/result.dart' hide Success, Error; diff --git a/packages/dart_client/pubspec.yaml b/packages/dart_client/pubspec.yaml index d4734e44..0032453a 100644 --- a/packages/dart_client/pubspec.yaml +++ b/packages/dart_client/pubspec.yaml @@ -19,12 +19,8 @@ dependencies: uuid: ^2.2.2 async: ^2.4.1 stream_channel: ^2.0.0 - moor: ^3.3.1 - path_provider: ^1.6.10 - path: ^1.6.4 rxdart: ^0.24.1 collection: ^1.14.12 - sqlite3_flutter_libs: ^0.3.0 pedantic: ^1.9.2 freezed: ^0.12.7 stream_chat_persistence: @@ -33,7 +29,6 @@ dependencies: dev_dependencies: build_runner: ^1.10.0 json_serializable: ^3.3.0 - moor_generator: ^3.1.0 flutter_test: sdk: flutter mockito: ^4.1.1 diff --git a/packages/flutter_widgets/pubspec.yaml b/packages/flutter_widgets/pubspec.yaml index 2b82aca2..5d7ff855 100644 --- a/packages/flutter_widgets/pubspec.yaml +++ b/packages/flutter_widgets/pubspec.yaml @@ -29,7 +29,8 @@ dependencies: image_picker: ^0.6.7+17 flutter_keyboard_visibility: ^4.0.2 mime: ^0.9.7 - stream_chat: ^0.2.24 + stream_chat: + path: ../dart_client video_compress: ^2.1.1 visibility_detector: ^0.1.5 http_parser: ^3.1.4 From ad979529d2c9d07219233d103644cdf9fe835683 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Tue, 26 Jan 2021 16:12:14 +0530 Subject: [PATCH 1038/1140] remove unwanted dependencies Signed-off-by: Sahil Kumar --- packages/dart_client/build.yaml | 3 -- .../dart_client/lib/src/utils/result.dart | 45 ------------------- packages/dart_client/lib/stream_chat.dart | 3 +- packages/dart_client/pubspec.yaml | 2 - packages/stream_chat_persistence/pubspec.yaml | 1 - 5 files changed, 1 insertion(+), 53 deletions(-) delete mode 100644 packages/dart_client/lib/src/utils/result.dart diff --git a/packages/dart_client/build.yaml b/packages/dart_client/build.yaml index ea58f519..ddbd70dd 100644 --- a/packages/dart_client/build.yaml +++ b/packages/dart_client/build.yaml @@ -1,9 +1,6 @@ targets: $default: builders: - moor_generator: - options: - generate_connect_constructor: true json_serializable: options: explicit_to_json: true diff --git a/packages/dart_client/lib/src/utils/result.dart b/packages/dart_client/lib/src/utils/result.dart deleted file mode 100644 index a2961ec4..00000000 --- a/packages/dart_client/lib/src/utils/result.dart +++ /dev/null @@ -1,45 +0,0 @@ -import 'package:flutter/foundation.dart'; -import 'package:freezed_annotation/freezed_annotation.dart'; - -import '../exceptions.dart'; - -part 'result.freezed.dart'; - -/// -@freezed -abstract class Result with _$Result { - /// - const factory Result.success({@required T data}) = Success; - - /// - const factory Result.error({@required ApiError error}) = Error; -} - -/// -extension ResultX on Result { - /// - bool get isSuccess => this is Success; - - /// - bool get isError => this is Error; - - /// - T get data { - if (isError) { - throw Exception( - 'Result is not successful. Check result.isSuccess before reading the data.', - ); - } - return (this as Success).data; - } - - /// - ApiError get error { - if (isSuccess) { - throw Exception( - 'Result is successful, not an error. Check result.isError before reading the error.', - ); - } - return (this as Error).error; - } -} diff --git a/packages/dart_client/lib/stream_chat.dart b/packages/dart_client/lib/stream_chat.dart index f9a366c3..0ff1f871 100644 --- a/packages/dart_client/lib/stream_chat.dart +++ b/packages/dart_client/lib/stream_chat.dart @@ -27,5 +27,4 @@ export './src/models/reaction.dart'; export './src/models/read.dart'; export './src/models/user.dart'; export './src/notifications.dart'; -export './src/db/stream_chat_persistence.dart'; -export './src/utils/result.dart' hide Success, Error; +export './src/db/stream_chat_persistence.dart'; \ No newline at end of file diff --git a/packages/dart_client/pubspec.yaml b/packages/dart_client/pubspec.yaml index 1c4afa80..5eca907a 100644 --- a/packages/dart_client/pubspec.yaml +++ b/packages/dart_client/pubspec.yaml @@ -18,11 +18,9 @@ dependencies: web_socket_channel: ^1.1.0 uuid: ^2.2.2 async: ^2.4.1 - stream_channel: ^2.0.0 rxdart: ^0.24.1 collection: ^1.14.12 pedantic: ^1.9.2 - freezed: ^0.12.7 stream_chat_persistence: path: ../stream_chat_persistence diff --git a/packages/stream_chat_persistence/pubspec.yaml b/packages/stream_chat_persistence/pubspec.yaml index a0c97c89..1ce6e604 100644 --- a/packages/stream_chat_persistence/pubspec.yaml +++ b/packages/stream_chat_persistence/pubspec.yaml @@ -11,7 +11,6 @@ dependencies: moor: ^3.4.0 path: ^1.7.0 path_provider: ^1.6.27 - sqlite3_flutter_libs: ^0.3.0 stream_chat: path: ../dart_client From 959aeab567bdde08f8d565782ed1777cf0f22d3a Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Tue, 26 Jan 2021 16:49:05 +0530 Subject: [PATCH 1039/1140] [StreamChatPersistence] Minor changes Signed-off-by: Sahil Kumar --- packages/stream_chat_persistence/build.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/stream_chat_persistence/build.yaml b/packages/stream_chat_persistence/build.yaml index b07425b6..373486d0 100644 --- a/packages/stream_chat_persistence/build.yaml +++ b/packages/stream_chat_persistence/build.yaml @@ -4,3 +4,6 @@ targets: moor_generator: options: generate_connect_constructor: true + data_class_to_companions: false + apply_converters_on_variables: true + generate_values_in_copy_with: true From a869e458f440264deba19fc7d4b8210625a3af63 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Tue, 26 Jan 2021 16:52:08 +0530 Subject: [PATCH 1040/1140] [StreamChatPersistence] Add generated files Signed-off-by: Sahil Kumar --- .../lib/src/dao/channel_dao.g.dart | 12 + .../lib/src/dao/channel_query_dao.g.dart | 13 + .../lib/src/dao/connection_event_dao.g.dart | 13 + .../lib/src/dao/member_dao.g.dart | 12 + .../lib/src/dao/message_dao.g.dart | 12 + .../lib/src/dao/reaction_dao.g.dart | 12 + .../lib/src/dao/read_dao.g.dart | 12 + .../lib/src/dao/user_dao.g.dart | 11 + .../lib/src/db/moor_chat_database.g.dart | 4030 +++++++++++++++++ 9 files changed, 4127 insertions(+) create mode 100644 packages/stream_chat_persistence/lib/src/dao/channel_dao.g.dart create mode 100644 packages/stream_chat_persistence/lib/src/dao/channel_query_dao.g.dart create mode 100644 packages/stream_chat_persistence/lib/src/dao/connection_event_dao.g.dart create mode 100644 packages/stream_chat_persistence/lib/src/dao/member_dao.g.dart create mode 100644 packages/stream_chat_persistence/lib/src/dao/message_dao.g.dart create mode 100644 packages/stream_chat_persistence/lib/src/dao/reaction_dao.g.dart create mode 100644 packages/stream_chat_persistence/lib/src/dao/read_dao.g.dart create mode 100644 packages/stream_chat_persistence/lib/src/dao/user_dao.g.dart create mode 100644 packages/stream_chat_persistence/lib/src/db/moor_chat_database.g.dart diff --git a/packages/stream_chat_persistence/lib/src/dao/channel_dao.g.dart b/packages/stream_chat_persistence/lib/src/dao/channel_dao.g.dart new file mode 100644 index 00000000..a3ac1713 --- /dev/null +++ b/packages/stream_chat_persistence/lib/src/dao/channel_dao.g.dart @@ -0,0 +1,12 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'channel_dao.dart'; + +// ************************************************************************** +// DaoGenerator +// ************************************************************************** + +mixin _$ChannelDaoMixin on DatabaseAccessor { + $ChannelsTable get channels => attachedDatabase.channels; + $UsersTable get users => attachedDatabase.users; +} diff --git a/packages/stream_chat_persistence/lib/src/dao/channel_query_dao.g.dart b/packages/stream_chat_persistence/lib/src/dao/channel_query_dao.g.dart new file mode 100644 index 00000000..5879d8bb --- /dev/null +++ b/packages/stream_chat_persistence/lib/src/dao/channel_query_dao.g.dart @@ -0,0 +1,13 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'channel_query_dao.dart'; + +// ************************************************************************** +// DaoGenerator +// ************************************************************************** + +mixin _$ChannelQueryDaoMixin on DatabaseAccessor { + $ChannelQueriesTable get channelQueries => attachedDatabase.channelQueries; + $ChannelsTable get channels => attachedDatabase.channels; + $UsersTable get users => attachedDatabase.users; +} diff --git a/packages/stream_chat_persistence/lib/src/dao/connection_event_dao.g.dart b/packages/stream_chat_persistence/lib/src/dao/connection_event_dao.g.dart new file mode 100644 index 00000000..a8245982 --- /dev/null +++ b/packages/stream_chat_persistence/lib/src/dao/connection_event_dao.g.dart @@ -0,0 +1,13 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'connection_event_dao.dart'; + +// ************************************************************************** +// DaoGenerator +// ************************************************************************** + +mixin _$ConnectionEventDaoMixin on DatabaseAccessor { + $ConnectionEventsTable get connectionEvents => + attachedDatabase.connectionEvents; + $UsersTable get users => attachedDatabase.users; +} diff --git a/packages/stream_chat_persistence/lib/src/dao/member_dao.g.dart b/packages/stream_chat_persistence/lib/src/dao/member_dao.g.dart new file mode 100644 index 00000000..dbda1351 --- /dev/null +++ b/packages/stream_chat_persistence/lib/src/dao/member_dao.g.dart @@ -0,0 +1,12 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'member_dao.dart'; + +// ************************************************************************** +// DaoGenerator +// ************************************************************************** + +mixin _$MemberDaoMixin on DatabaseAccessor { + $MembersTable get members => attachedDatabase.members; + $UsersTable get users => attachedDatabase.users; +} diff --git a/packages/stream_chat_persistence/lib/src/dao/message_dao.g.dart b/packages/stream_chat_persistence/lib/src/dao/message_dao.g.dart new file mode 100644 index 00000000..e27a5d42 --- /dev/null +++ b/packages/stream_chat_persistence/lib/src/dao/message_dao.g.dart @@ -0,0 +1,12 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'message_dao.dart'; + +// ************************************************************************** +// DaoGenerator +// ************************************************************************** + +mixin _$MessageDaoMixin on DatabaseAccessor { + $MessagesTable get messages => attachedDatabase.messages; + $UsersTable get users => attachedDatabase.users; +} diff --git a/packages/stream_chat_persistence/lib/src/dao/reaction_dao.g.dart b/packages/stream_chat_persistence/lib/src/dao/reaction_dao.g.dart new file mode 100644 index 00000000..b95e2126 --- /dev/null +++ b/packages/stream_chat_persistence/lib/src/dao/reaction_dao.g.dart @@ -0,0 +1,12 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'reaction_dao.dart'; + +// ************************************************************************** +// DaoGenerator +// ************************************************************************** + +mixin _$ReactionDaoMixin on DatabaseAccessor { + $ReactionsTable get reactions => attachedDatabase.reactions; + $UsersTable get users => attachedDatabase.users; +} diff --git a/packages/stream_chat_persistence/lib/src/dao/read_dao.g.dart b/packages/stream_chat_persistence/lib/src/dao/read_dao.g.dart new file mode 100644 index 00000000..b9ac9228 --- /dev/null +++ b/packages/stream_chat_persistence/lib/src/dao/read_dao.g.dart @@ -0,0 +1,12 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'read_dao.dart'; + +// ************************************************************************** +// DaoGenerator +// ************************************************************************** + +mixin _$ReadDaoMixin on DatabaseAccessor { + $ReadsTable get reads => attachedDatabase.reads; + $UsersTable get users => attachedDatabase.users; +} diff --git a/packages/stream_chat_persistence/lib/src/dao/user_dao.g.dart b/packages/stream_chat_persistence/lib/src/dao/user_dao.g.dart new file mode 100644 index 00000000..edd9a33b --- /dev/null +++ b/packages/stream_chat_persistence/lib/src/dao/user_dao.g.dart @@ -0,0 +1,11 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'user_dao.dart'; + +// ************************************************************************** +// DaoGenerator +// ************************************************************************** + +mixin _$UserDaoMixin on DatabaseAccessor { + $UsersTable get users => attachedDatabase.users; +} diff --git a/packages/stream_chat_persistence/lib/src/db/moor_chat_database.g.dart b/packages/stream_chat_persistence/lib/src/db/moor_chat_database.g.dart new file mode 100644 index 00000000..0ff6e9f5 --- /dev/null +++ b/packages/stream_chat_persistence/lib/src/db/moor_chat_database.g.dart @@ -0,0 +1,4030 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'moor_chat_database.dart'; + +// ************************************************************************** +// MoorGenerator +// ************************************************************************** + +// ignore_for_file: unnecessary_brace_in_string_interps, unnecessary_this +class ChannelEntity extends DataClass implements Insertable { + final String id; + final String type; + final String cid; + final Map config; + final bool frozen; + final DateTime lastMessageAt; + final DateTime createdAt; + final DateTime updatedAt; + final DateTime deletedAt; + final int memberCount; + final String createdById; + final Map extraData; + ChannelEntity( + {@required this.id, + @required this.type, + @required this.cid, + @required this.config, + @required this.frozen, + this.lastMessageAt, + this.createdAt, + this.updatedAt, + this.deletedAt, + this.memberCount, + this.createdById, + this.extraData}); + factory ChannelEntity.fromData( + Map data, GeneratedDatabase db, + {String prefix}) { + final effectivePrefix = prefix ?? ''; + final stringType = db.typeSystem.forDartType(); + final boolType = db.typeSystem.forDartType(); + final dateTimeType = db.typeSystem.forDartType(); + final intType = db.typeSystem.forDartType(); + return ChannelEntity( + id: stringType.mapFromDatabaseResponse(data['${effectivePrefix}id']), + type: stringType.mapFromDatabaseResponse(data['${effectivePrefix}type']), + cid: stringType.mapFromDatabaseResponse(data['${effectivePrefix}cid']), + config: $ChannelsTable.$converter0.mapToDart( + stringType.mapFromDatabaseResponse(data['${effectivePrefix}config'])), + frozen: + boolType.mapFromDatabaseResponse(data['${effectivePrefix}frozen']), + lastMessageAt: dateTimeType + .mapFromDatabaseResponse(data['${effectivePrefix}last_message_at']), + createdAt: dateTimeType + .mapFromDatabaseResponse(data['${effectivePrefix}created_at']), + updatedAt: dateTimeType + .mapFromDatabaseResponse(data['${effectivePrefix}updated_at']), + deletedAt: dateTimeType + .mapFromDatabaseResponse(data['${effectivePrefix}deleted_at']), + memberCount: intType + .mapFromDatabaseResponse(data['${effectivePrefix}member_count']), + createdById: stringType + .mapFromDatabaseResponse(data['${effectivePrefix}created_by_id']), + extraData: $ChannelsTable.$converter1.mapToDart(stringType + .mapFromDatabaseResponse(data['${effectivePrefix}extra_data'])), + ); + } + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (!nullToAbsent || id != null) { + map['id'] = Variable(id); + } + if (!nullToAbsent || type != null) { + map['type'] = Variable(type); + } + if (!nullToAbsent || cid != null) { + map['cid'] = Variable(cid); + } + if (!nullToAbsent || config != null) { + final converter = $ChannelsTable.$converter0; + map['config'] = Variable(converter.mapToSql(config)); + } + if (!nullToAbsent || frozen != null) { + map['frozen'] = Variable(frozen); + } + if (!nullToAbsent || lastMessageAt != null) { + map['last_message_at'] = Variable(lastMessageAt); + } + if (!nullToAbsent || createdAt != null) { + map['created_at'] = Variable(createdAt); + } + if (!nullToAbsent || updatedAt != null) { + map['updated_at'] = Variable(updatedAt); + } + if (!nullToAbsent || deletedAt != null) { + map['deleted_at'] = Variable(deletedAt); + } + if (!nullToAbsent || memberCount != null) { + map['member_count'] = Variable(memberCount); + } + if (!nullToAbsent || createdById != null) { + map['created_by_id'] = Variable(createdById); + } + if (!nullToAbsent || extraData != null) { + final converter = $ChannelsTable.$converter1; + map['extra_data'] = Variable(converter.mapToSql(extraData)); + } + return map; + } + + factory ChannelEntity.fromJson(Map json, + {ValueSerializer serializer}) { + serializer ??= moorRuntimeOptions.defaultSerializer; + return ChannelEntity( + id: serializer.fromJson(json['id']), + type: serializer.fromJson(json['type']), + cid: serializer.fromJson(json['cid']), + config: serializer.fromJson>(json['config']), + frozen: serializer.fromJson(json['frozen']), + lastMessageAt: serializer.fromJson(json['lastMessageAt']), + createdAt: serializer.fromJson(json['createdAt']), + updatedAt: serializer.fromJson(json['updatedAt']), + deletedAt: serializer.fromJson(json['deletedAt']), + memberCount: serializer.fromJson(json['memberCount']), + createdById: serializer.fromJson(json['createdById']), + extraData: serializer.fromJson>(json['extraData']), + ); + } + @override + Map toJson({ValueSerializer serializer}) { + serializer ??= moorRuntimeOptions.defaultSerializer; + return { + 'id': serializer.toJson(id), + 'type': serializer.toJson(type), + 'cid': serializer.toJson(cid), + 'config': serializer.toJson>(config), + 'frozen': serializer.toJson(frozen), + 'lastMessageAt': serializer.toJson(lastMessageAt), + 'createdAt': serializer.toJson(createdAt), + 'updatedAt': serializer.toJson(updatedAt), + 'deletedAt': serializer.toJson(deletedAt), + 'memberCount': serializer.toJson(memberCount), + 'createdById': serializer.toJson(createdById), + 'extraData': serializer.toJson>(extraData), + }; + } + + ChannelEntity copyWith( + {String id, + String type, + String cid, + Map config, + bool frozen, + Value lastMessageAt = const Value.absent(), + Value createdAt = const Value.absent(), + Value updatedAt = const Value.absent(), + Value deletedAt = const Value.absent(), + Value memberCount = const Value.absent(), + Value createdById = const Value.absent(), + Value> extraData = const Value.absent()}) => + ChannelEntity( + id: id ?? this.id, + type: type ?? this.type, + cid: cid ?? this.cid, + config: config ?? this.config, + frozen: frozen ?? this.frozen, + lastMessageAt: + lastMessageAt.present ? lastMessageAt.value : this.lastMessageAt, + createdAt: createdAt.present ? createdAt.value : this.createdAt, + updatedAt: updatedAt.present ? updatedAt.value : this.updatedAt, + deletedAt: deletedAt.present ? deletedAt.value : this.deletedAt, + memberCount: memberCount.present ? memberCount.value : this.memberCount, + createdById: createdById.present ? createdById.value : this.createdById, + extraData: extraData.present ? extraData.value : this.extraData, + ); + @override + String toString() { + return (StringBuffer('ChannelEntity(') + ..write('id: $id, ') + ..write('type: $type, ') + ..write('cid: $cid, ') + ..write('config: $config, ') + ..write('frozen: $frozen, ') + ..write('lastMessageAt: $lastMessageAt, ') + ..write('createdAt: $createdAt, ') + ..write('updatedAt: $updatedAt, ') + ..write('deletedAt: $deletedAt, ') + ..write('memberCount: $memberCount, ') + ..write('createdById: $createdById, ') + ..write('extraData: $extraData') + ..write(')')) + .toString(); + } + + @override + int get hashCode => $mrjf($mrjc( + id.hashCode, + $mrjc( + type.hashCode, + $mrjc( + cid.hashCode, + $mrjc( + config.hashCode, + $mrjc( + frozen.hashCode, + $mrjc( + lastMessageAt.hashCode, + $mrjc( + createdAt.hashCode, + $mrjc( + updatedAt.hashCode, + $mrjc( + deletedAt.hashCode, + $mrjc( + memberCount.hashCode, + $mrjc(createdById.hashCode, + extraData.hashCode)))))))))))); + @override + bool operator ==(dynamic other) => + identical(this, other) || + (other is ChannelEntity && + other.id == this.id && + other.type == this.type && + other.cid == this.cid && + other.config == this.config && + other.frozen == this.frozen && + other.lastMessageAt == this.lastMessageAt && + other.createdAt == this.createdAt && + other.updatedAt == this.updatedAt && + other.deletedAt == this.deletedAt && + other.memberCount == this.memberCount && + other.createdById == this.createdById && + other.extraData == this.extraData); +} + +class ChannelsCompanion extends UpdateCompanion { + final Value id; + final Value type; + final Value cid; + final Value> config; + final Value frozen; + final Value lastMessageAt; + final Value createdAt; + final Value updatedAt; + final Value deletedAt; + final Value memberCount; + final Value createdById; + final Value> extraData; + const ChannelsCompanion({ + this.id = const Value.absent(), + this.type = const Value.absent(), + this.cid = const Value.absent(), + this.config = const Value.absent(), + this.frozen = const Value.absent(), + this.lastMessageAt = const Value.absent(), + this.createdAt = const Value.absent(), + this.updatedAt = const Value.absent(), + this.deletedAt = const Value.absent(), + this.memberCount = const Value.absent(), + this.createdById = const Value.absent(), + this.extraData = const Value.absent(), + }); + ChannelsCompanion.insert({ + @required String id, + @required String type, + @required String cid, + @required Map config, + this.frozen = const Value.absent(), + this.lastMessageAt = const Value.absent(), + this.createdAt = const Value.absent(), + this.updatedAt = const Value.absent(), + this.deletedAt = const Value.absent(), + this.memberCount = const Value.absent(), + this.createdById = const Value.absent(), + this.extraData = const Value.absent(), + }) : id = Value(id), + type = Value(type), + cid = Value(cid), + config = Value(config); + static Insertable custom({ + Expression id, + Expression type, + Expression cid, + Expression config, + Expression frozen, + Expression lastMessageAt, + Expression createdAt, + Expression updatedAt, + Expression deletedAt, + Expression memberCount, + Expression createdById, + Expression extraData, + }) { + return RawValuesInsertable({ + if (id != null) 'id': id, + if (type != null) 'type': type, + if (cid != null) 'cid': cid, + if (config != null) 'config': config, + if (frozen != null) 'frozen': frozen, + if (lastMessageAt != null) 'last_message_at': lastMessageAt, + if (createdAt != null) 'created_at': createdAt, + if (updatedAt != null) 'updated_at': updatedAt, + if (deletedAt != null) 'deleted_at': deletedAt, + if (memberCount != null) 'member_count': memberCount, + if (createdById != null) 'created_by_id': createdById, + if (extraData != null) 'extra_data': extraData, + }); + } + + ChannelsCompanion copyWith( + {Value id, + Value type, + Value cid, + Value> config, + Value frozen, + Value lastMessageAt, + Value createdAt, + Value updatedAt, + Value deletedAt, + Value memberCount, + Value createdById, + Value> extraData}) { + return ChannelsCompanion( + id: id ?? this.id, + type: type ?? this.type, + cid: cid ?? this.cid, + config: config ?? this.config, + frozen: frozen ?? this.frozen, + lastMessageAt: lastMessageAt ?? this.lastMessageAt, + createdAt: createdAt ?? this.createdAt, + updatedAt: updatedAt ?? this.updatedAt, + deletedAt: deletedAt ?? this.deletedAt, + memberCount: memberCount ?? this.memberCount, + createdById: createdById ?? this.createdById, + extraData: extraData ?? this.extraData, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (id.present) { + map['id'] = Variable(id.value); + } + if (type.present) { + map['type'] = Variable(type.value); + } + if (cid.present) { + map['cid'] = Variable(cid.value); + } + if (config.present) { + final converter = $ChannelsTable.$converter0; + map['config'] = Variable(converter.mapToSql(config.value)); + } + if (frozen.present) { + map['frozen'] = Variable(frozen.value); + } + if (lastMessageAt.present) { + map['last_message_at'] = Variable(lastMessageAt.value); + } + if (createdAt.present) { + map['created_at'] = Variable(createdAt.value); + } + if (updatedAt.present) { + map['updated_at'] = Variable(updatedAt.value); + } + if (deletedAt.present) { + map['deleted_at'] = Variable(deletedAt.value); + } + if (memberCount.present) { + map['member_count'] = Variable(memberCount.value); + } + if (createdById.present) { + map['created_by_id'] = Variable(createdById.value); + } + if (extraData.present) { + final converter = $ChannelsTable.$converter1; + map['extra_data'] = Variable(converter.mapToSql(extraData.value)); + } + return map; + } + + @override + String toString() { + return (StringBuffer('ChannelsCompanion(') + ..write('id: $id, ') + ..write('type: $type, ') + ..write('cid: $cid, ') + ..write('config: $config, ') + ..write('frozen: $frozen, ') + ..write('lastMessageAt: $lastMessageAt, ') + ..write('createdAt: $createdAt, ') + ..write('updatedAt: $updatedAt, ') + ..write('deletedAt: $deletedAt, ') + ..write('memberCount: $memberCount, ') + ..write('createdById: $createdById, ') + ..write('extraData: $extraData') + ..write(')')) + .toString(); + } +} + +class $ChannelsTable extends Channels + with TableInfo<$ChannelsTable, ChannelEntity> { + final GeneratedDatabase _db; + final String _alias; + $ChannelsTable(this._db, [this._alias]); + final VerificationMeta _idMeta = const VerificationMeta('id'); + GeneratedTextColumn _id; + @override + GeneratedTextColumn get id => _id ??= _constructId(); + GeneratedTextColumn _constructId() { + return GeneratedTextColumn( + 'id', + $tableName, + false, + ); + } + + final VerificationMeta _typeMeta = const VerificationMeta('type'); + GeneratedTextColumn _type; + @override + GeneratedTextColumn get type => _type ??= _constructType(); + GeneratedTextColumn _constructType() { + return GeneratedTextColumn( + 'type', + $tableName, + false, + ); + } + + final VerificationMeta _cidMeta = const VerificationMeta('cid'); + GeneratedTextColumn _cid; + @override + GeneratedTextColumn get cid => _cid ??= _constructCid(); + GeneratedTextColumn _constructCid() { + return GeneratedTextColumn( + 'cid', + $tableName, + false, + ); + } + + final VerificationMeta _configMeta = const VerificationMeta('config'); + GeneratedTextColumn _config; + @override + GeneratedTextColumn get config => _config ??= _constructConfig(); + GeneratedTextColumn _constructConfig() { + return GeneratedTextColumn( + 'config', + $tableName, + false, + ); + } + + final VerificationMeta _frozenMeta = const VerificationMeta('frozen'); + GeneratedBoolColumn _frozen; + @override + GeneratedBoolColumn get frozen => _frozen ??= _constructFrozen(); + GeneratedBoolColumn _constructFrozen() { + return GeneratedBoolColumn('frozen', $tableName, false, + defaultValue: Constant(false)); + } + + final VerificationMeta _lastMessageAtMeta = + const VerificationMeta('lastMessageAt'); + GeneratedDateTimeColumn _lastMessageAt; + @override + GeneratedDateTimeColumn get lastMessageAt => + _lastMessageAt ??= _constructLastMessageAt(); + GeneratedDateTimeColumn _constructLastMessageAt() { + return GeneratedDateTimeColumn( + 'last_message_at', + $tableName, + true, + ); + } + + final VerificationMeta _createdAtMeta = const VerificationMeta('createdAt'); + GeneratedDateTimeColumn _createdAt; + @override + GeneratedDateTimeColumn get createdAt => _createdAt ??= _constructCreatedAt(); + GeneratedDateTimeColumn _constructCreatedAt() { + return GeneratedDateTimeColumn( + 'created_at', + $tableName, + true, + ); + } + + final VerificationMeta _updatedAtMeta = const VerificationMeta('updatedAt'); + GeneratedDateTimeColumn _updatedAt; + @override + GeneratedDateTimeColumn get updatedAt => _updatedAt ??= _constructUpdatedAt(); + GeneratedDateTimeColumn _constructUpdatedAt() { + return GeneratedDateTimeColumn( + 'updated_at', + $tableName, + true, + ); + } + + final VerificationMeta _deletedAtMeta = const VerificationMeta('deletedAt'); + GeneratedDateTimeColumn _deletedAt; + @override + GeneratedDateTimeColumn get deletedAt => _deletedAt ??= _constructDeletedAt(); + GeneratedDateTimeColumn _constructDeletedAt() { + return GeneratedDateTimeColumn( + 'deleted_at', + $tableName, + true, + ); + } + + final VerificationMeta _memberCountMeta = + const VerificationMeta('memberCount'); + GeneratedIntColumn _memberCount; + @override + GeneratedIntColumn get memberCount => + _memberCount ??= _constructMemberCount(); + GeneratedIntColumn _constructMemberCount() { + return GeneratedIntColumn( + 'member_count', + $tableName, + true, + ); + } + + final VerificationMeta _createdByIdMeta = + const VerificationMeta('createdById'); + GeneratedTextColumn _createdById; + @override + GeneratedTextColumn get createdById => + _createdById ??= _constructCreatedById(); + GeneratedTextColumn _constructCreatedById() { + return GeneratedTextColumn( + 'created_by_id', + $tableName, + true, + ); + } + + final VerificationMeta _extraDataMeta = const VerificationMeta('extraData'); + GeneratedTextColumn _extraData; + @override + GeneratedTextColumn get extraData => _extraData ??= _constructExtraData(); + GeneratedTextColumn _constructExtraData() { + return GeneratedTextColumn( + 'extra_data', + $tableName, + true, + ); + } + + @override + List get $columns => [ + id, + type, + cid, + config, + frozen, + lastMessageAt, + createdAt, + updatedAt, + deletedAt, + memberCount, + createdById, + extraData + ]; + @override + $ChannelsTable get asDslTable => this; + @override + String get $tableName => _alias ?? 'channels'; + @override + final String actualTableName = 'channels'; + @override + VerificationContext validateIntegrity(Insertable instance, + {bool isInserting = false}) { + final context = VerificationContext(); + final data = instance.toColumns(true); + if (data.containsKey('id')) { + context.handle(_idMeta, id.isAcceptableOrUnknown(data['id'], _idMeta)); + } else if (isInserting) { + context.missing(_idMeta); + } + if (data.containsKey('type')) { + context.handle( + _typeMeta, type.isAcceptableOrUnknown(data['type'], _typeMeta)); + } else if (isInserting) { + context.missing(_typeMeta); + } + if (data.containsKey('cid')) { + context.handle( + _cidMeta, cid.isAcceptableOrUnknown(data['cid'], _cidMeta)); + } else if (isInserting) { + context.missing(_cidMeta); + } + context.handle(_configMeta, const VerificationResult.success()); + if (data.containsKey('frozen')) { + context.handle(_frozenMeta, + frozen.isAcceptableOrUnknown(data['frozen'], _frozenMeta)); + } + if (data.containsKey('last_message_at')) { + context.handle( + _lastMessageAtMeta, + lastMessageAt.isAcceptableOrUnknown( + data['last_message_at'], _lastMessageAtMeta)); + } + if (data.containsKey('created_at')) { + context.handle(_createdAtMeta, + createdAt.isAcceptableOrUnknown(data['created_at'], _createdAtMeta)); + } + if (data.containsKey('updated_at')) { + context.handle(_updatedAtMeta, + updatedAt.isAcceptableOrUnknown(data['updated_at'], _updatedAtMeta)); + } + if (data.containsKey('deleted_at')) { + context.handle(_deletedAtMeta, + deletedAt.isAcceptableOrUnknown(data['deleted_at'], _deletedAtMeta)); + } + if (data.containsKey('member_count')) { + context.handle( + _memberCountMeta, + memberCount.isAcceptableOrUnknown( + data['member_count'], _memberCountMeta)); + } + if (data.containsKey('created_by_id')) { + context.handle( + _createdByIdMeta, + createdById.isAcceptableOrUnknown( + data['created_by_id'], _createdByIdMeta)); + } + context.handle(_extraDataMeta, const VerificationResult.success()); + return context; + } + + @override + Set get $primaryKey => {cid}; + @override + ChannelEntity map(Map data, {String tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : null; + return ChannelEntity.fromData(data, _db, prefix: effectivePrefix); + } + + @override + $ChannelsTable createAlias(String alias) { + return $ChannelsTable(_db, alias); + } + + static TypeConverter, String> $converter0 = + MapConverter(); + static TypeConverter, String> $converter1 = + MapConverter(); +} + +class MessageEntity extends DataClass implements Insertable { + final String id; + final String messageText; + final List attachments; + final MessageSendingStatus status; + final String type; + final List mentionedUsers; + final Map reactionCounts; + final Map reactionScores; + final String parentId; + final String quotedMessageId; + final int replyCount; + final bool showInChannel; + final bool shadowed; + final String command; + final DateTime createdAt; + final DateTime updatedAt; + final DateTime deletedAt; + final String userId; + final String channelCid; + final Map extraData; + MessageEntity( + {@required this.id, + this.messageText, + this.attachments, + this.status, + this.type, + this.mentionedUsers, + this.reactionCounts, + this.reactionScores, + this.parentId, + this.quotedMessageId, + this.replyCount, + this.showInChannel, + this.shadowed, + this.command, + @required this.createdAt, + this.updatedAt, + this.deletedAt, + this.userId, + this.channelCid, + this.extraData}); + factory MessageEntity.fromData( + Map data, GeneratedDatabase db, + {String prefix}) { + final effectivePrefix = prefix ?? ''; + final stringType = db.typeSystem.forDartType(); + final intType = db.typeSystem.forDartType(); + final boolType = db.typeSystem.forDartType(); + final dateTimeType = db.typeSystem.forDartType(); + return MessageEntity( + id: stringType.mapFromDatabaseResponse(data['${effectivePrefix}id']), + messageText: stringType + .mapFromDatabaseResponse(data['${effectivePrefix}message_text']), + attachments: $MessagesTable.$converter0.mapToDart(stringType + .mapFromDatabaseResponse(data['${effectivePrefix}attachments'])), + status: $MessagesTable.$converter1.mapToDart( + intType.mapFromDatabaseResponse(data['${effectivePrefix}status'])), + type: stringType.mapFromDatabaseResponse(data['${effectivePrefix}type']), + mentionedUsers: $MessagesTable.$converter2.mapToDart(stringType + .mapFromDatabaseResponse(data['${effectivePrefix}mentioned_users'])), + reactionCounts: $MessagesTable.$converter3.mapToDart(stringType + .mapFromDatabaseResponse(data['${effectivePrefix}reaction_counts'])), + reactionScores: $MessagesTable.$converter4.mapToDart(stringType + .mapFromDatabaseResponse(data['${effectivePrefix}reaction_scores'])), + parentId: stringType + .mapFromDatabaseResponse(data['${effectivePrefix}parent_id']), + quotedMessageId: stringType + .mapFromDatabaseResponse(data['${effectivePrefix}quoted_message_id']), + replyCount: intType + .mapFromDatabaseResponse(data['${effectivePrefix}reply_count']), + showInChannel: boolType + .mapFromDatabaseResponse(data['${effectivePrefix}show_in_channel']), + shadowed: + boolType.mapFromDatabaseResponse(data['${effectivePrefix}shadowed']), + command: + stringType.mapFromDatabaseResponse(data['${effectivePrefix}command']), + createdAt: dateTimeType + .mapFromDatabaseResponse(data['${effectivePrefix}created_at']), + updatedAt: dateTimeType + .mapFromDatabaseResponse(data['${effectivePrefix}updated_at']), + deletedAt: dateTimeType + .mapFromDatabaseResponse(data['${effectivePrefix}deleted_at']), + userId: + stringType.mapFromDatabaseResponse(data['${effectivePrefix}user_id']), + channelCid: stringType + .mapFromDatabaseResponse(data['${effectivePrefix}channel_cid']), + extraData: $MessagesTable.$converter5.mapToDart(stringType + .mapFromDatabaseResponse(data['${effectivePrefix}extra_data'])), + ); + } + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (!nullToAbsent || id != null) { + map['id'] = Variable(id); + } + if (!nullToAbsent || messageText != null) { + map['message_text'] = Variable(messageText); + } + if (!nullToAbsent || attachments != null) { + final converter = $MessagesTable.$converter0; + map['attachments'] = Variable(converter.mapToSql(attachments)); + } + if (!nullToAbsent || status != null) { + final converter = $MessagesTable.$converter1; + map['status'] = Variable(converter.mapToSql(status)); + } + if (!nullToAbsent || type != null) { + map['type'] = Variable(type); + } + if (!nullToAbsent || mentionedUsers != null) { + final converter = $MessagesTable.$converter2; + map['mentioned_users'] = + Variable(converter.mapToSql(mentionedUsers)); + } + if (!nullToAbsent || reactionCounts != null) { + final converter = $MessagesTable.$converter3; + map['reaction_counts'] = + Variable(converter.mapToSql(reactionCounts)); + } + if (!nullToAbsent || reactionScores != null) { + final converter = $MessagesTable.$converter4; + map['reaction_scores'] = + Variable(converter.mapToSql(reactionScores)); + } + if (!nullToAbsent || parentId != null) { + map['parent_id'] = Variable(parentId); + } + if (!nullToAbsent || quotedMessageId != null) { + map['quoted_message_id'] = Variable(quotedMessageId); + } + if (!nullToAbsent || replyCount != null) { + map['reply_count'] = Variable(replyCount); + } + if (!nullToAbsent || showInChannel != null) { + map['show_in_channel'] = Variable(showInChannel); + } + if (!nullToAbsent || shadowed != null) { + map['shadowed'] = Variable(shadowed); + } + if (!nullToAbsent || command != null) { + map['command'] = Variable(command); + } + if (!nullToAbsent || createdAt != null) { + map['created_at'] = Variable(createdAt); + } + if (!nullToAbsent || updatedAt != null) { + map['updated_at'] = Variable(updatedAt); + } + if (!nullToAbsent || deletedAt != null) { + map['deleted_at'] = Variable(deletedAt); + } + if (!nullToAbsent || userId != null) { + map['user_id'] = Variable(userId); + } + if (!nullToAbsent || channelCid != null) { + map['channel_cid'] = Variable(channelCid); + } + if (!nullToAbsent || extraData != null) { + final converter = $MessagesTable.$converter5; + map['extra_data'] = Variable(converter.mapToSql(extraData)); + } + return map; + } + + factory MessageEntity.fromJson(Map json, + {ValueSerializer serializer}) { + serializer ??= moorRuntimeOptions.defaultSerializer; + return MessageEntity( + id: serializer.fromJson(json['id']), + messageText: serializer.fromJson(json['messageText']), + attachments: serializer.fromJson>(json['attachments']), + status: serializer.fromJson(json['status']), + type: serializer.fromJson(json['type']), + mentionedUsers: serializer.fromJson>(json['mentionedUsers']), + reactionCounts: + serializer.fromJson>(json['reactionCounts']), + reactionScores: + serializer.fromJson>(json['reactionScores']), + parentId: serializer.fromJson(json['parentId']), + quotedMessageId: serializer.fromJson(json['quotedMessageId']), + replyCount: serializer.fromJson(json['replyCount']), + showInChannel: serializer.fromJson(json['showInChannel']), + shadowed: serializer.fromJson(json['shadowed']), + command: serializer.fromJson(json['command']), + createdAt: serializer.fromJson(json['createdAt']), + updatedAt: serializer.fromJson(json['updatedAt']), + deletedAt: serializer.fromJson(json['deletedAt']), + userId: serializer.fromJson(json['userId']), + channelCid: serializer.fromJson(json['channelCid']), + extraData: serializer.fromJson>(json['extraData']), + ); + } + @override + Map toJson({ValueSerializer serializer}) { + serializer ??= moorRuntimeOptions.defaultSerializer; + return { + 'id': serializer.toJson(id), + 'messageText': serializer.toJson(messageText), + 'attachments': serializer.toJson>(attachments), + 'status': serializer.toJson(status), + 'type': serializer.toJson(type), + 'mentionedUsers': serializer.toJson>(mentionedUsers), + 'reactionCounts': serializer.toJson>(reactionCounts), + 'reactionScores': serializer.toJson>(reactionScores), + 'parentId': serializer.toJson(parentId), + 'quotedMessageId': serializer.toJson(quotedMessageId), + 'replyCount': serializer.toJson(replyCount), + 'showInChannel': serializer.toJson(showInChannel), + 'shadowed': serializer.toJson(shadowed), + 'command': serializer.toJson(command), + 'createdAt': serializer.toJson(createdAt), + 'updatedAt': serializer.toJson(updatedAt), + 'deletedAt': serializer.toJson(deletedAt), + 'userId': serializer.toJson(userId), + 'channelCid': serializer.toJson(channelCid), + 'extraData': serializer.toJson>(extraData), + }; + } + + MessageEntity copyWith( + {String id, + Value messageText = const Value.absent(), + Value> attachments = const Value.absent(), + Value status = const Value.absent(), + Value type = const Value.absent(), + Value> mentionedUsers = const Value.absent(), + Value> reactionCounts = const Value.absent(), + Value> reactionScores = const Value.absent(), + Value parentId = const Value.absent(), + Value quotedMessageId = const Value.absent(), + Value replyCount = const Value.absent(), + Value showInChannel = const Value.absent(), + Value shadowed = const Value.absent(), + Value command = const Value.absent(), + DateTime createdAt, + Value updatedAt = const Value.absent(), + Value deletedAt = const Value.absent(), + Value userId = const Value.absent(), + Value channelCid = const Value.absent(), + Value> extraData = const Value.absent()}) => + MessageEntity( + id: id ?? this.id, + messageText: messageText.present ? messageText.value : this.messageText, + attachments: attachments.present ? attachments.value : this.attachments, + status: status.present ? status.value : this.status, + type: type.present ? type.value : this.type, + mentionedUsers: + mentionedUsers.present ? mentionedUsers.value : this.mentionedUsers, + reactionCounts: + reactionCounts.present ? reactionCounts.value : this.reactionCounts, + reactionScores: + reactionScores.present ? reactionScores.value : this.reactionScores, + parentId: parentId.present ? parentId.value : this.parentId, + quotedMessageId: quotedMessageId.present + ? quotedMessageId.value + : this.quotedMessageId, + replyCount: replyCount.present ? replyCount.value : this.replyCount, + showInChannel: + showInChannel.present ? showInChannel.value : this.showInChannel, + shadowed: shadowed.present ? shadowed.value : this.shadowed, + command: command.present ? command.value : this.command, + createdAt: createdAt ?? this.createdAt, + updatedAt: updatedAt.present ? updatedAt.value : this.updatedAt, + deletedAt: deletedAt.present ? deletedAt.value : this.deletedAt, + userId: userId.present ? userId.value : this.userId, + channelCid: channelCid.present ? channelCid.value : this.channelCid, + extraData: extraData.present ? extraData.value : this.extraData, + ); + @override + String toString() { + return (StringBuffer('MessageEntity(') + ..write('id: $id, ') + ..write('messageText: $messageText, ') + ..write('attachments: $attachments, ') + ..write('status: $status, ') + ..write('type: $type, ') + ..write('mentionedUsers: $mentionedUsers, ') + ..write('reactionCounts: $reactionCounts, ') + ..write('reactionScores: $reactionScores, ') + ..write('parentId: $parentId, ') + ..write('quotedMessageId: $quotedMessageId, ') + ..write('replyCount: $replyCount, ') + ..write('showInChannel: $showInChannel, ') + ..write('shadowed: $shadowed, ') + ..write('command: $command, ') + ..write('createdAt: $createdAt, ') + ..write('updatedAt: $updatedAt, ') + ..write('deletedAt: $deletedAt, ') + ..write('userId: $userId, ') + ..write('channelCid: $channelCid, ') + ..write('extraData: $extraData') + ..write(')')) + .toString(); + } + + @override + int get hashCode => $mrjf($mrjc( + id.hashCode, + $mrjc( + messageText.hashCode, + $mrjc( + attachments.hashCode, + $mrjc( + status.hashCode, + $mrjc( + type.hashCode, + $mrjc( + mentionedUsers.hashCode, + $mrjc( + reactionCounts.hashCode, + $mrjc( + reactionScores.hashCode, + $mrjc( + parentId.hashCode, + $mrjc( + quotedMessageId.hashCode, + $mrjc( + replyCount.hashCode, + $mrjc( + showInChannel.hashCode, + $mrjc( + shadowed.hashCode, + $mrjc( + command.hashCode, + $mrjc( + createdAt + .hashCode, + $mrjc( + updatedAt + .hashCode, + $mrjc( + deletedAt + .hashCode, + $mrjc( + userId + .hashCode, + $mrjc( + channelCid.hashCode, + extraData.hashCode)))))))))))))))))))); + @override + bool operator ==(dynamic other) => + identical(this, other) || + (other is MessageEntity && + other.id == this.id && + other.messageText == this.messageText && + other.attachments == this.attachments && + other.status == this.status && + other.type == this.type && + other.mentionedUsers == this.mentionedUsers && + other.reactionCounts == this.reactionCounts && + other.reactionScores == this.reactionScores && + other.parentId == this.parentId && + other.quotedMessageId == this.quotedMessageId && + other.replyCount == this.replyCount && + other.showInChannel == this.showInChannel && + other.shadowed == this.shadowed && + other.command == this.command && + other.createdAt == this.createdAt && + other.updatedAt == this.updatedAt && + other.deletedAt == this.deletedAt && + other.userId == this.userId && + other.channelCid == this.channelCid && + other.extraData == this.extraData); +} + +class MessagesCompanion extends UpdateCompanion { + final Value id; + final Value messageText; + final Value> attachments; + final Value status; + final Value type; + final Value> mentionedUsers; + final Value> reactionCounts; + final Value> reactionScores; + final Value parentId; + final Value quotedMessageId; + final Value replyCount; + final Value showInChannel; + final Value shadowed; + final Value command; + final Value createdAt; + final Value updatedAt; + final Value deletedAt; + final Value userId; + final Value channelCid; + final Value> extraData; + const MessagesCompanion({ + this.id = const Value.absent(), + this.messageText = const Value.absent(), + this.attachments = const Value.absent(), + this.status = const Value.absent(), + this.type = const Value.absent(), + this.mentionedUsers = const Value.absent(), + this.reactionCounts = const Value.absent(), + this.reactionScores = const Value.absent(), + this.parentId = const Value.absent(), + this.quotedMessageId = const Value.absent(), + this.replyCount = const Value.absent(), + this.showInChannel = const Value.absent(), + this.shadowed = const Value.absent(), + this.command = const Value.absent(), + this.createdAt = const Value.absent(), + this.updatedAt = const Value.absent(), + this.deletedAt = const Value.absent(), + this.userId = const Value.absent(), + this.channelCid = const Value.absent(), + this.extraData = const Value.absent(), + }); + MessagesCompanion.insert({ + @required String id, + this.messageText = const Value.absent(), + this.attachments = const Value.absent(), + this.status = const Value.absent(), + this.type = const Value.absent(), + this.mentionedUsers = const Value.absent(), + this.reactionCounts = const Value.absent(), + this.reactionScores = const Value.absent(), + this.parentId = const Value.absent(), + this.quotedMessageId = const Value.absent(), + this.replyCount = const Value.absent(), + this.showInChannel = const Value.absent(), + this.shadowed = const Value.absent(), + this.command = const Value.absent(), + @required DateTime createdAt, + this.updatedAt = const Value.absent(), + this.deletedAt = const Value.absent(), + this.userId = const Value.absent(), + this.channelCid = const Value.absent(), + this.extraData = const Value.absent(), + }) : id = Value(id), + createdAt = Value(createdAt); + static Insertable custom({ + Expression id, + Expression messageText, + Expression attachments, + Expression status, + Expression type, + Expression mentionedUsers, + Expression reactionCounts, + Expression reactionScores, + Expression parentId, + Expression quotedMessageId, + Expression replyCount, + Expression showInChannel, + Expression shadowed, + Expression command, + Expression createdAt, + Expression updatedAt, + Expression deletedAt, + Expression userId, + Expression channelCid, + Expression extraData, + }) { + return RawValuesInsertable({ + if (id != null) 'id': id, + if (messageText != null) 'message_text': messageText, + if (attachments != null) 'attachments': attachments, + if (status != null) 'status': status, + if (type != null) 'type': type, + if (mentionedUsers != null) 'mentioned_users': mentionedUsers, + if (reactionCounts != null) 'reaction_counts': reactionCounts, + if (reactionScores != null) 'reaction_scores': reactionScores, + if (parentId != null) 'parent_id': parentId, + if (quotedMessageId != null) 'quoted_message_id': quotedMessageId, + if (replyCount != null) 'reply_count': replyCount, + if (showInChannel != null) 'show_in_channel': showInChannel, + if (shadowed != null) 'shadowed': shadowed, + if (command != null) 'command': command, + if (createdAt != null) 'created_at': createdAt, + if (updatedAt != null) 'updated_at': updatedAt, + if (deletedAt != null) 'deleted_at': deletedAt, + if (userId != null) 'user_id': userId, + if (channelCid != null) 'channel_cid': channelCid, + if (extraData != null) 'extra_data': extraData, + }); + } + + MessagesCompanion copyWith( + {Value id, + Value messageText, + Value> attachments, + Value status, + Value type, + Value> mentionedUsers, + Value> reactionCounts, + Value> reactionScores, + Value parentId, + Value quotedMessageId, + Value replyCount, + Value showInChannel, + Value shadowed, + Value command, + Value createdAt, + Value updatedAt, + Value deletedAt, + Value userId, + Value channelCid, + Value> extraData}) { + return MessagesCompanion( + id: id ?? this.id, + messageText: messageText ?? this.messageText, + attachments: attachments ?? this.attachments, + status: status ?? this.status, + type: type ?? this.type, + mentionedUsers: mentionedUsers ?? this.mentionedUsers, + reactionCounts: reactionCounts ?? this.reactionCounts, + reactionScores: reactionScores ?? this.reactionScores, + parentId: parentId ?? this.parentId, + quotedMessageId: quotedMessageId ?? this.quotedMessageId, + replyCount: replyCount ?? this.replyCount, + showInChannel: showInChannel ?? this.showInChannel, + shadowed: shadowed ?? this.shadowed, + command: command ?? this.command, + createdAt: createdAt ?? this.createdAt, + updatedAt: updatedAt ?? this.updatedAt, + deletedAt: deletedAt ?? this.deletedAt, + userId: userId ?? this.userId, + channelCid: channelCid ?? this.channelCid, + extraData: extraData ?? this.extraData, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (id.present) { + map['id'] = Variable(id.value); + } + if (messageText.present) { + map['message_text'] = Variable(messageText.value); + } + if (attachments.present) { + final converter = $MessagesTable.$converter0; + map['attachments'] = + Variable(converter.mapToSql(attachments.value)); + } + if (status.present) { + final converter = $MessagesTable.$converter1; + map['status'] = Variable(converter.mapToSql(status.value)); + } + if (type.present) { + map['type'] = Variable(type.value); + } + if (mentionedUsers.present) { + final converter = $MessagesTable.$converter2; + map['mentioned_users'] = + Variable(converter.mapToSql(mentionedUsers.value)); + } + if (reactionCounts.present) { + final converter = $MessagesTable.$converter3; + map['reaction_counts'] = + Variable(converter.mapToSql(reactionCounts.value)); + } + if (reactionScores.present) { + final converter = $MessagesTable.$converter4; + map['reaction_scores'] = + Variable(converter.mapToSql(reactionScores.value)); + } + if (parentId.present) { + map['parent_id'] = Variable(parentId.value); + } + if (quotedMessageId.present) { + map['quoted_message_id'] = Variable(quotedMessageId.value); + } + if (replyCount.present) { + map['reply_count'] = Variable(replyCount.value); + } + if (showInChannel.present) { + map['show_in_channel'] = Variable(showInChannel.value); + } + if (shadowed.present) { + map['shadowed'] = Variable(shadowed.value); + } + if (command.present) { + map['command'] = Variable(command.value); + } + if (createdAt.present) { + map['created_at'] = Variable(createdAt.value); + } + if (updatedAt.present) { + map['updated_at'] = Variable(updatedAt.value); + } + if (deletedAt.present) { + map['deleted_at'] = Variable(deletedAt.value); + } + if (userId.present) { + map['user_id'] = Variable(userId.value); + } + if (channelCid.present) { + map['channel_cid'] = Variable(channelCid.value); + } + if (extraData.present) { + final converter = $MessagesTable.$converter5; + map['extra_data'] = Variable(converter.mapToSql(extraData.value)); + } + return map; + } + + @override + String toString() { + return (StringBuffer('MessagesCompanion(') + ..write('id: $id, ') + ..write('messageText: $messageText, ') + ..write('attachments: $attachments, ') + ..write('status: $status, ') + ..write('type: $type, ') + ..write('mentionedUsers: $mentionedUsers, ') + ..write('reactionCounts: $reactionCounts, ') + ..write('reactionScores: $reactionScores, ') + ..write('parentId: $parentId, ') + ..write('quotedMessageId: $quotedMessageId, ') + ..write('replyCount: $replyCount, ') + ..write('showInChannel: $showInChannel, ') + ..write('shadowed: $shadowed, ') + ..write('command: $command, ') + ..write('createdAt: $createdAt, ') + ..write('updatedAt: $updatedAt, ') + ..write('deletedAt: $deletedAt, ') + ..write('userId: $userId, ') + ..write('channelCid: $channelCid, ') + ..write('extraData: $extraData') + ..write(')')) + .toString(); + } +} + +class $MessagesTable extends Messages + with TableInfo<$MessagesTable, MessageEntity> { + final GeneratedDatabase _db; + final String _alias; + $MessagesTable(this._db, [this._alias]); + final VerificationMeta _idMeta = const VerificationMeta('id'); + GeneratedTextColumn _id; + @override + GeneratedTextColumn get id => _id ??= _constructId(); + GeneratedTextColumn _constructId() { + return GeneratedTextColumn( + 'id', + $tableName, + false, + ); + } + + final VerificationMeta _messageTextMeta = + const VerificationMeta('messageText'); + GeneratedTextColumn _messageText; + @override + GeneratedTextColumn get messageText => + _messageText ??= _constructMessageText(); + GeneratedTextColumn _constructMessageText() { + return GeneratedTextColumn( + 'message_text', + $tableName, + true, + ); + } + + final VerificationMeta _attachmentsMeta = + const VerificationMeta('attachments'); + GeneratedTextColumn _attachments; + @override + GeneratedTextColumn get attachments => + _attachments ??= _constructAttachments(); + GeneratedTextColumn _constructAttachments() { + return GeneratedTextColumn( + 'attachments', + $tableName, + true, + ); + } + + final VerificationMeta _statusMeta = const VerificationMeta('status'); + GeneratedIntColumn _status; + @override + GeneratedIntColumn get status => _status ??= _constructStatus(); + GeneratedIntColumn _constructStatus() { + return GeneratedIntColumn( + 'status', + $tableName, + true, + ); + } + + final VerificationMeta _typeMeta = const VerificationMeta('type'); + GeneratedTextColumn _type; + @override + GeneratedTextColumn get type => _type ??= _constructType(); + GeneratedTextColumn _constructType() { + return GeneratedTextColumn( + 'type', + $tableName, + true, + ); + } + + final VerificationMeta _mentionedUsersMeta = + const VerificationMeta('mentionedUsers'); + GeneratedTextColumn _mentionedUsers; + @override + GeneratedTextColumn get mentionedUsers => + _mentionedUsers ??= _constructMentionedUsers(); + GeneratedTextColumn _constructMentionedUsers() { + return GeneratedTextColumn( + 'mentioned_users', + $tableName, + true, + ); + } + + final VerificationMeta _reactionCountsMeta = + const VerificationMeta('reactionCounts'); + GeneratedTextColumn _reactionCounts; + @override + GeneratedTextColumn get reactionCounts => + _reactionCounts ??= _constructReactionCounts(); + GeneratedTextColumn _constructReactionCounts() { + return GeneratedTextColumn( + 'reaction_counts', + $tableName, + true, + ); + } + + final VerificationMeta _reactionScoresMeta = + const VerificationMeta('reactionScores'); + GeneratedTextColumn _reactionScores; + @override + GeneratedTextColumn get reactionScores => + _reactionScores ??= _constructReactionScores(); + GeneratedTextColumn _constructReactionScores() { + return GeneratedTextColumn( + 'reaction_scores', + $tableName, + true, + ); + } + + final VerificationMeta _parentIdMeta = const VerificationMeta('parentId'); + GeneratedTextColumn _parentId; + @override + GeneratedTextColumn get parentId => _parentId ??= _constructParentId(); + GeneratedTextColumn _constructParentId() { + return GeneratedTextColumn( + 'parent_id', + $tableName, + true, + ); + } + + final VerificationMeta _quotedMessageIdMeta = + const VerificationMeta('quotedMessageId'); + GeneratedTextColumn _quotedMessageId; + @override + GeneratedTextColumn get quotedMessageId => + _quotedMessageId ??= _constructQuotedMessageId(); + GeneratedTextColumn _constructQuotedMessageId() { + return GeneratedTextColumn( + 'quoted_message_id', + $tableName, + true, + ); + } + + final VerificationMeta _replyCountMeta = const VerificationMeta('replyCount'); + GeneratedIntColumn _replyCount; + @override + GeneratedIntColumn get replyCount => _replyCount ??= _constructReplyCount(); + GeneratedIntColumn _constructReplyCount() { + return GeneratedIntColumn( + 'reply_count', + $tableName, + true, + ); + } + + final VerificationMeta _showInChannelMeta = + const VerificationMeta('showInChannel'); + GeneratedBoolColumn _showInChannel; + @override + GeneratedBoolColumn get showInChannel => + _showInChannel ??= _constructShowInChannel(); + GeneratedBoolColumn _constructShowInChannel() { + return GeneratedBoolColumn( + 'show_in_channel', + $tableName, + true, + ); + } + + final VerificationMeta _shadowedMeta = const VerificationMeta('shadowed'); + GeneratedBoolColumn _shadowed; + @override + GeneratedBoolColumn get shadowed => _shadowed ??= _constructShadowed(); + GeneratedBoolColumn _constructShadowed() { + return GeneratedBoolColumn( + 'shadowed', + $tableName, + true, + ); + } + + final VerificationMeta _commandMeta = const VerificationMeta('command'); + GeneratedTextColumn _command; + @override + GeneratedTextColumn get command => _command ??= _constructCommand(); + GeneratedTextColumn _constructCommand() { + return GeneratedTextColumn( + 'command', + $tableName, + true, + ); + } + + final VerificationMeta _createdAtMeta = const VerificationMeta('createdAt'); + GeneratedDateTimeColumn _createdAt; + @override + GeneratedDateTimeColumn get createdAt => _createdAt ??= _constructCreatedAt(); + GeneratedDateTimeColumn _constructCreatedAt() { + return GeneratedDateTimeColumn( + 'created_at', + $tableName, + false, + ); + } + + final VerificationMeta _updatedAtMeta = const VerificationMeta('updatedAt'); + GeneratedDateTimeColumn _updatedAt; + @override + GeneratedDateTimeColumn get updatedAt => _updatedAt ??= _constructUpdatedAt(); + GeneratedDateTimeColumn _constructUpdatedAt() { + return GeneratedDateTimeColumn( + 'updated_at', + $tableName, + true, + ); + } + + final VerificationMeta _deletedAtMeta = const VerificationMeta('deletedAt'); + GeneratedDateTimeColumn _deletedAt; + @override + GeneratedDateTimeColumn get deletedAt => _deletedAt ??= _constructDeletedAt(); + GeneratedDateTimeColumn _constructDeletedAt() { + return GeneratedDateTimeColumn( + 'deleted_at', + $tableName, + true, + ); + } + + final VerificationMeta _userIdMeta = const VerificationMeta('userId'); + GeneratedTextColumn _userId; + @override + GeneratedTextColumn get userId => _userId ??= _constructUserId(); + GeneratedTextColumn _constructUserId() { + return GeneratedTextColumn( + 'user_id', + $tableName, + true, + ); + } + + final VerificationMeta _channelCidMeta = const VerificationMeta('channelCid'); + GeneratedTextColumn _channelCid; + @override + GeneratedTextColumn get channelCid => _channelCid ??= _constructChannelCid(); + GeneratedTextColumn _constructChannelCid() { + return GeneratedTextColumn('channel_cid', $tableName, true, + $customConstraints: + 'NULLABLE REFERENCES channels(cid) ON DELETE CASCADE'); + } + + final VerificationMeta _extraDataMeta = const VerificationMeta('extraData'); + GeneratedTextColumn _extraData; + @override + GeneratedTextColumn get extraData => _extraData ??= _constructExtraData(); + GeneratedTextColumn _constructExtraData() { + return GeneratedTextColumn( + 'extra_data', + $tableName, + true, + ); + } + + @override + List get $columns => [ + id, + messageText, + attachments, + status, + type, + mentionedUsers, + reactionCounts, + reactionScores, + parentId, + quotedMessageId, + replyCount, + showInChannel, + shadowed, + command, + createdAt, + updatedAt, + deletedAt, + userId, + channelCid, + extraData + ]; + @override + $MessagesTable get asDslTable => this; + @override + String get $tableName => _alias ?? 'messages'; + @override + final String actualTableName = 'messages'; + @override + VerificationContext validateIntegrity(Insertable instance, + {bool isInserting = false}) { + final context = VerificationContext(); + final data = instance.toColumns(true); + if (data.containsKey('id')) { + context.handle(_idMeta, id.isAcceptableOrUnknown(data['id'], _idMeta)); + } else if (isInserting) { + context.missing(_idMeta); + } + if (data.containsKey('message_text')) { + context.handle( + _messageTextMeta, + messageText.isAcceptableOrUnknown( + data['message_text'], _messageTextMeta)); + } + context.handle(_attachmentsMeta, const VerificationResult.success()); + context.handle(_statusMeta, const VerificationResult.success()); + if (data.containsKey('type')) { + context.handle( + _typeMeta, type.isAcceptableOrUnknown(data['type'], _typeMeta)); + } + context.handle(_mentionedUsersMeta, const VerificationResult.success()); + context.handle(_reactionCountsMeta, const VerificationResult.success()); + context.handle(_reactionScoresMeta, const VerificationResult.success()); + if (data.containsKey('parent_id')) { + context.handle(_parentIdMeta, + parentId.isAcceptableOrUnknown(data['parent_id'], _parentIdMeta)); + } + if (data.containsKey('quoted_message_id')) { + context.handle( + _quotedMessageIdMeta, + quotedMessageId.isAcceptableOrUnknown( + data['quoted_message_id'], _quotedMessageIdMeta)); + } + if (data.containsKey('reply_count')) { + context.handle( + _replyCountMeta, + replyCount.isAcceptableOrUnknown( + data['reply_count'], _replyCountMeta)); + } + if (data.containsKey('show_in_channel')) { + context.handle( + _showInChannelMeta, + showInChannel.isAcceptableOrUnknown( + data['show_in_channel'], _showInChannelMeta)); + } + if (data.containsKey('shadowed')) { + context.handle(_shadowedMeta, + shadowed.isAcceptableOrUnknown(data['shadowed'], _shadowedMeta)); + } + if (data.containsKey('command')) { + context.handle(_commandMeta, + command.isAcceptableOrUnknown(data['command'], _commandMeta)); + } + if (data.containsKey('created_at')) { + context.handle(_createdAtMeta, + createdAt.isAcceptableOrUnknown(data['created_at'], _createdAtMeta)); + } else if (isInserting) { + context.missing(_createdAtMeta); + } + if (data.containsKey('updated_at')) { + context.handle(_updatedAtMeta, + updatedAt.isAcceptableOrUnknown(data['updated_at'], _updatedAtMeta)); + } + if (data.containsKey('deleted_at')) { + context.handle(_deletedAtMeta, + deletedAt.isAcceptableOrUnknown(data['deleted_at'], _deletedAtMeta)); + } + if (data.containsKey('user_id')) { + context.handle(_userIdMeta, + userId.isAcceptableOrUnknown(data['user_id'], _userIdMeta)); + } + if (data.containsKey('channel_cid')) { + context.handle( + _channelCidMeta, + channelCid.isAcceptableOrUnknown( + data['channel_cid'], _channelCidMeta)); + } + context.handle(_extraDataMeta, const VerificationResult.success()); + return context; + } + + @override + Set get $primaryKey => {id}; + @override + MessageEntity map(Map data, {String tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : null; + return MessageEntity.fromData(data, _db, prefix: effectivePrefix); + } + + @override + $MessagesTable createAlias(String alias) { + return $MessagesTable(_db, alias); + } + + static TypeConverter, String> $converter0 = + ListConverter(); + static TypeConverter $converter1 = + MessageSendingStatusConverter(); + static TypeConverter, String> $converter2 = + ListConverter(); + static TypeConverter, String> $converter3 = + MapConverter(); + static TypeConverter, String> $converter4 = + MapConverter(); + static TypeConverter, String> $converter5 = + MapConverter(); +} + +class ReactionEntity extends DataClass implements Insertable { + final String userId; + final String messageId; + final String type; + final DateTime createdAt; + final int score; + final Map extraData; + ReactionEntity( + {@required this.userId, + @required this.messageId, + @required this.type, + @required this.createdAt, + this.score, + this.extraData}); + factory ReactionEntity.fromData( + Map data, GeneratedDatabase db, + {String prefix}) { + final effectivePrefix = prefix ?? ''; + final stringType = db.typeSystem.forDartType(); + final dateTimeType = db.typeSystem.forDartType(); + final intType = db.typeSystem.forDartType(); + return ReactionEntity( + userId: + stringType.mapFromDatabaseResponse(data['${effectivePrefix}user_id']), + messageId: stringType + .mapFromDatabaseResponse(data['${effectivePrefix}message_id']), + type: stringType.mapFromDatabaseResponse(data['${effectivePrefix}type']), + createdAt: dateTimeType + .mapFromDatabaseResponse(data['${effectivePrefix}created_at']), + score: intType.mapFromDatabaseResponse(data['${effectivePrefix}score']), + extraData: $ReactionsTable.$converter0.mapToDart(stringType + .mapFromDatabaseResponse(data['${effectivePrefix}extra_data'])), + ); + } + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (!nullToAbsent || userId != null) { + map['user_id'] = Variable(userId); + } + if (!nullToAbsent || messageId != null) { + map['message_id'] = Variable(messageId); + } + if (!nullToAbsent || type != null) { + map['type'] = Variable(type); + } + if (!nullToAbsent || createdAt != null) { + map['created_at'] = Variable(createdAt); + } + if (!nullToAbsent || score != null) { + map['score'] = Variable(score); + } + if (!nullToAbsent || extraData != null) { + final converter = $ReactionsTable.$converter0; + map['extra_data'] = Variable(converter.mapToSql(extraData)); + } + return map; + } + + factory ReactionEntity.fromJson(Map json, + {ValueSerializer serializer}) { + serializer ??= moorRuntimeOptions.defaultSerializer; + return ReactionEntity( + userId: serializer.fromJson(json['userId']), + messageId: serializer.fromJson(json['messageId']), + type: serializer.fromJson(json['type']), + createdAt: serializer.fromJson(json['createdAt']), + score: serializer.fromJson(json['score']), + extraData: serializer.fromJson>(json['extraData']), + ); + } + @override + Map toJson({ValueSerializer serializer}) { + serializer ??= moorRuntimeOptions.defaultSerializer; + return { + 'userId': serializer.toJson(userId), + 'messageId': serializer.toJson(messageId), + 'type': serializer.toJson(type), + 'createdAt': serializer.toJson(createdAt), + 'score': serializer.toJson(score), + 'extraData': serializer.toJson>(extraData), + }; + } + + ReactionEntity copyWith( + {String userId, + String messageId, + String type, + DateTime createdAt, + Value score = const Value.absent(), + Value> extraData = const Value.absent()}) => + ReactionEntity( + userId: userId ?? this.userId, + messageId: messageId ?? this.messageId, + type: type ?? this.type, + createdAt: createdAt ?? this.createdAt, + score: score.present ? score.value : this.score, + extraData: extraData.present ? extraData.value : this.extraData, + ); + @override + String toString() { + return (StringBuffer('ReactionEntity(') + ..write('userId: $userId, ') + ..write('messageId: $messageId, ') + ..write('type: $type, ') + ..write('createdAt: $createdAt, ') + ..write('score: $score, ') + ..write('extraData: $extraData') + ..write(')')) + .toString(); + } + + @override + int get hashCode => $mrjf($mrjc( + userId.hashCode, + $mrjc( + messageId.hashCode, + $mrjc( + type.hashCode, + $mrjc(createdAt.hashCode, + $mrjc(score.hashCode, extraData.hashCode)))))); + @override + bool operator ==(dynamic other) => + identical(this, other) || + (other is ReactionEntity && + other.userId == this.userId && + other.messageId == this.messageId && + other.type == this.type && + other.createdAt == this.createdAt && + other.score == this.score && + other.extraData == this.extraData); +} + +class ReactionsCompanion extends UpdateCompanion { + final Value userId; + final Value messageId; + final Value type; + final Value createdAt; + final Value score; + final Value> extraData; + const ReactionsCompanion({ + this.userId = const Value.absent(), + this.messageId = const Value.absent(), + this.type = const Value.absent(), + this.createdAt = const Value.absent(), + this.score = const Value.absent(), + this.extraData = const Value.absent(), + }); + ReactionsCompanion.insert({ + @required String userId, + @required String messageId, + @required String type, + @required DateTime createdAt, + this.score = const Value.absent(), + this.extraData = const Value.absent(), + }) : userId = Value(userId), + messageId = Value(messageId), + type = Value(type), + createdAt = Value(createdAt); + static Insertable custom({ + Expression userId, + Expression messageId, + Expression type, + Expression createdAt, + Expression score, + Expression extraData, + }) { + return RawValuesInsertable({ + if (userId != null) 'user_id': userId, + if (messageId != null) 'message_id': messageId, + if (type != null) 'type': type, + if (createdAt != null) 'created_at': createdAt, + if (score != null) 'score': score, + if (extraData != null) 'extra_data': extraData, + }); + } + + ReactionsCompanion copyWith( + {Value userId, + Value messageId, + Value type, + Value createdAt, + Value score, + Value> extraData}) { + return ReactionsCompanion( + userId: userId ?? this.userId, + messageId: messageId ?? this.messageId, + type: type ?? this.type, + createdAt: createdAt ?? this.createdAt, + score: score ?? this.score, + extraData: extraData ?? this.extraData, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (userId.present) { + map['user_id'] = Variable(userId.value); + } + if (messageId.present) { + map['message_id'] = Variable(messageId.value); + } + if (type.present) { + map['type'] = Variable(type.value); + } + if (createdAt.present) { + map['created_at'] = Variable(createdAt.value); + } + if (score.present) { + map['score'] = Variable(score.value); + } + if (extraData.present) { + final converter = $ReactionsTable.$converter0; + map['extra_data'] = Variable(converter.mapToSql(extraData.value)); + } + return map; + } + + @override + String toString() { + return (StringBuffer('ReactionsCompanion(') + ..write('userId: $userId, ') + ..write('messageId: $messageId, ') + ..write('type: $type, ') + ..write('createdAt: $createdAt, ') + ..write('score: $score, ') + ..write('extraData: $extraData') + ..write(')')) + .toString(); + } +} + +class $ReactionsTable extends Reactions + with TableInfo<$ReactionsTable, ReactionEntity> { + final GeneratedDatabase _db; + final String _alias; + $ReactionsTable(this._db, [this._alias]); + final VerificationMeta _userIdMeta = const VerificationMeta('userId'); + GeneratedTextColumn _userId; + @override + GeneratedTextColumn get userId => _userId ??= _constructUserId(); + GeneratedTextColumn _constructUserId() { + return GeneratedTextColumn( + 'user_id', + $tableName, + false, + ); + } + + final VerificationMeta _messageIdMeta = const VerificationMeta('messageId'); + GeneratedTextColumn _messageId; + @override + GeneratedTextColumn get messageId => _messageId ??= _constructMessageId(); + GeneratedTextColumn _constructMessageId() { + return GeneratedTextColumn('message_id', $tableName, false, + $customConstraints: 'REFERENCES messages(id) ON DELETE CASCADE'); + } + + final VerificationMeta _typeMeta = const VerificationMeta('type'); + GeneratedTextColumn _type; + @override + GeneratedTextColumn get type => _type ??= _constructType(); + GeneratedTextColumn _constructType() { + return GeneratedTextColumn( + 'type', + $tableName, + false, + ); + } + + final VerificationMeta _createdAtMeta = const VerificationMeta('createdAt'); + GeneratedDateTimeColumn _createdAt; + @override + GeneratedDateTimeColumn get createdAt => _createdAt ??= _constructCreatedAt(); + GeneratedDateTimeColumn _constructCreatedAt() { + return GeneratedDateTimeColumn( + 'created_at', + $tableName, + false, + ); + } + + final VerificationMeta _scoreMeta = const VerificationMeta('score'); + GeneratedIntColumn _score; + @override + GeneratedIntColumn get score => _score ??= _constructScore(); + GeneratedIntColumn _constructScore() { + return GeneratedIntColumn( + 'score', + $tableName, + true, + ); + } + + final VerificationMeta _extraDataMeta = const VerificationMeta('extraData'); + GeneratedTextColumn _extraData; + @override + GeneratedTextColumn get extraData => _extraData ??= _constructExtraData(); + GeneratedTextColumn _constructExtraData() { + return GeneratedTextColumn( + 'extra_data', + $tableName, + true, + ); + } + + @override + List get $columns => + [userId, messageId, type, createdAt, score, extraData]; + @override + $ReactionsTable get asDslTable => this; + @override + String get $tableName => _alias ?? 'reactions'; + @override + final String actualTableName = 'reactions'; + @override + VerificationContext validateIntegrity(Insertable instance, + {bool isInserting = false}) { + final context = VerificationContext(); + final data = instance.toColumns(true); + if (data.containsKey('user_id')) { + context.handle(_userIdMeta, + userId.isAcceptableOrUnknown(data['user_id'], _userIdMeta)); + } else if (isInserting) { + context.missing(_userIdMeta); + } + if (data.containsKey('message_id')) { + context.handle(_messageIdMeta, + messageId.isAcceptableOrUnknown(data['message_id'], _messageIdMeta)); + } else if (isInserting) { + context.missing(_messageIdMeta); + } + if (data.containsKey('type')) { + context.handle( + _typeMeta, type.isAcceptableOrUnknown(data['type'], _typeMeta)); + } else if (isInserting) { + context.missing(_typeMeta); + } + if (data.containsKey('created_at')) { + context.handle(_createdAtMeta, + createdAt.isAcceptableOrUnknown(data['created_at'], _createdAtMeta)); + } else if (isInserting) { + context.missing(_createdAtMeta); + } + if (data.containsKey('score')) { + context.handle( + _scoreMeta, score.isAcceptableOrUnknown(data['score'], _scoreMeta)); + } + context.handle(_extraDataMeta, const VerificationResult.success()); + return context; + } + + @override + Set get $primaryKey => {messageId, type, userId}; + @override + ReactionEntity map(Map data, {String tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : null; + return ReactionEntity.fromData(data, _db, prefix: effectivePrefix); + } + + @override + $ReactionsTable createAlias(String alias) { + return $ReactionsTable(_db, alias); + } + + static TypeConverter, String> $converter0 = + MapConverter(); +} + +class UserEntity extends DataClass implements Insertable { + final String id; + final String role; + final DateTime createdAt; + final DateTime updatedAt; + final DateTime lastActive; + final bool online; + final bool banned; + final Map extraData; + UserEntity( + {@required this.id, + this.role, + this.createdAt, + this.updatedAt, + this.lastActive, + this.online, + this.banned, + this.extraData}); + factory UserEntity.fromData(Map data, GeneratedDatabase db, + {String prefix}) { + final effectivePrefix = prefix ?? ''; + final stringType = db.typeSystem.forDartType(); + final dateTimeType = db.typeSystem.forDartType(); + final boolType = db.typeSystem.forDartType(); + return UserEntity( + id: stringType.mapFromDatabaseResponse(data['${effectivePrefix}id']), + role: stringType.mapFromDatabaseResponse(data['${effectivePrefix}role']), + createdAt: dateTimeType + .mapFromDatabaseResponse(data['${effectivePrefix}created_at']), + updatedAt: dateTimeType + .mapFromDatabaseResponse(data['${effectivePrefix}updated_at']), + lastActive: dateTimeType + .mapFromDatabaseResponse(data['${effectivePrefix}last_active']), + online: + boolType.mapFromDatabaseResponse(data['${effectivePrefix}online']), + banned: + boolType.mapFromDatabaseResponse(data['${effectivePrefix}banned']), + extraData: $UsersTable.$converter0.mapToDart(stringType + .mapFromDatabaseResponse(data['${effectivePrefix}extra_data'])), + ); + } + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (!nullToAbsent || id != null) { + map['id'] = Variable(id); + } + if (!nullToAbsent || role != null) { + map['role'] = Variable(role); + } + if (!nullToAbsent || createdAt != null) { + map['created_at'] = Variable(createdAt); + } + if (!nullToAbsent || updatedAt != null) { + map['updated_at'] = Variable(updatedAt); + } + if (!nullToAbsent || lastActive != null) { + map['last_active'] = Variable(lastActive); + } + if (!nullToAbsent || online != null) { + map['online'] = Variable(online); + } + if (!nullToAbsent || banned != null) { + map['banned'] = Variable(banned); + } + if (!nullToAbsent || extraData != null) { + final converter = $UsersTable.$converter0; + map['extra_data'] = Variable(converter.mapToSql(extraData)); + } + return map; + } + + factory UserEntity.fromJson(Map json, + {ValueSerializer serializer}) { + serializer ??= moorRuntimeOptions.defaultSerializer; + return UserEntity( + id: serializer.fromJson(json['id']), + role: serializer.fromJson(json['role']), + createdAt: serializer.fromJson(json['createdAt']), + updatedAt: serializer.fromJson(json['updatedAt']), + lastActive: serializer.fromJson(json['lastActive']), + online: serializer.fromJson(json['online']), + banned: serializer.fromJson(json['banned']), + extraData: serializer.fromJson>(json['extraData']), + ); + } + @override + Map toJson({ValueSerializer serializer}) { + serializer ??= moorRuntimeOptions.defaultSerializer; + return { + 'id': serializer.toJson(id), + 'role': serializer.toJson(role), + 'createdAt': serializer.toJson(createdAt), + 'updatedAt': serializer.toJson(updatedAt), + 'lastActive': serializer.toJson(lastActive), + 'online': serializer.toJson(online), + 'banned': serializer.toJson(banned), + 'extraData': serializer.toJson>(extraData), + }; + } + + UserEntity copyWith( + {String id, + Value role = const Value.absent(), + Value createdAt = const Value.absent(), + Value updatedAt = const Value.absent(), + Value lastActive = const Value.absent(), + Value online = const Value.absent(), + Value banned = const Value.absent(), + Value> extraData = const Value.absent()}) => + UserEntity( + id: id ?? this.id, + role: role.present ? role.value : this.role, + createdAt: createdAt.present ? createdAt.value : this.createdAt, + updatedAt: updatedAt.present ? updatedAt.value : this.updatedAt, + lastActive: lastActive.present ? lastActive.value : this.lastActive, + online: online.present ? online.value : this.online, + banned: banned.present ? banned.value : this.banned, + extraData: extraData.present ? extraData.value : this.extraData, + ); + @override + String toString() { + return (StringBuffer('UserEntity(') + ..write('id: $id, ') + ..write('role: $role, ') + ..write('createdAt: $createdAt, ') + ..write('updatedAt: $updatedAt, ') + ..write('lastActive: $lastActive, ') + ..write('online: $online, ') + ..write('banned: $banned, ') + ..write('extraData: $extraData') + ..write(')')) + .toString(); + } + + @override + int get hashCode => $mrjf($mrjc( + id.hashCode, + $mrjc( + role.hashCode, + $mrjc( + createdAt.hashCode, + $mrjc( + updatedAt.hashCode, + $mrjc( + lastActive.hashCode, + $mrjc(online.hashCode, + $mrjc(banned.hashCode, extraData.hashCode)))))))); + @override + bool operator ==(dynamic other) => + identical(this, other) || + (other is UserEntity && + other.id == this.id && + other.role == this.role && + other.createdAt == this.createdAt && + other.updatedAt == this.updatedAt && + other.lastActive == this.lastActive && + other.online == this.online && + other.banned == this.banned && + other.extraData == this.extraData); +} + +class UsersCompanion extends UpdateCompanion { + final Value id; + final Value role; + final Value createdAt; + final Value updatedAt; + final Value lastActive; + final Value online; + final Value banned; + final Value> extraData; + const UsersCompanion({ + this.id = const Value.absent(), + this.role = const Value.absent(), + this.createdAt = const Value.absent(), + this.updatedAt = const Value.absent(), + this.lastActive = const Value.absent(), + this.online = const Value.absent(), + this.banned = const Value.absent(), + this.extraData = const Value.absent(), + }); + UsersCompanion.insert({ + @required String id, + this.role = const Value.absent(), + this.createdAt = const Value.absent(), + this.updatedAt = const Value.absent(), + this.lastActive = const Value.absent(), + this.online = const Value.absent(), + this.banned = const Value.absent(), + this.extraData = const Value.absent(), + }) : id = Value(id); + static Insertable custom({ + Expression id, + Expression role, + Expression createdAt, + Expression updatedAt, + Expression lastActive, + Expression online, + Expression banned, + Expression extraData, + }) { + return RawValuesInsertable({ + if (id != null) 'id': id, + if (role != null) 'role': role, + if (createdAt != null) 'created_at': createdAt, + if (updatedAt != null) 'updated_at': updatedAt, + if (lastActive != null) 'last_active': lastActive, + if (online != null) 'online': online, + if (banned != null) 'banned': banned, + if (extraData != null) 'extra_data': extraData, + }); + } + + UsersCompanion copyWith( + {Value id, + Value role, + Value createdAt, + Value updatedAt, + Value lastActive, + Value online, + Value banned, + Value> extraData}) { + return UsersCompanion( + id: id ?? this.id, + role: role ?? this.role, + createdAt: createdAt ?? this.createdAt, + updatedAt: updatedAt ?? this.updatedAt, + lastActive: lastActive ?? this.lastActive, + online: online ?? this.online, + banned: banned ?? this.banned, + extraData: extraData ?? this.extraData, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (id.present) { + map['id'] = Variable(id.value); + } + if (role.present) { + map['role'] = Variable(role.value); + } + if (createdAt.present) { + map['created_at'] = Variable(createdAt.value); + } + if (updatedAt.present) { + map['updated_at'] = Variable(updatedAt.value); + } + if (lastActive.present) { + map['last_active'] = Variable(lastActive.value); + } + if (online.present) { + map['online'] = Variable(online.value); + } + if (banned.present) { + map['banned'] = Variable(banned.value); + } + if (extraData.present) { + final converter = $UsersTable.$converter0; + map['extra_data'] = Variable(converter.mapToSql(extraData.value)); + } + return map; + } + + @override + String toString() { + return (StringBuffer('UsersCompanion(') + ..write('id: $id, ') + ..write('role: $role, ') + ..write('createdAt: $createdAt, ') + ..write('updatedAt: $updatedAt, ') + ..write('lastActive: $lastActive, ') + ..write('online: $online, ') + ..write('banned: $banned, ') + ..write('extraData: $extraData') + ..write(')')) + .toString(); + } +} + +class $UsersTable extends Users with TableInfo<$UsersTable, UserEntity> { + final GeneratedDatabase _db; + final String _alias; + $UsersTable(this._db, [this._alias]); + final VerificationMeta _idMeta = const VerificationMeta('id'); + GeneratedTextColumn _id; + @override + GeneratedTextColumn get id => _id ??= _constructId(); + GeneratedTextColumn _constructId() { + return GeneratedTextColumn( + 'id', + $tableName, + false, + ); + } + + final VerificationMeta _roleMeta = const VerificationMeta('role'); + GeneratedTextColumn _role; + @override + GeneratedTextColumn get role => _role ??= _constructRole(); + GeneratedTextColumn _constructRole() { + return GeneratedTextColumn( + 'role', + $tableName, + true, + ); + } + + final VerificationMeta _createdAtMeta = const VerificationMeta('createdAt'); + GeneratedDateTimeColumn _createdAt; + @override + GeneratedDateTimeColumn get createdAt => _createdAt ??= _constructCreatedAt(); + GeneratedDateTimeColumn _constructCreatedAt() { + return GeneratedDateTimeColumn( + 'created_at', + $tableName, + true, + ); + } + + final VerificationMeta _updatedAtMeta = const VerificationMeta('updatedAt'); + GeneratedDateTimeColumn _updatedAt; + @override + GeneratedDateTimeColumn get updatedAt => _updatedAt ??= _constructUpdatedAt(); + GeneratedDateTimeColumn _constructUpdatedAt() { + return GeneratedDateTimeColumn( + 'updated_at', + $tableName, + true, + ); + } + + final VerificationMeta _lastActiveMeta = const VerificationMeta('lastActive'); + GeneratedDateTimeColumn _lastActive; + @override + GeneratedDateTimeColumn get lastActive => + _lastActive ??= _constructLastActive(); + GeneratedDateTimeColumn _constructLastActive() { + return GeneratedDateTimeColumn( + 'last_active', + $tableName, + true, + ); + } + + final VerificationMeta _onlineMeta = const VerificationMeta('online'); + GeneratedBoolColumn _online; + @override + GeneratedBoolColumn get online => _online ??= _constructOnline(); + GeneratedBoolColumn _constructOnline() { + return GeneratedBoolColumn( + 'online', + $tableName, + true, + ); + } + + final VerificationMeta _bannedMeta = const VerificationMeta('banned'); + GeneratedBoolColumn _banned; + @override + GeneratedBoolColumn get banned => _banned ??= _constructBanned(); + GeneratedBoolColumn _constructBanned() { + return GeneratedBoolColumn( + 'banned', + $tableName, + true, + ); + } + + final VerificationMeta _extraDataMeta = const VerificationMeta('extraData'); + GeneratedTextColumn _extraData; + @override + GeneratedTextColumn get extraData => _extraData ??= _constructExtraData(); + GeneratedTextColumn _constructExtraData() { + return GeneratedTextColumn( + 'extra_data', + $tableName, + true, + ); + } + + @override + List get $columns => + [id, role, createdAt, updatedAt, lastActive, online, banned, extraData]; + @override + $UsersTable get asDslTable => this; + @override + String get $tableName => _alias ?? 'users'; + @override + final String actualTableName = 'users'; + @override + VerificationContext validateIntegrity(Insertable instance, + {bool isInserting = false}) { + final context = VerificationContext(); + final data = instance.toColumns(true); + if (data.containsKey('id')) { + context.handle(_idMeta, id.isAcceptableOrUnknown(data['id'], _idMeta)); + } else if (isInserting) { + context.missing(_idMeta); + } + if (data.containsKey('role')) { + context.handle( + _roleMeta, role.isAcceptableOrUnknown(data['role'], _roleMeta)); + } + if (data.containsKey('created_at')) { + context.handle(_createdAtMeta, + createdAt.isAcceptableOrUnknown(data['created_at'], _createdAtMeta)); + } + if (data.containsKey('updated_at')) { + context.handle(_updatedAtMeta, + updatedAt.isAcceptableOrUnknown(data['updated_at'], _updatedAtMeta)); + } + if (data.containsKey('last_active')) { + context.handle( + _lastActiveMeta, + lastActive.isAcceptableOrUnknown( + data['last_active'], _lastActiveMeta)); + } + if (data.containsKey('online')) { + context.handle(_onlineMeta, + online.isAcceptableOrUnknown(data['online'], _onlineMeta)); + } + if (data.containsKey('banned')) { + context.handle(_bannedMeta, + banned.isAcceptableOrUnknown(data['banned'], _bannedMeta)); + } + context.handle(_extraDataMeta, const VerificationResult.success()); + return context; + } + + @override + Set get $primaryKey => {id}; + @override + UserEntity map(Map data, {String tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : null; + return UserEntity.fromData(data, _db, prefix: effectivePrefix); + } + + @override + $UsersTable createAlias(String alias) { + return $UsersTable(_db, alias); + } + + static TypeConverter, String> $converter0 = + MapConverter(); +} + +class MemberEntity extends DataClass implements Insertable { + final String userId; + final String channelCid; + final String role; + final DateTime inviteAcceptedAt; + final DateTime inviteRejectedAt; + final bool invited; + final bool banned; + final bool shadowBanned; + final bool isModerator; + final DateTime createdAt; + final DateTime updatedAt; + MemberEntity( + {@required this.userId, + @required this.channelCid, + this.role, + this.inviteAcceptedAt, + this.inviteRejectedAt, + this.invited, + this.banned, + this.shadowBanned, + this.isModerator, + @required this.createdAt, + this.updatedAt}); + factory MemberEntity.fromData(Map data, GeneratedDatabase db, + {String prefix}) { + final effectivePrefix = prefix ?? ''; + final stringType = db.typeSystem.forDartType(); + final dateTimeType = db.typeSystem.forDartType(); + final boolType = db.typeSystem.forDartType(); + return MemberEntity( + userId: + stringType.mapFromDatabaseResponse(data['${effectivePrefix}user_id']), + channelCid: stringType + .mapFromDatabaseResponse(data['${effectivePrefix}channel_cid']), + role: stringType.mapFromDatabaseResponse(data['${effectivePrefix}role']), + inviteAcceptedAt: dateTimeType.mapFromDatabaseResponse( + data['${effectivePrefix}invite_accepted_at']), + inviteRejectedAt: dateTimeType.mapFromDatabaseResponse( + data['${effectivePrefix}invite_rejected_at']), + invited: + boolType.mapFromDatabaseResponse(data['${effectivePrefix}invited']), + banned: + boolType.mapFromDatabaseResponse(data['${effectivePrefix}banned']), + shadowBanned: boolType + .mapFromDatabaseResponse(data['${effectivePrefix}shadow_banned']), + isModerator: boolType + .mapFromDatabaseResponse(data['${effectivePrefix}is_moderator']), + createdAt: dateTimeType + .mapFromDatabaseResponse(data['${effectivePrefix}created_at']), + updatedAt: dateTimeType + .mapFromDatabaseResponse(data['${effectivePrefix}updated_at']), + ); + } + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (!nullToAbsent || userId != null) { + map['user_id'] = Variable(userId); + } + if (!nullToAbsent || channelCid != null) { + map['channel_cid'] = Variable(channelCid); + } + if (!nullToAbsent || role != null) { + map['role'] = Variable(role); + } + if (!nullToAbsent || inviteAcceptedAt != null) { + map['invite_accepted_at'] = Variable(inviteAcceptedAt); + } + if (!nullToAbsent || inviteRejectedAt != null) { + map['invite_rejected_at'] = Variable(inviteRejectedAt); + } + if (!nullToAbsent || invited != null) { + map['invited'] = Variable(invited); + } + if (!nullToAbsent || banned != null) { + map['banned'] = Variable(banned); + } + if (!nullToAbsent || shadowBanned != null) { + map['shadow_banned'] = Variable(shadowBanned); + } + if (!nullToAbsent || isModerator != null) { + map['is_moderator'] = Variable(isModerator); + } + if (!nullToAbsent || createdAt != null) { + map['created_at'] = Variable(createdAt); + } + if (!nullToAbsent || updatedAt != null) { + map['updated_at'] = Variable(updatedAt); + } + return map; + } + + factory MemberEntity.fromJson(Map json, + {ValueSerializer serializer}) { + serializer ??= moorRuntimeOptions.defaultSerializer; + return MemberEntity( + userId: serializer.fromJson(json['userId']), + channelCid: serializer.fromJson(json['channelCid']), + role: serializer.fromJson(json['role']), + inviteAcceptedAt: serializer.fromJson(json['inviteAcceptedAt']), + inviteRejectedAt: serializer.fromJson(json['inviteRejectedAt']), + invited: serializer.fromJson(json['invited']), + banned: serializer.fromJson(json['banned']), + shadowBanned: serializer.fromJson(json['shadowBanned']), + isModerator: serializer.fromJson(json['isModerator']), + createdAt: serializer.fromJson(json['createdAt']), + updatedAt: serializer.fromJson(json['updatedAt']), + ); + } + @override + Map toJson({ValueSerializer serializer}) { + serializer ??= moorRuntimeOptions.defaultSerializer; + return { + 'userId': serializer.toJson(userId), + 'channelCid': serializer.toJson(channelCid), + 'role': serializer.toJson(role), + 'inviteAcceptedAt': serializer.toJson(inviteAcceptedAt), + 'inviteRejectedAt': serializer.toJson(inviteRejectedAt), + 'invited': serializer.toJson(invited), + 'banned': serializer.toJson(banned), + 'shadowBanned': serializer.toJson(shadowBanned), + 'isModerator': serializer.toJson(isModerator), + 'createdAt': serializer.toJson(createdAt), + 'updatedAt': serializer.toJson(updatedAt), + }; + } + + MemberEntity copyWith( + {String userId, + String channelCid, + Value role = const Value.absent(), + Value inviteAcceptedAt = const Value.absent(), + Value inviteRejectedAt = const Value.absent(), + Value invited = const Value.absent(), + Value banned = const Value.absent(), + Value shadowBanned = const Value.absent(), + Value isModerator = const Value.absent(), + DateTime createdAt, + Value updatedAt = const Value.absent()}) => + MemberEntity( + userId: userId ?? this.userId, + channelCid: channelCid ?? this.channelCid, + role: role.present ? role.value : this.role, + inviteAcceptedAt: inviteAcceptedAt.present + ? inviteAcceptedAt.value + : this.inviteAcceptedAt, + inviteRejectedAt: inviteRejectedAt.present + ? inviteRejectedAt.value + : this.inviteRejectedAt, + invited: invited.present ? invited.value : this.invited, + banned: banned.present ? banned.value : this.banned, + shadowBanned: + shadowBanned.present ? shadowBanned.value : this.shadowBanned, + isModerator: isModerator.present ? isModerator.value : this.isModerator, + createdAt: createdAt ?? this.createdAt, + updatedAt: updatedAt.present ? updatedAt.value : this.updatedAt, + ); + @override + String toString() { + return (StringBuffer('MemberEntity(') + ..write('userId: $userId, ') + ..write('channelCid: $channelCid, ') + ..write('role: $role, ') + ..write('inviteAcceptedAt: $inviteAcceptedAt, ') + ..write('inviteRejectedAt: $inviteRejectedAt, ') + ..write('invited: $invited, ') + ..write('banned: $banned, ') + ..write('shadowBanned: $shadowBanned, ') + ..write('isModerator: $isModerator, ') + ..write('createdAt: $createdAt, ') + ..write('updatedAt: $updatedAt') + ..write(')')) + .toString(); + } + + @override + int get hashCode => $mrjf($mrjc( + userId.hashCode, + $mrjc( + channelCid.hashCode, + $mrjc( + role.hashCode, + $mrjc( + inviteAcceptedAt.hashCode, + $mrjc( + inviteRejectedAt.hashCode, + $mrjc( + invited.hashCode, + $mrjc( + banned.hashCode, + $mrjc( + shadowBanned.hashCode, + $mrjc( + isModerator.hashCode, + $mrjc(createdAt.hashCode, + updatedAt.hashCode))))))))))); + @override + bool operator ==(dynamic other) => + identical(this, other) || + (other is MemberEntity && + other.userId == this.userId && + other.channelCid == this.channelCid && + other.role == this.role && + other.inviteAcceptedAt == this.inviteAcceptedAt && + other.inviteRejectedAt == this.inviteRejectedAt && + other.invited == this.invited && + other.banned == this.banned && + other.shadowBanned == this.shadowBanned && + other.isModerator == this.isModerator && + other.createdAt == this.createdAt && + other.updatedAt == this.updatedAt); +} + +class MembersCompanion extends UpdateCompanion { + final Value userId; + final Value channelCid; + final Value role; + final Value inviteAcceptedAt; + final Value inviteRejectedAt; + final Value invited; + final Value banned; + final Value shadowBanned; + final Value isModerator; + final Value createdAt; + final Value updatedAt; + const MembersCompanion({ + this.userId = const Value.absent(), + this.channelCid = const Value.absent(), + this.role = const Value.absent(), + this.inviteAcceptedAt = const Value.absent(), + this.inviteRejectedAt = const Value.absent(), + this.invited = const Value.absent(), + this.banned = const Value.absent(), + this.shadowBanned = const Value.absent(), + this.isModerator = const Value.absent(), + this.createdAt = const Value.absent(), + this.updatedAt = const Value.absent(), + }); + MembersCompanion.insert({ + @required String userId, + @required String channelCid, + this.role = const Value.absent(), + this.inviteAcceptedAt = const Value.absent(), + this.inviteRejectedAt = const Value.absent(), + this.invited = const Value.absent(), + this.banned = const Value.absent(), + this.shadowBanned = const Value.absent(), + this.isModerator = const Value.absent(), + @required DateTime createdAt, + this.updatedAt = const Value.absent(), + }) : userId = Value(userId), + channelCid = Value(channelCid), + createdAt = Value(createdAt); + static Insertable custom({ + Expression userId, + Expression channelCid, + Expression role, + Expression inviteAcceptedAt, + Expression inviteRejectedAt, + Expression invited, + Expression banned, + Expression shadowBanned, + Expression isModerator, + Expression createdAt, + Expression updatedAt, + }) { + return RawValuesInsertable({ + if (userId != null) 'user_id': userId, + if (channelCid != null) 'channel_cid': channelCid, + if (role != null) 'role': role, + if (inviteAcceptedAt != null) 'invite_accepted_at': inviteAcceptedAt, + if (inviteRejectedAt != null) 'invite_rejected_at': inviteRejectedAt, + if (invited != null) 'invited': invited, + if (banned != null) 'banned': banned, + if (shadowBanned != null) 'shadow_banned': shadowBanned, + if (isModerator != null) 'is_moderator': isModerator, + if (createdAt != null) 'created_at': createdAt, + if (updatedAt != null) 'updated_at': updatedAt, + }); + } + + MembersCompanion copyWith( + {Value userId, + Value channelCid, + Value role, + Value inviteAcceptedAt, + Value inviteRejectedAt, + Value invited, + Value banned, + Value shadowBanned, + Value isModerator, + Value createdAt, + Value updatedAt}) { + return MembersCompanion( + userId: userId ?? this.userId, + channelCid: channelCid ?? this.channelCid, + role: role ?? this.role, + inviteAcceptedAt: inviteAcceptedAt ?? this.inviteAcceptedAt, + inviteRejectedAt: inviteRejectedAt ?? this.inviteRejectedAt, + invited: invited ?? this.invited, + banned: banned ?? this.banned, + shadowBanned: shadowBanned ?? this.shadowBanned, + isModerator: isModerator ?? this.isModerator, + createdAt: createdAt ?? this.createdAt, + updatedAt: updatedAt ?? this.updatedAt, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (userId.present) { + map['user_id'] = Variable(userId.value); + } + if (channelCid.present) { + map['channel_cid'] = Variable(channelCid.value); + } + if (role.present) { + map['role'] = Variable(role.value); + } + if (inviteAcceptedAt.present) { + map['invite_accepted_at'] = Variable(inviteAcceptedAt.value); + } + if (inviteRejectedAt.present) { + map['invite_rejected_at'] = Variable(inviteRejectedAt.value); + } + if (invited.present) { + map['invited'] = Variable(invited.value); + } + if (banned.present) { + map['banned'] = Variable(banned.value); + } + if (shadowBanned.present) { + map['shadow_banned'] = Variable(shadowBanned.value); + } + if (isModerator.present) { + map['is_moderator'] = Variable(isModerator.value); + } + if (createdAt.present) { + map['created_at'] = Variable(createdAt.value); + } + if (updatedAt.present) { + map['updated_at'] = Variable(updatedAt.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('MembersCompanion(') + ..write('userId: $userId, ') + ..write('channelCid: $channelCid, ') + ..write('role: $role, ') + ..write('inviteAcceptedAt: $inviteAcceptedAt, ') + ..write('inviteRejectedAt: $inviteRejectedAt, ') + ..write('invited: $invited, ') + ..write('banned: $banned, ') + ..write('shadowBanned: $shadowBanned, ') + ..write('isModerator: $isModerator, ') + ..write('createdAt: $createdAt, ') + ..write('updatedAt: $updatedAt') + ..write(')')) + .toString(); + } +} + +class $MembersTable extends Members + with TableInfo<$MembersTable, MemberEntity> { + final GeneratedDatabase _db; + final String _alias; + $MembersTable(this._db, [this._alias]); + final VerificationMeta _userIdMeta = const VerificationMeta('userId'); + GeneratedTextColumn _userId; + @override + GeneratedTextColumn get userId => _userId ??= _constructUserId(); + GeneratedTextColumn _constructUserId() { + return GeneratedTextColumn( + 'user_id', + $tableName, + false, + ); + } + + final VerificationMeta _channelCidMeta = const VerificationMeta('channelCid'); + GeneratedTextColumn _channelCid; + @override + GeneratedTextColumn get channelCid => _channelCid ??= _constructChannelCid(); + GeneratedTextColumn _constructChannelCid() { + return GeneratedTextColumn('channel_cid', $tableName, false, + $customConstraints: 'REFERENCES channels(cid) ON DELETE CASCADE'); + } + + final VerificationMeta _roleMeta = const VerificationMeta('role'); + GeneratedTextColumn _role; + @override + GeneratedTextColumn get role => _role ??= _constructRole(); + GeneratedTextColumn _constructRole() { + return GeneratedTextColumn( + 'role', + $tableName, + true, + ); + } + + final VerificationMeta _inviteAcceptedAtMeta = + const VerificationMeta('inviteAcceptedAt'); + GeneratedDateTimeColumn _inviteAcceptedAt; + @override + GeneratedDateTimeColumn get inviteAcceptedAt => + _inviteAcceptedAt ??= _constructInviteAcceptedAt(); + GeneratedDateTimeColumn _constructInviteAcceptedAt() { + return GeneratedDateTimeColumn( + 'invite_accepted_at', + $tableName, + true, + ); + } + + final VerificationMeta _inviteRejectedAtMeta = + const VerificationMeta('inviteRejectedAt'); + GeneratedDateTimeColumn _inviteRejectedAt; + @override + GeneratedDateTimeColumn get inviteRejectedAt => + _inviteRejectedAt ??= _constructInviteRejectedAt(); + GeneratedDateTimeColumn _constructInviteRejectedAt() { + return GeneratedDateTimeColumn( + 'invite_rejected_at', + $tableName, + true, + ); + } + + final VerificationMeta _invitedMeta = const VerificationMeta('invited'); + GeneratedBoolColumn _invited; + @override + GeneratedBoolColumn get invited => _invited ??= _constructInvited(); + GeneratedBoolColumn _constructInvited() { + return GeneratedBoolColumn( + 'invited', + $tableName, + true, + ); + } + + final VerificationMeta _bannedMeta = const VerificationMeta('banned'); + GeneratedBoolColumn _banned; + @override + GeneratedBoolColumn get banned => _banned ??= _constructBanned(); + GeneratedBoolColumn _constructBanned() { + return GeneratedBoolColumn( + 'banned', + $tableName, + true, + ); + } + + final VerificationMeta _shadowBannedMeta = + const VerificationMeta('shadowBanned'); + GeneratedBoolColumn _shadowBanned; + @override + GeneratedBoolColumn get shadowBanned => + _shadowBanned ??= _constructShadowBanned(); + GeneratedBoolColumn _constructShadowBanned() { + return GeneratedBoolColumn( + 'shadow_banned', + $tableName, + true, + ); + } + + final VerificationMeta _isModeratorMeta = + const VerificationMeta('isModerator'); + GeneratedBoolColumn _isModerator; + @override + GeneratedBoolColumn get isModerator => + _isModerator ??= _constructIsModerator(); + GeneratedBoolColumn _constructIsModerator() { + return GeneratedBoolColumn( + 'is_moderator', + $tableName, + true, + ); + } + + final VerificationMeta _createdAtMeta = const VerificationMeta('createdAt'); + GeneratedDateTimeColumn _createdAt; + @override + GeneratedDateTimeColumn get createdAt => _createdAt ??= _constructCreatedAt(); + GeneratedDateTimeColumn _constructCreatedAt() { + return GeneratedDateTimeColumn( + 'created_at', + $tableName, + false, + ); + } + + final VerificationMeta _updatedAtMeta = const VerificationMeta('updatedAt'); + GeneratedDateTimeColumn _updatedAt; + @override + GeneratedDateTimeColumn get updatedAt => _updatedAt ??= _constructUpdatedAt(); + GeneratedDateTimeColumn _constructUpdatedAt() { + return GeneratedDateTimeColumn( + 'updated_at', + $tableName, + true, + ); + } + + @override + List get $columns => [ + userId, + channelCid, + role, + inviteAcceptedAt, + inviteRejectedAt, + invited, + banned, + shadowBanned, + isModerator, + createdAt, + updatedAt + ]; + @override + $MembersTable get asDslTable => this; + @override + String get $tableName => _alias ?? 'members'; + @override + final String actualTableName = 'members'; + @override + VerificationContext validateIntegrity(Insertable instance, + {bool isInserting = false}) { + final context = VerificationContext(); + final data = instance.toColumns(true); + if (data.containsKey('user_id')) { + context.handle(_userIdMeta, + userId.isAcceptableOrUnknown(data['user_id'], _userIdMeta)); + } else if (isInserting) { + context.missing(_userIdMeta); + } + if (data.containsKey('channel_cid')) { + context.handle( + _channelCidMeta, + channelCid.isAcceptableOrUnknown( + data['channel_cid'], _channelCidMeta)); + } else if (isInserting) { + context.missing(_channelCidMeta); + } + if (data.containsKey('role')) { + context.handle( + _roleMeta, role.isAcceptableOrUnknown(data['role'], _roleMeta)); + } + if (data.containsKey('invite_accepted_at')) { + context.handle( + _inviteAcceptedAtMeta, + inviteAcceptedAt.isAcceptableOrUnknown( + data['invite_accepted_at'], _inviteAcceptedAtMeta)); + } + if (data.containsKey('invite_rejected_at')) { + context.handle( + _inviteRejectedAtMeta, + inviteRejectedAt.isAcceptableOrUnknown( + data['invite_rejected_at'], _inviteRejectedAtMeta)); + } + if (data.containsKey('invited')) { + context.handle(_invitedMeta, + invited.isAcceptableOrUnknown(data['invited'], _invitedMeta)); + } + if (data.containsKey('banned')) { + context.handle(_bannedMeta, + banned.isAcceptableOrUnknown(data['banned'], _bannedMeta)); + } + if (data.containsKey('shadow_banned')) { + context.handle( + _shadowBannedMeta, + shadowBanned.isAcceptableOrUnknown( + data['shadow_banned'], _shadowBannedMeta)); + } + if (data.containsKey('is_moderator')) { + context.handle( + _isModeratorMeta, + isModerator.isAcceptableOrUnknown( + data['is_moderator'], _isModeratorMeta)); + } + if (data.containsKey('created_at')) { + context.handle(_createdAtMeta, + createdAt.isAcceptableOrUnknown(data['created_at'], _createdAtMeta)); + } else if (isInserting) { + context.missing(_createdAtMeta); + } + if (data.containsKey('updated_at')) { + context.handle(_updatedAtMeta, + updatedAt.isAcceptableOrUnknown(data['updated_at'], _updatedAtMeta)); + } + return context; + } + + @override + Set get $primaryKey => {userId, channelCid}; + @override + MemberEntity map(Map data, {String tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : null; + return MemberEntity.fromData(data, _db, prefix: effectivePrefix); + } + + @override + $MembersTable createAlias(String alias) { + return $MembersTable(_db, alias); + } +} + +class ReadEntity extends DataClass implements Insertable { + final DateTime lastRead; + final String userId; + final String channelCid; + final int unreadMessages; + ReadEntity( + {@required this.lastRead, + @required this.userId, + @required this.channelCid, + this.unreadMessages}); + factory ReadEntity.fromData(Map data, GeneratedDatabase db, + {String prefix}) { + final effectivePrefix = prefix ?? ''; + final dateTimeType = db.typeSystem.forDartType(); + final stringType = db.typeSystem.forDartType(); + final intType = db.typeSystem.forDartType(); + return ReadEntity( + lastRead: dateTimeType + .mapFromDatabaseResponse(data['${effectivePrefix}last_read']), + userId: + stringType.mapFromDatabaseResponse(data['${effectivePrefix}user_id']), + channelCid: stringType + .mapFromDatabaseResponse(data['${effectivePrefix}channel_cid']), + unreadMessages: intType + .mapFromDatabaseResponse(data['${effectivePrefix}unread_messages']), + ); + } + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (!nullToAbsent || lastRead != null) { + map['last_read'] = Variable(lastRead); + } + if (!nullToAbsent || userId != null) { + map['user_id'] = Variable(userId); + } + if (!nullToAbsent || channelCid != null) { + map['channel_cid'] = Variable(channelCid); + } + if (!nullToAbsent || unreadMessages != null) { + map['unread_messages'] = Variable(unreadMessages); + } + return map; + } + + factory ReadEntity.fromJson(Map json, + {ValueSerializer serializer}) { + serializer ??= moorRuntimeOptions.defaultSerializer; + return ReadEntity( + lastRead: serializer.fromJson(json['lastRead']), + userId: serializer.fromJson(json['userId']), + channelCid: serializer.fromJson(json['channelCid']), + unreadMessages: serializer.fromJson(json['unreadMessages']), + ); + } + @override + Map toJson({ValueSerializer serializer}) { + serializer ??= moorRuntimeOptions.defaultSerializer; + return { + 'lastRead': serializer.toJson(lastRead), + 'userId': serializer.toJson(userId), + 'channelCid': serializer.toJson(channelCid), + 'unreadMessages': serializer.toJson(unreadMessages), + }; + } + + ReadEntity copyWith( + {DateTime lastRead, + String userId, + String channelCid, + Value unreadMessages = const Value.absent()}) => + ReadEntity( + lastRead: lastRead ?? this.lastRead, + userId: userId ?? this.userId, + channelCid: channelCid ?? this.channelCid, + unreadMessages: + unreadMessages.present ? unreadMessages.value : this.unreadMessages, + ); + @override + String toString() { + return (StringBuffer('ReadEntity(') + ..write('lastRead: $lastRead, ') + ..write('userId: $userId, ') + ..write('channelCid: $channelCid, ') + ..write('unreadMessages: $unreadMessages') + ..write(')')) + .toString(); + } + + @override + int get hashCode => $mrjf($mrjc( + lastRead.hashCode, + $mrjc(userId.hashCode, + $mrjc(channelCid.hashCode, unreadMessages.hashCode)))); + @override + bool operator ==(dynamic other) => + identical(this, other) || + (other is ReadEntity && + other.lastRead == this.lastRead && + other.userId == this.userId && + other.channelCid == this.channelCid && + other.unreadMessages == this.unreadMessages); +} + +class ReadsCompanion extends UpdateCompanion { + final Value lastRead; + final Value userId; + final Value channelCid; + final Value unreadMessages; + const ReadsCompanion({ + this.lastRead = const Value.absent(), + this.userId = const Value.absent(), + this.channelCid = const Value.absent(), + this.unreadMessages = const Value.absent(), + }); + ReadsCompanion.insert({ + @required DateTime lastRead, + @required String userId, + @required String channelCid, + this.unreadMessages = const Value.absent(), + }) : lastRead = Value(lastRead), + userId = Value(userId), + channelCid = Value(channelCid); + static Insertable custom({ + Expression lastRead, + Expression userId, + Expression channelCid, + Expression unreadMessages, + }) { + return RawValuesInsertable({ + if (lastRead != null) 'last_read': lastRead, + if (userId != null) 'user_id': userId, + if (channelCid != null) 'channel_cid': channelCid, + if (unreadMessages != null) 'unread_messages': unreadMessages, + }); + } + + ReadsCompanion copyWith( + {Value lastRead, + Value userId, + Value channelCid, + Value unreadMessages}) { + return ReadsCompanion( + lastRead: lastRead ?? this.lastRead, + userId: userId ?? this.userId, + channelCid: channelCid ?? this.channelCid, + unreadMessages: unreadMessages ?? this.unreadMessages, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (lastRead.present) { + map['last_read'] = Variable(lastRead.value); + } + if (userId.present) { + map['user_id'] = Variable(userId.value); + } + if (channelCid.present) { + map['channel_cid'] = Variable(channelCid.value); + } + if (unreadMessages.present) { + map['unread_messages'] = Variable(unreadMessages.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('ReadsCompanion(') + ..write('lastRead: $lastRead, ') + ..write('userId: $userId, ') + ..write('channelCid: $channelCid, ') + ..write('unreadMessages: $unreadMessages') + ..write(')')) + .toString(); + } +} + +class $ReadsTable extends Reads with TableInfo<$ReadsTable, ReadEntity> { + final GeneratedDatabase _db; + final String _alias; + $ReadsTable(this._db, [this._alias]); + final VerificationMeta _lastReadMeta = const VerificationMeta('lastRead'); + GeneratedDateTimeColumn _lastRead; + @override + GeneratedDateTimeColumn get lastRead => _lastRead ??= _constructLastRead(); + GeneratedDateTimeColumn _constructLastRead() { + return GeneratedDateTimeColumn( + 'last_read', + $tableName, + false, + ); + } + + final VerificationMeta _userIdMeta = const VerificationMeta('userId'); + GeneratedTextColumn _userId; + @override + GeneratedTextColumn get userId => _userId ??= _constructUserId(); + GeneratedTextColumn _constructUserId() { + return GeneratedTextColumn( + 'user_id', + $tableName, + false, + ); + } + + final VerificationMeta _channelCidMeta = const VerificationMeta('channelCid'); + GeneratedTextColumn _channelCid; + @override + GeneratedTextColumn get channelCid => _channelCid ??= _constructChannelCid(); + GeneratedTextColumn _constructChannelCid() { + return GeneratedTextColumn('channel_cid', $tableName, false, + $customConstraints: 'REFERENCES channels(cid) ON DELETE CASCADE'); + } + + final VerificationMeta _unreadMessagesMeta = + const VerificationMeta('unreadMessages'); + GeneratedIntColumn _unreadMessages; + @override + GeneratedIntColumn get unreadMessages => + _unreadMessages ??= _constructUnreadMessages(); + GeneratedIntColumn _constructUnreadMessages() { + return GeneratedIntColumn( + 'unread_messages', + $tableName, + true, + ); + } + + @override + List get $columns => + [lastRead, userId, channelCid, unreadMessages]; + @override + $ReadsTable get asDslTable => this; + @override + String get $tableName => _alias ?? 'reads'; + @override + final String actualTableName = 'reads'; + @override + VerificationContext validateIntegrity(Insertable instance, + {bool isInserting = false}) { + final context = VerificationContext(); + final data = instance.toColumns(true); + if (data.containsKey('last_read')) { + context.handle(_lastReadMeta, + lastRead.isAcceptableOrUnknown(data['last_read'], _lastReadMeta)); + } else if (isInserting) { + context.missing(_lastReadMeta); + } + if (data.containsKey('user_id')) { + context.handle(_userIdMeta, + userId.isAcceptableOrUnknown(data['user_id'], _userIdMeta)); + } else if (isInserting) { + context.missing(_userIdMeta); + } + if (data.containsKey('channel_cid')) { + context.handle( + _channelCidMeta, + channelCid.isAcceptableOrUnknown( + data['channel_cid'], _channelCidMeta)); + } else if (isInserting) { + context.missing(_channelCidMeta); + } + if (data.containsKey('unread_messages')) { + context.handle( + _unreadMessagesMeta, + unreadMessages.isAcceptableOrUnknown( + data['unread_messages'], _unreadMessagesMeta)); + } + return context; + } + + @override + Set get $primaryKey => {userId, channelCid}; + @override + ReadEntity map(Map data, {String tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : null; + return ReadEntity.fromData(data, _db, prefix: effectivePrefix); + } + + @override + $ReadsTable createAlias(String alias) { + return $ReadsTable(_db, alias); + } +} + +class ChannelQueryEntity extends DataClass + implements Insertable { + final String queryHash; + final String channelCid; + ChannelQueryEntity({@required this.queryHash, @required this.channelCid}); + factory ChannelQueryEntity.fromData( + Map data, GeneratedDatabase db, + {String prefix}) { + final effectivePrefix = prefix ?? ''; + final stringType = db.typeSystem.forDartType(); + return ChannelQueryEntity( + queryHash: stringType + .mapFromDatabaseResponse(data['${effectivePrefix}query_hash']), + channelCid: stringType + .mapFromDatabaseResponse(data['${effectivePrefix}channel_cid']), + ); + } + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (!nullToAbsent || queryHash != null) { + map['query_hash'] = Variable(queryHash); + } + if (!nullToAbsent || channelCid != null) { + map['channel_cid'] = Variable(channelCid); + } + return map; + } + + factory ChannelQueryEntity.fromJson(Map json, + {ValueSerializer serializer}) { + serializer ??= moorRuntimeOptions.defaultSerializer; + return ChannelQueryEntity( + queryHash: serializer.fromJson(json['queryHash']), + channelCid: serializer.fromJson(json['channelCid']), + ); + } + @override + Map toJson({ValueSerializer serializer}) { + serializer ??= moorRuntimeOptions.defaultSerializer; + return { + 'queryHash': serializer.toJson(queryHash), + 'channelCid': serializer.toJson(channelCid), + }; + } + + ChannelQueryEntity copyWith({String queryHash, String channelCid}) => + ChannelQueryEntity( + queryHash: queryHash ?? this.queryHash, + channelCid: channelCid ?? this.channelCid, + ); + @override + String toString() { + return (StringBuffer('ChannelQueryEntity(') + ..write('queryHash: $queryHash, ') + ..write('channelCid: $channelCid') + ..write(')')) + .toString(); + } + + @override + int get hashCode => $mrjf($mrjc(queryHash.hashCode, channelCid.hashCode)); + @override + bool operator ==(dynamic other) => + identical(this, other) || + (other is ChannelQueryEntity && + other.queryHash == this.queryHash && + other.channelCid == this.channelCid); +} + +class ChannelQueriesCompanion extends UpdateCompanion { + final Value queryHash; + final Value channelCid; + const ChannelQueriesCompanion({ + this.queryHash = const Value.absent(), + this.channelCid = const Value.absent(), + }); + ChannelQueriesCompanion.insert({ + @required String queryHash, + @required String channelCid, + }) : queryHash = Value(queryHash), + channelCid = Value(channelCid); + static Insertable custom({ + Expression queryHash, + Expression channelCid, + }) { + return RawValuesInsertable({ + if (queryHash != null) 'query_hash': queryHash, + if (channelCid != null) 'channel_cid': channelCid, + }); + } + + ChannelQueriesCompanion copyWith( + {Value queryHash, Value channelCid}) { + return ChannelQueriesCompanion( + queryHash: queryHash ?? this.queryHash, + channelCid: channelCid ?? this.channelCid, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (queryHash.present) { + map['query_hash'] = Variable(queryHash.value); + } + if (channelCid.present) { + map['channel_cid'] = Variable(channelCid.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('ChannelQueriesCompanion(') + ..write('queryHash: $queryHash, ') + ..write('channelCid: $channelCid') + ..write(')')) + .toString(); + } +} + +class $ChannelQueriesTable extends ChannelQueries + with TableInfo<$ChannelQueriesTable, ChannelQueryEntity> { + final GeneratedDatabase _db; + final String _alias; + $ChannelQueriesTable(this._db, [this._alias]); + final VerificationMeta _queryHashMeta = const VerificationMeta('queryHash'); + GeneratedTextColumn _queryHash; + @override + GeneratedTextColumn get queryHash => _queryHash ??= _constructQueryHash(); + GeneratedTextColumn _constructQueryHash() { + return GeneratedTextColumn( + 'query_hash', + $tableName, + false, + ); + } + + final VerificationMeta _channelCidMeta = const VerificationMeta('channelCid'); + GeneratedTextColumn _channelCid; + @override + GeneratedTextColumn get channelCid => _channelCid ??= _constructChannelCid(); + GeneratedTextColumn _constructChannelCid() { + return GeneratedTextColumn( + 'channel_cid', + $tableName, + false, + ); + } + + @override + List get $columns => [queryHash, channelCid]; + @override + $ChannelQueriesTable get asDslTable => this; + @override + String get $tableName => _alias ?? 'channel_queries'; + @override + final String actualTableName = 'channel_queries'; + @override + VerificationContext validateIntegrity(Insertable instance, + {bool isInserting = false}) { + final context = VerificationContext(); + final data = instance.toColumns(true); + if (data.containsKey('query_hash')) { + context.handle(_queryHashMeta, + queryHash.isAcceptableOrUnknown(data['query_hash'], _queryHashMeta)); + } else if (isInserting) { + context.missing(_queryHashMeta); + } + if (data.containsKey('channel_cid')) { + context.handle( + _channelCidMeta, + channelCid.isAcceptableOrUnknown( + data['channel_cid'], _channelCidMeta)); + } else if (isInserting) { + context.missing(_channelCidMeta); + } + return context; + } + + @override + Set get $primaryKey => {queryHash, channelCid}; + @override + ChannelQueryEntity map(Map data, {String tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : null; + return ChannelQueryEntity.fromData(data, _db, prefix: effectivePrefix); + } + + @override + $ChannelQueriesTable createAlias(String alias) { + return $ChannelQueriesTable(_db, alias); + } +} + +class ConnectionEventEntity extends DataClass + implements Insertable { + final int id; + final Map ownUser; + final int totalUnreadCount; + final int unreadChannels; + final DateTime lastEventAt; + final DateTime lastSyncAt; + ConnectionEventEntity( + {@required this.id, + this.ownUser, + this.totalUnreadCount, + this.unreadChannels, + this.lastEventAt, + this.lastSyncAt}); + factory ConnectionEventEntity.fromData( + Map data, GeneratedDatabase db, + {String prefix}) { + final effectivePrefix = prefix ?? ''; + final intType = db.typeSystem.forDartType(); + final stringType = db.typeSystem.forDartType(); + final dateTimeType = db.typeSystem.forDartType(); + return ConnectionEventEntity( + id: intType.mapFromDatabaseResponse(data['${effectivePrefix}id']), + ownUser: $ConnectionEventsTable.$converter0.mapToDart(stringType + .mapFromDatabaseResponse(data['${effectivePrefix}own_user'])), + totalUnreadCount: intType.mapFromDatabaseResponse( + data['${effectivePrefix}total_unread_count']), + unreadChannels: intType + .mapFromDatabaseResponse(data['${effectivePrefix}unread_channels']), + lastEventAt: dateTimeType + .mapFromDatabaseResponse(data['${effectivePrefix}last_event_at']), + lastSyncAt: dateTimeType + .mapFromDatabaseResponse(data['${effectivePrefix}last_sync_at']), + ); + } + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (!nullToAbsent || id != null) { + map['id'] = Variable(id); + } + if (!nullToAbsent || ownUser != null) { + final converter = $ConnectionEventsTable.$converter0; + map['own_user'] = Variable(converter.mapToSql(ownUser)); + } + if (!nullToAbsent || totalUnreadCount != null) { + map['total_unread_count'] = Variable(totalUnreadCount); + } + if (!nullToAbsent || unreadChannels != null) { + map['unread_channels'] = Variable(unreadChannels); + } + if (!nullToAbsent || lastEventAt != null) { + map['last_event_at'] = Variable(lastEventAt); + } + if (!nullToAbsent || lastSyncAt != null) { + map['last_sync_at'] = Variable(lastSyncAt); + } + return map; + } + + factory ConnectionEventEntity.fromJson(Map json, + {ValueSerializer serializer}) { + serializer ??= moorRuntimeOptions.defaultSerializer; + return ConnectionEventEntity( + id: serializer.fromJson(json['id']), + ownUser: serializer.fromJson>(json['ownUser']), + totalUnreadCount: serializer.fromJson(json['totalUnreadCount']), + unreadChannels: serializer.fromJson(json['unreadChannels']), + lastEventAt: serializer.fromJson(json['lastEventAt']), + lastSyncAt: serializer.fromJson(json['lastSyncAt']), + ); + } + @override + Map toJson({ValueSerializer serializer}) { + serializer ??= moorRuntimeOptions.defaultSerializer; + return { + 'id': serializer.toJson(id), + 'ownUser': serializer.toJson>(ownUser), + 'totalUnreadCount': serializer.toJson(totalUnreadCount), + 'unreadChannels': serializer.toJson(unreadChannels), + 'lastEventAt': serializer.toJson(lastEventAt), + 'lastSyncAt': serializer.toJson(lastSyncAt), + }; + } + + ConnectionEventEntity copyWith( + {int id, + Value> ownUser = const Value.absent(), + Value totalUnreadCount = const Value.absent(), + Value unreadChannels = const Value.absent(), + Value lastEventAt = const Value.absent(), + Value lastSyncAt = const Value.absent()}) => + ConnectionEventEntity( + id: id ?? this.id, + ownUser: ownUser.present ? ownUser.value : this.ownUser, + totalUnreadCount: totalUnreadCount.present + ? totalUnreadCount.value + : this.totalUnreadCount, + unreadChannels: + unreadChannels.present ? unreadChannels.value : this.unreadChannels, + lastEventAt: lastEventAt.present ? lastEventAt.value : this.lastEventAt, + lastSyncAt: lastSyncAt.present ? lastSyncAt.value : this.lastSyncAt, + ); + @override + String toString() { + return (StringBuffer('ConnectionEventEntity(') + ..write('id: $id, ') + ..write('ownUser: $ownUser, ') + ..write('totalUnreadCount: $totalUnreadCount, ') + ..write('unreadChannels: $unreadChannels, ') + ..write('lastEventAt: $lastEventAt, ') + ..write('lastSyncAt: $lastSyncAt') + ..write(')')) + .toString(); + } + + @override + int get hashCode => $mrjf($mrjc( + id.hashCode, + $mrjc( + ownUser.hashCode, + $mrjc( + totalUnreadCount.hashCode, + $mrjc(unreadChannels.hashCode, + $mrjc(lastEventAt.hashCode, lastSyncAt.hashCode)))))); + @override + bool operator ==(dynamic other) => + identical(this, other) || + (other is ConnectionEventEntity && + other.id == this.id && + other.ownUser == this.ownUser && + other.totalUnreadCount == this.totalUnreadCount && + other.unreadChannels == this.unreadChannels && + other.lastEventAt == this.lastEventAt && + other.lastSyncAt == this.lastSyncAt); +} + +class ConnectionEventsCompanion extends UpdateCompanion { + final Value id; + final Value> ownUser; + final Value totalUnreadCount; + final Value unreadChannels; + final Value lastEventAt; + final Value lastSyncAt; + const ConnectionEventsCompanion({ + this.id = const Value.absent(), + this.ownUser = const Value.absent(), + this.totalUnreadCount = const Value.absent(), + this.unreadChannels = const Value.absent(), + this.lastEventAt = const Value.absent(), + this.lastSyncAt = const Value.absent(), + }); + ConnectionEventsCompanion.insert({ + this.id = const Value.absent(), + this.ownUser = const Value.absent(), + this.totalUnreadCount = const Value.absent(), + this.unreadChannels = const Value.absent(), + this.lastEventAt = const Value.absent(), + this.lastSyncAt = const Value.absent(), + }); + static Insertable custom({ + Expression id, + Expression ownUser, + Expression totalUnreadCount, + Expression unreadChannels, + Expression lastEventAt, + Expression lastSyncAt, + }) { + return RawValuesInsertable({ + if (id != null) 'id': id, + if (ownUser != null) 'own_user': ownUser, + if (totalUnreadCount != null) 'total_unread_count': totalUnreadCount, + if (unreadChannels != null) 'unread_channels': unreadChannels, + if (lastEventAt != null) 'last_event_at': lastEventAt, + if (lastSyncAt != null) 'last_sync_at': lastSyncAt, + }); + } + + ConnectionEventsCompanion copyWith( + {Value id, + Value> ownUser, + Value totalUnreadCount, + Value unreadChannels, + Value lastEventAt, + Value lastSyncAt}) { + return ConnectionEventsCompanion( + id: id ?? this.id, + ownUser: ownUser ?? this.ownUser, + totalUnreadCount: totalUnreadCount ?? this.totalUnreadCount, + unreadChannels: unreadChannels ?? this.unreadChannels, + lastEventAt: lastEventAt ?? this.lastEventAt, + lastSyncAt: lastSyncAt ?? this.lastSyncAt, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (id.present) { + map['id'] = Variable(id.value); + } + if (ownUser.present) { + final converter = $ConnectionEventsTable.$converter0; + map['own_user'] = Variable(converter.mapToSql(ownUser.value)); + } + if (totalUnreadCount.present) { + map['total_unread_count'] = Variable(totalUnreadCount.value); + } + if (unreadChannels.present) { + map['unread_channels'] = Variable(unreadChannels.value); + } + if (lastEventAt.present) { + map['last_event_at'] = Variable(lastEventAt.value); + } + if (lastSyncAt.present) { + map['last_sync_at'] = Variable(lastSyncAt.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('ConnectionEventsCompanion(') + ..write('id: $id, ') + ..write('ownUser: $ownUser, ') + ..write('totalUnreadCount: $totalUnreadCount, ') + ..write('unreadChannels: $unreadChannels, ') + ..write('lastEventAt: $lastEventAt, ') + ..write('lastSyncAt: $lastSyncAt') + ..write(')')) + .toString(); + } +} + +class $ConnectionEventsTable extends ConnectionEvents + with TableInfo<$ConnectionEventsTable, ConnectionEventEntity> { + final GeneratedDatabase _db; + final String _alias; + $ConnectionEventsTable(this._db, [this._alias]); + final VerificationMeta _idMeta = const VerificationMeta('id'); + GeneratedIntColumn _id; + @override + GeneratedIntColumn get id => _id ??= _constructId(); + GeneratedIntColumn _constructId() { + return GeneratedIntColumn( + 'id', + $tableName, + false, + ); + } + + final VerificationMeta _ownUserMeta = const VerificationMeta('ownUser'); + GeneratedTextColumn _ownUser; + @override + GeneratedTextColumn get ownUser => _ownUser ??= _constructOwnUser(); + GeneratedTextColumn _constructOwnUser() { + return GeneratedTextColumn( + 'own_user', + $tableName, + true, + ); + } + + final VerificationMeta _totalUnreadCountMeta = + const VerificationMeta('totalUnreadCount'); + GeneratedIntColumn _totalUnreadCount; + @override + GeneratedIntColumn get totalUnreadCount => + _totalUnreadCount ??= _constructTotalUnreadCount(); + GeneratedIntColumn _constructTotalUnreadCount() { + return GeneratedIntColumn( + 'total_unread_count', + $tableName, + true, + ); + } + + final VerificationMeta _unreadChannelsMeta = + const VerificationMeta('unreadChannels'); + GeneratedIntColumn _unreadChannels; + @override + GeneratedIntColumn get unreadChannels => + _unreadChannels ??= _constructUnreadChannels(); + GeneratedIntColumn _constructUnreadChannels() { + return GeneratedIntColumn( + 'unread_channels', + $tableName, + true, + ); + } + + final VerificationMeta _lastEventAtMeta = + const VerificationMeta('lastEventAt'); + GeneratedDateTimeColumn _lastEventAt; + @override + GeneratedDateTimeColumn get lastEventAt => + _lastEventAt ??= _constructLastEventAt(); + GeneratedDateTimeColumn _constructLastEventAt() { + return GeneratedDateTimeColumn( + 'last_event_at', + $tableName, + true, + ); + } + + final VerificationMeta _lastSyncAtMeta = const VerificationMeta('lastSyncAt'); + GeneratedDateTimeColumn _lastSyncAt; + @override + GeneratedDateTimeColumn get lastSyncAt => + _lastSyncAt ??= _constructLastSyncAt(); + GeneratedDateTimeColumn _constructLastSyncAt() { + return GeneratedDateTimeColumn( + 'last_sync_at', + $tableName, + true, + ); + } + + @override + List get $columns => + [id, ownUser, totalUnreadCount, unreadChannels, lastEventAt, lastSyncAt]; + @override + $ConnectionEventsTable get asDslTable => this; + @override + String get $tableName => _alias ?? 'connection_events'; + @override + final String actualTableName = 'connection_events'; + @override + VerificationContext validateIntegrity( + Insertable instance, + {bool isInserting = false}) { + final context = VerificationContext(); + final data = instance.toColumns(true); + if (data.containsKey('id')) { + context.handle(_idMeta, id.isAcceptableOrUnknown(data['id'], _idMeta)); + } + context.handle(_ownUserMeta, const VerificationResult.success()); + if (data.containsKey('total_unread_count')) { + context.handle( + _totalUnreadCountMeta, + totalUnreadCount.isAcceptableOrUnknown( + data['total_unread_count'], _totalUnreadCountMeta)); + } + if (data.containsKey('unread_channels')) { + context.handle( + _unreadChannelsMeta, + unreadChannels.isAcceptableOrUnknown( + data['unread_channels'], _unreadChannelsMeta)); + } + if (data.containsKey('last_event_at')) { + context.handle( + _lastEventAtMeta, + lastEventAt.isAcceptableOrUnknown( + data['last_event_at'], _lastEventAtMeta)); + } + if (data.containsKey('last_sync_at')) { + context.handle( + _lastSyncAtMeta, + lastSyncAt.isAcceptableOrUnknown( + data['last_sync_at'], _lastSyncAtMeta)); + } + return context; + } + + @override + Set get $primaryKey => {id}; + @override + ConnectionEventEntity map(Map data, {String tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : null; + return ConnectionEventEntity.fromData(data, _db, prefix: effectivePrefix); + } + + @override + $ConnectionEventsTable createAlias(String alias) { + return $ConnectionEventsTable(_db, alias); + } + + static TypeConverter, String> $converter0 = + MapConverter(); +} + +abstract class _$MoorChatDatabase extends GeneratedDatabase { + _$MoorChatDatabase(QueryExecutor e) : super(SqlTypeSystem.defaultInstance, e); + _$MoorChatDatabase.connect(DatabaseConnection c) : super.connect(c); + $ChannelsTable _channels; + $ChannelsTable get channels => _channels ??= $ChannelsTable(this); + $MessagesTable _messages; + $MessagesTable get messages => _messages ??= $MessagesTable(this); + $ReactionsTable _reactions; + $ReactionsTable get reactions => _reactions ??= $ReactionsTable(this); + $UsersTable _users; + $UsersTable get users => _users ??= $UsersTable(this); + $MembersTable _members; + $MembersTable get members => _members ??= $MembersTable(this); + $ReadsTable _reads; + $ReadsTable get reads => _reads ??= $ReadsTable(this); + $ChannelQueriesTable _channelQueries; + $ChannelQueriesTable get channelQueries => + _channelQueries ??= $ChannelQueriesTable(this); + $ConnectionEventsTable _connectionEvents; + $ConnectionEventsTable get connectionEvents => + _connectionEvents ??= $ConnectionEventsTable(this); + UserDao _userDao; + UserDao get userDao => _userDao ??= UserDao(this as MoorChatDatabase); + ChannelDao _channelDao; + ChannelDao get channelDao => + _channelDao ??= ChannelDao(this as MoorChatDatabase); + MessageDao _messageDao; + MessageDao get messageDao => + _messageDao ??= MessageDao(this as MoorChatDatabase); + MemberDao _memberDao; + MemberDao get memberDao => _memberDao ??= MemberDao(this as MoorChatDatabase); + ReactionDao _reactionDao; + ReactionDao get reactionDao => + _reactionDao ??= ReactionDao(this as MoorChatDatabase); + ReadDao _readDao; + ReadDao get readDao => _readDao ??= ReadDao(this as MoorChatDatabase); + ChannelQueryDao _channelQueryDao; + ChannelQueryDao get channelQueryDao => + _channelQueryDao ??= ChannelQueryDao(this as MoorChatDatabase); + ConnectionEventDao _connectionEventDao; + ConnectionEventDao get connectionEventDao => + _connectionEventDao ??= ConnectionEventDao(this as MoorChatDatabase); + @override + Iterable get allTables => allSchemaEntities.whereType(); + @override + List get allSchemaEntities => [ + channels, + messages, + reactions, + users, + members, + reads, + channelQueries, + connectionEvents + ]; +} From eaf322f660a8fc04c028e6222076ce7404867537 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Tue, 26 Jan 2021 16:55:23 +0530 Subject: [PATCH 1041/1140] [StreamChatPersistence] Ran formatter Signed-off-by: Sahil Kumar --- .../stream_chat_persistence/lib/src/converter/converter.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/stream_chat_persistence/lib/src/converter/converter.dart b/packages/stream_chat_persistence/lib/src/converter/converter.dart index f32f4b54..a5d7bbdc 100644 --- a/packages/stream_chat_persistence/lib/src/converter/converter.dart +++ b/packages/stream_chat_persistence/lib/src/converter/converter.dart @@ -1,3 +1,3 @@ export 'list_converter.dart'; export 'map_converter.dart'; -export 'message_sending_status_converter.dart'; \ No newline at end of file +export 'message_sending_status_converter.dart'; From f48b7c88826ded1bc5c3fd03941f17c1c5a5dff1 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Tue, 26 Jan 2021 16:58:18 +0530 Subject: [PATCH 1042/1140] [StreamChat] Fix test Signed-off-by: Sahil Kumar --- packages/dart_client/test/src/models/message_test.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/dart_client/test/src/models/message_test.dart b/packages/dart_client/test/src/models/message_test.dart index f318daac..de335c21 100644 --- a/packages/dart_client/test/src/models/message_test.dart +++ b/packages/dart_client/test/src/models/message_test.dart @@ -116,7 +116,7 @@ void main() { showInChannel: true, parentId: 'parentId', extraData: {'hey': 'test'}, - status: MessageSendingStatus.SENT, + status: MessageSendingStatus.sent, ); expect( From ec858e497376e31772a991733d78b75f5335cf56 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Tue, 26 Jan 2021 18:44:02 +0530 Subject: [PATCH 1043/1140] doc: Added some docs for core code --- .../lib/src/channel_list_core.dart | 32 +++++++++++++++---- .../lib/src/message_list_core.dart | 27 ++++++++++------ .../lib/src/message_search_list_core.dart | 9 ++++-- .../lib/src/user_list_core.dart | 26 +++++++++++++-- 4 files changed, 73 insertions(+), 21 deletions(-) diff --git a/packages/stream_chat_flutter_core/lib/src/channel_list_core.dart b/packages/stream_chat_flutter_core/lib/src/channel_list_core.dart index 972de62f..5b992470 100644 --- a/packages/stream_chat_flutter_core/lib/src/channel_list_core.dart +++ b/packages/stream_chat_flutter_core/lib/src/channel_list_core.dart @@ -11,14 +11,15 @@ import 'stream_chat_core.dart'; /// ![screenshot](https://raw.githubusercontent.com/GetStream/stream-chat-flutter/master/screenshots/channel_list_view.png) /// ![screenshot](https://raw.githubusercontent.com/GetStream/stream-chat-flutter/master/screenshots/channel_list_view_paint.png) /// -/// It shows the list of current channels. +/// [ChannelListCore] is a simplified class that allows fetching a list of channels while exposing UI builders. +/// A [ChannelListController] is used to reload and paginate data. /// /// ```dart /// class ChannelListPage extends StatelessWidget { /// @override /// Widget build(BuildContext context) { /// return Scaffold( -/// body: ChannelListView( +/// body: ChannelListCore( /// filter: { /// 'members': { /// '\$in': [StreamChat.of(context).user.id], @@ -28,7 +29,24 @@ import 'stream_chat_core.dart'; /// pagination: PaginationParams( /// limit: 20, /// ), -/// channelWidget: ChannelPage(), +/// errorBuilder: (err) { +/// return Center( +/// child: Text('An error has occured'), +/// ); +/// }, +/// emptyBuilder: (context) { +/// return Center( +/// child: Text('Nothing here...'), +/// ); +/// }, +/// emptyBuilder: (context) { +/// return Center( +/// child: CircularProgressIndicator(), +/// ); +/// }, +/// listBuilder: (context, list) { +/// return ChannelPage(list); +/// } /// ), /// ); /// } @@ -37,10 +55,6 @@ import 'stream_chat_core.dart'; /// /// /// Make sure to have a [StreamChatCore] ancestor in order to provide the information about the channels. -/// The widget uses a [ListView.custom] to render the list of channels. -/// -/// The widget components render the ui based on the first ancestor of type [StreamChatTheme]. -/// Modify it to change the widget appearance. class ChannelListCore extends StatefulWidget { /// Instantiate a new ChannelListView ChannelListCore({ @@ -56,13 +70,17 @@ class ChannelListCore extends StatefulWidget { this.channelListController, }) : super(key: key); + /// A [ChannelListController] allows reloading and pagination. + /// Use [ChannelListController.loadData] and [ChannelListController.paginateData] respectively for reloading and pagination. final ChannelListController channelListController; /// The builder that will be used in case of error final Widget Function(Error error) errorBuilder; + /// The builder that will be used in case of loading final WidgetBuilder loadingBuilder; + /// The builder which is used when list of channels loads final Function(BuildContext, List) listBuilder; /// The builder used when the channel list is empty. diff --git a/packages/stream_chat_flutter_core/lib/src/message_list_core.dart b/packages/stream_chat_flutter_core/lib/src/message_list_core.dart index a13c186c..6ef92569 100644 --- a/packages/stream_chat_flutter_core/lib/src/message_list_core.dart +++ b/packages/stream_chat_flutter_core/lib/src/message_list_core.dart @@ -8,7 +8,8 @@ import 'stream_channel.dart'; /// ![screenshot](https://raw.githubusercontent.com/GetStream/stream-chat-flutter/master/screenshots/message_listview.png) /// ![screenshot](https://raw.githubusercontent.com/GetStream/stream-chat-flutter/master/screenshots/message_listview_paint.png) /// -/// It shows the list of messages of the current channel. +/// [MessageListCore] is a simplified class that allows fetching a list of messages while exposing UI builders. +/// A [MessageListController] is used to paginate data. /// /// ```dart /// class ChannelPage extends StatelessWidget { @@ -19,19 +20,25 @@ import 'stream_channel.dart'; /// @override /// Widget build(BuildContext context) { /// return Scaffold( -/// appBar: ChannelHeader(), /// body: Column( /// children: [ /// Expanded( -/// child: MessageListView( -/// threadBuilder: (_, parentMessage) { -/// return ThreadPage( -/// parent: parentMessage, -/// ); -/// }, +/// child: MessageListCore( +/// emptyBuilder: (context) { +/// return Center( +/// child: Text('Nothing here...'), +/// ); +/// }, +/// emptyBuilder: (context) { +/// return Center( +/// child: CircularProgressIndicator(), +/// ); +/// }, +/// messageListBuilder: (context, list) { +/// return MessagesPage(list); +/// } /// ), /// ), -/// MessageInput(), /// ], /// ), /// ); @@ -57,6 +64,8 @@ class MessageListCore extends StatefulWidget { this.messageListController, }) : super(key: key); + /// A [MessageListController] allows pagination. + /// Use [ChannelListController.paginateData] pagination. final MessageListController messageListController; final Widget Function(BuildContext, List) messageListBuilder; diff --git a/packages/stream_chat_flutter_core/lib/src/message_search_list_core.dart b/packages/stream_chat_flutter_core/lib/src/message_search_list_core.dart index f011ee53..de0af711 100644 --- a/packages/stream_chat_flutter_core/lib/src/message_search_list_core.dart +++ b/packages/stream_chat_flutter_core/lib/src/message_search_list_core.dart @@ -5,14 +5,15 @@ import 'package:stream_chat/stream_chat.dart'; import 'message_search_bloc.dart'; /// -/// It shows the list of searched messages. +/// [MessageSearchListCore] is a simplified class that allows searching for messages across channels while exposing UI builders. +/// A [MessageSearchListController] is used to load and paginate data. /// /// ```dart /// class MessageSearchPage extends StatelessWidget { /// @override /// Widget build(BuildContext context) { /// return Scaffold( -/// body: MessageSearchListView( +/// body: MessageSearchListCore( /// messageQuery: _channelQuery, /// filters: { /// 'members': { @@ -48,6 +49,8 @@ class MessageSearchListCore extends StatefulWidget { this.messageSearchListController, }) : super(key: key); + /// A [MessageSearchListController] allows reloading and pagination. + /// Use [MessageSearchListController.loadData] and [MessageSearchListController.paginateData] respectively for reloading and pagination. final MessageSearchListController messageSearchListController; /// Message String to search on @@ -75,6 +78,7 @@ class MessageSearchListCore extends StatefulWidget { /// You can also filter other built-in channel fields. final Map messageFilters; + /// The builder that is used when the search messages are fetched final Widget Function(List) childBuilder; /// The builder used when the channel list is empty. @@ -83,6 +87,7 @@ class MessageSearchListCore extends StatefulWidget { /// The builder that will be used in case of error final Widget Function(Error error) errorBuilder; + /// The builder that will be used in case of loading final WidgetBuilder loadingBuilder; @override diff --git a/packages/stream_chat_flutter_core/lib/src/user_list_core.dart b/packages/stream_chat_flutter_core/lib/src/user_list_core.dart index bb8f81fe..d08e06ae 100644 --- a/packages/stream_chat_flutter_core/lib/src/user_list_core.dart +++ b/packages/stream_chat_flutter_core/lib/src/user_list_core.dart @@ -5,14 +5,15 @@ import 'package:stream_chat/stream_chat.dart'; import 'package:stream_chat_flutter_core/src/users_bloc.dart'; /// -/// It shows the list of current users. +/// [UserListCore] is a simplified class that allows fetching users while exposing UI builders. +/// A [UserListController] is used to load and paginate data. /// /// ```dart /// class UsersListPage extends StatelessWidget { /// @override /// Widget build(BuildContext context) { /// return Scaffold( -/// body: UsersListView( +/// body: UsersListCore( /// filter: { /// 'members': { /// '\$in': [StreamChat.of(context).user.id], @@ -22,7 +23,24 @@ import 'package:stream_chat_flutter_core/src/users_bloc.dart'; /// pagination: PaginationParams( /// limit: 20, /// ), -/// channelWidget: ChannelPage(), +/// errorBuilder: (err) { +/// return Center( +/// child: Text('An error has occured'), +/// ); +/// }, +/// emptyBuilder: (context) { +/// return Center( +/// child: Text('Nothing here...'), +/// ); +/// }, +/// emptyBuilder: (context) { +/// return Center( +/// child: CircularProgressIndicator(), +/// ); +/// }, +/// listBuilder: (context, list) { +/// return UsersPage(list); +/// } /// ), /// ); /// } @@ -51,6 +69,8 @@ class UserListCore extends StatefulWidget { this.userListController, }) : super(key: key); + /// A [UserListController] allows reloading and pagination. + /// Use [UserListController.loadData] and [UserListController.paginateData] respectively for reloading and pagination. final UserListController userListController; /// The builder that will be used in case of error From b2108c49dc985dd7f732dca3c652351485fce11f Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Tue, 26 Jan 2021 19:46:17 +0530 Subject: [PATCH 1044/1140] doc: Added basic README.md --- packages/stream_chat_flutter_core/README.md | 75 ++++++++++++++++++--- 1 file changed, 65 insertions(+), 10 deletions(-) diff --git a/packages/stream_chat_flutter_core/README.md b/packages/stream_chat_flutter_core/README.md index 0acef57c..30ab07f5 100644 --- a/packages/stream_chat_flutter_core/README.md +++ b/packages/stream_chat_flutter_core/README.md @@ -1,14 +1,69 @@ -# stream_chat_flutter_core +# Official Flutter SDK Core for [Stream Chat](https://getstream.io/chat/) -Stream Chat Official Flutter SDK Core. Build and customize your own chat experience using Dart and Flutter. +

+ Flutter Chat +

-## Getting Started +> The official Flutter core components for Stream Chat, a service for +> building chat applications. -This project is a starting point for a Dart -[package](https://flutter.dev/developing-packages/), -a library module containing code that can be shared easily across -multiple Flutter or Dart projects. +[![Pub](https://img.shields.io/pub/v/stream_chat_flutter.svg)](https://pub.dartlang.org/packages/stream_chat_flutter) +![](https://img.shields.io/badge/platform-flutter%20%7C%20flutter%20web-ff69b4.svg?style=flat-square) +[![Gitter](https://badges.gitter.im/GetStream/stream-chat-flutter.svg)](https://gitter.im/GetStream/stream-chat-flutter?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) +![CI](https://github.com/GetStream/stream-chat-flutter/workflows/CI/badge.svg?branch=master) + -For help getting started with Flutter, view our -[online documentation](https://flutter.dev/docs), which offers tutorials, -samples, guidance on mobile development, and a full API reference. +**Quick Links** + +- [Register](https://getstream.io/chat/trial/) to get an API key for Stream Chat +- [Flutter Chat Tutorial](https://getstream.io/chat/flutter/tutorial/) +- [Chat UI Kit](https://getstream.io/chat/ui-kit/) + +## Flutter Chat Tutorial + +The best place to start is the [Flutter Chat Tutorial](https://getstream.io/chat/flutter/tutorial/). +It teaches you how to use this SDK and also shows how to make frequently required changes. + +## Example App + +This repo includes a fully functional example app with setup instructions. +The example is available under the [example](https://github.com/GetStream/stream-chat-flutter/tree/master/example) folder. + +## Add dependency +Add this to your package's pubspec.yaml file, use the latest version [![Pub](https://img.shields.io/pub/v/stream_chat_flutter.svg)](https://pub.dartlang.org/packages/stream_chat_flutter) +```yaml +dependencies: + stream_chat_flutter_core: ^latest_version +``` + +You should then run `flutter packages get` + +This package requires no custom setup on any platform since it does not depend on any platform-specific dependency + +## Docs + +This package provides business logic to fetch common things required for integrating Stream Chat into your application. +The core package allows more customisation and hence provides business logic but no UI components. +Please use the stream_chat_flutter package for the full fledged suite of UI components. + +### Business logic components + +We provide widgets dedicated to business logic and state management: + +- [StreamChatCore](https://pub.dev/documentation/stream_chat_flutter/latest/stream_chat_flutter/StreamChat-class.html) +- [StreamChannel](https://pub.dev/documentation/stream_chat_flutter/latest/stream_chat_flutter/StreamChannel-class.html) +- [ChannelsBloc](https://pub.dev/documentation/stream_chat_flutter/0.2.0-alpha+2/stream_chat_flutter/ChannelsBloc-class.html) +- [MessageSearchBloc] +- [UsersBloc] +- [ChannelListCore] +- [MessageListCore] +- [MessageSearchListCore] +- [UserListCore] + +## Contributing + +We welcome code changes that improve this library or fix a problem, +please make sure to follow all best practices and add tests if applicable before submitting a Pull Request on Github. +We are pleased to merge your code into the official repository. +Make sure to sign our [Contributor License Agreement (CLA)](https://docs.google.com/forms/d/e/1FAIpQLScFKsKkAJI7mhCr7K9rEIOpqIDThrWxuvxnwUq2XkHyG154vQ/viewform) first. +See our license file for more details. From 27ee546eb0d9762bcb82b01f3343b092b762f08d Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Tue, 26 Jan 2021 20:10:39 +0530 Subject: [PATCH 1045/1140] fix: Fix analysis issues --- .../lib/src/message_search_list_view.dart | 2 -- .../lib/src/user_list_view.dart | 32 ++++++++----------- 2 files changed, 14 insertions(+), 20 deletions(-) diff --git a/packages/flutter_widgets/lib/src/message_search_list_view.dart b/packages/flutter_widgets/lib/src/message_search_list_view.dart index 0e8f9223..f1711cb8 100644 --- a/packages/flutter_widgets/lib/src/message_search_list_view.dart +++ b/packages/flutter_widgets/lib/src/message_search_list_view.dart @@ -1,5 +1,3 @@ -import 'dart:convert'; - import 'package:flutter/material.dart'; import 'package:stream_chat/stream_chat.dart'; import 'package:stream_chat_flutter/src/info_tile.dart'; diff --git a/packages/flutter_widgets/lib/src/user_list_view.dart b/packages/flutter_widgets/lib/src/user_list_view.dart index 7027a875..30c5db76 100644 --- a/packages/flutter_widgets/lib/src/user_list_view.dart +++ b/packages/flutter_widgets/lib/src/user_list_view.dart @@ -1,5 +1,3 @@ -import 'dart:convert'; - import 'package:flutter/material.dart'; import 'package:stream_chat/stream_chat.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; @@ -252,23 +250,21 @@ class _UserListViewState extends State return widget.emptyBuilder(context); } - if (widget.emptyBuilder == null) { - return LayoutBuilder( - builder: (context, viewportConstraints) { - return SingleChildScrollView( - physics: AlwaysScrollableScrollPhysics(), - child: ConstrainedBox( - constraints: BoxConstraints( - minHeight: viewportConstraints.maxHeight, - ), - child: Center( - child: Text('There are no users currently'), - ), + return LayoutBuilder( + builder: (context, viewportConstraints) { + return SingleChildScrollView( + physics: AlwaysScrollableScrollPhysics(), + child: ConstrainedBox( + constraints: BoxConstraints( + minHeight: viewportConstraints.maxHeight, ), - ); - }, - ); - } + child: Center( + child: Text('There are no users currently'), + ), + ), + ); + }, + ); } Widget _buildListView( From 29837e23f5965ae10e1259d404c9d43b8f07bcf0 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Tue, 26 Jan 2021 21:37:20 +0530 Subject: [PATCH 1046/1140] fix: analysis issues --- .../example/lib/main.dart | 4 ++++ .../lib/src/channel_list_core.dart | 3 +++ .../lib/src/message_list_core.dart | 2 ++ .../lib/src/message_search_list_core.dart | 3 +++ .../lib/src/stream_channel.dart | 16 +++++++++++++++- .../lib/src/stream_chat_core.dart | 4 ++++ .../lib/src/user_list_core.dart | 12 ++++++++++++ 7 files changed, 43 insertions(+), 1 deletion(-) diff --git a/packages/stream_chat_flutter_core/example/lib/main.dart b/packages/stream_chat_flutter_core/example/lib/main.dart index 11655b66..496f7c82 100644 --- a/packages/stream_chat_flutter_core/example/lib/main.dart +++ b/packages/stream_chat_flutter_core/example/lib/main.dart @@ -4,6 +4,7 @@ void main() { runApp(MyApp()); } +// ignore: public_member_api_docs class MyApp extends StatelessWidget { // This widget is the root of your application. @override @@ -31,7 +32,9 @@ class MyApp extends StatelessWidget { } } +// ignore: public_member_api_docs class MyHomePage extends StatefulWidget { + // ignore: public_member_api_docs MyHomePage({Key key, this.title}) : super(key: key); // This widget is the home page of your application. It is stateful, meaning @@ -43,6 +46,7 @@ class MyHomePage extends StatefulWidget { // used by the build method of the State. Fields in a Widget subclass are // always marked "final". + // ignore: public_member_api_docs final String title; @override diff --git a/packages/stream_chat_flutter_core/lib/src/channel_list_core.dart b/packages/stream_chat_flutter_core/lib/src/channel_list_core.dart index 5b992470..41c6f81d 100644 --- a/packages/stream_chat_flutter_core/lib/src/channel_list_core.dart +++ b/packages/stream_chat_flutter_core/lib/src/channel_list_core.dart @@ -261,6 +261,9 @@ class _ChannelListCoreState extends State /// Controller used for paginating data in [ChannelListCore] class ChannelListController { + /// Call this function to reload data VoidCallback loadData; + + /// Call this function to load further data VoidCallback paginateData; } diff --git a/packages/stream_chat_flutter_core/lib/src/message_list_core.dart b/packages/stream_chat_flutter_core/lib/src/message_list_core.dart index 6ef92569..1cd5162e 100644 --- a/packages/stream_chat_flutter_core/lib/src/message_list_core.dart +++ b/packages/stream_chat_flutter_core/lib/src/message_list_core.dart @@ -68,6 +68,7 @@ class MessageListCore extends StatefulWidget { /// Use [ChannelListController.paginateData] pagination. final MessageListController messageListController; + /// Function called when messages are fetched final Widget Function(BuildContext, List) messageListBuilder; /// Function used to build a loading widget @@ -168,5 +169,6 @@ class _MessageListCoreState extends State { /// Controller used for paginating data in [ChannelListView] class MessageListController { + /// Call this function to load further data Function({QueryDirection direction}) paginateData; } diff --git a/packages/stream_chat_flutter_core/lib/src/message_search_list_core.dart b/packages/stream_chat_flutter_core/lib/src/message_search_list_core.dart index de0af711..e5ff9527 100644 --- a/packages/stream_chat_flutter_core/lib/src/message_search_list_core.dart +++ b/packages/stream_chat_flutter_core/lib/src/message_search_list_core.dart @@ -196,6 +196,9 @@ class _MessageSearchListCoreState extends State { /// Controller used for paginating data in [ChannelListView] class MessageSearchListController { + /// Call this function to reload data VoidCallback loadData; + + /// Call this function to load further data VoidCallback paginateData; } diff --git a/packages/stream_chat_flutter_core/lib/src/stream_channel.dart b/packages/stream_chat_flutter_core/lib/src/stream_channel.dart index 8b4b97ef..85f7ecca 100644 --- a/packages/stream_chat_flutter_core/lib/src/stream_channel.dart +++ b/packages/stream_chat_flutter_core/lib/src/stream_channel.dart @@ -4,12 +4,20 @@ import 'package:flutter/material.dart'; import 'package:rxdart/rxdart.dart'; import 'package:stream_chat/stream_chat.dart'; -enum QueryDirection { top, bottom } +/// Specifies query direction for pagination +enum QueryDirection { + /// Query earlier messages + top, + + /// Query later messages + bottom, +} /// Widget used to provide information about the channel to the widget tree /// /// Use [StreamChannel.of] to get the current [StreamChannelState] instance. class StreamChannel extends StatefulWidget { + // ignore: public_member_api_docs const StreamChannel({ Key key, @required this.child, @@ -20,8 +28,13 @@ class StreamChannel extends StatefulWidget { assert(channel != null), super(key: key); + // ignore: public_member_api_docs final Widget child; + + /// [channel] specifies the channel with which child should be wrapped final Channel channel; + + /// Shows a loading indicator final bool showLoading; /// If passed the channel will load from this particular message. @@ -45,6 +58,7 @@ class StreamChannel extends StatefulWidget { StreamChannelState createState() => StreamChannelState(); } +// ignore: public_member_api_docs class StreamChannelState extends State { /// Current channel Channel get channel => widget.channel; diff --git a/packages/stream_chat_flutter_core/lib/src/stream_chat_core.dart b/packages/stream_chat_flutter_core/lib/src/stream_chat_core.dart index e8312638..b04542fc 100644 --- a/packages/stream_chat_flutter_core/lib/src/stream_chat_core.dart +++ b/packages/stream_chat_flutter_core/lib/src/stream_chat_core.dart @@ -26,9 +26,12 @@ import 'package:stream_chat/stream_chat.dart'; /// /// Use [StreamChatCore.of] to get the current [StreamChatCoreState] instance. class StreamChatCore extends StatefulWidget { + // ignore: public_member_api_docs final Client client; + // ignore: public_member_api_docs final Widget child; + // ignore: public_member_api_docs StreamChatCore({ Key key, @required this.client, @@ -58,6 +61,7 @@ class StreamChatCore extends StatefulWidget { /// The current state of the StreamChat widget class StreamChatCoreState extends State with WidgetsBindingObserver { + // ignore: public_member_api_docs Client get client => widget.client; Timer _disconnectTimer; diff --git a/packages/stream_chat_flutter_core/lib/src/user_list_core.dart b/packages/stream_chat_flutter_core/lib/src/user_list_core.dart index d08e06ae..e323591f 100644 --- a/packages/stream_chat_flutter_core/lib/src/user_list_core.dart +++ b/packages/stream_chat_flutter_core/lib/src/user_list_core.dart @@ -249,7 +249,9 @@ class _UserListCoreState extends State } } +// ignore: public_member_api_docs abstract class ListItem { + // ignore: public_member_api_docs String get key { if (this is ListHeaderItem) { final header = (this as ListHeaderItem).heading; @@ -262,6 +264,7 @@ abstract class ListItem { return null; } + // ignore: public_member_api_docs Widget when({ @required Widget Function(String heading) headerItem, @required Widget Function(User user) userItem, @@ -276,20 +279,29 @@ abstract class ListItem { } } +// ignore: public_member_api_docs class ListHeaderItem extends ListItem { + // ignore: public_member_api_docs final String heading; + // ignore: public_member_api_docs ListHeaderItem(this.heading); } +// ignore: public_member_api_docs class ListUserItem extends ListItem { + // ignore: public_member_api_docs final User user; + // ignore: public_member_api_docs ListUserItem(this.user); } /// Controller used for paginating data in [ChannelListView] class UserListController { + /// Call this function to reload data VoidCallback loadData; + + /// Call this function to load further data VoidCallback paginateData; } From 882b60bb8e038d07eab271fdd195e126673c2f4c Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Tue, 26 Jan 2021 21:47:12 +0530 Subject: [PATCH 1047/1140] fix: added stream_chat --- packages/flutter_widgets/pubspec.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/flutter_widgets/pubspec.yaml b/packages/flutter_widgets/pubspec.yaml index 059d4fb2..80f5da1e 100644 --- a/packages/flutter_widgets/pubspec.yaml +++ b/packages/flutter_widgets/pubspec.yaml @@ -14,6 +14,7 @@ dependencies: # TODO: Change over to main dependency when deployed stream_chat_flutter_core: path: ../stream_chat_flutter_core + stream_chat: ^0.2.24+1 flutter_app_badger: ^1.1.2 photo_view: ^0.10.3 rxdart: ^0.24.1 From bc53c7aa026aa5501293c8b23f44d51652aa6e76 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Tue, 26 Jan 2021 21:55:23 +0530 Subject: [PATCH 1048/1140] fix: dry run stuff --- packages/stream_chat_flutter_core/pubspec.yaml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/stream_chat_flutter_core/pubspec.yaml b/packages/stream_chat_flutter_core/pubspec.yaml index e318c67d..0a9be7a8 100644 --- a/packages/stream_chat_flutter_core/pubspec.yaml +++ b/packages/stream_chat_flutter_core/pubspec.yaml @@ -1,8 +1,9 @@ name: stream_chat_flutter_core -description: Stream Chat Official Flutter SDK Core. Build and customize your own chat experience using Dart and Flutter. +homepage: https://github.com/GetStream/stream-chat-flutter +description: Stream Chat official Flutter SDK Core. Build your own chat experience using Dart and Flutter. version: 0.0.1 -author: -homepage: +repository: https://github.com/GetStream/stream-chat-flutter +issue_tracker: https://github.com/GetStream/stream-chat-flutter/issues environment: sdk: ">=2.7.0 <3.0.0" From 6983b05a7258c1735a64f6d1b85ba75e2095f875 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Tue, 26 Jan 2021 22:59:52 +0530 Subject: [PATCH 1049/1140] fix: analysis and text --- packages/flutter_widgets/pubspec.yaml | 1 - .../lib/stream_chat_flutter_core.dart | 1 + .../stream_chat_flutter_core/pubspec.yaml | 1 + .../stream_chat_flutter_core/test/mocks.dart | 10 ++ .../test/stream_chat_flutter_core_test.dart | 93 ++++++++++++++++++- 5 files changed, 104 insertions(+), 2 deletions(-) create mode 100644 packages/stream_chat_flutter_core/test/mocks.dart diff --git a/packages/flutter_widgets/pubspec.yaml b/packages/flutter_widgets/pubspec.yaml index 80f5da1e..059d4fb2 100644 --- a/packages/flutter_widgets/pubspec.yaml +++ b/packages/flutter_widgets/pubspec.yaml @@ -14,7 +14,6 @@ dependencies: # TODO: Change over to main dependency when deployed stream_chat_flutter_core: path: ../stream_chat_flutter_core - stream_chat: ^0.2.24+1 flutter_app_badger: ^1.1.2 photo_view: ^0.10.3 rxdart: ^0.24.1 diff --git a/packages/stream_chat_flutter_core/lib/stream_chat_flutter_core.dart b/packages/stream_chat_flutter_core/lib/stream_chat_flutter_core.dart index d82b57fd..623c4424 100644 --- a/packages/stream_chat_flutter_core/lib/stream_chat_flutter_core.dart +++ b/packages/stream_chat_flutter_core/lib/stream_chat_flutter_core.dart @@ -10,3 +10,4 @@ export 'src/stream_channel.dart'; export 'src/stream_chat_core.dart'; export 'src/user_list_core.dart'; export 'src/users_bloc.dart'; +export 'package:stream_chat/stream_chat.dart'; diff --git a/packages/stream_chat_flutter_core/pubspec.yaml b/packages/stream_chat_flutter_core/pubspec.yaml index 0a9be7a8..c0c2a55a 100644 --- a/packages/stream_chat_flutter_core/pubspec.yaml +++ b/packages/stream_chat_flutter_core/pubspec.yaml @@ -16,6 +16,7 @@ dependencies: sdk: flutter dev_dependencies: + mockito: ^4.1.4 flutter_test: sdk: flutter diff --git a/packages/stream_chat_flutter_core/test/mocks.dart b/packages/stream_chat_flutter_core/test/mocks.dart new file mode 100644 index 00000000..37fa5530 --- /dev/null +++ b/packages/stream_chat_flutter_core/test/mocks.dart @@ -0,0 +1,10 @@ +import 'package:mockito/mockito.dart'; +import 'package:stream_chat/stream_chat.dart'; + +class MockClient extends Mock implements Client {} + +class MockClientState extends Mock implements ClientState {} + +class MockChannel extends Mock implements Channel {} + +class MockChannelState extends Mock implements ChannelClientState {} diff --git a/packages/stream_chat_flutter_core/test/stream_chat_flutter_core_test.dart b/packages/stream_chat_flutter_core/test/stream_chat_flutter_core_test.dart index ab73b3a2..be619db5 100644 --- a/packages/stream_chat_flutter_core/test/stream_chat_flutter_core_test.dart +++ b/packages/stream_chat_flutter_core/test/stream_chat_flutter_core_test.dart @@ -1 +1,92 @@ -void main() {} +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mockito/mockito.dart'; +import 'package:stream_chat/stream_chat.dart'; +import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; + +import 'mocks.dart'; + +void main() { + testWidgets( + 'it should show basic channel information', + (WidgetTester tester) async { + // final client = MockClient(); + // final clientState = MockClientState(); + // final channel = MockChannel(); + // final channelState = MockChannelState(); + // final lastMessageAt = DateTime.parse('2020-06-22 12:00:00'); + // + // when(client.state).thenReturn(clientState); + // when(clientState.user).thenReturn(OwnUser(id: 'user-id')); + // when(channel.lastMessageAt).thenReturn(lastMessageAt); + // when(channel.state).thenReturn(channelState); + // when(channel.client).thenReturn(client); + // when(channel.isMuted).thenReturn(false); + // when(channel.isMutedStream).thenAnswer((i) => Stream.value(false)); + // when(channel.extraDataStream).thenAnswer((i) => Stream.value({ + // 'name': 'test name', + // })); + // when(channel.extraData).thenReturn({ + // 'name': 'test name', + // }); + // when(channelState.unreadCount).thenReturn(1); + // when(channelState.unreadCountStream).thenAnswer((i) => Stream.value(1)); + // when(channelState.membersStream).thenAnswer((i) => Stream.value([ + // Member( + // userId: 'user-id', + // user: User(id: 'user-id'), + // ) + // ])); + // when(channelState.members).thenReturn([ + // Member( + // userId: 'user-id', + // user: User(id: 'user-id'), + // ), + // ]); + // when(channelState.messages).thenReturn([ + // Message( + // text: 'hello', + // user: User(id: 'other-user'), + // ) + // ]); + // when(channelState.messagesStream).thenAnswer((i) => Stream.value([ + // Message( + // text: 'hello', + // user: User(id: 'other-user'), + // ) + // ])); + + await tester.pumpWidget( + // MaterialApp( + // home: StreamChatCore( + // client: client, + // child: StreamChannel( + // channel: channel, + // child: Scaffold( + // body: MessageListCore( + // loadingBuilder: (context) { + // return Center(); + // }, + // emptyBuilder: (context) { + // return Center(); + // }, + // messageListBuilder: (context, list) { + // return ListView.builder( + // itemBuilder: (context, position) { + // return Text(list[position].text); + // }, + // itemCount: list.length, + // ); + // }, + // ), + // ), + // ), + // ), + // ), + MaterialApp(home: Scaffold(body: Text('hello'))), + ); + + expect(find.text('hello'), findsOneWidget); + }, + ); +} From 1521558304f536eea2baa8c3ac75a51eeb8edd81 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Wed, 27 Jan 2021 12:52:37 +0530 Subject: [PATCH 1050/1140] Make `stream_chat_persistence` a add on dependency instead of shipping it with the llc Signed-off-by: Sahil Kumar --- packages/dart_client/lib/src/api/channel.dart | 18 +++-- packages/dart_client/lib/src/client.dart | 55 ++++++-------- ...ence.dart => chat_persistence_client.dart} | 13 ++-- .../dart_client/lib/src/notifications.dart | 54 ++++---------- packages/dart_client/lib/stream_chat.dart | 2 +- .../example/lib/advanced_options_page.dart | 74 ++----------------- .../flutter_widgets/example/lib/main.dart | 9 ++- .../example/lib/notifications_service.dart | 14 +++- .../example/lib/routes/app_routes.dart | 6 ++ .../example/lib/routes/routes.dart | 1 + packages/flutter_widgets/example/pubspec.yaml | 4 +- .../lib/src/db/shared/unsupported_db.dart | 2 +- .../lib/src/mapper/channel_mapper.dart | 1 - ...rt => stream_chat_persistence_client.dart} | 57 +++++++------- .../lib/stream_chat_persistence.dart | 2 +- packages/stream_chat_persistence/pubspec.yaml | 1 + 16 files changed, 126 insertions(+), 187 deletions(-) rename packages/dart_client/lib/src/db/{stream_chat_persistence.dart => chat_persistence_client.dart} (95%) rename packages/stream_chat_persistence/lib/src/{stream_chat_persistence_impl.dart => stream_chat_persistence_client.dart} (79%) diff --git a/packages/dart_client/lib/src/api/channel.dart b/packages/dart_client/lib/src/api/channel.dart index a8952e34..3ba9aa1f 100644 --- a/packages/dart_client/lib/src/api/channel.dart +++ b/packages/dart_client/lib/src/api/channel.dart @@ -419,7 +419,7 @@ class Channel { } } - await _client.chatPersistence?.deleteMessageById(messageId); + await _client.chatPersistenceClient?.deleteMessageById(messageId); } return res; @@ -487,7 +487,7 @@ class Channel { PaginationParams options, { bool preferOffline = false, }) async { - final cachedReplies = await _client.chatPersistence?.getReplies( + final cachedReplies = await _client.chatPersistenceClient?.getReplies( parentId, lessThan: options?.lessThan, ); @@ -603,7 +603,8 @@ class Channel { } if (preferOffline && cid != null) { - final updatedState = await _client.chatPersistence?.getChannelStateByCid( + final updatedState = + await _client.chatPersistenceClient?.getChannelStateByCid( cid, messagePagination: messagesPagination, ); @@ -730,7 +731,7 @@ class Channel { if (clearHistory == true) { state.truncate(); - await _client.chatPersistence?.deleteMessageByCid(_cid); + await _client.chatPersistenceClient?.deleteMessageByCid(_cid); } return _client.decode(response.data, EmptyResponse.fromJson); @@ -869,7 +870,7 @@ class ChannelClientState { _computeInitialUnread(); - _channel._client.chatPersistence + _channel._client.chatPersistenceClient ?.getChannelThreads(_channel.cid) ?.then((threads) { _threads = threads; @@ -947,7 +948,8 @@ class ChannelClientState { .on(EventType.channelTruncated, EventType.notificationChannelTruncated) .listen((event) async { final channel = event.channel; - await _channel._client.chatPersistence?.deleteMessageByCid(channel.cid); + await _channel._client.chatPersistenceClient + ?.deleteMessageByCid(channel.cid); truncate(); })); } @@ -1401,7 +1403,7 @@ class ChannelClientState { set _channelState(ChannelState v) { _channelStateController.add(v); - _channel._client.chatPersistence?.updateChannelState(v); + _channel._client.chatPersistenceClient?.updateChannelState(v); } /// The channel threads related to this channel @@ -1414,7 +1416,7 @@ class ChannelClientState { BehaviorSubject.seeded({}); set _threads(Map> v) { - _channel._client.chatPersistence?.updateMessages( + _channel._client.chatPersistenceClient?.updateMessages( _channel.cid, v.values.expand((v) => v).toList(), ); diff --git a/packages/dart_client/lib/src/client.dart b/packages/dart_client/lib/src/client.dart index 99350636..714acbd5 100644 --- a/packages/dart_client/lib/src/client.dart +++ b/packages/dart_client/lib/src/client.dart @@ -6,7 +6,6 @@ import 'package:dio/dio.dart'; import 'package:flutter/cupertino.dart'; import 'package:logging/logging.dart'; import 'package:rxdart/rxdart.dart'; -import 'package:stream_chat_persistence/stream_chat_persistence.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:stream_chat/src/api/retry_policy.dart'; import 'package:stream_chat/src/event_type.dart'; @@ -21,7 +20,7 @@ import 'api/connection_status.dart'; import 'api/requests.dart'; import 'api/responses.dart'; import 'api/websocket.dart'; -import 'db/stream_chat_persistence.dart'; +import 'db/chat_persistence_client.dart'; import 'exceptions.dart'; import 'models/event.dart'; import 'models/message.dart'; @@ -87,7 +86,6 @@ class Client { this.baseURL = _defaultBaseURL, this.logLevel = Level.WARNING, this.logHandlerFunction, - this.persistenceEnabled = true, Duration connectTimeout = const Duration(seconds: 6), Duration receiveTimeout = const Duration(seconds: 6), Dio httpClient, @@ -111,10 +109,11 @@ class Client { logger.info('instantiating new client'); } - StreamChatPersistence _chatPersistence; + /// Client chat persistence client + ChatPersistenceClient chatPersistenceClient; - /// If true chat data will persist on disk - final bool persistenceEnabled; + /// Whether the chat persistence is available or not + bool get persistenceEnabled => chatPersistenceClient != null; RetryPolicy _retryPolicy; @@ -131,9 +130,6 @@ class Client { /// The amount of time that will pass before disconnecting the client in the background final Duration backgroundKeepAlive; - /// Client offline database - StreamChatPersistence get chatPersistence => _chatPersistence; - /// This client state ClientState state; @@ -345,7 +341,7 @@ class Client { /// Call this function to dispose the client void dispose() async { - await _chatPersistence?.disconnect(); + await chatPersistenceClient?.disconnect(); await _disconnect(); httpClient.close(); await _controller.close(); @@ -427,8 +423,8 @@ class Client { if (!event.isLocal) { if (_synced && event.createdAt != null) { - await _chatPersistence?.updateConnectionInfo(event); - await _chatPersistence?.updateLastSyncAt(event.createdAt); + await chatPersistenceClient?.updateConnectionInfo(event); + await chatPersistenceClient?.updateLastSyncAt(event.createdAt); } } @@ -459,12 +455,8 @@ class Client { wsConnectionStatus.value = ConnectionStatus.connecting; - if (persistenceEnabled && _chatPersistence == null) { - _chatPersistence = StreamChatPersistenceImpl( - state.user.id, - logger: _detachedLogger('💽'), - ); - await _chatPersistence.connect(); + if (persistenceEnabled) { + await chatPersistenceClient.connect('db_${state.user.id}'); } _ws = WebSocket( @@ -514,10 +506,10 @@ class Client { _ws.connectionStatus.addListener(_connectionStatusListener); - var event = await _chatPersistence?.getConnectionInfo(); + var event = await chatPersistenceClient?.getConnectionInfo(); await _ws.connect().then((e) async { - await _chatPersistence?.updateConnectionInfo(e); + await chatPersistenceClient?.updateConnectionInfo(e); event = e; await resync(); }).catchError((err, stacktrace) { @@ -532,14 +524,14 @@ class Client { /// Get the events missed while offline to sync the offline storage Future resync([List cids]) async { - final lastSyncAt = await chatPersistence?.getLastSyncAt(); + final lastSyncAt = await chatPersistenceClient?.getLastSyncAt(); if (lastSyncAt == null) { _synced = true; return; } - cids ??= await chatPersistence?.getChannelCids(); + cids ??= await chatPersistenceClient?.getChannelCids(); if (cids?.isEmpty == true) { return; @@ -568,7 +560,7 @@ class Client { handleEvent(event); }); - await _chatPersistence?.updateLastSyncAt(DateTime.now()); + await chatPersistenceClient?.updateLastSyncAt(DateTime.now()); _synced = true; } catch (error) { logger.severe('Error during resync $error'); @@ -714,7 +706,7 @@ class Client { channels.add(channel); } else { final newChannel = Channel.fromState(this, channelState); - await _chatPersistence + await chatPersistenceClient ?.updateChannelState(newChannel.state.channelState); newChannel.state?.updateChannelState(channelState); newChannels[newChannel.cid] = newChannel; @@ -725,7 +717,7 @@ class Client { state.channels = newChannels; - await _chatPersistence?.updateChannelQueries( + await chatPersistenceClient?.updateChannelQueries( filter, res.channels.map((c) => c.channel.cid).toList(), paginationParams?.offset == null || paginationParams.offset == 0, @@ -760,7 +752,7 @@ class Client { @required List sort, PaginationParams paginationParams = const PaginationParams(limit: 10), }) async { - final offlineChannels = await _chatPersistence?.getChannelStates( + final offlineChannels = await chatPersistenceClient?.getChannelStates( filter: filter, sort: sort, paginationParams: paginationParams, @@ -775,7 +767,8 @@ class Client { return channel; } else { final newChannel = Channel.fromState(this, channelState); - _chatPersistence?.updateChannelState(newChannel.state.channelState); + chatPersistenceClient + ?.updateChannelState(newChannel.state.channelState); newChannels[newChannel.cid] = newChannel; return newChannel; } @@ -938,8 +931,8 @@ class Client { logger.info( 'Disconnecting flushOfflineStorage: $flushChatPersistence; clearUser: $clearUser'); - await _chatPersistence?.disconnect(flush: flushChatPersistence); - _chatPersistence = null; + await chatPersistenceClient?.disconnect(flush: flushChatPersistence); + chatPersistenceClient = null; if (clearUser == true) { state.dispose(); @@ -1328,7 +1321,7 @@ class ClientState { void _listenChannelHidden() { _subscriptions.add(_client.on(EventType.channelHidden).listen((event) { - _client._chatPersistence?.deleteChannels([event.cid]); + _client.chatPersistenceClient?.deleteChannels([event.cid]); if (channels != null) { channels = channels..removeWhere((cid, ch) => cid == event.cid); } @@ -1353,7 +1346,7 @@ class ClientState { ) .listen((Event event) async { final eventChannel = event.channel; - await _client._chatPersistence?.deleteChannels([eventChannel.cid]); + await _client.chatPersistenceClient?.deleteChannels([eventChannel.cid]); if (channels != null) { channels = channels..remove(eventChannel.cid); } diff --git a/packages/dart_client/lib/src/db/stream_chat_persistence.dart b/packages/dart_client/lib/src/db/chat_persistence_client.dart similarity index 95% rename from packages/dart_client/lib/src/db/stream_chat_persistence.dart rename to packages/dart_client/lib/src/db/chat_persistence_client.dart index 40004825..c435df9e 100644 --- a/packages/dart_client/lib/src/db/stream_chat_persistence.dart +++ b/packages/dart_client/lib/src/db/chat_persistence_client.dart @@ -9,15 +9,12 @@ import 'package:stream_chat/src/models/read.dart'; import 'package:stream_chat/src/models/user.dart'; /// -abstract class StreamChatPersistence { - /// Creates a new connection to the database - Future connect({ - bool connectBackground = false, - bool logStatements = false, - }); +abstract class ChatPersistenceClient { + /// Creates a new connection to the client + Future connect(String name); - /// Closes the database instance - /// If [flush] is true, the database data will be deleted + /// Closes the client connection + /// If [flush] is true, the data will also be deleted Future disconnect({bool flush = false}); /// Get stored replies by messageId diff --git a/packages/dart_client/lib/src/notifications.dart b/packages/dart_client/lib/src/notifications.dart index e4cef9b5..82070fd2 100644 --- a/packages/dart_client/lib/src/notifications.dart +++ b/packages/dart_client/lib/src/notifications.dart @@ -1,12 +1,11 @@ import 'dart:convert'; -import 'package:logging/logging.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:stream_chat/src/api/responses.dart'; import 'package:stream_chat/src/models/channel_model.dart'; import 'package:stream_chat/src/models/channel_state.dart'; import 'package:stream_chat/src/models/message.dart'; -import 'package:stream_chat_persistence/stream_chat_persistence.dart'; +import 'package:meta/meta.dart'; import 'client.dart'; import 'models/own_user.dart'; @@ -20,21 +19,13 @@ class NotificationService { ) async { if (message != null && client.persistenceEnabled) { if (client?.state?.channels == null) { - final sharedPreferences = await _getSharedPreferences(); - final userId = sharedPreferences.getString(KEY_USER_ID); - - final chatPersistence = StreamChatPersistenceImpl( - userId, - logger: Logger('💽'), - ); - await chatPersistence.connect(); - await chatPersistence.updateChannelState( + final chatPersistenceClient = client.chatPersistenceClient; + await chatPersistenceClient.updateChannelState( ChannelState( channel: channelModel, messages: [message], ), ); - await chatPersistence.disconnect(); } else { final channel = client.state.channels[channelModel.cid]; channel.state.updateChannelState( @@ -56,14 +47,11 @@ class NotificationService { /// Gets the message using the client without storing it in the offline storage /// It returns an object containing the information about the message and the channel - static Future getMessage(String messageId) async { + static Future _getMessage(String messageId) async { final sharedPreferences = await _getSharedPreferences(); final apiKey = sharedPreferences.getString(KEY_API_KEY); - final client = Client( - apiKey, - persistenceEnabled: false, - ); + final client = Client(apiKey); final userId = sharedPreferences.getString(KEY_USER_ID); final token = sharedPreferences.getString(KEY_TOKEN); @@ -74,30 +62,16 @@ class NotificationService { return res; } - /// Stores the message in the offline storage - static Future storeMessage(GetMessageResponse messageResponse) async { - final sharedPreferences = await _getSharedPreferences(); - final userId = sharedPreferences.getString(KEY_USER_ID); - - final chatPersistence = StreamChatPersistenceImpl( - userId, - logger: Logger('💽'), - ); - await chatPersistence.connect(); - - await chatPersistence.updateChannelState(ChannelState( - messages: [messageResponse.message], - channel: messageResponse.channel, - )); - - await chatPersistence.disconnect(); - } - - /// Gets the message using the client and stores it in the offline storage + /// Gets the message using the client and calls a [storeMessageHandler] callback + /// with the message if the user wants to save the message in db + /// /// It returns an object containing the information about the message and the channel - static Future getAndStoreMessage(String messageId) async { - final getMessageResponse = await getMessage(messageId); - await storeMessage(getMessageResponse); + static Future getAndStoreMessage({ + @required String messageId, + @required Future Function(GetMessageResponse) storeMessageHandler, + }) async { + final getMessageResponse = await _getMessage(messageId); + await storeMessageHandler(getMessageResponse); return getMessageResponse; } diff --git a/packages/dart_client/lib/stream_chat.dart b/packages/dart_client/lib/stream_chat.dart index 0ff1f871..00525b40 100644 --- a/packages/dart_client/lib/stream_chat.dart +++ b/packages/dart_client/lib/stream_chat.dart @@ -27,4 +27,4 @@ export './src/models/reaction.dart'; export './src/models/read.dart'; export './src/models/user.dart'; export './src/notifications.dart'; -export './src/db/stream_chat_persistence.dart'; \ No newline at end of file +export './src/db/chat_persistence_client.dart'; diff --git a/packages/flutter_widgets/example/lib/advanced_options_page.dart b/packages/flutter_widgets/example/lib/advanced_options_page.dart index 023ce32c..915bcfcb 100644 --- a/packages/flutter_widgets/example/lib/advanced_options_page.dart +++ b/packages/flutter_widgets/example/lib/advanced_options_page.dart @@ -8,9 +8,11 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_secure_storage/flutter_secure_storage.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; +import 'package:stream_chat_persistence/stream_chat_persistence.dart'; import 'package:streaming_shared_preferences/streaming_shared_preferences.dart'; import 'choose_user_page.dart'; +import 'main.dart'; import 'notifications_service.dart'; class AdvancedOptionsPage extends StatefulWidget { @@ -278,8 +280,7 @@ class _AdvancedOptionsPageState extends State { showLocalNotification: (!kIsWeb && Platform.isAndroid) ? showLocalNotification : null, - persistenceEnabled: true, - ); + )..chatPersistenceClient = chatPersistentClient; try { await client.setUser( @@ -320,72 +321,13 @@ class _AdvancedOptionsPageState extends State { return; } - if (!kIsWeb) { - initNotifications(client); - } - Navigator.pop(context); - Navigator.pop(context); - await Navigator.pushReplacement( - context, - MaterialPageRoute( - builder: (context) { - return FutureBuilder( - future: StreamingSharedPreferences.instance, - builder: (context, snapshot) { - if (!snapshot.hasData) { - return SizedBox(); - } - return PreferenceBuilder( - preference: snapshot.data.getInt( - 'theme', - defaultValue: 0, - ), - builder: (context, snapshot) => MaterialApp( - builder: (context, child) { - return StreamChat( - client: client, - child: Builder( - builder: (context) => - AnnotatedRegion< - SystemUiOverlayStyle>( - child: child, - value: SystemUiOverlayStyle( - systemNavigationBarColor: - StreamChatTheme.of(context) - .colorTheme - .white, - systemNavigationBarIconBrightness: - Theme.of(context) - .brightness == - Brightness.dark - ? Brightness.light - : Brightness.dark, - ), - ), - ), - ); - }, - debugShowCheckedModeBanner: false, - theme: ThemeData.light(), - darkTheme: ThemeData.dark(), - themeMode: { - -1: ThemeMode.dark, - 0: ThemeMode.system, - 1: ThemeMode.light, - }[snapshot], - onGenerateRoute: AppRoutes.generateRoute, - initialRoute: client.state.user == null - ? Routes.CHOOSE_USER - : Routes.HOME, - ), - ); - }, - ); - }, - ), - ); loading = false; + await Navigator.pushReplacementNamed( + context, + Routes.APP, + arguments: client, + ); } }, ), diff --git a/packages/flutter_widgets/example/lib/main.dart b/packages/flutter_widgets/example/lib/main.dart index 10d73997..caa11198 100644 --- a/packages/flutter_widgets/example/lib/main.dart +++ b/packages/flutter_widgets/example/lib/main.dart @@ -10,6 +10,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_secure_storage/flutter_secure_storage.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; +import 'package:stream_chat_persistence/stream_chat_persistence.dart'; import 'package:streaming_shared_preferences/streaming_shared_preferences.dart'; import 'notifications_service.dart'; @@ -17,6 +18,11 @@ import 'routes/app_routes.dart'; import 'routes/routes.dart'; import 'search_text_field.dart'; +final chatPersistentClient = StreamChatPersistenceClient( + logLevel: Level.INFO, + connectionMode: ConnectionMode.background, +); + void main() async { WidgetsFlutterBinding.ensureInitialized(); final secureStorage = FlutterSecureStorage(); @@ -29,8 +35,7 @@ void main() async { logLevel: Level.INFO, showLocalNotification: (!kIsWeb && Platform.isAndroid) ? showLocalNotification : null, - persistenceEnabled: true, - ); + )..chatPersistenceClient = chatPersistentClient; if (userId != null) { final token = await secureStorage.read(key: kStreamToken); diff --git a/packages/flutter_widgets/example/lib/notifications_service.dart b/packages/flutter_widgets/example/lib/notifications_service.dart index 298ab3ab..0eeb9cc0 100644 --- a/packages/flutter_widgets/example/lib/notifications_service.dart +++ b/packages/flutter_widgets/example/lib/notifications_service.dart @@ -1,5 +1,6 @@ import 'dart:io'; +import 'package:example/main.dart'; import 'package:flutter_apns/flutter_apns.dart'; import 'package:flutter_local_notifications/flutter_local_notifications.dart' hide Message; @@ -36,8 +37,17 @@ Future backgroundHandler(Map notification) async { print('new notification ${notification}'); final messageId = notification['data']['id']; - final notificationData = - await NotificationService.getAndStoreMessage(messageId); + final notificationData = await NotificationService.getAndStoreMessage( + messageId: messageId, + storeMessageHandler: (messageResponse) { + return chatPersistentClient.updateChannelState( + ChannelState( + messages: [messageResponse.message], + channel: messageResponse.channel, + ), + ); + }, + ); showLocalNotification( notificationData.message, diff --git a/packages/flutter_widgets/example/lib/routes/app_routes.dart b/packages/flutter_widgets/example/lib/routes/app_routes.dart index 0c8a899f..e7c7e318 100644 --- a/packages/flutter_widgets/example/lib/routes/app_routes.dart +++ b/packages/flutter_widgets/example/lib/routes/app_routes.dart @@ -15,6 +15,12 @@ class AppRoutes { static Route generateRoute(RouteSettings settings) { final args = settings.arguments; switch (settings.name) { + case Routes.APP: + return MaterialPageRoute( + settings: const RouteSettings(name: Routes.APP), + builder: (_) { + return MyApp(args); + }); case Routes.HOME: return MaterialPageRoute( settings: const RouteSettings(name: Routes.HOME), diff --git a/packages/flutter_widgets/example/lib/routes/routes.dart b/packages/flutter_widgets/example/lib/routes/routes.dart index 0d2f4e5f..2280ca30 100644 --- a/packages/flutter_widgets/example/lib/routes/routes.dart +++ b/packages/flutter_widgets/example/lib/routes/routes.dart @@ -1,5 +1,6 @@ /// Define all the route names here class Routes { + static const String APP = '/app'; static const String HOME = '/home'; static const String CHOOSE_USER = '/choose_user'; static const String ADVANCED_OPTIONS = '/advance_options'; diff --git a/packages/flutter_widgets/example/pubspec.yaml b/packages/flutter_widgets/example/pubspec.yaml index fea15136..1a3f93df 100644 --- a/packages/flutter_widgets/example/pubspec.yaml +++ b/packages/flutter_widgets/example/pubspec.yaml @@ -9,8 +9,10 @@ environment: dependencies: flutter: sdk: flutter - stream_chat_flutter: + stream_chat_flutter: path: ../ + stream_chat_persistence: + path: ../../stream_chat_persistence flutter_apns: ^1.4.1 flutter_local_notifications: ^2.0.2 flutter_svg: ^0.19.1 diff --git a/packages/stream_chat_persistence/lib/src/db/shared/unsupported_db.dart b/packages/stream_chat_persistence/lib/src/db/shared/unsupported_db.dart index 7415fdba..647314eb 100644 --- a/packages/stream_chat_persistence/lib/src/db/shared/unsupported_db.dart +++ b/packages/stream_chat_persistence/lib/src/db/shared/unsupported_db.dart @@ -11,7 +11,7 @@ class SharedDB { static constructOfflineStorage( String dbName, { - logStatements = false, + bool logStatements = false, }) { throw 'Unsupported Platform'; } diff --git a/packages/stream_chat_persistence/lib/src/mapper/channel_mapper.dart b/packages/stream_chat_persistence/lib/src/mapper/channel_mapper.dart index cdabf17f..4d35340b 100644 --- a/packages/stream_chat_persistence/lib/src/mapper/channel_mapper.dart +++ b/packages/stream_chat_persistence/lib/src/mapper/channel_mapper.dart @@ -1,5 +1,4 @@ import 'package:stream_chat/stream_chat.dart'; -import 'user_mapper.dart'; import 'package:stream_chat_persistence/src/db/moor_chat_database.dart'; /// diff --git a/packages/stream_chat_persistence/lib/src/stream_chat_persistence_impl.dart b/packages/stream_chat_persistence/lib/src/stream_chat_persistence_client.dart similarity index 79% rename from packages/stream_chat_persistence/lib/src/stream_chat_persistence_impl.dart rename to packages/stream_chat_persistence/lib/src/stream_chat_persistence_client.dart index 2d4caae8..72536b93 100644 --- a/packages/stream_chat_persistence/lib/src/stream_chat_persistence_impl.dart +++ b/packages/stream_chat_persistence/lib/src/stream_chat_persistence_client.dart @@ -3,18 +3,30 @@ import 'package:stream_chat/stream_chat.dart'; import 'db/moor_chat_database.dart'; import 'db/shared/shared_db.dart'; +/// Various connection modes on which [StreamChatPersistenceClient] can work +enum ConnectionMode { + /// Connects the [StreamChatPersistenceClient] on a regular/default isolate + regular, + + /// Connects the [StreamChatPersistenceClient] on a background isolate + background, +} + /// -class StreamChatPersistenceImpl extends StreamChatPersistence { +class StreamChatPersistenceClient extends ChatPersistenceClient { /// - StreamChatPersistenceImpl( - this._userId, { - Logger logger, - }) : _logger = logger, - assert(_userId != null); + StreamChatPersistenceClient({ + /// Connection mode on which the client will work + ConnectionMode connectionMode = ConnectionMode.regular, + Level logLevel = Level.WARNING, + }) : assert(connectionMode != null), + assert(logLevel != null), + _connectionMode = connectionMode, + _logger = Logger.detached('💽')..level = logLevel; - final String _userId; - final Logger _logger; MoorChatDatabase _db; + final Logger _logger; + final ConnectionMode _connectionMode; bool get _debugAssertConnected { assert(() { @@ -30,27 +42,22 @@ class StreamChatPersistenceImpl extends StreamChatPersistence { } @override - Future connect({ - bool connectBackground = false, - bool logStatements = false, - }) async { + Future connect(String name) async { if (_db != null) { throw Exception( 'An instance of StreamChatDatabase is already connected.\n' 'disconnect the previous instance before connecting again.', ); } - - final dbName = 'db_$_userId'; - if (connectBackground) { - _logger?.info('Connecting on background isolate'); - _db = await SharedDB.constructOfflineStorage( - dbName, - logStatements: logStatements, - ); - } else { - _logger?.info('Connecting on a regular isolate'); - _db = MoorChatDatabase(dbName, logStatements: logStatements); + switch (_connectionMode) { + case ConnectionMode.regular: + _logger.info('Connecting on a regular isolate'); + _db = MoorChatDatabase(name); + return; + case ConnectionMode.background: + _logger.info('Connecting on background isolate'); + _db = await SharedDB.constructOfflineStorage(name); + return; } } @@ -202,9 +209,9 @@ class StreamChatPersistenceImpl extends StreamChatPersistence { @override Future disconnect({bool flush = false}) async { if (_db != null) { - _logger?.info('Disconnecting'); + _logger.info('Disconnecting'); if (flush) { - _logger?.info('Flushing'); + _logger.info('Flushing'); await _db.batch((batch) { _db.allTables.forEach((table) { _db.delete(table).go(); diff --git a/packages/stream_chat_persistence/lib/stream_chat_persistence.dart b/packages/stream_chat_persistence/lib/stream_chat_persistence.dart index 3d58cb17..5f9aff5b 100644 --- a/packages/stream_chat_persistence/lib/stream_chat_persistence.dart +++ b/packages/stream_chat_persistence/lib/stream_chat_persistence.dart @@ -1,3 +1,3 @@ library stream_chat_persistence; -export 'src/stream_chat_persistence_impl.dart'; +export 'src/stream_chat_persistence_client.dart'; diff --git a/packages/stream_chat_persistence/pubspec.yaml b/packages/stream_chat_persistence/pubspec.yaml index 1ce6e604..a0c97c89 100644 --- a/packages/stream_chat_persistence/pubspec.yaml +++ b/packages/stream_chat_persistence/pubspec.yaml @@ -11,6 +11,7 @@ dependencies: moor: ^3.4.0 path: ^1.7.0 path_provider: ^1.6.27 + sqlite3_flutter_libs: ^0.3.0 stream_chat: path: ../dart_client From 00b561e0185616c71c5071764a60540da8da297b Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Wed, 27 Jan 2021 12:55:22 +0530 Subject: [PATCH 1051/1140] [LLC] Remove `stream_chat_persistence_client` dependency Signed-off-by: Sahil Kumar --- packages/dart_client/pubspec.yaml | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/dart_client/pubspec.yaml b/packages/dart_client/pubspec.yaml index 5eca907a..99d6794b 100644 --- a/packages/dart_client/pubspec.yaml +++ b/packages/dart_client/pubspec.yaml @@ -21,8 +21,6 @@ dependencies: rxdart: ^0.24.1 collection: ^1.14.12 pedantic: ^1.9.2 - stream_chat_persistence: - path: ../stream_chat_persistence dev_dependencies: build_runner: ^1.10.0 From e74a0d40ff61c5dc0e4fa554848651cd886910ed Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Wed, 27 Jan 2021 14:08:37 +0530 Subject: [PATCH 1052/1140] [LLC] Fix tests Signed-off-by: Sahil Kumar --- .../dart_client/test/src/client_test.dart | 50 ++----------------- 1 file changed, 3 insertions(+), 47 deletions(-) diff --git a/packages/dart_client/test/src/client_test.dart b/packages/dart_client/test/src/client_test.dart index 8f4dc41e..011789be 100644 --- a/packages/dart_client/test/src/client_test.dart +++ b/packages/dart_client/test/src/client_test.dart @@ -41,10 +41,7 @@ void main() { }); test('should create the object correctly', () { - final client = Client( - 'api-key', - persistenceEnabled: false, - ); + final client = Client('api-key'); expect(client.baseURL, 'chat-us-east-1.stream-io-api.com'); expect(client.apiKey, 'api-key'); @@ -60,7 +57,6 @@ void main() { final client = Client( 'api-key', - persistenceEnabled: false, connectTimeout: Duration(seconds: 10), receiveTimeout: Duration(seconds: 12), logLevel: Level.INFO, @@ -82,10 +78,7 @@ void main() { })); test('Channel', () { - final client = Client( - 'test', - persistenceEnabled: false, - ); + final client = Client('test'); final Map data = {'test': 1}; final channelClient = client.channel('type', id: 'id', extraData: data); expect(channelClient.type, 'type'); @@ -103,7 +96,6 @@ void main() { final client = Client( 'api-key', httpClient: mockDio, - persistenceEnabled: false, ); final queryParams = { @@ -135,7 +127,6 @@ void main() { final client = Client( 'api-key', httpClient: mockDio, - persistenceEnabled: false, ); final queryFilter = { @@ -186,7 +177,6 @@ void main() { final client = Client( 'api-key', - persistenceEnabled: false, httpClient: mockDio, ); @@ -215,7 +205,6 @@ void main() { final client = Client( 'api-key', - persistenceEnabled: false, httpClient: mockDio, ); @@ -260,7 +249,6 @@ void main() { final client = Client( 'api-key', - persistenceEnabled: false, httpClient: mockDio, ); @@ -287,7 +275,6 @@ void main() { final client = Client( 'api-key', - persistenceEnabled: false, httpClient: mockDio, ); @@ -307,7 +294,6 @@ void main() { final client = Client( 'api-key', - persistenceEnabled: false, httpClient: mockDio, ); @@ -323,10 +309,7 @@ void main() { }); test('devToken', () { - final client = Client( - 'api-key', - persistenceEnabled: false, - ); + final client = Client('api-key'); final token = client.devToken('test'); expect( @@ -344,7 +327,6 @@ void main() { final client = Client( 'api-key', - persistenceEnabled: false, httpClient: mockDio, ); @@ -373,7 +355,6 @@ void main() { final client = Client( 'api-key', - persistenceEnabled: false, httpClient: mockDio, ); @@ -417,7 +398,6 @@ void main() { final client = Client( 'api-key', - persistenceEnabled: false, httpClient: mockDio, ); @@ -439,7 +419,6 @@ void main() { final client = Client( 'api-key', - persistenceEnabled: false, httpClient: mockDio, ); @@ -455,7 +434,6 @@ void main() { final client = Client( 'api-key', - persistenceEnabled: false, httpClient: mockDio, ); @@ -477,7 +455,6 @@ void main() { final client = Client( 'api-key', - persistenceEnabled: false, httpClient: mockDio, ); @@ -503,7 +480,6 @@ void main() { final client = Client( 'api-key', - persistenceEnabled: false, httpClient: mockDio, ); @@ -533,7 +509,6 @@ void main() { final client = Client( 'api-key', - persistenceEnabled: false, httpClient: mockDio, ); @@ -555,7 +530,6 @@ void main() { final client = Client( 'api-key', - persistenceEnabled: false, httpClient: mockDio, ); @@ -578,7 +552,6 @@ void main() { final client = Client( 'api-key', - persistenceEnabled: false, httpClient: mockDio, ); @@ -600,7 +573,6 @@ void main() { final client = Client( 'api-key', - persistenceEnabled: false, httpClient: mockDio, ); @@ -624,7 +596,6 @@ void main() { final client = Client( 'api-key', - persistenceEnabled: false, httpClient: mockDio, ); @@ -646,7 +617,6 @@ void main() { final client = Client( 'api-key', - persistenceEnabled: false, httpClient: mockDio, ); @@ -668,7 +638,6 @@ void main() { final client = Client( 'api-key', - persistenceEnabled: false, httpClient: mockDio, ); @@ -696,7 +665,6 @@ void main() { final client = Client( 'api-key', - persistenceEnabled: false, httpClient: mockDio, ); @@ -718,7 +686,6 @@ void main() { final client = Client( 'api-key', - persistenceEnabled: false, httpClient: mockDio, ); @@ -740,7 +707,6 @@ void main() { final client = Client( 'api-key', - persistenceEnabled: false, httpClient: mockDio, ); @@ -763,7 +729,6 @@ void main() { final client = Client( 'api-key', - persistenceEnabled: false, httpClient: mockDio, ); @@ -789,7 +754,6 @@ void main() { final client = Client( 'api-key', - persistenceEnabled: false, httpClient: dioHttp, ); @@ -809,7 +773,6 @@ void main() { final client = Client( 'api-key', - persistenceEnabled: false, httpClient: mockDio, ); @@ -833,7 +796,6 @@ void main() { final client = Client( 'api-key', - persistenceEnabled: false, httpClient: dioHttp, ); @@ -853,7 +815,6 @@ void main() { final client = Client( 'api-key', - persistenceEnabled: false, httpClient: mockDio, ); @@ -877,7 +838,6 @@ void main() { final client = Client( 'api-key', - persistenceEnabled: false, httpClient: dioHttp, ); @@ -897,7 +857,6 @@ void main() { final client = Client( 'api-key', - persistenceEnabled: false, httpClient: mockDio, ); @@ -922,7 +881,6 @@ void main() { final client = Client( 'api-key', - persistenceEnabled: false, httpClient: dioHttp, ); @@ -942,7 +900,6 @@ void main() { final client = Client( 'api-key', - persistenceEnabled: false, httpClient: mockDio, ); @@ -968,7 +925,6 @@ void main() { final client = Client( 'api-key', - persistenceEnabled: false, httpClient: dioHttp, ); From 3b9af052143858a34ed7f7009c983ffe49093cdf Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Wed, 27 Jan 2021 15:51:55 +0530 Subject: [PATCH 1053/1140] [StreamChatPersistence] Fix ownReactions userId bug Signed-off-by: Sahil Kumar --- packages/dart_client/lib/src/client.dart | 2 +- .../lib/src/db/chat_persistence_client.dart | 2 +- .../lib/src/dao/message_dao.dart | 4 ++-- .../lib/src/dao/reaction_dao.dart | 2 +- .../lib/src/db/moor_chat_database.dart | 14 ++++++++++---- .../lib/src/db/shared/native_db.dart | 8 +++++--- .../lib/src/db/shared/unsupported_db.dart | 4 ++-- .../lib/src/db/shared/web_db.dart | 6 ++++-- .../lib/src/stream_chat_persistence_client.dart | 6 +++--- 9 files changed, 29 insertions(+), 19 deletions(-) diff --git a/packages/dart_client/lib/src/client.dart b/packages/dart_client/lib/src/client.dart index 714acbd5..f2a6f0c0 100644 --- a/packages/dart_client/lib/src/client.dart +++ b/packages/dart_client/lib/src/client.dart @@ -456,7 +456,7 @@ class Client { wsConnectionStatus.value = ConnectionStatus.connecting; if (persistenceEnabled) { - await chatPersistenceClient.connect('db_${state.user.id}'); + await chatPersistenceClient.connect(state.user.id); } _ws = WebSocket( diff --git a/packages/dart_client/lib/src/db/chat_persistence_client.dart b/packages/dart_client/lib/src/db/chat_persistence_client.dart index c435df9e..c0cb68b2 100644 --- a/packages/dart_client/lib/src/db/chat_persistence_client.dart +++ b/packages/dart_client/lib/src/db/chat_persistence_client.dart @@ -11,7 +11,7 @@ import 'package:stream_chat/src/models/user.dart'; /// abstract class ChatPersistenceClient { /// Creates a new connection to the client - Future connect(String name); + Future connect(String userId); /// Closes the client connection /// If [flush] is true, the data will also be deleted diff --git a/packages/stream_chat_persistence/lib/src/dao/message_dao.dart b/packages/stream_chat_persistence/lib/src/dao/message_dao.dart index 320cb022..ee779845 100644 --- a/packages/stream_chat_persistence/lib/src/dao/message_dao.dart +++ b/packages/stream_chat_persistence/lib/src/dao/message_dao.dart @@ -36,9 +36,9 @@ class MessageDao extends DatabaseAccessor final userEntity = rows.readTable(users); final msgEntity = rows.readTable(messages); final latestReactions = await _db.reactionDao.getReactions(msgEntity.id); - final ownReactions = await _db.reactionDao.getOwnReactions( + final ownReactions = await _db.reactionDao.getReactionsByUserId( msgEntity.id, - userEntity.id, + _db.userId, ); Message quotedMessage; if (msgEntity.quotedMessageId != null) { diff --git a/packages/stream_chat_persistence/lib/src/dao/reaction_dao.dart b/packages/stream_chat_persistence/lib/src/dao/reaction_dao.dart index 8df23d44..dc6faefb 100644 --- a/packages/stream_chat_persistence/lib/src/dao/reaction_dao.dart +++ b/packages/stream_chat_persistence/lib/src/dao/reaction_dao.dart @@ -29,7 +29,7 @@ class ReactionDao extends DatabaseAccessor } /// - Future> getOwnReactions( + Future> getReactionsByUserId( String messageId, String userId, ) async { diff --git a/packages/stream_chat_persistence/lib/src/db/moor_chat_database.dart b/packages/stream_chat_persistence/lib/src/db/moor_chat_database.dart index e32c3e3c..691961a7 100644 --- a/packages/stream_chat_persistence/lib/src/db/moor_chat_database.dart +++ b/packages/stream_chat_persistence/lib/src/db/moor_chat_database.dart @@ -10,12 +10,12 @@ import 'shared/shared_db.dart'; part 'moor_chat_database.g.dart'; LazyDatabase _openConnection( - String dbName, { + String userId, { logStatements = false, }) { return LazyDatabase(() async { return await SharedDB.constructDatabase( - dbName, + userId, logStatements: logStatements, ); }); @@ -44,19 +44,25 @@ LazyDatabase _openConnection( class MoorChatDatabase extends _$MoorChatDatabase { /// Instantiate a new database instance MoorChatDatabase( - String dbName, { + this._userId, { logStatements = false, }) : super(_openConnection( - dbName, + _userId, logStatements: logStatements, )); /// Instantiate a new database instance MoorChatDatabase.connect( + this._userId, this._isolate, DatabaseConnection connection, ) : super.connect(connection); + final String _userId; + + /// User id to which the database is connected + String get userId => _userId; + MoorIsolate _isolate; // you should bump this number whenever you change or add a table definition. diff --git a/packages/stream_chat_persistence/lib/src/db/shared/native_db.dart b/packages/stream_chat_persistence/lib/src/db/shared/native_db.dart index 198b9010..90f19de6 100644 --- a/packages/stream_chat_persistence/lib/src/db/shared/native_db.dart +++ b/packages/stream_chat_persistence/lib/src/db/shared/native_db.dart @@ -12,9 +12,10 @@ import '../moor_chat_database.dart'; class SharedDB { static Future constructDatabase( - String dbName, { + String userId, { bool logStatements = false, }) async { + final dbName = 'db_$userId'; if (Platform.isIOS || Platform.isAndroid) { final dir = await getApplicationDocumentsDirectory(); final path = join(dir.path, '$dbName.sqlite'); @@ -62,15 +63,16 @@ class SharedDB { } static Future constructOfflineStorage( - String dbName, { + String userId, { bool logStatements = false, }) async { + final dbName = 'db_$userId'; final isolate = await _createMoorIsolate( dbName, logStatements: logStatements, ); final connection = await isolate.connect(); - return MoorChatDatabase.connect(isolate, connection); + return MoorChatDatabase.connect(userId, isolate, connection); } } diff --git a/packages/stream_chat_persistence/lib/src/db/shared/unsupported_db.dart b/packages/stream_chat_persistence/lib/src/db/shared/unsupported_db.dart index 647314eb..b014c833 100644 --- a/packages/stream_chat_persistence/lib/src/db/shared/unsupported_db.dart +++ b/packages/stream_chat_persistence/lib/src/db/shared/unsupported_db.dart @@ -3,14 +3,14 @@ class SharedDB { static constructDatabase( - String dbName, { + String userId, { bool logStatements = false, }) { throw 'Unsupported Platform'; } static constructOfflineStorage( - String dbName, { + String userId, { bool logStatements = false, }) { throw 'Unsupported Platform'; diff --git a/packages/stream_chat_persistence/lib/src/db/shared/web_db.dart b/packages/stream_chat_persistence/lib/src/db/shared/web_db.dart index 31b4f4b6..e30d08ea 100644 --- a/packages/stream_chat_persistence/lib/src/db/shared/web_db.dart +++ b/packages/stream_chat_persistence/lib/src/db/shared/web_db.dart @@ -6,16 +6,18 @@ import '../moor_chat_database.dart'; class SharedDB { static constructDatabase( - String dbName, { + String userId, { bool logStatements = false, }) async { + final dbName = 'db_$userId'; return WebDatabase(dbName, logStatements: logStatements); } static Future constructOfflineStorage( - String dbName, { + String userId, { bool logStatements = false, }) async { + final dbName = 'db_$userId'; return MoorChatDatabase(dbName, logStatements: logStatements); } } diff --git a/packages/stream_chat_persistence/lib/src/stream_chat_persistence_client.dart b/packages/stream_chat_persistence/lib/src/stream_chat_persistence_client.dart index 72536b93..cfcc5c68 100644 --- a/packages/stream_chat_persistence/lib/src/stream_chat_persistence_client.dart +++ b/packages/stream_chat_persistence/lib/src/stream_chat_persistence_client.dart @@ -42,7 +42,7 @@ class StreamChatPersistenceClient extends ChatPersistenceClient { } @override - Future connect(String name) async { + Future connect(String userId) async { if (_db != null) { throw Exception( 'An instance of StreamChatDatabase is already connected.\n' @@ -52,11 +52,11 @@ class StreamChatPersistenceClient extends ChatPersistenceClient { switch (_connectionMode) { case ConnectionMode.regular: _logger.info('Connecting on a regular isolate'); - _db = MoorChatDatabase(name); + _db = MoorChatDatabase(userId); return; case ConnectionMode.background: _logger.info('Connecting on background isolate'); - _db = await SharedDB.constructOfflineStorage(name); + _db = await SharedDB.constructOfflineStorage(userId); return; } } From fa6e6aff17732ec4ae6d7404d92acf4615664345 Mon Sep 17 00:00:00 2001 From: Neevash Ramdial Date: Wed, 27 Jan 2021 06:35:30 -0400 Subject: [PATCH 1054/1140] WIP example --- .../example/lib/main.dart | 316 ++++++++++++------ .../example/test/widget_test.dart | 30 -- 2 files changed, 222 insertions(+), 124 deletions(-) delete mode 100644 packages/stream_chat_flutter_core/example/test/widget_test.dart diff --git a/packages/stream_chat_flutter_core/example/lib/main.dart b/packages/stream_chat_flutter_core/example/lib/main.dart index 496f7c82..f0c5ebd9 100644 --- a/packages/stream_chat_flutter_core/example/lib/main.dart +++ b/packages/stream_chat_flutter_core/example/lib/main.dart @@ -1,121 +1,249 @@ import 'package:flutter/material.dart'; +import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; -void main() { - runApp(MyApp()); +Future main() async { + /// Create a new instance of [Client] passing the apikey obtained from your + /// project dashboard. + final client = Client('b67pax5b2wdq'); + + /// Set the current user. In a production scenario, this should be done using + /// a backend to generate a user token using our server SDK. + /// Please see the following for more information: + /// https://getstream.io/chat/docs/ios_user_setup_and_tokens/ + await client.setUser( + User( + id: 'cool-shadow-7', + extraData: { + 'image': + 'https://getstream.io/random_png/?id=cool-shadow-7&name=Cool+shadow', + }, + ), + 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoiY29vbC1zaGFkb3ctNyJ9.gkOlCRb1qgy4joHPaxFwPOdXcGvSPvp6QY0S4mpRkVo', + ); + + runApp( + StreamExample( + client: client, + ), + ); } -// ignore: public_member_api_docs -class MyApp extends StatelessWidget { - // This widget is the root of your application. +class StreamExample extends StatelessWidget { + const StreamExample({ + Key key, + @required this.client, + }) : super(key: key); + + final Client client; + @override Widget build(BuildContext context) { return MaterialApp( - title: 'Flutter Demo', - theme: ThemeData( - // This is the theme of your application. - // - // Try running your application with "flutter run". You'll see the - // application has a blue toolbar. Then, without quitting the app, try - // changing the primarySwatch below to Colors.green and then invoke - // "hot reload" (press "r" in the console where you ran "flutter run", - // or simply save your changes to "hot reload" in a Flutter IDE). - // Notice that the counter didn't reset back to zero; the application - // is not restarted. - primarySwatch: Colors.blue, - // This makes the visual density adapt to the platform that you run - // the app on. For desktop platforms, the controls will be smaller and - // closer together (more dense) than on mobile platforms. - visualDensity: VisualDensity.adaptivePlatformDensity, + title: 'Stream Chat Dart Example', + home: _HomeScreen(), + builder: (context, child) => StreamChatCore( + client: client, + child: ChannelsBloc(child: child), ), - home: MyHomePage(title: 'Flutter Demo Home Page'), ); } } -// ignore: public_member_api_docs -class MyHomePage extends StatefulWidget { - // ignore: public_member_api_docs - MyHomePage({Key key, this.title}) : super(key: key); - - // This widget is the home page of your application. It is stateful, meaning - // that it has a State object (defined below) that contains fields that affect - // how it looks. - - // This class is the configuration for the state. It holds the values (in this - // case the title) provided by the parent (in this case the App widget) and - // used by the build method of the State. Fields in a Widget subclass are - // always marked "final". - - // ignore: public_member_api_docs - final String title; - +class _HomeScreen extends StatelessWidget { @override - _MyHomePageState createState() => _MyHomePageState(); + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('Channels'), + ), + body: ChannelListCore( + emptyBuilder: (BuildContext context) { + return Center( + child: Text('Looks like you are not in any channels'), + ); + }, + loadingBuilder: (BuildContext context) { + return Center( + child: SizedBox( + height: 100.0, + width: 100.0, + child: CircularProgressIndicator(), + ), + ); + }, + errorBuilder: (Error error) { + return Center( + child: + Text('Oh no, something went wrong. Please check your config.'), + ); + }, + listBuilder: (BuildContext context, List channels) => + ListView.builder( + itemCount: channels.length, + itemBuilder: (BuildContext context, int index) { + final item = channels[index]; + return ListTile( + title: Text(item.name), + subtitle: Text(item.state.lastMessage.text), + onTap: () { + Navigator.of(context).push( + MaterialPageRoute( + builder: (context) => StreamChannel( + channel: item, + child: MessageScreen(), + ), + ), + ); + }, + ); + }, + ), + ), + ); + } } -class _MyHomePageState extends State { - int _counter = 0; +class MessageScreen extends StatefulWidget { + @override + _MessageScreenState createState() => _MessageScreenState(); +} - void _incrementCounter() { - setState(() { - // This call to setState tells the Flutter framework that something has - // changed in this State, which causes it to rerun the build method below - // so that the display can reflect the updated values. If we changed - // _counter without calling setState(), then the build method would not be - // called again, and so nothing would appear to happen. - _counter++; - }); +class _MessageScreenState extends State { + TextEditingController _controller; + ScrollController _scrollController; + + @override + void initState() { + super.initState(); + _controller = TextEditingController(); + _scrollController = ScrollController(); + } + + @override + void dispose() { + _controller.dispose(); + _scrollController.dispose(); + super.dispose(); + } + + void _updateList() { + _scrollController.animateTo( + _scrollController.position.maxScrollExtent, + duration: const Duration(milliseconds: 200), + curve: Curves.easeOut, + ); } @override Widget build(BuildContext context) { - // This method is rerun every time setState is called, for instance as done - // by the _incrementCounter method above. - // - // The Flutter framework has been optimized to make rerunning build methods - // fast, so that you can just rebuild anything that needs updating rather - // than having to individually change instances of widgets. return Scaffold( - appBar: AppBar( - // Here we take the value from the MyHomePage object that was created by - // the App.build method, and use it to set our appbar title. - title: Text(widget.title), - ), - body: Center( - // Center is a layout widget. It takes a single child and positions it - // in the middle of the parent. - child: Column( - // Column is also a layout widget. It takes a list of children and - // arranges them vertically. By default, it sizes itself to fit its - // children horizontally, and tries to be as tall as its parent. - // - // Invoke "debug painting" (press "p" in the console, choose the - // "Toggle Debug Paint" action from the Flutter Inspector in Android - // Studio, or the "Toggle Debug Paint" command in Visual Studio Code) - // to see the wireframe for each widget. - // - // Column has various properties to control how it sizes itself and - // how it positions its children. Here we use mainAxisAlignment to - // center the children vertically; the main axis here is the vertical - // axis because Columns are vertical (the cross axis would be - // horizontal). - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text( - 'You have pushed the button this many times:', + body: Column( + children: [ + Expanded( + child: MessageListCore( + emptyBuilder: (BuildContext context) { + return Center( + child: Text('Looks like you are not in any channels'), + ); + }, + loadingBuilder: (BuildContext context) { + return Center( + child: SizedBox( + height: 100.0, + width: 100.0, + child: CircularProgressIndicator(), + ), + ); + }, + messageListBuilder: + (BuildContext context, List messages) { + return ListView.builder( + controller: _scrollController, + itemCount: messages.length, + reverse: true, + itemBuilder: (BuildContext context, int index) { + final item = messages[index]; + final client = StreamChatCore.of(context).client; + if (item.user.id == client.uid) { + return Align( + alignment: Alignment.centerRight, + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Text(item.text), + ), + ); + } else { + return Align( + alignment: Alignment.centerLeft, + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Text(item.text), + ), + ); + } + }, + ); + }, ), - Text( - '$_counter', - style: Theme.of(context).textTheme.headline4, + ), + Padding( + padding: const EdgeInsets.all(8.0), + child: Row( + children: [ + Expanded( + child: TextField( + controller: _controller, + decoration: const InputDecoration( + hintText: 'Enter your message', + ), + ), + ), + Material( + type: MaterialType.circle, + color: Colors.blue, + clipBehavior: Clip.hardEdge, + child: InkWell( + onTap: () async { + if (_controller.value.text.isNotEmpty) { + //TODO(Nash): Send Message + // await widget.channel.sendMessage( + // Message(text: _controller.value.text), + // ); + _controller.clear(); + _updateList(); + } + }, + child: const Padding( + padding: EdgeInsets.all(8.0), + child: Center( + child: Icon( + Icons.send, + color: Colors.white, + ), + ), + ), + ), + ) + ], ), - ], - ), + ) + ], ), - floatingActionButton: FloatingActionButton( - onPressed: _incrementCounter, - tooltip: 'Increment', - child: Icon(Icons.add), - ), // This trailing comma makes auto-formatting nicer for build methods. ); } } + +extension on Client { + String get uid => state.user.id; +} + +extension on Channel { + String get name { + final _channelName = extraData['name']; + if (_channelName != null) { + return _channelName; + } else { + return cid; + } + } +} \ No newline at end of file diff --git a/packages/stream_chat_flutter_core/example/test/widget_test.dart b/packages/stream_chat_flutter_core/example/test/widget_test.dart deleted file mode 100644 index 747db1da..00000000 --- a/packages/stream_chat_flutter_core/example/test/widget_test.dart +++ /dev/null @@ -1,30 +0,0 @@ -// This is a basic Flutter widget test. -// -// To perform an interaction with a widget in your test, use the WidgetTester -// utility that Flutter provides. For example, you can send tap and scroll -// gestures. You can also use WidgetTester to find child widgets in the widget -// tree, read text, and verify that the values of widget properties are correct. - -import 'package:flutter/material.dart'; -import 'package:flutter_test/flutter_test.dart'; - -import 'package:example/main.dart'; - -void main() { - testWidgets('Counter increments smoke test', (WidgetTester tester) async { - // Build our app and trigger a frame. - await tester.pumpWidget(MyApp()); - - // Verify that our counter starts at 0. - expect(find.text('0'), findsOneWidget); - expect(find.text('1'), findsNothing); - - // Tap the '+' icon and trigger a frame. - await tester.tap(find.byIcon(Icons.add)); - await tester.pump(); - - // Verify that our counter has incremented. - expect(find.text('0'), findsNothing); - expect(find.text('1'), findsOneWidget); - }); -} From e906f88975057ca972d624633fe3f1059b2f1dd5 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Wed, 27 Jan 2021 18:17:32 +0530 Subject: [PATCH 1055/1140] [Example] Minor fixes Signed-off-by: Sahil Kumar --- .../flutter_widgets/example/lib/advanced_options_page.dart | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/flutter_widgets/example/lib/advanced_options_page.dart b/packages/flutter_widgets/example/lib/advanced_options_page.dart index 915bcfcb..25cbf51c 100644 --- a/packages/flutter_widgets/example/lib/advanced_options_page.dart +++ b/packages/flutter_widgets/example/lib/advanced_options_page.dart @@ -320,12 +320,11 @@ class _AdvancedOptionsPageState extends State { await client.disconnect(); return; } - - Navigator.pop(context); loading = false; - await Navigator.pushReplacementNamed( + await Navigator.pushNamedAndRemoveUntil( context, Routes.APP, + ModalRoute.withName(Routes.APP), arguments: client, ); } From 3e9734133d9525140368e28f14e308f36e52dbc7 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Wed, 27 Jan 2021 14:11:58 +0100 Subject: [PATCH 1056/1140] add streamchatcore tests --- .../example/ios/Flutter/Debug.xcconfig | 1 + .../example/ios/Flutter/Release.xcconfig | 1 + .../lib/src/stream_chat_core.dart | 1 + .../stream_chat_flutter_core/pubspec.yaml | 39 +--- .../test/stream_chat_core_test.dart | 189 ++++++++++++++++++ .../test/stream_chat_flutter_core_test.dart | 92 --------- 6 files changed, 194 insertions(+), 129 deletions(-) create mode 100644 packages/stream_chat_flutter_core/test/stream_chat_core_test.dart delete mode 100644 packages/stream_chat_flutter_core/test/stream_chat_flutter_core_test.dart diff --git a/packages/stream_chat_flutter_core/example/ios/Flutter/Debug.xcconfig b/packages/stream_chat_flutter_core/example/ios/Flutter/Debug.xcconfig index 592ceee8..e8efba11 100644 --- a/packages/stream_chat_flutter_core/example/ios/Flutter/Debug.xcconfig +++ b/packages/stream_chat_flutter_core/example/ios/Flutter/Debug.xcconfig @@ -1 +1,2 @@ +#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" #include "Generated.xcconfig" diff --git a/packages/stream_chat_flutter_core/example/ios/Flutter/Release.xcconfig b/packages/stream_chat_flutter_core/example/ios/Flutter/Release.xcconfig index 592ceee8..399e9340 100644 --- a/packages/stream_chat_flutter_core/example/ios/Flutter/Release.xcconfig +++ b/packages/stream_chat_flutter_core/example/ios/Flutter/Release.xcconfig @@ -1 +1,2 @@ +#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" #include "Generated.xcconfig" diff --git a/packages/stream_chat_flutter_core/lib/src/stream_chat_core.dart b/packages/stream_chat_flutter_core/lib/src/stream_chat_core.dart index b04542fc..73f5eb61 100644 --- a/packages/stream_chat_flutter_core/lib/src/stream_chat_core.dart +++ b/packages/stream_chat_flutter_core/lib/src/stream_chat_core.dart @@ -142,6 +142,7 @@ class StreamChatCoreState extends State @override void dispose() { WidgetsBinding.instance.removeObserver(this); + _disconnectTimer?.cancel(); super.dispose(); } } diff --git a/packages/stream_chat_flutter_core/pubspec.yaml b/packages/stream_chat_flutter_core/pubspec.yaml index c0c2a55a..5037e5e8 100644 --- a/packages/stream_chat_flutter_core/pubspec.yaml +++ b/packages/stream_chat_flutter_core/pubspec.yaml @@ -19,40 +19,5 @@ dev_dependencies: mockito: ^4.1.4 flutter_test: sdk: flutter - -# For information on the generic Dart part of this file, see the -# following page: https://dart.dev/tools/pub/pubspec - -# The following section is specific to Flutter. -flutter: - - # To add assets to your package, add an assets section, like this: - # assets: - # - images/a_dot_burr.jpeg - # - images/a_dot_ham.jpeg - # - # For details regarding assets in packages, see - # https://flutter.dev/assets-and-images/#from-packages - # - # An image asset can refer to one or more resolution-specific "variants", see - # https://flutter.dev/assets-and-images/#resolution-aware. - - # To add custom fonts to your package, add a fonts section here, - # in this "flutter" section. Each entry in this list should have a - # "family" key with the font family name, and a "fonts" key with a - # list giving the asset and other descriptors for the font. For - # example: - # fonts: - # - family: Schyler - # fonts: - # - asset: fonts/Schyler-Regular.ttf - # - asset: fonts/Schyler-Italic.ttf - # style: italic - # - family: Trajan Pro - # fonts: - # - asset: fonts/TrajanPro.ttf - # - asset: fonts/TrajanPro_Bold.ttf - # weight: 700 - # - # For details regarding fonts in packages, see - # https://flutter.dev/custom-fonts/#from-packages + fake_async: ^1.1.0 + \ No newline at end of file diff --git a/packages/stream_chat_flutter_core/test/stream_chat_core_test.dart b/packages/stream_chat_flutter_core/test/stream_chat_core_test.dart new file mode 100644 index 00000000..714375de --- /dev/null +++ b/packages/stream_chat_flutter_core/test/stream_chat_core_test.dart @@ -0,0 +1,189 @@ +import 'dart:async'; + +import 'package:fake_async/fake_async.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; +import 'package:mockito/mockito.dart'; + +import 'mocks.dart'; + +class MockShowLocalNotifications extends Mock { + void call(Message m, ChannelModel cm); +} + +void main() { + testWidgets( + 'StreamChatCore.of(context) should throw an exception', + (WidgetTester tester) async { + await tester.pumpWidget( + Builder( + builder: (context) { + expect(() => StreamChatCore.of(context), throwsException); + return Container(); + }, + ), + ); + }, + ); + + testWidgets( + 'StreamChatCore.of(context) should return the StreamChatCore ancestor', + (WidgetTester tester) async { + final client = MockClient(); + await tester.pumpWidget( + StreamChatCore( + client: client, + child: Builder( + builder: (context) { + final sc = StreamChatCore.of(context); + expect(sc, isNotNull); + return Container(); + }, + ), + ), + ); + }, + ); + + testWidgets( + 'StreamChatCore.of(context).client should return the client', + (WidgetTester tester) async { + final client = MockClient(); + final clientState = MockClientState(); + when(client.state).thenReturn(clientState); + when(clientState.user).thenReturn( + OwnUser( + id: 'test', + ), + ); + final userStream = Stream.value( + OwnUser( + id: 'test', + ), + ); + when(clientState.userStream).thenAnswer( + (_) => userStream, + ); + + await tester.pumpWidget( + StreamChatCore( + client: client, + child: Builder( + builder: (context) { + final sc = StreamChatCore.of(context); + expect(sc.client, client); + expect(sc.user, client.state.user); + expect(sc.userStream, userStream); + return Container(); + }, + ), + ), + ); + }, + ); + + testWidgets( + 'StreamChatCore should disconnect on background', + (WidgetTester tester) async { + await fakeAsync((_async) { + final client = MockClient(); + final clientState = MockClientState(); + final channel = MockChannel(); + when(client.state).thenReturn(clientState); + when(clientState.user).thenReturn( + OwnUser( + id: 'test', + ), + ); + final showLocalNotificationMock = MockShowLocalNotifications().call; + when(client.showLocalNotification) + .thenReturn(showLocalNotificationMock); + when(client.backgroundKeepAlive).thenReturn(Duration( + seconds: 4, + )); + final eventStreamController = StreamController(); + when(client.on(EventType.messageNew)) + .thenAnswer((_) => eventStreamController.stream); + + when(client.channel('test', id: 'testid')).thenReturn(channel); + + final scKey = GlobalKey(); + tester.pumpWidget( + StreamChatCore( + key: scKey, + client: client, + child: Builder( + builder: (context) { + return Container(); + }, + ), + ), + ); + + final sc = scKey.currentState; + sc.didChangeAppLifecycleState(AppLifecycleState.paused); + + _async.elapse(Duration(seconds: 5)); + + verify(client.disconnect()).called(1); + }); + }, + ); + + testWidgets( + 'StreamChatCore should handle notifications when on background and connected', + (WidgetTester tester) async { + final client = MockClient(); + final clientState = MockClientState(); + final channel = MockChannel(); + when(client.state).thenReturn(clientState); + when(clientState.user).thenReturn( + OwnUser( + id: 'test', + ), + ); + final showLocalNotificationMock = MockShowLocalNotifications().call; + when(client.showLocalNotification).thenReturn(showLocalNotificationMock); + when(client.backgroundKeepAlive).thenReturn(Duration( + seconds: 4, + )); + final eventStreamController = StreamController(); + when(client.on(EventType.messageNew)) + .thenAnswer((_) => eventStreamController.stream); + + when(client.channel('test', id: 'testid')).thenReturn(channel); + + final scKey = GlobalKey(); + await tester.pumpWidget( + StreamChatCore( + key: scKey, + client: client, + child: Builder( + builder: (context) { + return Container(); + }, + ), + ), + ); + + final sc = scKey.currentState; + sc.didChangeAppLifecycleState(AppLifecycleState.paused); + final event = Event( + type: EventType.messageNew, + message: Message(text: 'hey'), + channelType: 'test', + channelId: 'testid', + user: User(id: 'other user'), + ); + eventStreamController.add(event); + + await untilCalled(showLocalNotificationMock(any, any)); + + verify(showLocalNotificationMock( + event.message, + any, + )).called(1); + }, + ); +} diff --git a/packages/stream_chat_flutter_core/test/stream_chat_flutter_core_test.dart b/packages/stream_chat_flutter_core/test/stream_chat_flutter_core_test.dart deleted file mode 100644 index be619db5..00000000 --- a/packages/stream_chat_flutter_core/test/stream_chat_flutter_core_test.dart +++ /dev/null @@ -1,92 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:mockito/mockito.dart'; -import 'package:stream_chat/stream_chat.dart'; -import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; - -import 'mocks.dart'; - -void main() { - testWidgets( - 'it should show basic channel information', - (WidgetTester tester) async { - // final client = MockClient(); - // final clientState = MockClientState(); - // final channel = MockChannel(); - // final channelState = MockChannelState(); - // final lastMessageAt = DateTime.parse('2020-06-22 12:00:00'); - // - // when(client.state).thenReturn(clientState); - // when(clientState.user).thenReturn(OwnUser(id: 'user-id')); - // when(channel.lastMessageAt).thenReturn(lastMessageAt); - // when(channel.state).thenReturn(channelState); - // when(channel.client).thenReturn(client); - // when(channel.isMuted).thenReturn(false); - // when(channel.isMutedStream).thenAnswer((i) => Stream.value(false)); - // when(channel.extraDataStream).thenAnswer((i) => Stream.value({ - // 'name': 'test name', - // })); - // when(channel.extraData).thenReturn({ - // 'name': 'test name', - // }); - // when(channelState.unreadCount).thenReturn(1); - // when(channelState.unreadCountStream).thenAnswer((i) => Stream.value(1)); - // when(channelState.membersStream).thenAnswer((i) => Stream.value([ - // Member( - // userId: 'user-id', - // user: User(id: 'user-id'), - // ) - // ])); - // when(channelState.members).thenReturn([ - // Member( - // userId: 'user-id', - // user: User(id: 'user-id'), - // ), - // ]); - // when(channelState.messages).thenReturn([ - // Message( - // text: 'hello', - // user: User(id: 'other-user'), - // ) - // ]); - // when(channelState.messagesStream).thenAnswer((i) => Stream.value([ - // Message( - // text: 'hello', - // user: User(id: 'other-user'), - // ) - // ])); - - await tester.pumpWidget( - // MaterialApp( - // home: StreamChatCore( - // client: client, - // child: StreamChannel( - // channel: channel, - // child: Scaffold( - // body: MessageListCore( - // loadingBuilder: (context) { - // return Center(); - // }, - // emptyBuilder: (context) { - // return Center(); - // }, - // messageListBuilder: (context, list) { - // return ListView.builder( - // itemBuilder: (context, position) { - // return Text(list[position].text); - // }, - // itemCount: list.length, - // ); - // }, - // ), - // ), - // ), - // ), - // ), - MaterialApp(home: Scaffold(body: Text('hello'))), - ); - - expect(find.text('hello'), findsOneWidget); - }, - ); -} From 303abee427b89dc2a5f980b4e5619b07578eb12e Mon Sep 17 00:00:00 2001 From: Neevash Ramdial Date: Wed, 27 Jan 2021 22:14:14 -0400 Subject: [PATCH 1057/1140] Complete example - Update code - Add docs --- .../example/lib/main.dart | 226 +++++++++++------- 1 file changed, 134 insertions(+), 92 deletions(-) diff --git a/packages/stream_chat_flutter_core/example/lib/main.dart b/packages/stream_chat_flutter_core/example/lib/main.dart index f0c5ebd9..a4237148 100644 --- a/packages/stream_chat_flutter_core/example/lib/main.dart +++ b/packages/stream_chat_flutter_core/example/lib/main.dart @@ -28,19 +28,31 @@ Future main() async { ); } +/// Example application using Stream Chat core widgets. +/// Stream Chat Core is a set of Flutter wrappers which provide basic functionality +/// for building Flutter applications using Stream. +/// If you'd prefer using pre-made UI widgets for your app, please see our other +/// package, `stream_chat_flutter`. class StreamExample extends StatelessWidget { + /// Minimal example using Stream's core Flutter package. + /// If you'd prefer using pre-made UI widgets for your app, please see our other + /// package, `stream_chat_flutter`. const StreamExample({ Key key, @required this.client, }) : super(key: key); + /// Instance of Stream Client. + /// Stream's [Client] can be used to connect to our servers and set the default + /// user for the application. Performing these actions trigger a websocket connection + /// allowing for real-time updates. final Client client; @override Widget build(BuildContext context) { return MaterialApp( - title: 'Stream Chat Dart Example', - home: _HomeScreen(), + title: 'Stream Chat Core Example', + home: HomeScreen(), builder: (context, child) => StreamChatCore( client: client, child: ChannelsBloc(child: child), @@ -49,7 +61,12 @@ class StreamExample extends StatelessWidget { } } -class _HomeScreen extends StatelessWidget { +/// Basic layout displaying a list of [Channel]s the user is a part of. +/// This is implemented using [ChannelListCore]. +/// +/// [ChannelListCore] is a `builder` with callbacks for constructing UIs based +/// on different scenarios. +class HomeScreen extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( @@ -81,15 +98,21 @@ class _HomeScreen extends StatelessWidget { ListView.builder( itemCount: channels.length, itemBuilder: (BuildContext context, int index) { - final item = channels[index]; + final _item = channels[index]; return ListTile( - title: Text(item.name), - subtitle: Text(item.state.lastMessage.text), + title: Text(_item.name), + subtitle: Text(_item.state.lastMessage.text), onTap: () { + /// Display a list of messages when the user taps on an item. + /// We can use [StreamChannel] to wrap our [MessageScreen] screen + /// with the selected channel. + /// + /// This allows us to use a built-in inherited widget for accessing + /// our `channel` later on. Navigator.of(context).push( MaterialPageRoute( builder: (context) => StreamChannel( - channel: item, + channel: _item, child: MessageScreen(), ), ), @@ -103,6 +126,12 @@ class _HomeScreen extends StatelessWidget { } } +/// A list of messages sent in the current channel. +/// When a user taps on a channel in [HomeScreen], a navigator push [MessageScreen] +/// to display the list of messages in the selected channel. +/// +/// This is implemented using [MessageListCore], a convenience builder with +/// callbacks for building UIs based on different api results. class MessageScreen extends StatefulWidget { @override _MessageScreenState createState() => _MessageScreenState(); @@ -136,108 +165,121 @@ class _MessageScreenState extends State { @override Widget build(BuildContext context) { + /// To access the current channel, we can use the `.of()` method on [StreamChannel] + /// to fetch the closest instance. + final channel = StreamChannel.of(context).channel; return Scaffold( - body: Column( - children: [ - Expanded( - child: MessageListCore( - emptyBuilder: (BuildContext context) { - return Center( - child: Text('Looks like you are not in any channels'), - ); - }, - loadingBuilder: (BuildContext context) { - return Center( - child: SizedBox( - height: 100.0, - width: 100.0, - child: CircularProgressIndicator(), - ), - ); - }, - messageListBuilder: - (BuildContext context, List messages) { - return ListView.builder( - controller: _scrollController, - itemCount: messages.length, - reverse: true, - itemBuilder: (BuildContext context, int index) { - final item = messages[index]; - final client = StreamChatCore.of(context).client; - if (item.user.id == client.uid) { - return Align( - alignment: Alignment.centerRight, - child: Padding( - padding: const EdgeInsets.all(8.0), - child: Text(item.text), - ), - ); - } else { - return Align( - alignment: Alignment.centerLeft, - child: Padding( - padding: const EdgeInsets.all(8.0), - child: Text(item.text), - ), - ); - } - }, - ); - }, - ), - ), - Padding( - padding: const EdgeInsets.all(8.0), - child: Row( - children: [ - Expanded( - child: TextField( - controller: _controller, - decoration: const InputDecoration( - hintText: 'Enter your message', + appBar: AppBar( + title: Text(channel.name), + ), + body: SafeArea( + child: Column( + children: [ + Expanded( + child: MessageListCore( + emptyBuilder: (BuildContext context) { + return Center( + child: Text('Looks like you are not in any channels'), + ); + }, + loadingBuilder: (BuildContext context) { + return Center( + child: SizedBox( + height: 100.0, + width: 100.0, + child: CircularProgressIndicator(), ), - ), - ), - Material( - type: MaterialType.circle, - color: Colors.blue, - clipBehavior: Clip.hardEdge, - child: InkWell( - onTap: () async { - if (_controller.value.text.isNotEmpty) { - //TODO(Nash): Send Message - // await widget.channel.sendMessage( - // Message(text: _controller.value.text), - // ); - _controller.clear(); - _updateList(); + ); + }, + messageListBuilder: ( + BuildContext context, + List messages, + ) { + return ListView.builder( + controller: _scrollController, + itemCount: messages.length, + reverse: true, + itemBuilder: (BuildContext context, int index) { + final item = messages[index]; + final client = StreamChatCore.of(context).client; + if (item.user.id == client.uid) { + return Align( + alignment: Alignment.centerRight, + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Text(item.text), + ), + ); + } else { + return Align( + alignment: Alignment.centerLeft, + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Text(item.text), + ), + ); } }, - child: const Padding( - padding: EdgeInsets.all(8.0), - child: Center( - child: Icon( - Icons.send, - color: Colors.white, - ), + ); + }, + ), + ), + Padding( + padding: const EdgeInsets.all(8.0), + child: Row( + children: [ + Expanded( + child: TextField( + controller: _controller, + decoration: const InputDecoration( + hintText: 'Enter your message', ), ), ), - ) - ], - ), - ) - ], + Material( + type: MaterialType.circle, + color: Colors.blue, + clipBehavior: Clip.hardEdge, + child: InkWell( + onTap: () async { + if (_controller.value.text.isNotEmpty) { + await channel.sendMessage( + Message(text: _controller.value.text), + ); + _controller.clear(); + _updateList(); + } + }, + child: const Padding( + padding: EdgeInsets.all(8.0), + child: Center( + child: Icon( + Icons.send, + color: Colors.white, + ), + ), + ), + ), + ) + ], + ), + ) + ], + ), ), ); } } +/// Extensions can be used to add functionality to the SDK. In the examples +/// below, we add two simple extensions to the [Client] and [Channel]. extension on Client { + /// Fetches the current user id. String get uid => state.user.id; } extension on Channel { + /// Fetches the name of the channel by accessing [extraData] or [cid]. String get name { final _channelName = extraData['name']; if (_channelName != null) { From 18f104cda7be27f95e1cca17886c54d9aefa429b Mon Sep 17 00:00:00 2001 From: Neevash Ramdial Date: Wed, 27 Jan 2021 22:17:45 -0400 Subject: [PATCH 1058/1140] fixed lint warnings - Removed Unused imports --- .../test/stream_chat_flutter_core_test.dart | 5 ----- 1 file changed, 5 deletions(-) diff --git a/packages/stream_chat_flutter_core/test/stream_chat_flutter_core_test.dart b/packages/stream_chat_flutter_core/test/stream_chat_flutter_core_test.dart index be619db5..2100f744 100644 --- a/packages/stream_chat_flutter_core/test/stream_chat_flutter_core_test.dart +++ b/packages/stream_chat_flutter_core/test/stream_chat_flutter_core_test.dart @@ -1,10 +1,5 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; -import 'package:mockito/mockito.dart'; -import 'package:stream_chat/stream_chat.dart'; -import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; - -import 'mocks.dart'; void main() { testWidgets( From e7d68aa36aef47ccfaccd9a91812261f9257741e Mon Sep 17 00:00:00 2001 From: Neevash Ramdial Date: Wed, 27 Jan 2021 22:30:37 -0400 Subject: [PATCH 1059/1140] expose error builder in message list core --- .../lib/src/message_list_core.dart | 24 +++++++++++++++---- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/packages/stream_chat_flutter_core/lib/src/message_list_core.dart b/packages/stream_chat_flutter_core/lib/src/message_list_core.dart index 1cd5162e..81d29a6b 100644 --- a/packages/stream_chat_flutter_core/lib/src/message_list_core.dart +++ b/packages/stream_chat_flutter_core/lib/src/message_list_core.dart @@ -5,6 +5,12 @@ import 'package:flutter/material.dart'; import 'package:stream_chat/stream_chat.dart'; import 'stream_channel.dart'; +/// A signature for a callback which exposes an error and returns a function. +/// This Callback can be used in cases where an API failure occurs and the widget +/// is unable to render data. +typedef StreamErrorBuilder = Widget Function( + BuildContext context, Object error); + /// ![screenshot](https://raw.githubusercontent.com/GetStream/stream-chat-flutter/master/screenshots/message_listview.png) /// ![screenshot](https://raw.githubusercontent.com/GetStream/stream-chat-flutter/master/screenshots/message_listview_paint.png) /// @@ -61,6 +67,7 @@ class MessageListCore extends StatefulWidget { @required this.loadingBuilder, @required this.emptyBuilder, @required this.messageListBuilder, + @required this.errorWidgetBuilder, this.messageListController, }) : super(key: key); @@ -77,6 +84,11 @@ class MessageListCore extends StatefulWidget { /// Function used to build an empty widget final WidgetBuilder emptyBuilder; + /// Callback triggered when an error occurs while performing the given request. + /// This parameter can be used to display an error message to users in the event + /// of a connection failure. + final StreamErrorBuilder errorWidgetBuilder; + /// If true will show a scroll to bottom message when there are new messages and the scroll offset is not zero final bool showScrollToBottom; @@ -118,9 +130,10 @@ class _MessageListCoreState extends State { ?.toList()), builder: (context, snapshot) { if (!snapshot.hasData) { - return widget.loadingBuilder(context); - } - + return widget.loadingBuilder(context); + } else if (snapshot.hasError) { + return widget.errorWidgetBuilder(context, snapshot.error); + } else { final messageList = snapshot.data?.reversed?.toList() ?? []; if (messageList.isEmpty) { if (_upToDate) { @@ -129,9 +142,10 @@ class _MessageListCoreState extends State { } else { messages = messageList; } - return widget.messageListBuilder(context, messages); - }); + } + }, + ); } Future paginateData( From 24d528fc792a9cf11503bb6342e59eef0b9b8163 Mon Sep 17 00:00:00 2001 From: Neevash Ramdial Date: Wed, 27 Jan 2021 22:30:49 -0400 Subject: [PATCH 1060/1140] update sample app with new api --- .../stream_chat_flutter_core/example/lib/main.dart | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/packages/stream_chat_flutter_core/example/lib/main.dart b/packages/stream_chat_flutter_core/example/lib/main.dart index a4237148..218bba1c 100644 --- a/packages/stream_chat_flutter_core/example/lib/main.dart +++ b/packages/stream_chat_flutter_core/example/lib/main.dart @@ -222,6 +222,16 @@ class _MessageScreenState extends State { }, ); }, + errorWidgetBuilder: (BuildContext context, error) { + print(error?.toString()); + return Center( + child: SizedBox( + height: 100.0, + width: 100.0, + child: Text('Oh no, an error occured. Please see logs.'), + ), + ); + }, ), ), Padding( From f162b006ce62e47e7a61bdef9327dafdde4242c2 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Thu, 28 Jan 2021 13:32:48 +0530 Subject: [PATCH 1061/1140] [LLC] Replace `flutter_test` with `test` Signed-off-by: Sahil Kumar --- packages/dart_client/pubspec.yaml | 4 ++-- .../dart_client/test/src/client_test.dart | 2 +- .../test/src/models/action_test.dart | 2 +- .../test/src/models/attachment_test.dart | 2 +- .../test/src/models/channel_state_test.dart | 2 +- .../test/src/models/channel_test.dart | 2 +- .../test/src/models/command_test.dart | 2 +- .../test/src/models/device_test.dart | 2 +- .../test/src/models/event_test.dart | 2 +- .../test/src/models/member_test.dart | 2 +- .../test/src/models/message_test.dart | 2 +- .../test/src/models/reaction_test.dart | 2 +- .../test/src/models/read_test.dart | 2 +- .../test/src/models/serialization_test.dart | 2 +- .../test/src/models/user_test.dart | 2 +- packages/dart_client/test/version_test.dart | 2 +- .../test_integration/client_test.dart | 21 ------------------- 17 files changed, 17 insertions(+), 38 deletions(-) delete mode 100644 packages/dart_client/test_integration/client_test.dart diff --git a/packages/dart_client/pubspec.yaml b/packages/dart_client/pubspec.yaml index 99d6794b..024f9d90 100644 --- a/packages/dart_client/pubspec.yaml +++ b/packages/dart_client/pubspec.yaml @@ -21,10 +21,10 @@ dependencies: rxdart: ^0.24.1 collection: ^1.14.12 pedantic: ^1.9.2 + freezed: ^0.12.7 dev_dependencies: build_runner: ^1.10.0 json_serializable: ^3.3.0 - flutter_test: - sdk: flutter + test: ^1.15.7 mockito: ^4.1.1 diff --git a/packages/dart_client/test/src/client_test.dart b/packages/dart_client/test/src/client_test.dart index 011789be..299ccecb 100644 --- a/packages/dart_client/test/src/client_test.dart +++ b/packages/dart_client/test/src/client_test.dart @@ -3,7 +3,7 @@ import 'dart:convert'; import 'package:dio/dio.dart'; import 'package:dio/native_imp.dart'; -import 'package:flutter_test/flutter_test.dart'; +import 'package:test/test.dart'; import 'package:logging/logging.dart'; import 'package:mockito/mockito.dart'; import 'package:stream_chat/src/api/requests.dart'; diff --git a/packages/dart_client/test/src/models/action_test.dart b/packages/dart_client/test/src/models/action_test.dart index 2f75dddb..4859fcbe 100644 --- a/packages/dart_client/test/src/models/action_test.dart +++ b/packages/dart_client/test/src/models/action_test.dart @@ -1,6 +1,6 @@ import 'dart:convert'; -import 'package:flutter_test/flutter_test.dart'; +import 'package:test/test.dart'; import 'package:stream_chat/src/models/action.dart'; void main() { diff --git a/packages/dart_client/test/src/models/attachment_test.dart b/packages/dart_client/test/src/models/attachment_test.dart index eaa8e9cc..b15458ad 100644 --- a/packages/dart_client/test/src/models/attachment_test.dart +++ b/packages/dart_client/test/src/models/attachment_test.dart @@ -2,7 +2,7 @@ import 'package:stream_chat/src/models/attachment.dart'; import 'package:stream_chat/src/models/action.dart'; import 'dart:convert'; -import 'package:flutter_test/flutter_test.dart'; +import 'package:test/test.dart'; void main() { group('src/models/attachment', () { diff --git a/packages/dart_client/test/src/models/channel_state_test.dart b/packages/dart_client/test/src/models/channel_state_test.dart index 21ffb20c..b8ce3c80 100644 --- a/packages/dart_client/test/src/models/channel_state_test.dart +++ b/packages/dart_client/test/src/models/channel_state_test.dart @@ -1,6 +1,6 @@ import 'dart:convert'; -import 'package:flutter_test/flutter_test.dart'; +import 'package:test/test.dart'; import 'package:stream_chat/src/models/channel_config.dart'; import 'package:stream_chat/src/models/channel_state.dart'; import 'package:stream_chat/src/models/command.dart'; diff --git a/packages/dart_client/test/src/models/channel_test.dart b/packages/dart_client/test/src/models/channel_test.dart index 7197d083..69b18197 100644 --- a/packages/dart_client/test/src/models/channel_test.dart +++ b/packages/dart_client/test/src/models/channel_test.dart @@ -1,6 +1,6 @@ import 'dart:convert'; -import 'package:flutter_test/flutter_test.dart'; +import 'package:test/test.dart'; import 'package:stream_chat/src/models/channel_model.dart'; void main() { diff --git a/packages/dart_client/test/src/models/command_test.dart b/packages/dart_client/test/src/models/command_test.dart index 51774b84..dc44f736 100644 --- a/packages/dart_client/test/src/models/command_test.dart +++ b/packages/dart_client/test/src/models/command_test.dart @@ -1,7 +1,7 @@ import 'package:stream_chat/src/models/command.dart'; import 'dart:convert'; -import 'package:flutter_test/flutter_test.dart'; +import 'package:test/test.dart'; void main() { group('src/models/command', () { diff --git a/packages/dart_client/test/src/models/device_test.dart b/packages/dart_client/test/src/models/device_test.dart index 3f68929f..3f8de16e 100644 --- a/packages/dart_client/test/src/models/device_test.dart +++ b/packages/dart_client/test/src/models/device_test.dart @@ -1,6 +1,6 @@ import 'dart:convert'; -import 'package:flutter_test/flutter_test.dart'; +import 'package:test/test.dart'; import 'package:stream_chat/src/models/device.dart'; void main() { diff --git a/packages/dart_client/test/src/models/event_test.dart b/packages/dart_client/test/src/models/event_test.dart index eb7d0f5a..db99b01a 100644 --- a/packages/dart_client/test/src/models/event_test.dart +++ b/packages/dart_client/test/src/models/event_test.dart @@ -1,6 +1,6 @@ import 'dart:convert'; -import 'package:flutter_test/flutter_test.dart'; +import 'package:test/test.dart'; import 'package:stream_chat/src/models/event.dart'; import 'package:stream_chat/src/models/own_user.dart'; import 'package:stream_chat/stream_chat.dart'; diff --git a/packages/dart_client/test/src/models/member_test.dart b/packages/dart_client/test/src/models/member_test.dart index 121b470f..237f0030 100644 --- a/packages/dart_client/test/src/models/member_test.dart +++ b/packages/dart_client/test/src/models/member_test.dart @@ -1,6 +1,6 @@ import 'dart:convert'; -import 'package:flutter_test/flutter_test.dart'; +import 'package:test/test.dart'; import 'package:stream_chat/src/models/member.dart'; import 'package:stream_chat/src/models/user.dart'; diff --git a/packages/dart_client/test/src/models/message_test.dart b/packages/dart_client/test/src/models/message_test.dart index de335c21..7541f722 100644 --- a/packages/dart_client/test/src/models/message_test.dart +++ b/packages/dart_client/test/src/models/message_test.dart @@ -1,6 +1,6 @@ import 'dart:convert'; -import 'package:flutter_test/flutter_test.dart'; +import 'package:test/test.dart'; import 'package:stream_chat/src/models/attachment.dart'; import 'package:stream_chat/src/models/message.dart'; import 'package:stream_chat/src/models/reaction.dart'; diff --git a/packages/dart_client/test/src/models/reaction_test.dart b/packages/dart_client/test/src/models/reaction_test.dart index 2e8fe5f8..8bc92081 100644 --- a/packages/dart_client/test/src/models/reaction_test.dart +++ b/packages/dart_client/test/src/models/reaction_test.dart @@ -1,4 +1,4 @@ -import 'package:flutter_test/flutter_test.dart'; +import 'package:test/test.dart'; import 'package:stream_chat/src/models/reaction.dart'; import 'dart:convert'; diff --git a/packages/dart_client/test/src/models/read_test.dart b/packages/dart_client/test/src/models/read_test.dart index 83596170..b15ce66a 100644 --- a/packages/dart_client/test/src/models/read_test.dart +++ b/packages/dart_client/test/src/models/read_test.dart @@ -1,6 +1,6 @@ import 'dart:convert'; -import 'package:flutter_test/flutter_test.dart'; +import 'package:test/test.dart'; import 'package:stream_chat/src/models/read.dart'; import 'package:stream_chat/src/models/user.dart'; diff --git a/packages/dart_client/test/src/models/serialization_test.dart b/packages/dart_client/test/src/models/serialization_test.dart index c20d0012..e8a2de3f 100644 --- a/packages/dart_client/test/src/models/serialization_test.dart +++ b/packages/dart_client/test/src/models/serialization_test.dart @@ -1,4 +1,4 @@ -import 'package:flutter_test/flutter_test.dart'; +import 'package:test/test.dart'; import 'package:stream_chat/src/models/serialization.dart'; void main() { diff --git a/packages/dart_client/test/src/models/user_test.dart b/packages/dart_client/test/src/models/user_test.dart index a148ec6e..6100b218 100644 --- a/packages/dart_client/test/src/models/user_test.dart +++ b/packages/dart_client/test/src/models/user_test.dart @@ -1,6 +1,6 @@ import 'dart:convert'; -import 'package:flutter_test/flutter_test.dart'; +import 'package:test/test.dart'; import 'package:stream_chat/src/models/user.dart'; void main() { diff --git a/packages/dart_client/test/version_test.dart b/packages/dart_client/test/version_test.dart index 698f79e1..ada2a85c 100644 --- a/packages/dart_client/test/version_test.dart +++ b/packages/dart_client/test/version_test.dart @@ -1,6 +1,6 @@ import 'dart:io'; -import 'package:flutter_test/flutter_test.dart'; +import 'package:test/test.dart'; import 'package:stream_chat/version.dart'; void prepareTest() { diff --git a/packages/dart_client/test_integration/client_test.dart b/packages/dart_client/test_integration/client_test.dart deleted file mode 100644 index 98ec39cf..00000000 --- a/packages/dart_client/test_integration/client_test.dart +++ /dev/null @@ -1,21 +0,0 @@ -import 'package:flutter_test/flutter_test.dart'; -import 'package:logging/logging.dart'; -import 'package:stream_chat/src/client.dart'; -import 'package:stream_chat/stream_chat.dart'; - -const API_KEY = '6xjf3dex3n7d'; -const TOKEN = - 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoid2lsZC1icmVlemUtNyJ9.VM2EX1EXOfgqa-bTH_3JzeY0T99ngWzWahSauP3dBMo'; - -void main() { - test('test', () async { - final client = Client( - '6xjf3dex3n7d', - logLevel: Level.INFO, - tokenProvider: (_) async => '', - ); - final user = User(id: 'wild-breeze-7'); - - await client.setGuestUser(user); - }); -} From cb90146a8b78b9626889a1d431f4eb05f6194850 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Thu, 28 Jan 2021 10:25:52 +0100 Subject: [PATCH 1062/1140] fix examples --- .gitignore | 1 + .../example/android/gradle.properties | 1 + .../gradle/wrapper/gradle-wrapper.properties | 2 +- packages/dart_client/example/lib/main.dart | 2 +- .../example/android/gradle.properties | 1 + .../gradle/wrapper/gradle-wrapper.properties | 2 +- .../example/ios/Flutter/Debug.xcconfig | 1 + .../example/ios/Flutter/Release.xcconfig | 1 + .../example/lib/main.dart | 103 +++++++++--------- 9 files changed, 62 insertions(+), 52 deletions(-) diff --git a/.gitignore b/.gitignore index 6d180702..f7a23bbb 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ .DS_Store .atom/ .idea/ +.vscode/ .packages .pub/ diff --git a/packages/dart_client/example/android/gradle.properties b/packages/dart_client/example/android/gradle.properties index 94adc3a3..a6738207 100644 --- a/packages/dart_client/example/android/gradle.properties +++ b/packages/dart_client/example/android/gradle.properties @@ -1,3 +1,4 @@ org.gradle.jvmargs=-Xmx1536M android.useAndroidX=true android.enableJetifier=true +android.enableR8=true diff --git a/packages/dart_client/example/android/gradle/wrapper/gradle-wrapper.properties b/packages/dart_client/example/android/gradle/wrapper/gradle-wrapper.properties index 296b146b..de2ccd60 100644 --- a/packages/dart_client/example/android/gradle/wrapper/gradle-wrapper.properties +++ b/packages/dart_client/example/android/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-bin.zip diff --git a/packages/dart_client/example/lib/main.dart b/packages/dart_client/example/lib/main.dart index 8f68c100..ed21df76 100644 --- a/packages/dart_client/example/lib/main.dart +++ b/packages/dart_client/example/lib/main.dart @@ -156,7 +156,7 @@ class _MessageViewState extends State { /// Convenience method for scrolling the list view when a new message is sent. void _updateList() { _scrollController.animateTo( - _scrollController.position.maxScrollExtent, + 0, duration: const Duration(milliseconds: 200), curve: Curves.easeOut, ); diff --git a/packages/stream_chat_flutter_core/example/android/gradle.properties b/packages/stream_chat_flutter_core/example/android/gradle.properties index 94adc3a3..a6738207 100644 --- a/packages/stream_chat_flutter_core/example/android/gradle.properties +++ b/packages/stream_chat_flutter_core/example/android/gradle.properties @@ -1,3 +1,4 @@ org.gradle.jvmargs=-Xmx1536M android.useAndroidX=true android.enableJetifier=true +android.enableR8=true diff --git a/packages/stream_chat_flutter_core/example/android/gradle/wrapper/gradle-wrapper.properties b/packages/stream_chat_flutter_core/example/android/gradle/wrapper/gradle-wrapper.properties index 296b146b..de2ccd60 100644 --- a/packages/stream_chat_flutter_core/example/android/gradle/wrapper/gradle-wrapper.properties +++ b/packages/stream_chat_flutter_core/example/android/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-bin.zip diff --git a/packages/stream_chat_flutter_core/example/ios/Flutter/Debug.xcconfig b/packages/stream_chat_flutter_core/example/ios/Flutter/Debug.xcconfig index 592ceee8..e8efba11 100644 --- a/packages/stream_chat_flutter_core/example/ios/Flutter/Debug.xcconfig +++ b/packages/stream_chat_flutter_core/example/ios/Flutter/Debug.xcconfig @@ -1 +1,2 @@ +#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" #include "Generated.xcconfig" diff --git a/packages/stream_chat_flutter_core/example/ios/Flutter/Release.xcconfig b/packages/stream_chat_flutter_core/example/ios/Flutter/Release.xcconfig index 592ceee8..399e9340 100644 --- a/packages/stream_chat_flutter_core/example/ios/Flutter/Release.xcconfig +++ b/packages/stream_chat_flutter_core/example/ios/Flutter/Release.xcconfig @@ -1 +1,2 @@ +#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" #include "Generated.xcconfig" diff --git a/packages/stream_chat_flutter_core/example/lib/main.dart b/packages/stream_chat_flutter_core/example/lib/main.dart index a4237148..19945dff 100644 --- a/packages/stream_chat_flutter_core/example/lib/main.dart +++ b/packages/stream_chat_flutter_core/example/lib/main.dart @@ -55,7 +55,7 @@ class StreamExample extends StatelessWidget { home: HomeScreen(), builder: (context, child) => StreamChatCore( client: client, - child: ChannelsBloc(child: child), + child: child, ), ); } @@ -73,53 +73,58 @@ class HomeScreen extends StatelessWidget { appBar: AppBar( title: Text('Channels'), ), - body: ChannelListCore( - emptyBuilder: (BuildContext context) { - return Center( - child: Text('Looks like you are not in any channels'), - ); - }, - loadingBuilder: (BuildContext context) { - return Center( - child: SizedBox( - height: 100.0, - width: 100.0, - child: CircularProgressIndicator(), - ), - ); - }, - errorBuilder: (Error error) { - return Center( - child: - Text('Oh no, something went wrong. Please check your config.'), - ); - }, - listBuilder: (BuildContext context, List channels) => - ListView.builder( - itemCount: channels.length, - itemBuilder: (BuildContext context, int index) { - final _item = channels[index]; - return ListTile( - title: Text(_item.name), - subtitle: Text(_item.state.lastMessage.text), - onTap: () { - /// Display a list of messages when the user taps on an item. - /// We can use [StreamChannel] to wrap our [MessageScreen] screen - /// with the selected channel. - /// - /// This allows us to use a built-in inherited widget for accessing - /// our `channel` later on. - Navigator.of(context).push( - MaterialPageRoute( - builder: (context) => StreamChannel( - channel: _item, - child: MessageScreen(), - ), - ), - ); - }, + body: ChannelsBloc( + child: ChannelListCore( + emptyBuilder: (BuildContext context) { + return Center( + child: Text('Looks like you are not in any channels'), ); }, + loadingBuilder: (BuildContext context) { + return Center( + child: SizedBox( + height: 100.0, + width: 100.0, + child: CircularProgressIndicator(), + ), + ); + }, + errorBuilder: (Error error) { + return Center( + child: Text( + 'Oh no, something went wrong. Please check your config.'), + ); + }, + listBuilder: ( + BuildContext context, + List channels, + ) => + ListView.builder( + itemCount: channels.length, + itemBuilder: (BuildContext context, int index) { + final _item = channels[index]; + return ListTile( + title: Text(_item.name), + subtitle: Text(_item.state.lastMessage.text), + onTap: () { + /// Display a list of messages when the user taps on an item. + /// We can use [StreamChannel] to wrap our [MessageScreen] screen + /// with the selected channel. + /// + /// This allows us to use a built-in inherited widget for accessing + /// our `channel` later on. + Navigator.of(context).push( + MaterialPageRoute( + builder: (context) => StreamChannel( + channel: _item, + child: MessageScreen(), + ), + ), + ); + }, + ); + }, + ), ), ), ); @@ -157,7 +162,7 @@ class _MessageScreenState extends State { void _updateList() { _scrollController.animateTo( - _scrollController.position.maxScrollExtent, + 0, duration: const Duration(milliseconds: 200), curve: Curves.easeOut, ); @@ -179,7 +184,7 @@ class _MessageScreenState extends State { child: MessageListCore( emptyBuilder: (BuildContext context) { return Center( - child: Text('Looks like you are not in any channels'), + child: Text('Nothing here yet'), ); }, loadingBuilder: (BuildContext context) { @@ -288,4 +293,4 @@ extension on Channel { return cid; } } -} \ No newline at end of file +} From 55c1cae390daa6874a16445f50c9befda4225efe Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Thu, 28 Jan 2021 12:02:06 +0100 Subject: [PATCH 1063/1140] update default apikey and users --- .gitignore | 1 + .../example/lib/choose_user_page.dart | 89 +++++++++++++------ 2 files changed, 65 insertions(+), 25 deletions(-) diff --git a/.gitignore b/.gitignore index 6d180702..f7a23bbb 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ .DS_Store .atom/ .idea/ +.vscode/ .packages .pub/ diff --git a/packages/flutter_widgets/example/lib/choose_user_page.dart b/packages/flutter_widgets/example/lib/choose_user_page.dart index 6da88a29..8e36e748 100644 --- a/packages/flutter_widgets/example/lib/choose_user_page.dart +++ b/packages/flutter_widgets/example/lib/choose_user_page.dart @@ -11,52 +11,91 @@ import 'routes/routes.dart'; const kStreamApiKey = 'STREAM_API_KEY'; const kStreamUserId = 'STREAM_USER_ID'; const kStreamToken = 'STREAM_TOKEN'; -const kDefaultStreamApiKey = 'uj7qrdbfrzvg'; +const kDefaultStreamApiKey = 'kv7mcsxr24p8'; class ChooseUserPage extends StatelessWidget { @override Widget build(BuildContext context) { final users = { - 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoidmlzaGFsIn0.lCz-idDgaZ-xszjnuB_hTfeIOhTFmJtTB2fEjhwrcCI': - User( - id: 'vishal', - extraData: { - 'name': 'Vishal', - }, - ), - 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoic3VwZXItYmFuZC05In0.1AvvK2TvEsfcxAlfOK2iUMFACucnk6N-Q8f5bbfnjCM': - User( - id: 'super-band-9', - extraData: { - 'name': 'John Doe', - }, - ), - 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoic2FsdmF0b3JlIn0.uQ-pz8e1_C-Df2rIFpkkvWf7g4M0aW2Zkr7pHVhmU1Y': + 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoic2FsdmF0b3JlIn0.pgiJz7sIc7iP29BHKFwe3nLm5-OaR_1l2P-SlgiC9a8': User( id: 'salvatore', extraData: { - 'name': 'Salvatore', + 'name': 'Salvatore Giordano', + 'image': + 'https://ca.slack-edge.com/T02RM6X6B-USKK9FFRT-30c415e207a9-512', }, ), - 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoidG9tbWFzbyJ9.feLvMytd5_3-eETKrRdwtO3jcA0HxD8woFUbFU7gQCg': + 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoic2FoaWwifQ.WnIUoB5gR2kcAsFhiDvkiD6zdHXZ-VSU2aQWWkhsvfo': + User( + id: 'sahil', + extraData: { + 'name': 'Sahil Kumar', + 'image': + 'https://ca.slack-edge.com/T02RM6X6B-U01EYU51M89-bbc152b40321-512', + }, + ), + 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoiYmVuIn0.nAz2sNFGQwY7rl2Og2z3TGHUsdpnN53tOsUglJFvLmg': + User( + id: 'ben', + extraData: { + 'name': 'Ben Golden', + 'image': + 'https://ca.slack-edge.com/T02RM6X6B-U01AXAF23MG-f57403a3cb0d-512', + }, + ), + 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoidGhpZXJyeSJ9.lEq6TrZtHzjoNtf7HHRufUPyGo_pa8vg4_XhEBp4ckY': + User( + id: 'thierry', + extraData: { + 'name': 'Thierry Schellenbach', + 'image': + 'https://ca.slack-edge.com/T02RM6X6B-U02RM6X6D-g28a1278a98e-512', + }, + ), + 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoidG9tbWFzbyJ9.GLSI0ESshERMo2WjUpysD709NEtn1zmGimUN2an7g9o': User( id: 'tommaso', extraData: { - 'name': 'Tommaso', + 'name': 'Tommaso Barbugli', + 'image': + 'https://ca.slack-edge.com/T02RM6X6B-U02U7SJP4-0f65a5997877-512', }, ), - 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoiamFhcCJ9.VLkLs6KH-jRRkPvhYMa4_lqN0R6WiK7JhJVmYvxcKz0': + 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoiZGV2ZW4ifQ.z3zI4PqJnNhc-1o-VKcmb6BnnQ0oxFNCRHwEulHqcWc': User( - id: 'jaap', + id: 'deven', extraData: { - 'name': 'Jaap', + 'name': 'Deven Joshi', + 'image': + 'https://ca.slack-edge.com/T02RM6X6B-U01AM7ELPTL-8a60da32704c-512', + }, + ), + 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoibmVldmFzaCJ9.3EdHegTxibrz3A9cTiKmpEyawwcCVB8FXnoFzr4eKvw': + User( + id: 'neevash', + extraData: { + 'name': 'Neevash Ramdial', + 'image': + 'https://ca.slack-edge.com/T02RM6X6B-U01DZ046DS8-b00d321d2880-512', + }, + ), + 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoicWF0ZXN0MSJ9.fnelU7HcP7QoEEsCGteNlF1fppofzNlrnpDQuIgeKCU': + User( + id: 'qatest1', + extraData: { + 'name': 'QA test 1', + }, + ), + 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoicWF0ZXN0MiJ9.vSCqAEbs2WVmMWsOsa7065Fsjq-rsTih6qsHPynl7XM': + User( + id: 'qatest2', + extraData: { + 'name': 'QA test 2', }, ), }; - users.updateAll( - (_, value) => value..extraData['image'] = getRandomPicUrl(value)); - return Scaffold( backgroundColor: StreamChatTheme.of(context).colorTheme.whiteSnow, body: SafeArea( From c87c1d5368bdc18a708a3b0656de3d62c5bf00fa Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Thu, 28 Jan 2021 16:40:36 +0530 Subject: [PATCH 1064/1140] [LLC] Remove flutter dependency Signed-off-by: Sahil Kumar --- .../dart_client/lib/src/api/retry_policy.dart | 2 +- .../dart_client/lib/src/api/retry_queue.dart | 3 +- .../dart_client/lib/src/api/websocket.dart | 26 +++++++---- packages/dart_client/lib/src/client.dart | 46 +++++++++++-------- packages/dart_client/pubspec.yaml | 3 -- 5 files changed, 45 insertions(+), 35 deletions(-) diff --git a/packages/dart_client/lib/src/api/retry_policy.dart b/packages/dart_client/lib/src/api/retry_policy.dart index 43af3b8e..270d558c 100644 --- a/packages/dart_client/lib/src/api/retry_policy.dart +++ b/packages/dart_client/lib/src/api/retry_policy.dart @@ -1,4 +1,4 @@ -import 'package:flutter/foundation.dart'; +import 'package:meta/meta.dart'; import 'package:stream_chat/src/client.dart'; import 'package:stream_chat/src/exceptions.dart'; diff --git a/packages/dart_client/lib/src/api/retry_queue.dart b/packages/dart_client/lib/src/api/retry_queue.dart index 376854af..534d9c08 100644 --- a/packages/dart_client/lib/src/api/retry_queue.dart +++ b/packages/dart_client/lib/src/api/retry_queue.dart @@ -1,8 +1,7 @@ import 'dart:async'; import 'package:collection/collection.dart'; -import 'package:flutter/cupertino.dart'; -import 'package:flutter/foundation.dart'; +import 'package:meta/meta.dart'; import 'package:logging/logging.dart'; import 'package:stream_chat/src/api/channel.dart'; import 'package:stream_chat/src/api/retry_policy.dart'; diff --git a/packages/dart_client/lib/src/api/websocket.dart b/packages/dart_client/lib/src/api/websocket.dart index bdd14a1e..a610c041 100644 --- a/packages/dart_client/lib/src/api/websocket.dart +++ b/packages/dart_client/lib/src/api/websocket.dart @@ -2,9 +2,9 @@ import 'dart:async'; import 'dart:convert'; import 'dart:math'; -import 'package:flutter/foundation.dart'; -import 'package:flutter/material.dart'; +import 'package:meta/meta.dart'; import 'package:logging/logging.dart'; +import 'package:rxdart/rxdart.dart'; import 'package:web_socket_channel/web_socket_channel.dart'; import '../models/event.dart'; @@ -99,9 +99,15 @@ class WebSocket { /// The timeout that uses the reconnection monitor timer to consider the connection unhealthy final int reconnectionMonitorTimeout; + final _connectionStatusController = + BehaviorSubject.seeded(ConnectionStatus.disconnected); + + set _connectionStatus(ConnectionStatus status) => + _connectionStatusController.add(status); + /// This notifies of connection status changes - final ValueNotifier connectionStatus = - ValueNotifier(ConnectionStatus.disconnected); + Stream get connectionStatusStream => + _connectionStatusController.stream; String _path; int _retryAttempt = 1; @@ -128,7 +134,7 @@ class WebSocket { } _connecting = true; - connectionStatus.value = ConnectionStatus.connecting; + _connectionStatus = ConnectionStatus.connecting; logger.info('connecting to $_path'); @@ -175,7 +181,7 @@ class WebSocket { _reconnecting = false; _lastEventAt = DateTime.now(); - connectionStatus.value = ConnectionStatus.connected; + _connectionStatus = ConnectionStatus.connected; _retryAttempt = 1; if (!_connectionCompleter.isCompleted) { @@ -199,7 +205,7 @@ class WebSocket { _connecting = false; if (!_reconnecting) { - connectionStatus.value = ConnectionStatus.disconnected; + _connectionStatus = ConnectionStatus.disconnected; } if (!_connectionCompleter.isCompleted) { @@ -258,7 +264,7 @@ class WebSocket { logger.info('reconnect'); if (!_reconnecting) { _reconnecting = true; - connectionStatus.value = ConnectionStatus.connecting; + _connectionStatus = ConnectionStatus.connecting; } _reconnectTimer(); @@ -300,8 +306,8 @@ class WebSocket { _cancelTimers(); _reconnecting = false; _manuallyDisconnected = true; - connectionStatus.value = ConnectionStatus.disconnected; - connectionStatus.dispose(); + _connectionStatus = ConnectionStatus.disconnected; + await _connectionStatusController.close(); return _channel.sink.close(); } } diff --git a/packages/dart_client/lib/src/client.dart b/packages/dart_client/lib/src/client.dart index f2a6f0c0..603b9b0e 100644 --- a/packages/dart_client/lib/src/client.dart +++ b/packages/dart_client/lib/src/client.dart @@ -3,7 +3,7 @@ import 'dart:convert'; import 'dart:io'; import 'package:dio/dio.dart'; -import 'package:flutter/cupertino.dart'; +import 'package:meta/meta.dart'; import 'package:logging/logging.dart'; import 'package:rxdart/rxdart.dart'; import 'package:shared_preferences/shared_preferences.dart'; @@ -93,8 +93,6 @@ class Client { this.backgroundKeepAlive = const Duration(minutes: 1), RetryPolicy retryPolicy, }) { - WidgetsFlutterBinding.ensureInitialized(); - _retryPolicy ??= RetryPolicy( retryTimeout: (Client client, int attempt, ApiError error) => Duration(seconds: 1 * attempt), @@ -180,7 +178,8 @@ class Client { static const _defaultBaseURL = 'chat-us-east-1.stream-io-api.com'; static const _tokenExpiredErrorCode = 40; - VoidCallback _connectionStatusListener; + StreamSubscription _connectionStatusSubscription; + Future Function(ConnectionStatus) _connectionStatusHandler; final BehaviorSubject _controller = BehaviorSubject(); @@ -188,10 +187,20 @@ class Client { /// Listen to this or use the [on] method to filter specific event types Stream get stream => _controller.stream; + final _wsConnectionStatusController = + BehaviorSubject.seeded(ConnectionStatus.disconnected); + + set _wsConnectionStatus(ConnectionStatus status) => + _wsConnectionStatusController.add(status); + + /// The current status value of the websocket connection + ConnectionStatus get wsConnectionStatus => + _wsConnectionStatusController.value; + /// This notifies the connection status of the websocket connection. /// Listen to this to get notified when the websocket tries to reconnect. - final ValueNotifier wsConnectionStatus = - ValueNotifier(ConnectionStatus.disconnected); + Stream get wsConnectionStatusStream => + _wsConnectionStatusController.stream; /// The current user token String token; @@ -275,8 +284,6 @@ class Client { httpClient.lock(); final userId = state.user.id; - _ws.connectionStatus.removeListener(_connectionStatusListener); - await _disconnect(); final newToken = await tokenProvider(userId); @@ -345,8 +352,8 @@ class Client { await _disconnect(); httpClient.close(); await _controller.close(); - state.channels.values.forEach((c) => c.dispose()); state.dispose(); + await _wsConnectionStatusController.close(); } Map get _httpHeaders => { @@ -443,17 +450,17 @@ class Client { /// Connect the client websocket Future connect() async { logger.info('connecting'); - if (wsConnectionStatus.value == ConnectionStatus.connecting) { + if (wsConnectionStatus == ConnectionStatus.connecting) { logger.warning('Already connecting'); throw Exception('Already connecting'); } - if (wsConnectionStatus.value == ConnectionStatus.connected) { + if (wsConnectionStatus == ConnectionStatus.connected) { logger.warning('Already connected'); throw Exception('Already connected'); } - wsConnectionStatus.value = ConnectionStatus.connecting; + _wsConnectionStatus = ConnectionStatus.connecting; if (persistenceEnabled) { await chatPersistenceClient.connect(state.user.id); @@ -476,15 +483,14 @@ class Client { logger: _detachedLogger('🔌'), ); - _connectionStatusListener = () async { - final value = _ws.connectionStatus.value; - wsConnectionStatus.value = value; + _connectionStatusHandler = (ConnectionStatus status) async { + _wsConnectionStatus = status; handleEvent(Event( type: EventType.connectionChanged, - online: value == ConnectionStatus.connected, + online: status == ConnectionStatus.connected, )); - if (value == ConnectionStatus.connected && + if (status == ConnectionStatus.connected && state.channels?.isNotEmpty == true) { unawaited(queryChannels(filter: { 'cid': { @@ -504,7 +510,8 @@ class Client { } }; - _ws.connectionStatus.addListener(_connectionStatusListener); + _connectionStatusSubscription = + _ws.connectionStatusStream.listen(_connectionStatusHandler); var event = await chatPersistenceClient?.getConnectionInfo(); @@ -588,7 +595,7 @@ class Client { logger.info('awaiting connection completer'); await _connectCompleter.future; } - if (wsConnectionStatus.value != ConnectionStatus.connected) { + if (wsConnectionStatus != ConnectionStatus.connected) { final errorMessage = 'You cannot use queryChannels without an active connection. Please call setUser to connect the client.'; if (persistenceEnabled) { @@ -946,6 +953,7 @@ class Client { logger.info('Client disconnecting'); await _ws?.disconnect(); + await _connectionStatusSubscription?.cancel(); } /// Requests users with a given query. diff --git a/packages/dart_client/pubspec.yaml b/packages/dart_client/pubspec.yaml index 024f9d90..c55753e6 100644 --- a/packages/dart_client/pubspec.yaml +++ b/packages/dart_client/pubspec.yaml @@ -9,8 +9,6 @@ environment: sdk: ">=2.7.0 <3.0.0" dependencies: - flutter: - sdk: flutter json_annotation: ^3.0.1 shared_preferences: ^0.5.7+3 logging: ^0.11.4 @@ -21,7 +19,6 @@ dependencies: rxdart: ^0.24.1 collection: ^1.14.12 pedantic: ^1.9.2 - freezed: ^0.12.7 dev_dependencies: build_runner: ^1.10.0 From a2a40b5f86c3e6078726d13e9b2191143480965f Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Thu, 28 Jan 2021 16:42:51 +0530 Subject: [PATCH 1065/1140] [LLC] Remove notification handling logics Signed-off-by: Sahil Kumar --- packages/dart_client/lib/src/client.dart | 15 --- .../dart_client/lib/src/notifications.dart | 99 ------------------- packages/dart_client/lib/stream_chat.dart | 1 - packages/dart_client/pubspec.yaml | 1 - 4 files changed, 116 deletions(-) delete mode 100644 packages/dart_client/lib/src/notifications.dart diff --git a/packages/dart_client/lib/src/client.dart b/packages/dart_client/lib/src/client.dart index 603b9b0e..988f0f8f 100644 --- a/packages/dart_client/lib/src/client.dart +++ b/packages/dart_client/lib/src/client.dart @@ -6,7 +6,6 @@ import 'package:dio/dio.dart'; import 'package:meta/meta.dart'; import 'package:logging/logging.dart'; import 'package:rxdart/rxdart.dart'; -import 'package:shared_preferences/shared_preferences.dart'; import 'package:stream_chat/src/api/retry_policy.dart'; import 'package:stream_chat/src/event_type.dart'; import 'package:stream_chat/src/models/channel_model.dart'; @@ -37,15 +36,6 @@ typedef DecoderFunction = T Function(Map); /// own backend server. Function requires a single [userId]. typedef TokenProvider = Future Function(String userId); -/// The key used to save the userId to sharedPreferences -const String KEY_USER_ID = 'KEY_USER_ID'; - -/// The key used to save the token to sharedPreferences -const String KEY_TOKEN = 'KEY_TOKEN'; - -/// The key used to save the apiKey to sharedPreferences -const String KEY_API_KEY = 'KEY_API_KEY'; - /// Provider used to send push notifications. enum PushProvider { /// Send notifications using Google's Firebase Cloud Messaging @@ -378,11 +368,6 @@ class Client { this.token = token; _anonymous = false; - final sharedPreferences = await SharedPreferences.getInstance(); - await sharedPreferences.setString(KEY_USER_ID, user.id); - await sharedPreferences.setString(KEY_TOKEN, token); - await sharedPreferences.setString(KEY_API_KEY, apiKey); - return connect().then((event) { _connectCompleter.complete(event); return event; diff --git a/packages/dart_client/lib/src/notifications.dart b/packages/dart_client/lib/src/notifications.dart deleted file mode 100644 index 82070fd2..00000000 --- a/packages/dart_client/lib/src/notifications.dart +++ /dev/null @@ -1,99 +0,0 @@ -import 'dart:convert'; - -import 'package:shared_preferences/shared_preferences.dart'; -import 'package:stream_chat/src/api/responses.dart'; -import 'package:stream_chat/src/models/channel_model.dart'; -import 'package:stream_chat/src/models/channel_state.dart'; -import 'package:stream_chat/src/models/message.dart'; -import 'package:meta/meta.dart'; - -import 'client.dart'; -import 'models/own_user.dart'; - -/// Utility class to handle and show notifications -class NotificationService { - static Future _handleNotification( - Message message, - ChannelModel channelModel, - Client client, - ) async { - if (message != null && client.persistenceEnabled) { - if (client?.state?.channels == null) { - final chatPersistenceClient = client.chatPersistenceClient; - await chatPersistenceClient.updateChannelState( - ChannelState( - channel: channelModel, - messages: [message], - ), - ); - } else { - final channel = client.state.channels[channelModel.cid]; - channel.state.updateChannelState( - ChannelState( - channel: channelModel, - messages: [message], - ), - ); - } - } - } - - static SharedPreferences _sharedPreferences; - - static Future _getSharedPreferences() async { - _sharedPreferences ??= await SharedPreferences.getInstance(); - return _sharedPreferences; - } - - /// Gets the message using the client without storing it in the offline storage - /// It returns an object containing the information about the message and the channel - static Future _getMessage(String messageId) async { - final sharedPreferences = await _getSharedPreferences(); - final apiKey = sharedPreferences.getString(KEY_API_KEY); - - final client = Client(apiKey); - final userId = sharedPreferences.getString(KEY_USER_ID); - final token = sharedPreferences.getString(KEY_TOKEN); - - client.state.user = OwnUser(id: userId); - client.token = token; - - final res = await client.getMessage(messageId); - return res; - } - - /// Gets the message using the client and calls a [storeMessageHandler] callback - /// with the message if the user wants to save the message in db - /// - /// It returns an object containing the information about the message and the channel - static Future getAndStoreMessage({ - @required String messageId, - @required Future Function(GetMessageResponse) storeMessageHandler, - }) async { - final getMessageResponse = await _getMessage(messageId); - await storeMessageHandler(getMessageResponse); - return getMessageResponse; - } - - /// Handles the ios message queue generated by the Notification Service Extension - static Future handleIosMessageQueue(Client client) async { - final sharedPreferences = await SharedPreferences.getInstance(); - await sharedPreferences.reload(); - final messageQueue = sharedPreferences.getStringList('messageQueue'); - if (messageQueue != null) { - messageQueue.forEach((m) { - final jsonMessage = jsonDecode(m); - - final message = Message.fromJson(jsonMessage); - final channelModel = ChannelModel.fromJson(jsonMessage['channel']); - - _handleNotification( - message, - channelModel, - client, - ); - }); - await sharedPreferences.remove('messageQueue'); - } - } -} diff --git a/packages/dart_client/lib/stream_chat.dart b/packages/dart_client/lib/stream_chat.dart index 00525b40..590175c4 100644 --- a/packages/dart_client/lib/stream_chat.dart +++ b/packages/dart_client/lib/stream_chat.dart @@ -26,5 +26,4 @@ export './src/models/own_user.dart'; export './src/models/reaction.dart'; export './src/models/read.dart'; export './src/models/user.dart'; -export './src/notifications.dart'; export './src/db/chat_persistence_client.dart'; diff --git a/packages/dart_client/pubspec.yaml b/packages/dart_client/pubspec.yaml index c55753e6..e548fcae 100644 --- a/packages/dart_client/pubspec.yaml +++ b/packages/dart_client/pubspec.yaml @@ -10,7 +10,6 @@ environment: dependencies: json_annotation: ^3.0.1 - shared_preferences: ^0.5.7+3 logging: ^0.11.4 dio: ^3.0.10 web_socket_channel: ^1.1.0 From b480d73da0cfe71db0bc62c5c6e755dfe6e463a5 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Thu, 28 Jan 2021 12:17:34 +0100 Subject: [PATCH 1066/1140] bump version of example app --- packages/flutter_widgets/example/pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/flutter_widgets/example/pubspec.yaml b/packages/flutter_widgets/example/pubspec.yaml index fea15136..d3116148 100644 --- a/packages/flutter_widgets/example/pubspec.yaml +++ b/packages/flutter_widgets/example/pubspec.yaml @@ -1,7 +1,7 @@ name: example description: A new Flutter project. publish_to: 'none' -version: 1.1.3+6 +version: 1.2.0 environment: sdk: ">=2.2.2 <3.0.0" From c741a86c3ee3a4a555f226861db73ede57948d17 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Thu, 28 Jan 2021 17:22:44 +0530 Subject: [PATCH 1067/1140] feat: Added better README.md for both packages, added LICENSE --- packages/flutter_widgets/README.md | 10 +- packages/stream_chat_flutter_core/LICENSE | 220 +++++++++++++++++- packages/stream_chat_flutter_core/README.md | 47 ++-- .../lib/src/message_list_core.dart | 25 +- 4 files changed, 271 insertions(+), 31 deletions(-) diff --git a/packages/flutter_widgets/README.md b/packages/flutter_widgets/README.md index c5e4c9e7..8104e83a 100644 --- a/packages/flutter_widgets/README.md +++ b/packages/flutter_widgets/README.md @@ -60,13 +60,9 @@ If it seems related to the [flutter file picker plugin](https://github.com/migue ## Docs -### Business logic components - -We provide 3 Widgets dedicated to business logic and state management: - -- [StreamChat](https://pub.dev/documentation/stream_chat_flutter/latest/stream_chat_flutter/StreamChat-class.html) -- [StreamChannel](https://pub.dev/documentation/stream_chat_flutter/latest/stream_chat_flutter/StreamChannel-class.html) -- [ChannelsBloc](https://pub.dev/documentation/stream_chat_flutter/0.2.0-alpha+2/stream_chat_flutter/ChannelsBloc-class.html) +This package provides UI components required for integrating Stream Chat into your application. +Alternatively, you may use the core package (stream_chat_flutter_core) which allows more customisation and provides business logic but no UI components. +If you require the maximum amount of control over the API, please use the low level client package: stream_chat. ### UI Components diff --git a/packages/stream_chat_flutter_core/LICENSE b/packages/stream_chat_flutter_core/LICENSE index ba75c69f..49088d47 100644 --- a/packages/stream_chat_flutter_core/LICENSE +++ b/packages/stream_chat_flutter_core/LICENSE @@ -1 +1,219 @@ -TODO: Add your license here. +SOURCE CODE LICENSE AGREEMENT + +IMPORTANT - READ THIS CAREFULLY BEFORE DOWNLOADING, INSTALLING, USING OR +ELECTRONICALLY ACCESSING THIS PROPRIETARY PRODUCT. + +THIS IS A LEGAL AGREEMENT BETWEEN STREAM.IO, INC. (“STREAM.IO”) AND THE +BUSINESS ENTITY OR PERSON FOR WHOM YOU (“YOU”) ARE ACTING (“CUSTOMER”) AS THE +LICENSEE OF THE PROPRIETARY SOFTWARE INTO WHICH THIS AGREEMENT HAS BEEN +INCLUDED (THE “AGREEMENT”). YOU AGREE THAT YOU ARE THE CUSTOMER, OR YOU ARE AN +EMPLOYEE OR AGENT OF CUSTOMER AND ARE ENTERING INTO THIS AGREEMENT FOR LICENSE +OF THE SOFTWARE BY CUSTOMER FOR CUSTOMER’S BUSINESS PURPOSES AS DESCRIBED IN +AND IN ACCORDANCE WITH THIS AGREEMENT. YOU HEREBY AGREE THAT YOU ENTER INTO +THIS AGREEMENT ON BEHALF OF CUSTOMER AND THAT YOU HAVE THE AUTHORITY TO BIND +CUSTOMER TO THIS AGREEMENT. + +STREAM.IO IS WILLING TO LICENSE THE SOFTWARE TO CUSTOMER ONLY ON THE FOLLOWING +CONDITIONS: (1) YOU ARE A CURRENT CUSTOMER OF STREAM.IO; (2) YOU ARE NOT A +COMPETITOR OF STREAM.IO; AND (3) THAT YOU ACCEPT ALL THE TERMS IN THIS +AGREEMENT. BY DOWNLOADING, INSTALLING, CONFIGURING, ACCESSING OR OTHERWISE +USING THE SOFTWARE, INCLUDING ANY UPDATES, UPGRADES, OR NEWER VERSIONS, YOU +REPRESENT, WARRANT AND ACKNOWLEDGE THAT (A) CUSTOMER IS A CURRENT CUSTOMER OF +STREAM.IO; (B) CUSTOMER IS NOT A COMPETITOR OF STREAM.IO; AND THAT (C) YOU HAVE +READ THIS AGREEMENT, UNDERSTAND THIS AGREEMENT, AND THAT CUSTOMER AGREES TO BE +BOUND BY ALL THE TERMS OF THIS AGREEMENT. + +IF YOU DO NOT AGREE TO ALL THE TERMS AND CONDITIONS OF THIS AGREEMENT, +STREAM.IO IS UNWILLING TO LICENSE THE SOFTWARE TO CUSTOMER, AND THEREFORE, DO +NOT COMPLETE THE DOWNLOAD PROCESS, ACCESS OR OTHERWISE USE THE SOFTWARE, AND +CUSTOMER SHOULD IMMEDIATELY RETURN THE SOFTWARE AND CEASE ANY USE OF THE +SOFTWARE. + +1. SOFTWARE. The Stream.io software accompanying this Agreement, may include +Source Code, Executable Object Code, associated media, printed materials and +documentation (collectively, the “Software”). The Software also includes any +updates or upgrades to or new versions of the original Software, if and when +made available to you by Stream.io. “Source Code” means computer programming +code in human readable form that is not suitable for machine execution without +the intervening steps of interpretation or compilation. “Executable Object +Code" means the computer programming code in any other form than Source Code +that is not readily perceivable by humans and suitable for machine execution +without the intervening steps of interpretation or compilation. “Site” means a +Customer location controlled by Customer. “Authorized User” means any employee +or contractor of Customer working at the Site, who has signed a written +confidentiality agreement with Customer or is otherwise bound in writing by +confidentiality and use obligations at least as restrictive as those imposed +under this Agreement. + +2. LICENSE GRANT. Subject to the terms and conditions of this Agreement, in +consideration for the representations, warranties, and covenants made by +Customer in this Agreement, Stream.io grants to Customer, during the term of +this Agreement, a personal, non-exclusive, non-transferable, non-sublicensable +license to: + +a. install and use Software Source Code on password protected computers at a Site, +restricted to Authorized Users; + +b. create derivative works, improvements (whether or not patentable), extensions +and other modifications to the Software Source Code (“Modifications”) to build +unique scalable newsfeeds, activity streams, and in-app messaging via Stream’s +application program interface (“API”); + +c. compile the Software Source Code to create Executable Object Code versions of +the Software Source Code and Modifications to build such newsfeeds, activity +streams, and in-app messaging via the API; + +d. install, execute and use such Executable Object Code versions solely for +Customer’s internal business use (including development of websites through +which data generated by Stream services will be streamed (“Apps”)); + +e. use and distribute such Executable Object Code as part of Customer’s Apps; and + +f. make electronic copies of the Software and Modifications as required for backup +or archival purposes. + +3. RESTRICTIONS. Customer is responsible for all activities that occur in +connection with the Software. Customer will not, and will not attempt to: (a) +sublicense or transfer the Software or any Source Code related to the Software +or any of Customer’s rights under this Agreement, except as otherwise provided +in this Agreement, (b) use the Software Source Code for the benefit of a third +party or to operate a service; (c) allow any third party to access or use the +Software Source Code; (d) sublicense or distribute the Software Source Code or +any Modifications in Source Code or other derivative works based on any part of +the Software Source Code; (e) use the Software in any manner that competes with +Stream.io or its business; or (e) otherwise use the Software in any manner that +exceeds the scope of use permitted in this Agreement. Customer shall use the +Software in compliance with any accompanying documentation any laws applicable +to Customer. + +4. OPEN SOURCE. Customer and its Authorized Users shall not use any software or +software components that are open source in conjunction with the Software +Source Code or any Modifications in Source Code or in any way that could +subject the Software to any open source licenses. + +5. CONTRACTORS. Under the rights granted to Customer under this Agreement, +Customer may permit its employees, contractors, and agencies of Customer to +become Authorized Users to exercise the rights to the Software granted to +Customer in accordance with this Agreement solely on behalf of Customer to +provide services to Customer; provided that Customer shall be liable for the +acts and omissions of all Authorized Users to the extent any of such acts or +omissions, if performed by Customer, would constitute a breach of, or otherwise +give rise to liability to Customer under, this Agreement. Customer shall not +and shall not permit any Authorized User to use the Software except as +expressly permitted in this Agreement. + +6. COMPETITIVE PRODUCT DEVELOPMENT. Customer shall not use the Software in any way +to engage in the development of products or services which could be reasonably +construed to provide a complete or partial functional or commercial alternative +to Stream.io’s products or services (a “Competitive Product”). Customer shall +ensure that there is no direct or indirect use of, or sharing of, Software +source code, or other information based upon or derived from the Software to +develop such products or services. Without derogating from the generality of +the foregoing, development of Competitive Products shall include having direct +or indirect access to, supervising, consulting or assisting in the development +of, or producing any specifications, documentation, object code or source code +for, all or part of a Competitive Product. + +7. LIMITATION ON MODIFICATIONS. Notwithstanding any provision in this Agreement, +Modifications may only be created and used by Customer as permitted by this +Agreement and Modification Source Code may not be distributed to third parties. +Customer will not assert against Stream.io, its affiliates, or their customers, +direct or indirect, agents and contractors, in any way, any patent rights that +Customer may obtain relating to any Modifications for Stream.io, its +affiliates’, or their customers’, direct or indirect, agents’ and contractors’ +manufacture, use, import, offer for sale or sale of any Stream.io products or +services. + +8. DELIVERY AND ACCEPTANCE. The Software will be delivered electronically pursuant +to Stream.io standard download procedures. The Software is deemed accepted upon +delivery. + +9. IMPLEMENTATION AND SUPPORT. Stream.io has no obligation under this Agreement to +provide any support or consultation concerning the Software. + +10. TERM AND TERMINATION. The term of this Agreement begins when the Software is +downloaded or accessed and shall continue until terminated. Either party may +terminate this Agreement upon written notice. This Agreement shall +automatically terminate if Customer is or becomes a competitor of Stream.io or +makes or sells any Competitive Products. Upon termination of this Agreement for +any reason, (a) all rights granted to Customer in this Agreement immediately +cease to exist, (b) Customer must promptly discontinue all use of the Software +and return to Stream.io or destroy all copies of the Software in Customer’s +possession or control. Any continued use of the Software by Customer or attempt +by Customer to exercise any rights under this Agreement after this Agreement +has terminated shall be considered copyright infringement and subject Customer +to applicable remedies for copyright infringement. Sections 2, 5, 6, 8 and 9 +shall survive expiration or termination of this Agreement for any reason. + +11. OWNERSHIP. As between the parties, the Software and all worldwide intellectual +property rights and proprietary rights relating thereto or embodied therein, +are the exclusive property of Stream.io and its suppliers. Stream.io and its +suppliers reserve all rights in and to the Software not expressly granted to +Customer in this Agreement, and no other licenses or rights are granted by +implication, estoppel or otherwise. + +12. WARRANTY DISCLAIMER. USE OF THIS SOFTWARE IS ENTIRELY AT YOURS AND CUSTOMER’S +OWN RISK. THE SOFTWARE IS PROVIDED “AS IS” WITHOUT ANY WARRANTY OF ANY KIND +WHATSOEVER. STREAM.IO DOES NOT MAKE, AND HEREBY DISCLAIMS, ANY WARRANTY OF ANY +KIND, WHETHER EXPRESS, IMPLIED, STATUTORY OR OTHERWISE, INCLUDING WITHOUT +LIMITATION, THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +PURPOSE, TITLE, NON-INFRINGEMENT OF THIRD-PARTY RIGHTS, RESULTS, EFFORTS, +QUALITY OR QUIET ENJOYMENT. STREAM.IO DOES NOT WARRANT THAT THE SOFTWARE IS +ERROR-FREE, WILL FUNCTION WITHOUT INTERRUPTION, WILL MEET ANY SPECIFIC NEED +THAT CUSTOMER HAS, THAT ALL DEFECTS WILL BE CORRECTED OR THAT IT IS +SUFFICIENTLY DOCUMENTED TO BE USABLE BY CUSTOMER. TO THE EXTENT THAT STREAM.IO +MAY NOT DISCLAIM ANY WARRANTY AS A MATTER OF APPLICABLE LAW, THE SCOPE AND +DURATION OF SUCH WARRANTY WILL BE THE MINIMUM PERMITTED UNDER SUCH LAW. +CUSTOMER ACKNOWLEDGES THAT IT HAS RELIED ON NO WARRANTIES OTHER THAN THE +EXPRESS WARRANTIES IN THIS AGREEMENT. + +13. LIMITATION OF LIABILITY. TO THE FULLEST EXTENT PERMISSIBLE BY LAW, STREAM.IO’S +TOTAL LIABILITY FOR ALL DAMAGES ARISING OUT OF OR RELATED TO THE SOFTWARE OR +THIS AGREEMENT, WHETHER IN CONTRACT, TORT (INCLUDING NEGLIGENCE) OR OTHERWISE, +SHALL NOT EXCEED $100. IN NO EVENT WILL STREAM.IO BE LIABLE FOR ANY INDIRECT, +CONSEQUENTIAL, EXEMPLARY, PUNITIVE, SPECIAL OR INCIDENTAL DAMAGES OF ANY KIND +WHATSOEVER, INCLUDING ANY LOST DATA AND LOST PROFITS, ARISING FROM OR RELATING +TO THE SOFTWARE EVEN IF STREAM.IO HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. CUSTOMER ACKNOWLEDGES THAT THIS PROVISION REFLECTS THE AGREED UPON +ALLOCATION OF RISK FOR THIS AGREEMENT AND THAT STREAM.IO WOULD NOT ENTER INTO +THIS AGREEMENT WITHOUT THESE LIMITATIONS ON ITS LIABILITY. + +14. General. Customer may not assign or transfer this Agreement, by operation of +law or otherwise, or any of its rights under this Agreement (including the +license rights granted to Customer) to any third party without Stream.io’s +prior written consent, which consent will not be unreasonably withheld or +delayed. Stream.io may assign this Agreement, without consent, including, but +limited to, affiliate or any successor to all or substantially all its business +or assets to which this Agreement relates, whether by merger, sale of assets, +sale of stock, reorganization or otherwise. Any attempted assignment or +transfer in violation of the foregoing will be null and void. Stream.io shall +not be liable hereunder by reason of any failure or delay in the performance of +its obligations hereunder for any cause which is beyond the reasonable control. +All notices, consents, and approvals under this Agreement must be delivered in +writing by courier, by electronic mail, or by certified or registered mail, +(postage prepaid and return receipt requested) to the other party at the +address set forth in the customer agreement between Stream.io and Customer and +will be effective upon receipt or when delivery is refused. This Agreement will +be governed by and interpreted in accordance with the laws of the State of +Colorado, without reference to its choice of laws rules. The United Nations +Convention on Contracts for the International Sale of Goods does not apply to +this Agreement. Any action or proceeding arising from or relating to this +Agreement shall be brought in a federal or state court in Denver, Colorado, and +each party irrevocably submits to the jurisdiction and venue of any such court +in any such action or proceeding. All waivers must be in writing. Any waiver or +failure to enforce any provision of this Agreement on one occasion will not be +deemed a waiver of any other provision or of such provision on any other +occasion. If any provision of this Agreement is unenforceable, such provision +will be changed and interpreted to accomplish the objectives of such provision +to the greatest extent possible under applicable law and the remaining +provisions will continue in full force and effect. Customer shall not violate +any applicable law, rule or regulation, including those regarding the export of +technical data. The headings of Sections of this Agreement are for convenience +and are not to be used in interpreting this Agreement. As used in this +Agreement, the word “including” means “including but not limited to.” This +Agreement (including all exhibits and attachments) constitutes the entire +agreement between the parties regarding the subject hereof and supersedes all +prior or contemporaneous agreements, understandings and communication, whether +written or oral. This Agreement may be amended only by a written document +signed by both parties. The terms of any purchase order or similar document +submitted by Customer to Stream.io will have no effect. diff --git a/packages/stream_chat_flutter_core/README.md b/packages/stream_chat_flutter_core/README.md index 30ab07f5..a62da863 100644 --- a/packages/stream_chat_flutter_core/README.md +++ b/packages/stream_chat_flutter_core/README.md @@ -27,7 +27,7 @@ It teaches you how to use this SDK and also shows how to make frequently require ## Example App This repo includes a fully functional example app with setup instructions. -The example is available under the [example](https://github.com/GetStream/stream-chat-flutter/tree/master/example) folder. +The example is available under the [example](https://github.com/GetStream/stream-chat-flutter-core/tree/master/example) folder. ## Add dependency Add this to your package's pubspec.yaml file, use the latest version [![Pub](https://img.shields.io/pub/v/stream_chat_flutter.svg)](https://pub.dartlang.org/packages/stream_chat_flutter) @@ -44,21 +44,42 @@ This package requires no custom setup on any platform since it does not depend o This package provides business logic to fetch common things required for integrating Stream Chat into your application. The core package allows more customisation and hence provides business logic but no UI components. -Please use the stream_chat_flutter package for the full fledged suite of UI components. +Please use the stream_chat_flutter package for the full fledged suite of UI components or stream_chat for the low-level client. -### Business logic components +The package primarily contains three types of classes: -We provide widgets dedicated to business logic and state management: +1) Business Logic Components +2) Core Components +3) Core Controllers -- [StreamChatCore](https://pub.dev/documentation/stream_chat_flutter/latest/stream_chat_flutter/StreamChat-class.html) -- [StreamChannel](https://pub.dev/documentation/stream_chat_flutter/latest/stream_chat_flutter/StreamChannel-class.html) -- [ChannelsBloc](https://pub.dev/documentation/stream_chat_flutter/0.2.0-alpha+2/stream_chat_flutter/ChannelsBloc-class.html) -- [MessageSearchBloc] -- [UsersBloc] -- [ChannelListCore] -- [MessageListCore] -- [MessageSearchListCore] -- [UserListCore] +### Business Logic Components + +These components allow you to have the maximum and lower-level control of the queries being executed. +The BLoCs we provide are: + +1) ChannelsBloc +2) MessageSearchBloc +3) UsersBloc + +### Core Components + +Core components usually are an easy way to fetch data associated with Stream Chat which are decoupled from UI and often expose UI builders. +Data fetching can be controlled with the controllers of the respective core components. + +1) ChannelListCore (Fetch a list of channels) +2) MessageListCore (Fetch a list of messages from a channel) +3) MessageSearchListCore (Fetch a list of search messages) +4) UserListCore (Fetch a list of users) +5) StreamChatCore (This is different from the other core components - it is a version of StreamChat decoupled from theme and initialisations.) + +### Core Controllers + +Core Controllers are supplied to respective CoreList widgets which allows reloading and pagination of data whenever needed. + +1) ChannelListController +2) MessageListController +3) MessageSearchListController +4) ChannelListController ## Contributing diff --git a/packages/stream_chat_flutter_core/lib/src/message_list_core.dart b/packages/stream_chat_flutter_core/lib/src/message_list_core.dart index 81d29a6b..e6754ee8 100644 --- a/packages/stream_chat_flutter_core/lib/src/message_list_core.dart +++ b/packages/stream_chat_flutter_core/lib/src/message_list_core.dart @@ -35,14 +35,19 @@ typedef StreamErrorBuilder = Widget Function( /// child: Text('Nothing here...'), /// ); /// }, -/// emptyBuilder: (context) { +/// loadingBuilder: (context) { /// return Center( /// child: CircularProgressIndicator(), /// ); /// }, /// messageListBuilder: (context, list) { /// return MessagesPage(list); -/// } +/// }, +/// errorWidgetBuilder: (context, err) { +/// return Center( +/// child: Text('Error'), +/// ); +/// }, /// ), /// ), /// ], @@ -122,14 +127,14 @@ class _MessageListCoreState extends State { : streamChannel.channel.state?.messagesStream; return StreamBuilder>( - stream: messagesStream?.map((messages) => messages - ?.where((e) => - (!e.isDeleted && e.shadowed != true) || - (e.isDeleted && - e.user.id == streamChannel.channel.client.state.user.id)) - ?.toList()), - builder: (context, snapshot) { - if (!snapshot.hasData) { + stream: messagesStream?.map((messages) => messages + ?.where((e) => + (!e.isDeleted && e.shadowed != true) || + (e.isDeleted && + e.user.id == streamChannel.channel.client.state.user.id)) + ?.toList()), + builder: (context, snapshot) { + if (!snapshot.hasData) { return widget.loadingBuilder(context); } else if (snapshot.hasError) { return widget.errorWidgetBuilder(context, snapshot.error); From 6e5894eebeaeb2c735c8a024ec8e93e9ceee63a0 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Thu, 28 Jan 2021 17:23:59 +0530 Subject: [PATCH 1068/1140] [LLC] fix tests Signed-off-by: Sahil Kumar --- packages/dart_client/lib/src/api/websocket.dart | 3 +++ packages/dart_client/test/src/api/channel_test.dart | 2 +- packages/dart_client/test/src/api/requests_test.dart | 2 +- packages/dart_client/test/src/api/responses_test.dart | 2 +- packages/dart_client/test/src/api/web_socket_stub_test.dart | 2 +- packages/dart_client/test/src/api/websocket_test.dart | 4 ++-- 6 files changed, 9 insertions(+), 6 deletions(-) diff --git a/packages/dart_client/lib/src/api/websocket.dart b/packages/dart_client/lib/src/api/websocket.dart index a610c041..15102c6e 100644 --- a/packages/dart_client/lib/src/api/websocket.dart +++ b/packages/dart_client/lib/src/api/websocket.dart @@ -105,6 +105,9 @@ class WebSocket { set _connectionStatus(ConnectionStatus status) => _connectionStatusController.add(status); + /// The current connection status value + ConnectionStatus get connectionStatus => _connectionStatusController.value; + /// This notifies of connection status changes Stream get connectionStatusStream => _connectionStatusController.stream; diff --git a/packages/dart_client/test/src/api/channel_test.dart b/packages/dart_client/test/src/api/channel_test.dart index d83d6f12..3897eb04 100644 --- a/packages/dart_client/test/src/api/channel_test.dart +++ b/packages/dart_client/test/src/api/channel_test.dart @@ -1,6 +1,6 @@ import 'package:dio/dio.dart'; import 'package:dio/native_imp.dart'; -import 'package:flutter_test/flutter_test.dart'; +import 'package:test/test.dart'; import 'package:mockito/mockito.dart'; import 'package:stream_chat/src/api/requests.dart'; import 'package:stream_chat/src/client.dart'; diff --git a/packages/dart_client/test/src/api/requests_test.dart b/packages/dart_client/test/src/api/requests_test.dart index 3ad762a7..6f7324ed 100644 --- a/packages/dart_client/test/src/api/requests_test.dart +++ b/packages/dart_client/test/src/api/requests_test.dart @@ -1,4 +1,4 @@ -import 'package:flutter_test/flutter_test.dart'; +import 'package:test/test.dart'; import 'package:stream_chat/stream_chat.dart'; void main() { diff --git a/packages/dart_client/test/src/api/responses_test.dart b/packages/dart_client/test/src/api/responses_test.dart index df576ba4..bfd4e5a7 100644 --- a/packages/dart_client/test/src/api/responses_test.dart +++ b/packages/dart_client/test/src/api/responses_test.dart @@ -1,6 +1,6 @@ import 'dart:convert'; -import 'package:flutter_test/flutter_test.dart'; +import 'package:test/test.dart'; import 'package:stream_chat/src/api/responses.dart'; import 'package:stream_chat/src/models/device.dart'; import 'package:stream_chat/src/models/member.dart'; diff --git a/packages/dart_client/test/src/api/web_socket_stub_test.dart b/packages/dart_client/test/src/api/web_socket_stub_test.dart index 5de61b4a..e60706dc 100644 --- a/packages/dart_client/test/src/api/web_socket_stub_test.dart +++ b/packages/dart_client/test/src/api/web_socket_stub_test.dart @@ -1,4 +1,4 @@ -import 'package:flutter_test/flutter_test.dart'; +import 'package:test/test.dart'; import 'package:stream_chat/src/api/web_socket_channel_stub.dart'; void main() { diff --git a/packages/dart_client/test/src/api/websocket_test.dart b/packages/dart_client/test/src/api/websocket_test.dart index e5a88bd8..d9486477 100644 --- a/packages/dart_client/test/src/api/websocket_test.dart +++ b/packages/dart_client/test/src/api/websocket_test.dart @@ -1,6 +1,6 @@ import 'dart:async'; -import 'package:flutter_test/flutter_test.dart'; +import 'package:test/test.dart'; import 'package:logging/logging.dart'; import 'package:mockito/mockito.dart'; import 'package:stream_chat/src/api/connection_status.dart'; @@ -67,7 +67,7 @@ void main() { await ws.connect(); verify(connectFunc(computedUrl)).called(1); - expect(ws.connectionStatus.value, ConnectionStatus.connected); + expect(ws.connectionStatus, ConnectionStatus.connected); await streamController.close(); timer.cancel(); From af3779eb21e75c40b8392e650a8c0730c189ff84 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Thu, 28 Jan 2021 17:28:03 +0530 Subject: [PATCH 1069/1140] fix: Added CHANGELOG.md and pubspec.yaml changes --- packages/flutter_widgets/CHANGELOG.md | 4 ++++ packages/flutter_widgets/pubspec.yaml | 2 +- packages/stream_chat_flutter_core/CHANGELOG.md | 4 ++-- packages/stream_chat_flutter_core/pubspec.yaml | 2 +- 4 files changed, 8 insertions(+), 4 deletions(-) diff --git a/packages/flutter_widgets/CHANGELOG.md b/packages/flutter_widgets/CHANGELOG.md index 8ca3aa04..8a80dbc5 100644 --- a/packages/flutter_widgets/CHANGELOG.md +++ b/packages/flutter_widgets/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.0.0-rc + +- Integrated new-ui, split package functionality, + ## 0.2.20+2 - Added `shouldAddChannel` to ChannelsBloc in order to check if a channel has to be added to the list when a new message arrives diff --git a/packages/flutter_widgets/pubspec.yaml b/packages/flutter_widgets/pubspec.yaml index 059d4fb2..9321f992 100644 --- a/packages/flutter_widgets/pubspec.yaml +++ b/packages/flutter_widgets/pubspec.yaml @@ -1,7 +1,7 @@ name: stream_chat_flutter homepage: https://github.com/GetStream/stream-chat-flutter description: Stream Chat official Flutter SDK. Build your own chat experience using Dart and Flutter. -version: 0.2.13+1 +version: 1.0.0-rc repository: https://github.com/GetStream/stream-chat-flutter issue_tracker: https://github.com/GetStream/stream-chat-flutter/issues diff --git a/packages/stream_chat_flutter_core/CHANGELOG.md b/packages/stream_chat_flutter_core/CHANGELOG.md index ac071598..ec6ae55e 100644 --- a/packages/stream_chat_flutter_core/CHANGELOG.md +++ b/packages/stream_chat_flutter_core/CHANGELOG.md @@ -1,3 +1,3 @@ -## [0.0.1] - TODO: Add release date. +## 1.0.0-rc -* TODO: Describe initial release. +* First release diff --git a/packages/stream_chat_flutter_core/pubspec.yaml b/packages/stream_chat_flutter_core/pubspec.yaml index 5037e5e8..19dd8eb0 100644 --- a/packages/stream_chat_flutter_core/pubspec.yaml +++ b/packages/stream_chat_flutter_core/pubspec.yaml @@ -1,7 +1,7 @@ name: stream_chat_flutter_core homepage: https://github.com/GetStream/stream-chat-flutter description: Stream Chat official Flutter SDK Core. Build your own chat experience using Dart and Flutter. -version: 0.0.1 +version: 1.0.0-rc repository: https://github.com/GetStream/stream-chat-flutter issue_tracker: https://github.com/GetStream/stream-chat-flutter/issues From 2a3e5529b8903582b8bfba35a2a3175789b70137 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Thu, 28 Jan 2021 17:34:56 +0530 Subject: [PATCH 1070/1140] fix: Fixed errorBuilder warning --- .../flutter_widgets/lib/src/message_list_view.dart | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/packages/flutter_widgets/lib/src/message_list_view.dart b/packages/flutter_widgets/lib/src/message_list_view.dart index bb11a469..c6378bb6 100644 --- a/packages/flutter_widgets/lib/src/message_list_view.dart +++ b/packages/flutter_widgets/lib/src/message_list_view.dart @@ -264,6 +264,18 @@ class _MessageListViewState extends State { messageListController: _messageListController, parentMessage: widget.parentMessage, showScrollToBottom: widget.showScrollToBottom, + errorWidgetBuilder: (BuildContext context, Object error) { + return Center( + child: Text( + 'Something went wrong', + style: StreamChatTheme.of(context).textTheme.footnote.copyWith( + color: StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(.5)), + ), + ); + }, ); } From 212a48c0b29136239f75599f84e8d4e42cd0a7fe Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Thu, 28 Jan 2021 17:51:28 +0530 Subject: [PATCH 1071/1140] fix: changed over dependency --- packages/flutter_widgets/lib/src/attachment_error.dart | 3 +-- packages/flutter_widgets/lib/src/attachment_title.dart | 2 +- packages/flutter_widgets/lib/src/channel_header.dart | 2 +- packages/flutter_widgets/lib/src/channel_image.dart | 2 +- packages/flutter_widgets/lib/src/channel_list_header.dart | 2 +- packages/flutter_widgets/lib/src/channel_name.dart | 2 +- packages/flutter_widgets/lib/src/channel_preview.dart | 2 +- packages/flutter_widgets/lib/src/channel_unread_indicator.dart | 2 +- packages/flutter_widgets/lib/src/file_attachment.dart | 2 +- packages/flutter_widgets/lib/src/image_footer.dart | 2 +- packages/flutter_widgets/lib/src/image_group.dart | 2 +- packages/flutter_widgets/lib/src/image_header.dart | 2 +- packages/flutter_widgets/lib/src/message_actions_modal.dart | 2 +- packages/flutter_widgets/lib/src/message_input.dart | 2 +- packages/flutter_widgets/lib/src/message_list_view.dart | 2 +- packages/flutter_widgets/lib/src/message_reactions_modal.dart | 2 +- packages/flutter_widgets/lib/src/message_search_item.dart | 2 +- packages/flutter_widgets/lib/src/message_search_list_view.dart | 2 +- packages/flutter_widgets/lib/src/message_text.dart | 2 +- packages/flutter_widgets/lib/src/quoted_message_widget.dart | 2 +- packages/flutter_widgets/lib/src/stream_chat.dart | 2 +- packages/flutter_widgets/lib/src/stream_chat_theme.dart | 2 +- packages/flutter_widgets/lib/src/thread_header.dart | 2 +- packages/flutter_widgets/lib/src/typing_indicator.dart | 2 +- packages/flutter_widgets/lib/src/user_avatar.dart | 2 +- packages/flutter_widgets/lib/src/user_item.dart | 2 +- packages/flutter_widgets/lib/src/user_list_view.dart | 2 +- packages/flutter_widgets/lib/src/user_reaction_display.dart | 2 +- packages/flutter_widgets/lib/src/utils.dart | 2 +- 29 files changed, 29 insertions(+), 30 deletions(-) diff --git a/packages/flutter_widgets/lib/src/attachment_error.dart b/packages/flutter_widgets/lib/src/attachment_error.dart index d24423c4..46b7b814 100644 --- a/packages/flutter_widgets/lib/src/attachment_error.dart +++ b/packages/flutter_widgets/lib/src/attachment_error.dart @@ -1,8 +1,7 @@ import 'dart:io'; import 'package:flutter/material.dart'; -import 'package:stream_chat/stream_chat.dart'; - +import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; import '../stream_chat_flutter.dart'; class AttachmentError extends StatelessWidget { diff --git a/packages/flutter_widgets/lib/src/attachment_title.dart b/packages/flutter_widgets/lib/src/attachment_title.dart index 7ed42a59..af5a1115 100644 --- a/packages/flutter_widgets/lib/src/attachment_title.dart +++ b/packages/flutter_widgets/lib/src/attachment_title.dart @@ -1,5 +1,5 @@ import 'package:flutter/material.dart'; -import 'package:stream_chat/stream_chat.dart'; +import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; import 'stream_chat_theme.dart'; import 'utils.dart'; diff --git a/packages/flutter_widgets/lib/src/channel_header.dart b/packages/flutter_widgets/lib/src/channel_header.dart index 73ee23a5..fb681d59 100644 --- a/packages/flutter_widgets/lib/src/channel_header.dart +++ b/packages/flutter_widgets/lib/src/channel_header.dart @@ -1,5 +1,5 @@ import 'package:flutter/material.dart'; -import 'package:stream_chat/stream_chat.dart'; +import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; import 'package:stream_chat_flutter/src/back_button.dart'; import 'package:stream_chat_flutter/src/channel_info.dart'; import 'package:stream_chat_flutter/src/channel_name.dart'; diff --git a/packages/flutter_widgets/lib/src/channel_image.dart b/packages/flutter_widgets/lib/src/channel_image.dart index 2f5862f3..18d67dfb 100644 --- a/packages/flutter_widgets/lib/src/channel_image.dart +++ b/packages/flutter_widgets/lib/src/channel_image.dart @@ -1,6 +1,6 @@ import 'package:cached_network_image/cached_network_image.dart'; import 'package:flutter/material.dart'; -import 'package:stream_chat/stream_chat.dart'; +import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; import 'package:stream_chat_flutter/src/group_image.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; diff --git a/packages/flutter_widgets/lib/src/channel_list_header.dart b/packages/flutter_widgets/lib/src/channel_list_header.dart index e8583d11..8ced0422 100644 --- a/packages/flutter_widgets/lib/src/channel_list_header.dart +++ b/packages/flutter_widgets/lib/src/channel_list_header.dart @@ -2,7 +2,7 @@ import 'dart:ui'; import 'package:flutter/material.dart'; import 'package:flutter_svg/flutter_svg.dart'; -import 'package:stream_chat/stream_chat.dart'; +import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; import 'package:stream_chat_flutter/src/stream_neumorphic_button.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; diff --git a/packages/flutter_widgets/lib/src/channel_name.dart b/packages/flutter_widgets/lib/src/channel_name.dart index 1d51f3fc..7907de9a 100644 --- a/packages/flutter_widgets/lib/src/channel_name.dart +++ b/packages/flutter_widgets/lib/src/channel_name.dart @@ -1,6 +1,6 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; -import 'package:stream_chat/stream_chat.dart'; +import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; import '../stream_chat_flutter.dart'; diff --git a/packages/flutter_widgets/lib/src/channel_preview.dart b/packages/flutter_widgets/lib/src/channel_preview.dart index 3564be7a..eddd0ea6 100644 --- a/packages/flutter_widgets/lib/src/channel_preview.dart +++ b/packages/flutter_widgets/lib/src/channel_preview.dart @@ -1,7 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/widgets.dart'; import 'package:jiffy/jiffy.dart'; -import 'package:stream_chat/stream_chat.dart'; +import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; import 'package:stream_chat_flutter/src/stream_svg_icon.dart'; import '../stream_chat_flutter.dart'; diff --git a/packages/flutter_widgets/lib/src/channel_unread_indicator.dart b/packages/flutter_widgets/lib/src/channel_unread_indicator.dart index c15db13a..cb9dc362 100644 --- a/packages/flutter_widgets/lib/src/channel_unread_indicator.dart +++ b/packages/flutter_widgets/lib/src/channel_unread_indicator.dart @@ -1,5 +1,5 @@ import 'package:flutter/material.dart'; -import 'package:stream_chat/stream_chat.dart'; +import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; import 'package:stream_chat_flutter/src/stream_chat_theme.dart'; class ChannelUnreadIndicator extends StatelessWidget { diff --git a/packages/flutter_widgets/lib/src/file_attachment.dart b/packages/flutter_widgets/lib/src/file_attachment.dart index dc7fae4b..0fff2445 100644 --- a/packages/flutter_widgets/lib/src/file_attachment.dart +++ b/packages/flutter_widgets/lib/src/file_attachment.dart @@ -3,7 +3,7 @@ import 'dart:io'; import 'package:cached_network_image/cached_network_image.dart'; import 'package:file_picker/file_picker.dart'; import 'package:flutter/material.dart'; -import 'package:stream_chat/stream_chat.dart'; +import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; import 'package:stream_chat_flutter/src/stream_chat_theme.dart'; import 'package:stream_chat_flutter/src/stream_svg_icon.dart'; import 'package:stream_chat_flutter/src/utils.dart'; diff --git a/packages/flutter_widgets/lib/src/image_footer.dart b/packages/flutter_widgets/lib/src/image_footer.dart index 0131561e..4e87423e 100644 --- a/packages/flutter_widgets/lib/src/image_footer.dart +++ b/packages/flutter_widgets/lib/src/image_footer.dart @@ -7,7 +7,7 @@ import 'package:dio/dio.dart'; import 'package:esys_flutter_share/esys_flutter_share.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; -import 'package:stream_chat/stream_chat.dart'; +import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; import 'package:stream_chat_flutter/src/stream_chat_theme.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; diff --git a/packages/flutter_widgets/lib/src/image_group.dart b/packages/flutter_widgets/lib/src/image_group.dart index bb577a4b..3a290c60 100644 --- a/packages/flutter_widgets/lib/src/image_group.dart +++ b/packages/flutter_widgets/lib/src/image_group.dart @@ -1,6 +1,6 @@ import 'package:cached_network_image/cached_network_image.dart'; import 'package:flutter/material.dart'; -import 'package:stream_chat/stream_chat.dart'; +import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; import 'package:stream_chat_flutter/src/full_screen_media.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; diff --git a/packages/flutter_widgets/lib/src/image_header.dart b/packages/flutter_widgets/lib/src/image_header.dart index f31ee3a6..e4c28d53 100644 --- a/packages/flutter_widgets/lib/src/image_header.dart +++ b/packages/flutter_widgets/lib/src/image_header.dart @@ -1,5 +1,5 @@ import 'package:flutter/material.dart'; -import 'package:stream_chat/stream_chat.dart'; +import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; import 'package:stream_chat_flutter/src/stream_chat_theme.dart'; import 'package:stream_chat_flutter/src/stream_svg_icon.dart'; import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; diff --git a/packages/flutter_widgets/lib/src/message_actions_modal.dart b/packages/flutter_widgets/lib/src/message_actions_modal.dart index 3cee6ba4..74490ddd 100644 --- a/packages/flutter_widgets/lib/src/message_actions_modal.dart +++ b/packages/flutter_widgets/lib/src/message_actions_modal.dart @@ -4,7 +4,7 @@ import 'dart:ui'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; -import 'package:stream_chat/stream_chat.dart'; +import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; import 'package:stream_chat_flutter/src/reaction_picker.dart'; import 'package:stream_chat_flutter/src/stream_svg_icon.dart'; import 'package:stream_chat_flutter/src/utils.dart'; diff --git a/packages/flutter_widgets/lib/src/message_input.dart b/packages/flutter_widgets/lib/src/message_input.dart index 35a9441e..59d748c2 100644 --- a/packages/flutter_widgets/lib/src/message_input.dart +++ b/packages/flutter_widgets/lib/src/message_input.dart @@ -13,7 +13,7 @@ import 'package:http_parser/http_parser.dart' as httpParser; import 'package:image_picker/image_picker.dart'; import 'package:mime/mime.dart'; import 'package:photo_manager/photo_manager.dart'; -import 'package:stream_chat/stream_chat.dart'; +import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; import 'package:stream_chat_flutter/src/compress_video_service.dart'; import 'package:stream_chat_flutter/src/media_list_view.dart'; import 'package:stream_chat_flutter/src/message_list_view.dart'; diff --git a/packages/flutter_widgets/lib/src/message_list_view.dart b/packages/flutter_widgets/lib/src/message_list_view.dart index c6378bb6..9ce29117 100644 --- a/packages/flutter_widgets/lib/src/message_list_view.dart +++ b/packages/flutter_widgets/lib/src/message_list_view.dart @@ -6,7 +6,7 @@ import 'package:flutter/material.dart'; import 'package:jiffy/jiffy.dart'; import 'package:rxdart/rxdart.dart'; import 'package:scrollable_positioned_list/scrollable_positioned_list.dart'; -import 'package:stream_chat/stream_chat.dart'; +import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; import 'package:stream_chat_flutter/src/info_tile.dart'; import 'package:stream_chat_flutter/src/message_widget.dart'; import 'package:stream_chat_flutter/src/stream_svg_icon.dart'; diff --git a/packages/flutter_widgets/lib/src/message_reactions_modal.dart b/packages/flutter_widgets/lib/src/message_reactions_modal.dart index 1ee3486d..eeb3d58b 100644 --- a/packages/flutter_widgets/lib/src/message_reactions_modal.dart +++ b/packages/flutter_widgets/lib/src/message_reactions_modal.dart @@ -1,7 +1,7 @@ import 'dart:ui'; import 'package:flutter/material.dart'; -import 'package:stream_chat/stream_chat.dart'; +import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; import 'package:stream_chat_flutter/src/reaction_bubble.dart'; import 'package:stream_chat_flutter/src/reaction_picker.dart'; import 'package:stream_chat_flutter/src/stream_chat.dart'; diff --git a/packages/flutter_widgets/lib/src/message_search_item.dart b/packages/flutter_widgets/lib/src/message_search_item.dart index 9c951a56..4d8d9148 100644 --- a/packages/flutter_widgets/lib/src/message_search_item.dart +++ b/packages/flutter_widgets/lib/src/message_search_item.dart @@ -1,6 +1,6 @@ import 'package:flutter/material.dart'; import 'package:jiffy/jiffy.dart'; -import 'package:stream_chat/stream_chat.dart'; +import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; /// It shows the current [Message] preview. diff --git a/packages/flutter_widgets/lib/src/message_search_list_view.dart b/packages/flutter_widgets/lib/src/message_search_list_view.dart index f1711cb8..64f92f2d 100644 --- a/packages/flutter_widgets/lib/src/message_search_list_view.dart +++ b/packages/flutter_widgets/lib/src/message_search_list_view.dart @@ -1,5 +1,5 @@ import 'package:flutter/material.dart'; -import 'package:stream_chat/stream_chat.dart'; +import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; import 'package:stream_chat_flutter/src/info_tile.dart'; import 'package:stream_chat_flutter/src/message_search_item.dart'; import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; diff --git a/packages/flutter_widgets/lib/src/message_text.dart b/packages/flutter_widgets/lib/src/message_text.dart index c64d9520..373acbfc 100644 --- a/packages/flutter_widgets/lib/src/message_text.dart +++ b/packages/flutter_widgets/lib/src/message_text.dart @@ -1,6 +1,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_markdown/flutter_markdown.dart'; -import 'package:stream_chat/stream_chat.dart'; +import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; import 'stream_chat_theme.dart'; import 'utils.dart'; diff --git a/packages/flutter_widgets/lib/src/quoted_message_widget.dart b/packages/flutter_widgets/lib/src/quoted_message_widget.dart index e4e10e17..8b0912eb 100644 --- a/packages/flutter_widgets/lib/src/quoted_message_widget.dart +++ b/packages/flutter_widgets/lib/src/quoted_message_widget.dart @@ -2,7 +2,7 @@ import 'dart:math'; import 'package:cached_network_image/cached_network_image.dart'; import 'package:flutter/material.dart'; -import 'package:stream_chat/stream_chat.dart'; +import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; import 'package:video_player/video_player.dart'; import 'attachment_error.dart'; diff --git a/packages/flutter_widgets/lib/src/stream_chat.dart b/packages/flutter_widgets/lib/src/stream_chat.dart index ee7e049f..37a163ec 100644 --- a/packages/flutter_widgets/lib/src/stream_chat.dart +++ b/packages/flutter_widgets/lib/src/stream_chat.dart @@ -4,7 +4,7 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_app_badger/flutter_app_badger.dart'; import 'package:flutter_portal/flutter_portal.dart'; -import 'package:stream_chat/stream_chat.dart'; +import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; import 'package:stream_chat_flutter/src/stream_chat_theme.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; diff --git a/packages/flutter_widgets/lib/src/stream_chat_theme.dart b/packages/flutter_widgets/lib/src/stream_chat_theme.dart index 3945a033..c65f36cc 100644 --- a/packages/flutter_widgets/lib/src/stream_chat_theme.dart +++ b/packages/flutter_widgets/lib/src/stream_chat_theme.dart @@ -1,6 +1,6 @@ import 'package:cached_network_image/cached_network_image.dart'; import 'package:flutter/material.dart'; -import 'package:stream_chat/stream_chat.dart'; +import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; import 'package:stream_chat_flutter/src/channel_header.dart'; import 'package:stream_chat_flutter/src/channel_preview.dart'; import 'package:stream_chat_flutter/src/message_input.dart'; diff --git a/packages/flutter_widgets/lib/src/thread_header.dart b/packages/flutter_widgets/lib/src/thread_header.dart index 35d554a6..b33b8bc1 100644 --- a/packages/flutter_widgets/lib/src/thread_header.dart +++ b/packages/flutter_widgets/lib/src/thread_header.dart @@ -1,5 +1,5 @@ import 'package:flutter/material.dart'; -import 'package:stream_chat/stream_chat.dart'; +import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; import 'package:stream_chat_flutter/src/stream_chat_theme.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; diff --git a/packages/flutter_widgets/lib/src/typing_indicator.dart b/packages/flutter_widgets/lib/src/typing_indicator.dart index c9e579be..14adc198 100644 --- a/packages/flutter_widgets/lib/src/typing_indicator.dart +++ b/packages/flutter_widgets/lib/src/typing_indicator.dart @@ -1,6 +1,6 @@ import 'package:flutter/material.dart'; import 'package:lottie/lottie.dart'; -import 'package:stream_chat/stream_chat.dart'; +import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; /// Widget to show the current list of typing users diff --git a/packages/flutter_widgets/lib/src/user_avatar.dart b/packages/flutter_widgets/lib/src/user_avatar.dart index 706c4d7e..f38a9a68 100644 --- a/packages/flutter_widgets/lib/src/user_avatar.dart +++ b/packages/flutter_widgets/lib/src/user_avatar.dart @@ -1,6 +1,6 @@ import 'package:cached_network_image/cached_network_image.dart'; import 'package:flutter/material.dart'; -import 'package:stream_chat/stream_chat.dart'; +import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; import '../stream_chat_flutter.dart'; diff --git a/packages/flutter_widgets/lib/src/user_item.dart b/packages/flutter_widgets/lib/src/user_item.dart index 58a354fc..cb82e311 100644 --- a/packages/flutter_widgets/lib/src/user_item.dart +++ b/packages/flutter_widgets/lib/src/user_item.dart @@ -1,6 +1,6 @@ import 'package:flutter/material.dart'; import 'package:jiffy/jiffy.dart'; -import 'package:stream_chat/stream_chat.dart'; +import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; import 'package:stream_chat_flutter/src/stream_svg_icon.dart'; import 'package:stream_chat_flutter/src/user_list_view.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; diff --git a/packages/flutter_widgets/lib/src/user_list_view.dart b/packages/flutter_widgets/lib/src/user_list_view.dart index 30c5db76..a53ba97a 100644 --- a/packages/flutter_widgets/lib/src/user_list_view.dart +++ b/packages/flutter_widgets/lib/src/user_list_view.dart @@ -1,5 +1,5 @@ import 'package:flutter/material.dart'; -import 'package:stream_chat/stream_chat.dart'; +import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; import 'user_item.dart'; diff --git a/packages/flutter_widgets/lib/src/user_reaction_display.dart b/packages/flutter_widgets/lib/src/user_reaction_display.dart index 92f66aa2..af2797ca 100644 --- a/packages/flutter_widgets/lib/src/user_reaction_display.dart +++ b/packages/flutter_widgets/lib/src/user_reaction_display.dart @@ -1,5 +1,5 @@ import 'package:flutter/material.dart'; -import 'package:stream_chat/stream_chat.dart'; +import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; import 'package:stream_chat_flutter/src/user_avatar.dart'; class UserReactionDisplay extends StatelessWidget { diff --git a/packages/flutter_widgets/lib/src/utils.dart b/packages/flutter_widgets/lib/src/utils.dart index 060d2416..93d87ab2 100644 --- a/packages/flutter_widgets/lib/src/utils.dart +++ b/packages/flutter_widgets/lib/src/utils.dart @@ -1,5 +1,5 @@ import 'package:flutter/material.dart'; -import 'package:stream_chat/stream_chat.dart'; +import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; import 'package:url_launcher/url_launcher.dart'; import '../stream_chat_flutter.dart'; From 8d105b7e4508c1cafebfc5d09a6332b95c8e153b Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Thu, 28 Jan 2021 18:00:37 +0530 Subject: [PATCH 1072/1140] fix: duplicate imports --- packages/flutter_widgets/lib/src/image_header.dart | 1 - packages/flutter_widgets/lib/src/message_actions_modal.dart | 1 - packages/flutter_widgets/lib/src/message_search_list_view.dart | 1 - packages/flutter_widgets/lib/src/typing_indicator.dart | 1 - 4 files changed, 4 deletions(-) diff --git a/packages/flutter_widgets/lib/src/image_header.dart b/packages/flutter_widgets/lib/src/image_header.dart index e4c28d53..a818ee13 100644 --- a/packages/flutter_widgets/lib/src/image_header.dart +++ b/packages/flutter_widgets/lib/src/image_header.dart @@ -2,7 +2,6 @@ import 'package:flutter/material.dart'; import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; import 'package:stream_chat_flutter/src/stream_chat_theme.dart'; import 'package:stream_chat_flutter/src/stream_svg_icon.dart'; -import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; import 'image_actions_modal.dart'; class ImageHeader extends StatelessWidget implements PreferredSizeWidget { diff --git a/packages/flutter_widgets/lib/src/message_actions_modal.dart b/packages/flutter_widgets/lib/src/message_actions_modal.dart index 74490ddd..295bcf26 100644 --- a/packages/flutter_widgets/lib/src/message_actions_modal.dart +++ b/packages/flutter_widgets/lib/src/message_actions_modal.dart @@ -8,7 +8,6 @@ import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; import 'package:stream_chat_flutter/src/reaction_picker.dart'; import 'package:stream_chat_flutter/src/stream_svg_icon.dart'; import 'package:stream_chat_flutter/src/utils.dart'; -import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; import 'message_input.dart'; import 'message_widget.dart'; diff --git a/packages/flutter_widgets/lib/src/message_search_list_view.dart b/packages/flutter_widgets/lib/src/message_search_list_view.dart index 64f92f2d..2cbea145 100644 --- a/packages/flutter_widgets/lib/src/message_search_list_view.dart +++ b/packages/flutter_widgets/lib/src/message_search_list_view.dart @@ -2,7 +2,6 @@ import 'package:flutter/material.dart'; import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; import 'package:stream_chat_flutter/src/info_tile.dart'; import 'package:stream_chat_flutter/src/message_search_item.dart'; -import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; import '../stream_chat_flutter.dart'; diff --git a/packages/flutter_widgets/lib/src/typing_indicator.dart b/packages/flutter_widgets/lib/src/typing_indicator.dart index 14adc198..8a53c3e8 100644 --- a/packages/flutter_widgets/lib/src/typing_indicator.dart +++ b/packages/flutter_widgets/lib/src/typing_indicator.dart @@ -1,7 +1,6 @@ import 'package:flutter/material.dart'; import 'package:lottie/lottie.dart'; import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; -import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; /// Widget to show the current list of typing users class TypingIndicator extends StatelessWidget { From 34da746ac28d58c3367b715a10e07336695a1608 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Thu, 28 Jan 2021 18:08:20 +0530 Subject: [PATCH 1073/1140] fix: import/export --- packages/flutter_widgets/lib/stream_chat_flutter.dart | 2 -- packages/flutter_widgets/test/src/mocks.dart | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/flutter_widgets/lib/stream_chat_flutter.dart b/packages/flutter_widgets/lib/stream_chat_flutter.dart index c4e0e2e1..3f52c8c6 100644 --- a/packages/flutter_widgets/lib/stream_chat_flutter.dart +++ b/packages/flutter_widgets/lib/stream_chat_flutter.dart @@ -1,5 +1,3 @@ -export 'package:stream_chat/stream_chat.dart'; - export 'src/back_button.dart'; export 'src/channel_header.dart'; export 'src/channel_image.dart'; diff --git a/packages/flutter_widgets/test/src/mocks.dart b/packages/flutter_widgets/test/src/mocks.dart index 37fa5530..25b438d6 100644 --- a/packages/flutter_widgets/test/src/mocks.dart +++ b/packages/flutter_widgets/test/src/mocks.dart @@ -1,5 +1,5 @@ import 'package:mockito/mockito.dart'; -import 'package:stream_chat/stream_chat.dart'; +import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; class MockClient extends Mock implements Client {} From ee745af2d9d72fa0b0ce463a7d43d763ba50c350 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Thu, 28 Jan 2021 14:25:26 +0100 Subject: [PATCH 1074/1140] remove screenshots --- .../stream_chat_flutter_core/lib/src/channel_list_core.dart | 3 --- .../stream_chat_flutter_core/lib/src/message_list_core.dart | 3 --- 2 files changed, 6 deletions(-) diff --git a/packages/stream_chat_flutter_core/lib/src/channel_list_core.dart b/packages/stream_chat_flutter_core/lib/src/channel_list_core.dart index 41c6f81d..d2fd53c7 100644 --- a/packages/stream_chat_flutter_core/lib/src/channel_list_core.dart +++ b/packages/stream_chat_flutter_core/lib/src/channel_list_core.dart @@ -8,9 +8,6 @@ import 'package:stream_chat_flutter_core/src/channels_bloc.dart'; import 'stream_chat_core.dart'; -/// ![screenshot](https://raw.githubusercontent.com/GetStream/stream-chat-flutter/master/screenshots/channel_list_view.png) -/// ![screenshot](https://raw.githubusercontent.com/GetStream/stream-chat-flutter/master/screenshots/channel_list_view_paint.png) -/// /// [ChannelListCore] is a simplified class that allows fetching a list of channels while exposing UI builders. /// A [ChannelListController] is used to reload and paginate data. /// diff --git a/packages/stream_chat_flutter_core/lib/src/message_list_core.dart b/packages/stream_chat_flutter_core/lib/src/message_list_core.dart index e6754ee8..697e7e39 100644 --- a/packages/stream_chat_flutter_core/lib/src/message_list_core.dart +++ b/packages/stream_chat_flutter_core/lib/src/message_list_core.dart @@ -11,9 +11,6 @@ import 'stream_channel.dart'; typedef StreamErrorBuilder = Widget Function( BuildContext context, Object error); -/// ![screenshot](https://raw.githubusercontent.com/GetStream/stream-chat-flutter/master/screenshots/message_listview.png) -/// ![screenshot](https://raw.githubusercontent.com/GetStream/stream-chat-flutter/master/screenshots/message_listview_paint.png) -/// /// [MessageListCore] is a simplified class that allows fetching a list of messages while exposing UI builders. /// A [MessageListController] is used to paginate data. /// From 86a122aa23f696742515d84454cb8ac08e388b20 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Thu, 28 Jan 2021 19:48:54 +0530 Subject: [PATCH 1075/1140] [LLC, Persistence] Add doc comments Signed-off-by: Sahil Kumar --- .../dart_client/lib/src/models/message.dart | 2 +- .../dart_client/lib/src/models/reaction.dart | 2 +- .../lib/src/converter/list_converter.dart | 3 ++- .../lib/src/converter/map_converter.dart | 3 ++- .../message_sending_status_converter.dart | 3 ++- .../lib/src/dao/channel_dao.dart | 6 ++--- .../lib/src/dao/channel_query_dao.dart | 4 ++-- .../lib/src/dao/connection_event_dao.dart | 4 ++-- .../lib/src/dao/member_dao.dart | 6 ++--- .../lib/src/dao/message_dao.dart | 18 +++++++++------ .../lib/src/dao/reaction_dao.dart | 14 +++++++----- .../lib/src/dao/read_dao.dart | 7 +++--- .../lib/src/dao/user_dao.dart | 6 ++--- .../lib/src/db/moor_chat_database.dart | 4 ++-- .../lib/src/entity/channel_queries.dart | 3 +++ .../lib/src/entity/channels.dart | 13 +++++++++++ .../lib/src/entity/connection_events.dart | 7 ++++++ .../lib/src/entity/members.dart | 12 ++++++++++ .../lib/src/entity/messages.dart | 22 +++++++++++++++++++ .../lib/src/entity/reactions.dart | 7 ++++++ .../lib/src/entity/reads.dart | 5 +++++ .../lib/src/entity/users.dart | 9 ++++++++ .../lib/src/mapper/channel_mapper.dart | 10 ++++----- .../lib/src/mapper/event_mapper.dart | 5 ++--- .../lib/src/mapper/member_mapper.dart | 9 ++++---- .../lib/src/mapper/message_mapper.dart | 8 +++---- .../lib/src/mapper/reaction_mapper.dart | 9 ++++---- .../lib/src/mapper/read_mapper.dart | 9 ++++---- .../lib/src/mapper/user_mapper.dart | 8 +++---- .../src/stream_chat_persistence_client.dart | 4 ++-- 30 files changed, 154 insertions(+), 68 deletions(-) diff --git a/packages/dart_client/lib/src/models/message.dart b/packages/dart_client/lib/src/models/message.dart index df188e35..a2eef86e 100644 --- a/packages/dart_client/lib/src/models/message.dart +++ b/packages/dart_client/lib/src/models/message.dart @@ -72,7 +72,7 @@ class Message { @JsonKey(includeIfNull: false, toJson: Serialization.readOnly) final List ownReactions; - /// The ID of the parent message, if the message is a reply. + /// The ID of the parent message, if the message is a thread reply. final String parentId; /// A quoted reply message diff --git a/packages/dart_client/lib/src/models/reaction.dart b/packages/dart_client/lib/src/models/reaction.dart index fb0c4fad..9a4869f7 100644 --- a/packages/dart_client/lib/src/models/reaction.dart +++ b/packages/dart_client/lib/src/models/reaction.dart @@ -29,7 +29,7 @@ class Reaction { @JsonKey(includeIfNull: false, toJson: Serialization.readOnly) final String userId; - /// The score of the reaction (ie. number of reactions sent) + /// Reaction custom extraData @JsonKey(includeIfNull: false) final Map extraData; diff --git a/packages/stream_chat_persistence/lib/src/converter/list_converter.dart b/packages/stream_chat_persistence/lib/src/converter/list_converter.dart index 5d0a628f..d14642ce 100644 --- a/packages/stream_chat_persistence/lib/src/converter/list_converter.dart +++ b/packages/stream_chat_persistence/lib/src/converter/list_converter.dart @@ -2,7 +2,8 @@ import 'dart:convert'; import 'package:moor/moor.dart'; -/// +/// Maps a [List] of type [T] into a [String] understood +/// by the sqlite backend. class ListConverter extends TypeConverter, String> { @override List mapToDart(fromDb) { diff --git a/packages/stream_chat_persistence/lib/src/converter/map_converter.dart b/packages/stream_chat_persistence/lib/src/converter/map_converter.dart index 9fde0003..6e7a648d 100644 --- a/packages/stream_chat_persistence/lib/src/converter/map_converter.dart +++ b/packages/stream_chat_persistence/lib/src/converter/map_converter.dart @@ -2,7 +2,8 @@ import 'dart:convert'; import 'package:moor/moor.dart'; -/// +/// Maps a [Map] of type [String], [T] into a [String] understood +/// by the sqlite backend. class MapConverter extends TypeConverter, String> { @override Map mapToDart(fromDb) { diff --git a/packages/stream_chat_persistence/lib/src/converter/message_sending_status_converter.dart b/packages/stream_chat_persistence/lib/src/converter/message_sending_status_converter.dart index b8d92b82..75b006bb 100644 --- a/packages/stream_chat_persistence/lib/src/converter/message_sending_status_converter.dart +++ b/packages/stream_chat_persistence/lib/src/converter/message_sending_status_converter.dart @@ -1,7 +1,8 @@ import 'package:moor/moor.dart'; import 'package:stream_chat/stream_chat.dart'; -/// +/// Maps a [MessageSendingStatus] into a [int] understood +/// by the sqlite backend. class MessageSendingStatusConverter extends TypeConverter { @override diff --git a/packages/stream_chat_persistence/lib/src/dao/channel_dao.dart b/packages/stream_chat_persistence/lib/src/dao/channel_dao.dart index fa902f52..57ec95d3 100644 --- a/packages/stream_chat_persistence/lib/src/dao/channel_dao.dart +++ b/packages/stream_chat_persistence/lib/src/dao/channel_dao.dart @@ -7,11 +7,11 @@ import '../mapper/mapper.dart'; part 'channel_dao.g.dart'; -/// +/// The Data Access Object for operations in [Channels] table. @UseDao(tables: [Channels, Users]) class ChannelDao extends DatabaseAccessor with _$ChannelDaoMixin { - /// + /// Creates a new channel dao instance ChannelDao(MoorChatDatabase db) : super(db); /// Get channel by cid @@ -44,7 +44,7 @@ class ChannelDao extends DatabaseAccessor .get(); } - /// + /// Updates all the channels using the new [channelList] data Future updateChannels(List channelList) { return batch( (it) => it.insertAll( diff --git a/packages/stream_chat_persistence/lib/src/dao/channel_query_dao.dart b/packages/stream_chat_persistence/lib/src/dao/channel_query_dao.dart index a42dd01e..1492420c 100644 --- a/packages/stream_chat_persistence/lib/src/dao/channel_query_dao.dart +++ b/packages/stream_chat_persistence/lib/src/dao/channel_query_dao.dart @@ -10,11 +10,11 @@ import '../mapper/mapper.dart'; part 'channel_query_dao.g.dart'; -/// +/// The Data Access Object for operations in [ChannelQueries] table. @UseDao(tables: [ChannelQueries, Channels, Users]) class ChannelQueryDao extends DatabaseAccessor with _$ChannelQueryDaoMixin { - /// + /// Creates a new channel query dao instance ChannelQueryDao(this._db) : super(_db); final MoorChatDatabase _db; diff --git a/packages/stream_chat_persistence/lib/src/dao/connection_event_dao.dart b/packages/stream_chat_persistence/lib/src/dao/connection_event_dao.dart index baf91095..8d2033b2 100644 --- a/packages/stream_chat_persistence/lib/src/dao/connection_event_dao.dart +++ b/packages/stream_chat_persistence/lib/src/dao/connection_event_dao.dart @@ -7,11 +7,11 @@ import '../mapper/mapper.dart'; part 'connection_event_dao.g.dart'; -/// +/// The Data Access Object for operations in [ConnectionEvents] table. @UseDao(tables: [ConnectionEvents, Users]) class ConnectionEventDao extends DatabaseAccessor with _$ConnectionEventDaoMixin { - /// + /// Creates a new connection event dao instance ConnectionEventDao(MoorChatDatabase db) : super(db); /// Get the latest stored connection event diff --git a/packages/stream_chat_persistence/lib/src/dao/member_dao.dart b/packages/stream_chat_persistence/lib/src/dao/member_dao.dart index f21ab334..c535af9a 100644 --- a/packages/stream_chat_persistence/lib/src/dao/member_dao.dart +++ b/packages/stream_chat_persistence/lib/src/dao/member_dao.dart @@ -9,11 +9,11 @@ import '../mapper/mapper.dart'; part 'member_dao.g.dart'; -/// +/// The Data Access Object for operations in [Members] table. @UseDao(tables: [Members, Users]) class MemberDao extends DatabaseAccessor with _$MemberDaoMixin { - /// + /// Creates a new member dao instance MemberDao(MoorChatDatabase db) : super(db); /// Get all members where [members.channelCid] matches [cid] @@ -30,7 +30,7 @@ class MemberDao extends DatabaseAccessor }).get(); } - /// + /// Updates all the members using the new [memberList] data Future updateMembers(String cid, List memberList) async { return batch( (it) => it.insertAll( diff --git a/packages/stream_chat_persistence/lib/src/dao/message_dao.dart b/packages/stream_chat_persistence/lib/src/dao/message_dao.dart index ee779845..0b6ba97c 100644 --- a/packages/stream_chat_persistence/lib/src/dao/message_dao.dart +++ b/packages/stream_chat_persistence/lib/src/dao/message_dao.dart @@ -7,11 +7,11 @@ import '../mapper/mapper.dart'; part 'message_dao.g.dart'; -/// +/// The Data Access Object for operations in [Messages] table. @UseDao(tables: [Messages, Users]) class MessageDao extends DatabaseAccessor with _$MessageDaoMixin { - /// + /// Creates a new message dao instance MessageDao(this._db) : super(_db); final MoorChatDatabase _db; @@ -52,7 +52,7 @@ class MessageDao extends DatabaseAccessor ); } - /// + /// Returns a single message by matching the [messages.id] with [id] Future getMessageById(String id) async { return await (select(messages).join([ leftOuterJoin(users, messages.userId.equalsExp(users.id)), @@ -62,7 +62,8 @@ class MessageDao extends DatabaseAccessor .getSingle(); } - /// + /// Returns all the messages of a particular thread by matching + /// [messages.channelCid] with [cid] Future> getThreadMessages(String cid) async { return Future.wait(await (select(messages).join([ leftOuterJoin(users, messages.userId.equalsExp(users.id)), @@ -74,7 +75,8 @@ class MessageDao extends DatabaseAccessor .get()); } - /// + /// Returns all the messages of a particular thread by matching + /// [messages.parentId] with [parentId] Future> getThreadMessagesByParentId( String parentId, { String lessThan, @@ -94,7 +96,8 @@ class MessageDao extends DatabaseAccessor return msgList; } - /// + /// Returns all the messages of a channel by matching + /// [messages.channelCid] with [parentId] Future> getMessagesByCid( String cid, { PaginationParams messagePagination, @@ -131,7 +134,8 @@ class MessageDao extends DatabaseAccessor return msgList; } - /// + /// Updates the message data of a particular channel with + /// the new [messageList] data Future updateMessages(String cid, List messageList) { return batch((batch) { batch.insertAll( diff --git a/packages/stream_chat_persistence/lib/src/dao/reaction_dao.dart b/packages/stream_chat_persistence/lib/src/dao/reaction_dao.dart index dc6faefb..249bd011 100644 --- a/packages/stream_chat_persistence/lib/src/dao/reaction_dao.dart +++ b/packages/stream_chat_persistence/lib/src/dao/reaction_dao.dart @@ -7,14 +7,15 @@ import '../mapper/mapper.dart'; part 'reaction_dao.g.dart'; -/// +/// The Data Access Object for operations in [Reactions] table. @UseDao(tables: [Reactions, Users]) class ReactionDao extends DatabaseAccessor with _$ReactionDaoMixin { - /// + /// Creates a new reaction dao instance ReactionDao(MoorChatDatabase db) : super(db); - /// + /// Returns all the reactions of a particular message by matching + /// [reactions.messageId] with [messageId] Future> getReactions(String messageId) { return (select(reactions).join([ leftOuterJoin(users, reactions.userId.equalsExp(users.id)), @@ -28,7 +29,10 @@ class ReactionDao extends DatabaseAccessor }).get(); } - /// + /// Returns all the reactions of a particular message + /// added by a particular user by matching + /// [reactions.messageId] with [messageId] and + /// [reactions.userId] with [userId] Future> getReactionsByUserId( String messageId, String userId, @@ -37,7 +41,7 @@ class ReactionDao extends DatabaseAccessor return reactions.where((it) => it.userId == userId).toList(); } - /// + /// Updates the reactions data with the new [reactionList] data Future updateReactions(List reactionList) { return batch((it) { it.insertAll( diff --git a/packages/stream_chat_persistence/lib/src/dao/read_dao.dart b/packages/stream_chat_persistence/lib/src/dao/read_dao.dart index cd4da0f6..00af6b6d 100644 --- a/packages/stream_chat_persistence/lib/src/dao/read_dao.dart +++ b/packages/stream_chat_persistence/lib/src/dao/read_dao.dart @@ -7,10 +7,10 @@ import '../mapper/mapper.dart'; part 'read_dao.g.dart'; -/// +/// The Data Access Object for operations in [Reads] table. @UseDao(tables: [Reads, Users]) class ReadDao extends DatabaseAccessor with _$ReadDaoMixin { - /// + /// Creates a new read dao instance ReadDao(MoorChatDatabase db) : super(db); /// Get all reads where [reads.channelCid] matches [cid] @@ -29,7 +29,8 @@ class ReadDao extends DatabaseAccessor with _$ReadDaoMixin { }).get(); } - /// + /// Updates the read data of a particular channel with + /// the new [readList] data Future updateReads(String cid, List readList) { return batch( (it) => it.insertAll( diff --git a/packages/stream_chat_persistence/lib/src/dao/user_dao.dart b/packages/stream_chat_persistence/lib/src/dao/user_dao.dart index 630a8252..795c7968 100644 --- a/packages/stream_chat_persistence/lib/src/dao/user_dao.dart +++ b/packages/stream_chat_persistence/lib/src/dao/user_dao.dart @@ -6,13 +6,13 @@ import '../mapper/user_mapper.dart'; part 'user_dao.g.dart'; -/// +/// The Data Access Object for operations in [Users] table. @UseDao(tables: [Users]) class UserDao extends DatabaseAccessor with _$UserDaoMixin { - /// + /// Creates a new user dao instance UserDao(MoorChatDatabase db) : super(db); - /// + /// Updates the users data with the new [userList] data Future updateUsers(List userList) { return batch( (it) => it.insertAll( diff --git a/packages/stream_chat_persistence/lib/src/db/moor_chat_database.dart b/packages/stream_chat_persistence/lib/src/db/moor_chat_database.dart index 691961a7..4230f278 100644 --- a/packages/stream_chat_persistence/lib/src/db/moor_chat_database.dart +++ b/packages/stream_chat_persistence/lib/src/db/moor_chat_database.dart @@ -21,7 +21,7 @@ LazyDatabase _openConnection( }); } -/// +/// A chat database implemented using moor @UseMoor(tables: [ Channels, Messages, @@ -42,7 +42,7 @@ LazyDatabase _openConnection( ConnectionEventDao, ]) class MoorChatDatabase extends _$MoorChatDatabase { - /// Instantiate a new database instance + /// Creates a new moor chat database instance MoorChatDatabase( this._userId, { logStatements = false, diff --git a/packages/stream_chat_persistence/lib/src/entity/channel_queries.dart b/packages/stream_chat_persistence/lib/src/entity/channel_queries.dart index fefdc925..301e3592 100644 --- a/packages/stream_chat_persistence/lib/src/entity/channel_queries.dart +++ b/packages/stream_chat_persistence/lib/src/entity/channel_queries.dart @@ -1,9 +1,12 @@ import 'package:moor/moor.dart'; +/// Represents a [ChannelQueries] table in [MoorChatDatabase]. @DataClassName('ChannelQueryEntity') class ChannelQueries extends Table { + /// The unique hash of this query TextColumn get queryHash => text()(); + /// The channel cid of this query TextColumn get channelCid => text()(); @override diff --git a/packages/stream_chat_persistence/lib/src/entity/channels.dart b/packages/stream_chat_persistence/lib/src/entity/channels.dart index 9f652ed1..38a40081 100644 --- a/packages/stream_chat_persistence/lib/src/entity/channels.dart +++ b/packages/stream_chat_persistence/lib/src/entity/channels.dart @@ -1,30 +1,43 @@ import 'package:moor/moor.dart'; import 'package:stream_chat_persistence/src/converter/map_converter.dart'; +/// Represents a [Channels] table in [MoorChatDatabase]. @DataClassName('ChannelEntity') class Channels extends Table { + /// The id of this channel TextColumn get id => text()(); + /// The type of this channel TextColumn get type => text()(); + /// The cid of this channel TextColumn get cid => text()(); + /// The channel configuration data TextColumn get config => text().map(MapConverter())(); + /// True if this channel entity is frozen BoolColumn get frozen => boolean().withDefault(Constant(false))(); + /// The date of the last message DateTimeColumn get lastMessageAt => dateTime().nullable()(); + /// The date of channel creation DateTimeColumn get createdAt => dateTime().nullable()(); + /// The date of the last channel update DateTimeColumn get updatedAt => dateTime().nullable()(); + /// The date of channel deletion DateTimeColumn get deletedAt => dateTime().nullable()(); + /// The count of this channel members IntColumn get memberCount => integer().nullable()(); + /// The id of the user that created this channel TextColumn get createdById => text().nullable()(); + /// Map of custom channel extraData TextColumn get extraData => text().nullable().map(MapConverter())(); @override diff --git a/packages/stream_chat_persistence/lib/src/entity/connection_events.dart b/packages/stream_chat_persistence/lib/src/entity/connection_events.dart index 3ca4592e..7caa0407 100644 --- a/packages/stream_chat_persistence/lib/src/entity/connection_events.dart +++ b/packages/stream_chat_persistence/lib/src/entity/connection_events.dart @@ -1,18 +1,25 @@ import 'package:moor/moor.dart'; import 'package:stream_chat_persistence/src/converter/map_converter.dart'; +/// Represents a [ConnectionEvents] table in [MoorChatDatabase]. @DataClassName('ConnectionEventEntity') class ConnectionEvents extends Table { + /// event id IntColumn get id => integer()(); + /// User object of the current user TextColumn get ownUser => text().nullable().map(MapConverter())(); + /// The number of unread messages for current user IntColumn get totalUnreadCount => integer().nullable()(); + /// User total unread channels for current user IntColumn get unreadChannels => integer().nullable()(); + /// DateTime of the last event DateTimeColumn get lastEventAt => dateTime().nullable()(); + /// DateTime of the last sync DateTimeColumn get lastSyncAt => dateTime().nullable()(); @override diff --git a/packages/stream_chat_persistence/lib/src/entity/members.dart b/packages/stream_chat_persistence/lib/src/entity/members.dart index 39e224e0..9eafd4aa 100644 --- a/packages/stream_chat_persistence/lib/src/entity/members.dart +++ b/packages/stream_chat_persistence/lib/src/entity/members.dart @@ -1,28 +1,40 @@ import 'package:moor/moor.dart'; +/// Represents a [Members] table in [MoorChatDatabase]. @DataClassName('MemberEntity') class Members extends Table { + /// The interested user id TextColumn get userId => text()(); + /// The channel cid of which this user is part of TextColumn get channelCid => text().customConstraint('REFERENCES channels(cid) ON DELETE CASCADE')(); + /// The role of the user in the channel TextColumn get role => text().nullable()(); + /// The date on which the user accepted the invite to the channel DateTimeColumn get inviteAcceptedAt => dateTime().nullable()(); + /// The date on which the user rejected the invite to the channel DateTimeColumn get inviteRejectedAt => dateTime().nullable()(); + /// True if the user has been invited to the channel BoolColumn get invited => boolean().nullable()(); + /// True if the member is banned from the channel BoolColumn get banned => boolean().nullable()(); + /// True if the member is shadow banned from the channel BoolColumn get shadowBanned => boolean().nullable()(); + /// True if the user is a moderator of the channel BoolColumn get isModerator => boolean().nullable()(); + /// The date of creation DateTimeColumn get createdAt => dateTime()(); + /// The last date of update DateTimeColumn get updatedAt => dateTime().nullable()(); @override diff --git a/packages/stream_chat_persistence/lib/src/entity/messages.dart b/packages/stream_chat_persistence/lib/src/entity/messages.dart index 10c98315..8a151ae6 100644 --- a/packages/stream_chat_persistence/lib/src/entity/messages.dart +++ b/packages/stream_chat_persistence/lib/src/entity/messages.dart @@ -3,50 +3,72 @@ import 'package:stream_chat_persistence/src/converter/list_converter.dart'; import 'package:stream_chat_persistence/src/converter/map_converter.dart'; import 'package:stream_chat_persistence/src/converter/message_sending_status_converter.dart'; +/// Represents a [Messages] table in [MoorChatDatabase]. @DataClassName('MessageEntity') class Messages extends Table { + /// The message id TextColumn get id => text()(); + /// The text of this message TextColumn get messageText => text().nullable()(); + /// The list of attachments, either provided by the user + /// or generated from a command or as a result of URL scraping. TextColumn get attachments => text().nullable().map(ListConverter())(); + /// The status of a sending message IntColumn get status => integer().nullable().map(MessageSendingStatusConverter())(); + /// The message type TextColumn get type => text().nullable()(); + /// The list of user mentioned in the message TextColumn get mentionedUsers => text().nullable().map(ListConverter())(); + /// A map describing the count of number of every reaction TextColumn get reactionCounts => text().nullable().map(MapConverter())(); + /// A map describing the count of score of every reaction TextColumn get reactionScores => text().nullable().map(MapConverter())(); + /// The ID of the parent message, if the message is a thread reply. TextColumn get parentId => text().nullable()(); + /// The ID of the quoted message, if the message is a quoted reply. TextColumn get quotedMessageId => text().nullable()(); + /// Number of replies for this message. IntColumn get replyCount => integer().nullable()(); + /// Check if this message needs to show in the channel. BoolColumn get showInChannel => boolean().nullable()(); + /// If true the message is shadowed BoolColumn get shadowed => boolean().nullable()(); + /// A used command name. TextColumn get command => text().nullable()(); + /// The DateTime when the message was created. DateTimeColumn get createdAt => dateTime()(); + /// The DateTime when the message was updated last time. DateTimeColumn get updatedAt => dateTime().nullable()(); + /// The DateTime when the message was deleted. DateTimeColumn get deletedAt => dateTime().nullable()(); + /// Id of the User who sent the message TextColumn get userId => text().nullable()(); + /// The channel cid of which this message is part of TextColumn get channelCid => text().nullable().customConstraint( 'NULLABLE REFERENCES channels(cid) ON DELETE CASCADE')(); + /// Message custom extraData TextColumn get extraData => text().nullable().map(MapConverter())(); @override diff --git a/packages/stream_chat_persistence/lib/src/entity/reactions.dart b/packages/stream_chat_persistence/lib/src/entity/reactions.dart index a20ffbeb..b7e6342f 100644 --- a/packages/stream_chat_persistence/lib/src/entity/reactions.dart +++ b/packages/stream_chat_persistence/lib/src/entity/reactions.dart @@ -1,19 +1,26 @@ import 'package:moor/moor.dart'; import 'package:stream_chat_persistence/src/converter/map_converter.dart'; +/// Represents a [Reactions] table in [MoorChatDatabase]. @DataClassName('ReactionEntity') class Reactions extends Table { + /// The id of the user that sent the reaction TextColumn get userId => text()(); + /// The messageId to which the reaction belongs TextColumn get messageId => text().customConstraint('REFERENCES messages(id) ON DELETE CASCADE')(); + /// The type of the reaction TextColumn get type => text()(); + /// The DateTime on which the reaction is created DateTimeColumn get createdAt => dateTime()(); + /// The score of the reaction (ie. number of reactions sent) IntColumn get score => integer().nullable()(); + /// Reaction custom extraData TextColumn get extraData => text().nullable().map(MapConverter())(); @override diff --git a/packages/stream_chat_persistence/lib/src/entity/reads.dart b/packages/stream_chat_persistence/lib/src/entity/reads.dart index c36dceef..4b9ce6fb 100644 --- a/packages/stream_chat_persistence/lib/src/entity/reads.dart +++ b/packages/stream_chat_persistence/lib/src/entity/reads.dart @@ -1,14 +1,19 @@ import 'package:moor/moor.dart'; +/// Represents a [Reads] table in [MoorChatDatabase]. @DataClassName('ReadEntity') class Reads extends Table { + /// Date of the read event DateTimeColumn get lastRead => dateTime()(); + /// Id of the User who sent the event TextColumn get userId => text()(); + /// The channel cid of which this read belongs TextColumn get channelCid => text().customConstraint('REFERENCES channels(cid) ON DELETE CASCADE')(); + /// Number of unread messages IntColumn get unreadMessages => integer().nullable()(); @override diff --git a/packages/stream_chat_persistence/lib/src/entity/users.dart b/packages/stream_chat_persistence/lib/src/entity/users.dart index 4beee396..4916ad28 100644 --- a/packages/stream_chat_persistence/lib/src/entity/users.dart +++ b/packages/stream_chat_persistence/lib/src/entity/users.dart @@ -1,22 +1,31 @@ import 'package:moor/moor.dart'; import 'package:stream_chat_persistence/src/converter/map_converter.dart'; +/// Represents a [Users] table in [MoorChatDatabase]. @DataClassName('UserEntity') class Users extends Table { + /// User id TextColumn get id => text()(); + /// User role TextColumn get role => text().nullable()(); + /// Date of user creation DateTimeColumn get createdAt => dateTime().nullable()(); + /// Date of last user update DateTimeColumn get updatedAt => dateTime().nullable()(); + /// Date of last user connection DateTimeColumn get lastActive => dateTime().nullable()(); + /// True if user is online BoolColumn get online => boolean().nullable()(); + /// True if user is banned from the chat BoolColumn get banned => boolean().nullable()(); + /// Map of custom user extraData TextColumn get extraData => text().nullable().map(MapConverter())(); @override diff --git a/packages/stream_chat_persistence/lib/src/mapper/channel_mapper.dart b/packages/stream_chat_persistence/lib/src/mapper/channel_mapper.dart index 4d35340b..7d0e152f 100644 --- a/packages/stream_chat_persistence/lib/src/mapper/channel_mapper.dart +++ b/packages/stream_chat_persistence/lib/src/mapper/channel_mapper.dart @@ -1,9 +1,9 @@ import 'package:stream_chat/stream_chat.dart'; import 'package:stream_chat_persistence/src/db/moor_chat_database.dart'; -/// +/// Useful mapping functions for [ChannelEntity] extension ChannelEntityX on ChannelEntity { - /// + /// Maps a [ChannelEntity] into [ChannelModel] ChannelModel toChannelModel({User createdBy}) { final config = ChannelConfig.fromJson(this.config ?? {}); return ChannelModel( @@ -22,7 +22,7 @@ extension ChannelEntityX on ChannelEntity { ); } - /// + /// Maps a [ChannelEntity] into [ChannelState] ChannelState toChannelState({ User createdBy, List members, @@ -38,9 +38,9 @@ extension ChannelEntityX on ChannelEntity { } } -/// +/// Useful mapping functions for [ChannelModel] extension ChannelModelX on ChannelModel { - /// + /// Maps a [ChannelModel] into [ChannelEntity] ChannelEntity toEntity() { return ChannelEntity( id: id, diff --git a/packages/stream_chat_persistence/lib/src/mapper/event_mapper.dart b/packages/stream_chat_persistence/lib/src/mapper/event_mapper.dart index 9746dc20..7bc1739c 100644 --- a/packages/stream_chat_persistence/lib/src/mapper/event_mapper.dart +++ b/packages/stream_chat_persistence/lib/src/mapper/event_mapper.dart @@ -1,10 +1,9 @@ import 'package:stream_chat/stream_chat.dart'; -import 'user_mapper.dart'; import 'package:stream_chat_persistence/src/db/moor_chat_database.dart'; -/// +/// Useful mapping functions for [ConnectionEventEntity] extension ConnectionEventX on ConnectionEventEntity { - /// + /// Maps a [ConnectionEventEntity] into [Event] Event toEvent() { return Event( me: ownUser != null ? OwnUser.fromJson(ownUser) : null, diff --git a/packages/stream_chat_persistence/lib/src/mapper/member_mapper.dart b/packages/stream_chat_persistence/lib/src/mapper/member_mapper.dart index 42f463ba..2d32c9f1 100644 --- a/packages/stream_chat_persistence/lib/src/mapper/member_mapper.dart +++ b/packages/stream_chat_persistence/lib/src/mapper/member_mapper.dart @@ -1,10 +1,9 @@ import 'package:stream_chat/stream_chat.dart'; import 'package:stream_chat_persistence/src/db/moor_chat_database.dart'; -import 'user_mapper.dart'; -/// +/// Useful mapping functions for [MemberEntity] extension MemberEntityX on MemberEntity { - /// + /// Maps a [MemberEntity] into [Member] Member toMember({User user}) { return Member( user: user, @@ -22,9 +21,9 @@ extension MemberEntityX on MemberEntity { } } -/// +/// Useful mapping functions for [Member] extension MemberX on Member { - /// + /// Maps a [Member] into [MemberEntity] MemberEntity toEntity({String cid}) { return MemberEntity( userId: user?.id, diff --git a/packages/stream_chat_persistence/lib/src/mapper/message_mapper.dart b/packages/stream_chat_persistence/lib/src/mapper/message_mapper.dart index 4ea001a1..510675e6 100644 --- a/packages/stream_chat_persistence/lib/src/mapper/message_mapper.dart +++ b/packages/stream_chat_persistence/lib/src/mapper/message_mapper.dart @@ -3,9 +3,9 @@ import 'dart:convert'; import 'package:stream_chat/stream_chat.dart'; import 'package:stream_chat_persistence/src/db/moor_chat_database.dart'; -/// +/// Useful mapping functions for [MessageEntity] extension MessageEntityX on MessageEntity { - /// + /// Maps a [MessageEntity] into [Message] Message toMessage({ User user, List latestReactions, @@ -41,9 +41,9 @@ extension MessageEntityX on MessageEntity { } } -/// +/// Useful mapping functions for [Message] extension MessageX on Message { - /// + /// Maps a [Message] into [MessageEntity] MessageEntity toEntity({String cid}) { return MessageEntity( id: id, diff --git a/packages/stream_chat_persistence/lib/src/mapper/reaction_mapper.dart b/packages/stream_chat_persistence/lib/src/mapper/reaction_mapper.dart index d468d11c..407816be 100644 --- a/packages/stream_chat_persistence/lib/src/mapper/reaction_mapper.dart +++ b/packages/stream_chat_persistence/lib/src/mapper/reaction_mapper.dart @@ -1,9 +1,9 @@ import 'package:stream_chat/stream_chat.dart'; import 'package:stream_chat_persistence/src/db/moor_chat_database.dart'; -/// +/// Useful mapping functions for [ReactionEntity] extension ReactionEntityX on ReactionEntity { - /// + /// Maps a [ReactionEntity] into [Reaction] Reaction toReaction({User user}) { return Reaction( extraData: extraData, @@ -17,10 +17,9 @@ extension ReactionEntityX on ReactionEntity { } } -/// +/// Useful mapping functions for [Reaction] extension ReactionX on Reaction { - /// - ReactionEntity toEntity() { + ReactionEntity toEntity() { return ReactionEntity( extraData: extraData, type: type, diff --git a/packages/stream_chat_persistence/lib/src/mapper/read_mapper.dart b/packages/stream_chat_persistence/lib/src/mapper/read_mapper.dart index 0f9ea560..c79cf8d5 100644 --- a/packages/stream_chat_persistence/lib/src/mapper/read_mapper.dart +++ b/packages/stream_chat_persistence/lib/src/mapper/read_mapper.dart @@ -1,10 +1,9 @@ import 'package:stream_chat/stream_chat.dart'; import 'package:stream_chat_persistence/src/db/moor_chat_database.dart'; -import 'user_mapper.dart'; -/// +/// Useful mapping functions for [ReadEntity] extension ReadEntityX on ReadEntity { - /// + /// Maps a [ReadEntity] into [Read] Read toRead({User user}) { return Read( user: user, @@ -14,9 +13,9 @@ extension ReadEntityX on ReadEntity { } } -/// +/// Useful mapping functions for [Read] extension ReadX on Read { - /// + /// Maps a [Read] into [ReadEntity] ReadEntity toEntity({String cid}) { return ReadEntity( lastRead: lastRead, diff --git a/packages/stream_chat_persistence/lib/src/mapper/user_mapper.dart b/packages/stream_chat_persistence/lib/src/mapper/user_mapper.dart index cb775ab7..b1e53786 100644 --- a/packages/stream_chat_persistence/lib/src/mapper/user_mapper.dart +++ b/packages/stream_chat_persistence/lib/src/mapper/user_mapper.dart @@ -1,9 +1,9 @@ import 'package:stream_chat/stream_chat.dart'; import 'package:stream_chat_persistence/src/db/moor_chat_database.dart'; -/// +/// Useful mapping functions for [UserEntity] extension UserEntityX on UserEntity { - /// + /// Maps a [UserEntity] into [User] User toUser() { return User( id: id, @@ -18,9 +18,9 @@ extension UserEntityX on UserEntity { } } -/// +/// Useful mapping functions for [User] extension UserX on User { - /// + /// Maps a [User] into [UserEntity] UserEntity toEntity() { return UserEntity( id: id, diff --git a/packages/stream_chat_persistence/lib/src/stream_chat_persistence_client.dart b/packages/stream_chat_persistence/lib/src/stream_chat_persistence_client.dart index cfcc5c68..c0aceff5 100644 --- a/packages/stream_chat_persistence/lib/src/stream_chat_persistence_client.dart +++ b/packages/stream_chat_persistence/lib/src/stream_chat_persistence_client.dart @@ -12,9 +12,9 @@ enum ConnectionMode { background, } -/// +/// A [MoorChatDatabase] based implementation of the [ChatPersistenceClient] class StreamChatPersistenceClient extends ChatPersistenceClient { - /// + /// Creates a new instance of the stream chat persistence client StreamChatPersistenceClient({ /// Connection mode on which the client will work ConnectionMode connectionMode = ConnectionMode.regular, From db275bfa7115f9b56910d2af8e9190f2a3882fc5 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Thu, 28 Jan 2021 19:51:48 +0530 Subject: [PATCH 1076/1140] [LLC, Persistence] Use pagination options instead of single filter Signed-off-by: Sahil Kumar --- packages/dart_client/lib/src/api/channel.dart | 2 +- .../dart_client/lib/src/db/chat_persistence_client.dart | 2 +- .../stream_chat_persistence/lib/src/dao/message_dao.dart | 6 +++--- .../lib/src/stream_chat_persistence_client.dart | 4 ++-- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/dart_client/lib/src/api/channel.dart b/packages/dart_client/lib/src/api/channel.dart index 3ba9aa1f..45dd5da8 100644 --- a/packages/dart_client/lib/src/api/channel.dart +++ b/packages/dart_client/lib/src/api/channel.dart @@ -489,7 +489,7 @@ class Channel { }) async { final cachedReplies = await _client.chatPersistenceClient?.getReplies( parentId, - lessThan: options?.lessThan, + options: options, ); if (cachedReplies != null && cachedReplies.isNotEmpty) { state?.updateThreadInfo(parentId, cachedReplies); diff --git a/packages/dart_client/lib/src/db/chat_persistence_client.dart b/packages/dart_client/lib/src/db/chat_persistence_client.dart index c0cb68b2..19a9164e 100644 --- a/packages/dart_client/lib/src/db/chat_persistence_client.dart +++ b/packages/dart_client/lib/src/db/chat_persistence_client.dart @@ -20,7 +20,7 @@ abstract class ChatPersistenceClient { /// Get stored replies by messageId Future> getReplies( String parentId, { - String lessThan, + PaginationParams options, }); /// Get stored connection event diff --git a/packages/stream_chat_persistence/lib/src/dao/message_dao.dart b/packages/stream_chat_persistence/lib/src/dao/message_dao.dart index 0b6ba97c..57aa055d 100644 --- a/packages/stream_chat_persistence/lib/src/dao/message_dao.dart +++ b/packages/stream_chat_persistence/lib/src/dao/message_dao.dart @@ -79,7 +79,7 @@ class MessageDao extends DatabaseAccessor /// [messages.parentId] with [parentId] Future> getThreadMessagesByParentId( String parentId, { - String lessThan, + PaginationParams options, }) async { final msgList = await Future.wait(await (select(messages).join([ innerJoin(users, messages.userId.equalsExp(users.id)), @@ -89,8 +89,8 @@ class MessageDao extends DatabaseAccessor .map(_messageFromJoinRow) .get()); - if (lessThan != null) { - final lessThanIndex = msgList.indexWhere((m) => m.id == lessThan); + if (options?.lessThan != null) { + final lessThanIndex = msgList.indexWhere((m) => m.id == options.lessThan); msgList.removeRange(lessThanIndex, msgList.length); } return msgList; diff --git a/packages/stream_chat_persistence/lib/src/stream_chat_persistence_client.dart b/packages/stream_chat_persistence/lib/src/stream_chat_persistence_client.dart index c0aceff5..49a59423 100644 --- a/packages/stream_chat_persistence/lib/src/stream_chat_persistence_client.dart +++ b/packages/stream_chat_persistence/lib/src/stream_chat_persistence_client.dart @@ -142,11 +142,11 @@ class StreamChatPersistenceClient extends ChatPersistenceClient { @override Future> getReplies( String parentId, { - String lessThan, + PaginationParams options, }) { return _db.messageDao.getThreadMessagesByParentId( parentId, - lessThan: lessThan, + options: options, ); } From e537c0e78a714d9806a31084f81ffcbd55a53176 Mon Sep 17 00:00:00 2001 From: Neevash Ramdial Date: Thu, 28 Jan 2021 20:24:55 -0400 Subject: [PATCH 1077/1140] Update docs --- .../lib/src/channel_list_core.dart | 12 +++--- .../lib/src/message_search_list_core.dart | 14 +++---- .../lib/src/stream_chat_core.dart | 35 +++++++++++------ .../lib/src/user_list_core.dart | 39 +++++++++++-------- .../lib/src/users_bloc.dart | 6 ++- 5 files changed, 64 insertions(+), 42 deletions(-) diff --git a/packages/stream_chat_flutter_core/lib/src/channel_list_core.dart b/packages/stream_chat_flutter_core/lib/src/channel_list_core.dart index d2fd53c7..94ca0525 100644 --- a/packages/stream_chat_flutter_core/lib/src/channel_list_core.dart +++ b/packages/stream_chat_flutter_core/lib/src/channel_list_core.dart @@ -11,6 +11,8 @@ import 'stream_chat_core.dart'; /// [ChannelListCore] is a simplified class that allows fetching a list of channels while exposing UI builders. /// A [ChannelListController] is used to reload and paginate data. /// +/// {@tool snippet} +/// /// ```dart /// class ChannelListPage extends StatelessWidget { /// @override @@ -49,21 +51,21 @@ import 'stream_chat_core.dart'; /// } /// } /// ``` -/// +/// {@end-tool} /// /// Make sure to have a [StreamChatCore] ancestor in order to provide the information about the channels. class ChannelListCore extends StatefulWidget { /// Instantiate a new ChannelListView ChannelListCore({ Key key, - this.filter, - this.options, - this.sort, - this.pagination, @required this.errorBuilder, @required this.emptyBuilder, @required this.loadingBuilder, @required this.listBuilder, + this.filter, + this.options, + this.sort, + this.pagination, this.channelListController, }) : super(key: key); diff --git a/packages/stream_chat_flutter_core/lib/src/message_search_list_core.dart b/packages/stream_chat_flutter_core/lib/src/message_search_list_core.dart index e5ff9527..5b64bd8c 100644 --- a/packages/stream_chat_flutter_core/lib/src/message_search_list_core.dart +++ b/packages/stream_chat_flutter_core/lib/src/message_search_list_core.dart @@ -8,6 +8,8 @@ import 'message_search_bloc.dart'; /// [MessageSearchListCore] is a simplified class that allows searching for messages across channels while exposing UI builders. /// A [MessageSearchListController] is used to load and paginate data. /// +/// {@tool snippet} +/// /// ```dart /// class MessageSearchPage extends StatelessWidget { /// @override @@ -26,26 +28,24 @@ import 'message_search_bloc.dart'; /// } /// } /// ``` -/// +/// {@end-tool} /// /// Make sure to have a [MessageSearchBloc] ancestor in order to provide the information about the messages. /// The widget uses a [ListView.separated] to render the list of messages. /// -/// The widget components render the ui based on the first ancestor of type [StreamChatTheme]. -/// Modify it to change the widget appearance. class MessageSearchListCore extends StatefulWidget { /// Instantiate a new MessageSearchListView const MessageSearchListCore({ Key key, + @required this.emptyBuilder, + @required this.errorBuilder, + @required this.loadingBuilder, + @required this.childBuilder, this.messageQuery, this.filters, this.sortOptions, this.paginationParams, this.messageFilters, - @required this.emptyBuilder, - @required this.errorBuilder, - @required this.loadingBuilder, - @required this.childBuilder, this.messageSearchListController, }) : super(key: key); diff --git a/packages/stream_chat_flutter_core/lib/src/stream_chat_core.dart b/packages/stream_chat_flutter_core/lib/src/stream_chat_core.dart index 73f5eb61..c98ef7c9 100644 --- a/packages/stream_chat_flutter_core/lib/src/stream_chat_core.dart +++ b/packages/stream_chat_flutter_core/lib/src/stream_chat_core.dart @@ -4,8 +4,16 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:stream_chat/stream_chat.dart'; -/// Widget used to provide information about the chat to the widget tree +/// Widget used to provide information about the chat to the widget tree. +/// This Widget is used to react to life cycle changes and system updates. +/// When the app goes into the background, the websocket connection is kept alive +/// for two minutes before being terminated. /// +/// Conversely, when app is resumed or restarted, a new connection is initiated. +/// +/// {@tool snippet} +/// +/// ```dart /// class MyApp extends StatelessWidget { /// final Client client; /// @@ -15,7 +23,7 @@ import 'package:stream_chat/stream_chat.dart'; /// Widget build(BuildContext context) { /// return MaterialApp( /// home: Container( -/// child: StreamChat( +/// child: StreamChatCore( /// client: client, /// child: ChannelListPage(), /// ), @@ -23,22 +31,26 @@ import 'package:stream_chat/stream_chat.dart'; /// ); /// } /// } +/// ``` +/// {@end-tool} /// -/// Use [StreamChatCore.of] to get the current [StreamChatCoreState] instance. class StreamChatCore extends StatefulWidget { - // ignore: public_member_api_docs + /// Instance of Stream Chat Client containing information about the current + /// application. final Client client; - // ignore: public_member_api_docs + + /// Widget descendant. final Widget child; - // ignore: public_member_api_docs + /// Constructor used for creating a new instance of [StreamChatCore]. + /// + /// [StreamChatCore] is a stateful widget which reacts to system events and updates + /// Stream's connection status accordingly. StreamChatCore({ Key key, @required this.client, @required this.child, - }) : super( - key: key, - ); + }) : super(key: key); @override StreamChatCoreState createState() => StreamChatCoreState(); @@ -58,11 +70,12 @@ class StreamChatCore extends StatefulWidget { } } -/// The current state of the StreamChat widget +/// State class associated with [StreamChatCore]. class StreamChatCoreState extends State with WidgetsBindingObserver { - // ignore: public_member_api_docs + /// Initialized client used throughout the application. Client get client => widget.client; + Timer _disconnectTimer; @override diff --git a/packages/stream_chat_flutter_core/lib/src/user_list_core.dart b/packages/stream_chat_flutter_core/lib/src/user_list_core.dart index e323591f..3d0981af 100644 --- a/packages/stream_chat_flutter_core/lib/src/user_list_core.dart +++ b/packages/stream_chat_flutter_core/lib/src/user_list_core.dart @@ -8,6 +8,8 @@ import 'package:stream_chat_flutter_core/src/users_bloc.dart'; /// [UserListCore] is a simplified class that allows fetching users while exposing UI builders. /// A [UserListController] is used to load and paginate data. /// +/// {@tool snippet} +/// /// ```dart /// class UsersListPage extends StatelessWidget { /// @override @@ -46,26 +48,27 @@ import 'package:stream_chat_flutter_core/src/users_bloc.dart'; /// } /// } /// ``` +/// {@end-tool} /// +/// [UsersBloc] must be the ancestor of this widget. This is necessary since +/// [UserListCore] depends on functionality contained within [UsersBloc]. /// -/// Make sure to have a [UsersBloc] ancestor in order to provide the information about the users. /// The widget uses a [ListView.separated], [GridView.builder] to render the list, grid of channels. -/// -/// The widget components render the ui based on the first ancestor of type [StreamChatTheme]. -/// Modify it to change the widget appearance. +/// The parameters [listBuilder], [loadingBuilder], [emptyBuilder] and [errorBuilder] must all be supplied +/// and not null. class UserListCore extends StatefulWidget { - /// Instantiate a new UserListView + /// Instantiate a new [UserListCore] const UserListCore({ Key key, + @required this.errorBuilder, + @required this.emptyBuilder, + @required this.loadingBuilder, + @required this.listBuilder, this.filter, this.options, this.sort, this.pagination, this.groupAlphabetically = false, - @required this.errorBuilder, - @required this.emptyBuilder, - @required this.loadingBuilder, - @required this.listBuilder, this.userListController, }) : super(key: key); @@ -138,9 +141,9 @@ class _UserListCoreState extends State @override Widget build(BuildContext context) { - final usersBloc = UsersBloc.of(context); + final _usersBloc = UsersBloc.of(context); - return _buildListView(usersBloc); + return _buildListView(_usersBloc); } bool get isListAlreadySorted => @@ -207,9 +210,9 @@ class _UserListCoreState extends State } void loadData() { - final usersBloc = UsersBloc.of(context); + final _usersBloc = UsersBloc.of(context); - usersBloc.queryUsers( + _usersBloc.queryUsers( filter: widget.filter, sort: widget.sort, pagination: widget.pagination, @@ -218,13 +221,13 @@ class _UserListCoreState extends State } void paginateData() { - final usersBloc = UsersBloc.of(context); + final _usersBloc = UsersBloc.of(context); - usersBloc.queryUsers( + _usersBloc.queryUsers( filter: widget.filter, sort: widget.sort, pagination: widget.pagination.copyWith( - offset: usersBloc.users?.length ?? 0, + offset: _usersBloc.users?.length ?? 0, ), options: widget.options, ); @@ -249,7 +252,9 @@ class _UserListCoreState extends State } } -// ignore: public_member_api_docs +/// Represents an item in a the user stream list. +/// Header items are prefixed with the key `HEADER` While users are prefixed with +/// `USER`. abstract class ListItem { // ignore: public_member_api_docs String get key { diff --git a/packages/stream_chat_flutter_core/lib/src/users_bloc.dart b/packages/stream_chat_flutter_core/lib/src/users_bloc.dart index 489461ef..5ada9d90 100644 --- a/packages/stream_chat_flutter_core/lib/src/users_bloc.dart +++ b/packages/stream_chat_flutter_core/lib/src/users_bloc.dart @@ -4,7 +4,7 @@ import 'package:stream_chat/stream_chat.dart'; import 'stream_chat_core.dart'; -/// Widget dedicated to the management of a users list with pagination +/// Widget dedicated to the management of a users list with pagination. class UsersBloc extends StatefulWidget { /// The widget child final Widget child; @@ -49,7 +49,9 @@ class UsersBlocState extends State /// The stream notifying the state of queryUsers call Stream get queryUsersLoading => _queryUsersLoadingController.stream; - /// Calls [Client.queryUsers] updating [queryUsersLoading] stream + /// The Query Users method allows you to search for users and see if they are + /// online/offline. + /// [API Reference](https://getstream.io/chat/docs/flutter-dart/query_users/?language=dart) Future queryUsers({ Map filter, List sort, From 935a38f089f0af934bddadc4d15221fdc84a0b75 Mon Sep 17 00:00:00 2001 From: Neevash Ramdial Date: Thu, 28 Jan 2021 20:44:55 -0400 Subject: [PATCH 1078/1140] remove @tool annotation --- .../stream_chat_flutter_core/lib/src/channel_list_core.dart | 2 -- .../lib/src/message_search_list_core.dart | 3 --- .../stream_chat_flutter_core/lib/src/stream_chat_core.dart | 3 --- packages/stream_chat_flutter_core/lib/src/user_list_core.dart | 3 --- 4 files changed, 11 deletions(-) diff --git a/packages/stream_chat_flutter_core/lib/src/channel_list_core.dart b/packages/stream_chat_flutter_core/lib/src/channel_list_core.dart index 94ca0525..d60292d1 100644 --- a/packages/stream_chat_flutter_core/lib/src/channel_list_core.dart +++ b/packages/stream_chat_flutter_core/lib/src/channel_list_core.dart @@ -11,7 +11,6 @@ import 'stream_chat_core.dart'; /// [ChannelListCore] is a simplified class that allows fetching a list of channels while exposing UI builders. /// A [ChannelListController] is used to reload and paginate data. /// -/// {@tool snippet} /// /// ```dart /// class ChannelListPage extends StatelessWidget { @@ -51,7 +50,6 @@ import 'stream_chat_core.dart'; /// } /// } /// ``` -/// {@end-tool} /// /// Make sure to have a [StreamChatCore] ancestor in order to provide the information about the channels. class ChannelListCore extends StatefulWidget { diff --git a/packages/stream_chat_flutter_core/lib/src/message_search_list_core.dart b/packages/stream_chat_flutter_core/lib/src/message_search_list_core.dart index 5b64bd8c..cfdfb0ae 100644 --- a/packages/stream_chat_flutter_core/lib/src/message_search_list_core.dart +++ b/packages/stream_chat_flutter_core/lib/src/message_search_list_core.dart @@ -8,8 +8,6 @@ import 'message_search_bloc.dart'; /// [MessageSearchListCore] is a simplified class that allows searching for messages across channels while exposing UI builders. /// A [MessageSearchListController] is used to load and paginate data. /// -/// {@tool snippet} -/// /// ```dart /// class MessageSearchPage extends StatelessWidget { /// @override @@ -28,7 +26,6 @@ import 'message_search_bloc.dart'; /// } /// } /// ``` -/// {@end-tool} /// /// Make sure to have a [MessageSearchBloc] ancestor in order to provide the information about the messages. /// The widget uses a [ListView.separated] to render the list of messages. diff --git a/packages/stream_chat_flutter_core/lib/src/stream_chat_core.dart b/packages/stream_chat_flutter_core/lib/src/stream_chat_core.dart index c98ef7c9..3d23eb08 100644 --- a/packages/stream_chat_flutter_core/lib/src/stream_chat_core.dart +++ b/packages/stream_chat_flutter_core/lib/src/stream_chat_core.dart @@ -11,8 +11,6 @@ import 'package:stream_chat/stream_chat.dart'; /// /// Conversely, when app is resumed or restarted, a new connection is initiated. /// -/// {@tool snippet} -/// /// ```dart /// class MyApp extends StatelessWidget { /// final Client client; @@ -32,7 +30,6 @@ import 'package:stream_chat/stream_chat.dart'; /// } /// } /// ``` -/// {@end-tool} /// class StreamChatCore extends StatefulWidget { /// Instance of Stream Chat Client containing information about the current diff --git a/packages/stream_chat_flutter_core/lib/src/user_list_core.dart b/packages/stream_chat_flutter_core/lib/src/user_list_core.dart index 3d0981af..a9398d89 100644 --- a/packages/stream_chat_flutter_core/lib/src/user_list_core.dart +++ b/packages/stream_chat_flutter_core/lib/src/user_list_core.dart @@ -8,8 +8,6 @@ import 'package:stream_chat_flutter_core/src/users_bloc.dart'; /// [UserListCore] is a simplified class that allows fetching users while exposing UI builders. /// A [UserListController] is used to load and paginate data. /// -/// {@tool snippet} -/// /// ```dart /// class UsersListPage extends StatelessWidget { /// @override @@ -48,7 +46,6 @@ import 'package:stream_chat_flutter_core/src/users_bloc.dart'; /// } /// } /// ``` -/// {@end-tool} /// /// [UsersBloc] must be the ancestor of this widget. This is necessary since /// [UserListCore] depends on functionality contained within [UsersBloc]. From d5c57f3cb5db43deb622af05e2e5e99ae74ae296 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Fri, 29 Jan 2021 13:33:45 +0530 Subject: [PATCH 1079/1140] [UI-KIT] Add connection status builder Signed-off-by: Sahil Kumar --- .../lib/group_chat_details_screen.dart | 200 ++++----- .../example/lib/new_chat_screen.dart | 5 +- .../example/lib/new_group_chat_screen.dart | 406 +++++++++--------- .../lib/src/channel_header.dart | 7 +- .../flutter_widgets/lib/src/channel_info.dart | 7 +- .../lib/src/channel_list_header.dart | 11 +- .../lib/src/connection_status_builder.dart | 55 +++ .../lib/src/message_list_view.dart | 347 ++++++++------- .../lib/stream_chat_flutter.dart | 1 + packages/flutter_widgets/pubspec.yaml | 2 - .../stream_chat_flutter_core/pubspec.yaml | 4 +- 11 files changed, 546 insertions(+), 499 deletions(-) create mode 100644 packages/flutter_widgets/lib/src/connection_status_builder.dart diff --git a/packages/flutter_widgets/example/lib/group_chat_details_screen.dart b/packages/flutter_widgets/example/lib/group_chat_details_screen.dart index 83ec94bb..afc9d12f 100644 --- a/packages/flutter_widgets/example/lib/group_chat_details_screen.dart +++ b/packages/flutter_widgets/example/lib/group_chat_details_screen.dart @@ -150,116 +150,116 @@ class _GroupChatDetailsScreenState extends State { ), ], ), - body: ValueListenableBuilder( - valueListenable: StreamChat.of(context).client.wsConnectionStatus, - builder: (context, status, _) { - String statusString = ''; - bool showStatus = true; + body: ConnectionStatusBuilder( + statusBuilder: (context, status) { + String statusString = ''; + bool showStatus = true; - switch (status) { - case ConnectionStatus.connected: - statusString = 'Connected'; - showStatus = false; - break; - case ConnectionStatus.connecting: - statusString = 'Reconnecting...'; - break; - case ConnectionStatus.disconnected: - statusString = 'Disconnected'; - break; - } - return InfoTile( - showMessage: showStatus, - tileAnchor: Alignment.topCenter, - childAnchor: Alignment.topCenter, - message: statusString, - child: Column( - children: [ - Container( - width: double.maxFinite, - decoration: BoxDecoration( - gradient: - StreamChatTheme.of(context).colorTheme.bgGradient, + switch (status) { + case ConnectionStatus.connected: + statusString = 'Connected'; + showStatus = false; + break; + case ConnectionStatus.connecting: + statusString = 'Reconnecting...'; + break; + case ConnectionStatus.disconnected: + statusString = 'Disconnected'; + break; + } + return InfoTile( + showMessage: showStatus, + tileAnchor: Alignment.topCenter, + childAnchor: Alignment.topCenter, + message: statusString, + child: Column( + children: [ + Container( + width: double.maxFinite, + decoration: BoxDecoration( + gradient: + StreamChatTheme.of(context).colorTheme.bgGradient, + ), + child: Padding( + padding: const EdgeInsets.symmetric( + vertical: 8, + horizontal: 8, ), - child: Padding( - padding: const EdgeInsets.symmetric( - vertical: 8, - horizontal: 8, - ), - child: Text( - '$_totalUsers ${_totalUsers > 1 ? 'Members' : 'Member'}', - style: TextStyle( - color: StreamChatTheme.of(context).colorTheme.grey, - ), + child: Text( + '$_totalUsers ${_totalUsers > 1 ? 'Members' : 'Member'}', + style: TextStyle( + color: StreamChatTheme.of(context).colorTheme.grey, ), ), ), - Expanded( - child: GestureDetector( - behavior: HitTestBehavior.opaque, - onPanDown: (_) => FocusScope.of(context).unfocus(), - child: ListView.separated( - itemCount: _selectedUsers.length + 1, - separatorBuilder: (_, __) => Container( - height: 1, - color: StreamChatTheme.of(context) - .colorTheme - .greyWhisper, - ), - itemBuilder: (_, index) { - if (index == _selectedUsers.length) { - return Container( - height: 1, + ), + Expanded( + child: GestureDetector( + behavior: HitTestBehavior.opaque, + onPanDown: (_) => FocusScope.of(context).unfocus(), + child: ListView.separated( + itemCount: _selectedUsers.length + 1, + separatorBuilder: (_, __) => Container( + height: 1, + color: StreamChatTheme.of(context) + .colorTheme + .greyWhisper, + ), + itemBuilder: (_, index) { + if (index == _selectedUsers.length) { + return Container( + height: 1, + color: StreamChatTheme.of(context) + .colorTheme + .greyWhisper, + ); + } + final user = _selectedUsers[index]; + return ListTile( + key: ObjectKey(user), + leading: UserAvatar( + user: user, + constraints: BoxConstraints.tightFor( + width: 40, + height: 40, + ), + ), + title: Text( + user.name, + style: TextStyle(fontWeight: FontWeight.bold), + ), + contentPadding: const EdgeInsets.symmetric( + horizontal: 12, + vertical: 8, + ), + trailing: IconButton( + icon: Icon( + Icons.clear_rounded, color: StreamChatTheme.of(context) .colorTheme - .greyWhisper, - ); - } - final user = _selectedUsers[index]; - return ListTile( - key: ObjectKey(user), - leading: UserAvatar( - user: user, - constraints: BoxConstraints.tightFor( - width: 40, - height: 40, - ), + .black, ), - title: Text( - user.name, - style: TextStyle(fontWeight: FontWeight.bold), - ), - contentPadding: const EdgeInsets.symmetric( - horizontal: 12, - vertical: 8, - ), - trailing: IconButton( - icon: Icon( - Icons.clear_rounded, - color: StreamChatTheme.of(context) - .colorTheme - .black, - ), - padding: const EdgeInsets.all(0), - splashRadius: 24, - onPressed: () { - setState(() { - _selectedUsers.remove(user); - }); - if (_selectedUsers.isEmpty) { - Navigator.pop(context, _selectedUsers); - } - }, - ), - ); - }, - ), + padding: const EdgeInsets.all(0), + splashRadius: 24, + onPressed: () { + setState(() { + _selectedUsers.remove(user); + }); + if (_selectedUsers.isEmpty) { + Navigator.pop(context, _selectedUsers); + } + }, + ), + ); + }, ), ), - ], - ), - ); - }), + ), + ], + ), + ); + }, + ), ), ); } diff --git a/packages/flutter_widgets/example/lib/new_chat_screen.dart b/packages/flutter_widgets/example/lib/new_chat_screen.dart index baddd570..7f47e871 100644 --- a/packages/flutter_widgets/example/lib/new_chat_screen.dart +++ b/packages/flutter_widgets/example/lib/new_chat_screen.dart @@ -134,9 +134,8 @@ class _NewChatScreenState extends State { ), centerTitle: true, ), - body: ValueListenableBuilder( - valueListenable: StreamChat.of(context).client.wsConnectionStatus, - builder: (context, status, _) { + body: ConnectionStatusBuilder( + statusBuilder: (context, status) { String statusString = ''; bool showStatus = true; diff --git a/packages/flutter_widgets/example/lib/new_group_chat_screen.dart b/packages/flutter_widgets/example/lib/new_group_chat_screen.dart index 4d0274e2..4e924d86 100644 --- a/packages/flutter_widgets/example/lib/new_group_chat_screen.dart +++ b/packages/flutter_widgets/example/lib/new_group_chat_screen.dart @@ -87,227 +87,225 @@ class _NewGroupChatScreenState extends State { ) ], ), - body: ValueListenableBuilder( - valueListenable: StreamChat.of(context).client.wsConnectionStatus, - builder: (context, status, _) { - String statusString = ''; - bool showStatus = true; + body: ConnectionStatusBuilder( + statusBuilder: (context, status) { + String statusString = ''; + bool showStatus = true; - switch (status) { - case ConnectionStatus.connected: - statusString = 'Connected'; - showStatus = false; - break; - case ConnectionStatus.connecting: - statusString = 'Reconnecting...'; - break; - case ConnectionStatus.disconnected: - statusString = 'Disconnected'; - break; - } - return InfoTile( - showMessage: showStatus, - tileAnchor: Alignment.topCenter, - childAnchor: Alignment.topCenter, - message: statusString, - child: NestedScrollView( - floatHeaderSlivers: true, - headerSliverBuilder: - (BuildContext context, bool innerBoxIsScrolled) { - return [ - SliverToBoxAdapter( - child: SearchTextField( - controller: _controller, - ), + switch (status) { + case ConnectionStatus.connected: + statusString = 'Connected'; + showStatus = false; + break; + case ConnectionStatus.connecting: + statusString = 'Reconnecting...'; + break; + case ConnectionStatus.disconnected: + statusString = 'Disconnected'; + break; + } + return InfoTile( + showMessage: showStatus, + tileAnchor: Alignment.topCenter, + childAnchor: Alignment.topCenter, + message: statusString, + child: NestedScrollView( + floatHeaderSlivers: true, + headerSliverBuilder: + (BuildContext context, bool innerBoxIsScrolled) { + return [ + SliverToBoxAdapter( + child: SearchTextField( + controller: _controller, ), - if (_selectedUsers.isNotEmpty) - SliverToBoxAdapter( - child: Container( - height: 104, - child: ListView.separated( - scrollDirection: Axis.horizontal, - itemCount: _selectedUsers.length, - padding: const EdgeInsets.all(8), - separatorBuilder: (_, __) => SizedBox(width: 16), - itemBuilder: (_, index) { - final user = _selectedUsers.elementAt(index); - return Column( - children: [ - Stack( - children: [ - UserAvatar( - onlineIndicatorAlignment: - Alignment(0.9, 0.9), - user: user, - showOnlineStatus: true, - borderRadius: BorderRadius.circular(32), - constraints: BoxConstraints.tightFor( - height: 64, - width: 64, - ), + ), + if (_selectedUsers.isNotEmpty) + SliverToBoxAdapter( + child: Container( + height: 104, + child: ListView.separated( + scrollDirection: Axis.horizontal, + itemCount: _selectedUsers.length, + padding: const EdgeInsets.all(8), + separatorBuilder: (_, __) => SizedBox(width: 16), + itemBuilder: (_, index) { + final user = _selectedUsers.elementAt(index); + return Column( + children: [ + Stack( + children: [ + UserAvatar( + onlineIndicatorAlignment: + Alignment(0.9, 0.9), + user: user, + showOnlineStatus: true, + borderRadius: BorderRadius.circular(32), + constraints: BoxConstraints.tightFor( + height: 64, + width: 64, ), - Positioned( - top: -4, - right: -4, - child: GestureDetector( - onTap: () { - if (_selectedUsers.contains(user)) { - setState(() => - _selectedUsers.remove(user)); - } - }, - child: Container( - decoration: BoxDecoration( + ), + Positioned( + top: -4, + right: -4, + child: GestureDetector( + onTap: () { + if (_selectedUsers.contains(user)) { + setState(() => + _selectedUsers.remove(user)); + } + }, + child: Container( + decoration: BoxDecoration( + color: StreamChatTheme.of(context) + .colorTheme + .white, + shape: BoxShape.circle, + border: Border.all( color: StreamChatTheme.of(context) .colorTheme - .white, - shape: BoxShape.circle, - border: Border.all( - color: - StreamChatTheme.of(context) - .colorTheme - .whiteSnow, - ), - ), - child: StreamSvgIcon.close( - color: StreamChatTheme.of(context) - .colorTheme - .black, - size: 24, + .whiteSnow, ), ), - ), - ) - ], - ), - SizedBox(height: 4), - Text( - user.name.split(' ')[0], - style: TextStyle( - fontWeight: FontWeight.bold, - fontSize: 12, - ), - ), - ], - ); - }, - ), - ), - ), - SliverPersistentHeader( - pinned: true, - delegate: _HeaderDelegate( - height: 30, - child: Container( - width: double.maxFinite, - decoration: BoxDecoration( - gradient: StreamChatTheme.of(context) - .colorTheme - .bgGradient, - ), - child: Padding( - padding: const EdgeInsets.symmetric( - vertical: 8, - horizontal: 8, - ), - child: Text( - _isSearchActive - ? 'Matches for \"$_userNameQuery\"' - : 'On the platform', - style: TextStyle( - color: - StreamChatTheme.of(context).colorTheme.grey, - ), - ), - ), - ), - ), - ), - ]; - }, - body: GestureDetector( - behavior: HitTestBehavior.opaque, - onPanDown: (_) => FocusScope.of(context).unfocus(), - child: UsersBloc( - child: UserListView( - selectedUsers: _selectedUsers, - pullToRefresh: false, - groupAlphabetically: _isSearchActive ? false : true, - onUserTap: (user, _) { - if (!_selectedUsers.contains(user)) { - setState(() { - _selectedUsers.add(user); - }); - } else { - setState(() { - _selectedUsers.remove(user); - }); - } - }, - pagination: PaginationParams( - limit: 25, - ), - filter: { - if (_userNameQuery.isNotEmpty) - 'name': { - r'$autocomplete': _userNameQuery, - }, - 'id': { - r'$ne': StreamChat.of(context).user.id, - } - }, - sort: [ - SortOption( - 'name', - direction: 1, - ), - ], - emptyBuilder: (_) { - return LayoutBuilder( - builder: (context, viewportConstraints) { - return SingleChildScrollView( - physics: AlwaysScrollableScrollPhysics(), - child: ConstrainedBox( - constraints: BoxConstraints( - minHeight: viewportConstraints.maxHeight, - ), - child: Center( - child: Column( - children: [ - Padding( - padding: const EdgeInsets.all(24), - child: StreamSvgIcon.search( - size: 96, - color: StreamChatTheme.of(context) - .colorTheme - .grey, + child: StreamSvgIcon.close( + color: StreamChatTheme.of(context) + .colorTheme + .black, + size: 24, + ), ), ), - Text( - 'No user matches these keywords...', - style: StreamChatTheme.of(context) - .textTheme - .footnote - .copyWith( - color: StreamChatTheme.of(context) - .colorTheme - .grey, - ), - ), - ], + ) + ], + ), + SizedBox(height: 4), + Text( + user.name.split(' ')[0], + style: TextStyle( + fontWeight: FontWeight.bold, + fontSize: 12, ), ), - ), + ], ); }, - ); - }, + ), + ), ), + SliverPersistentHeader( + pinned: true, + delegate: _HeaderDelegate( + height: 30, + child: Container( + width: double.maxFinite, + decoration: BoxDecoration( + gradient: + StreamChatTheme.of(context).colorTheme.bgGradient, + ), + child: Padding( + padding: const EdgeInsets.symmetric( + vertical: 8, + horizontal: 8, + ), + child: Text( + _isSearchActive + ? 'Matches for \"$_userNameQuery\"' + : 'On the platform', + style: TextStyle( + color: + StreamChatTheme.of(context).colorTheme.grey, + ), + ), + ), + ), + ), + ), + ]; + }, + body: GestureDetector( + behavior: HitTestBehavior.opaque, + onPanDown: (_) => FocusScope.of(context).unfocus(), + child: UsersBloc( + child: UserListView( + selectedUsers: _selectedUsers, + pullToRefresh: false, + groupAlphabetically: _isSearchActive ? false : true, + onUserTap: (user, _) { + if (!_selectedUsers.contains(user)) { + setState(() { + _selectedUsers.add(user); + }); + } else { + setState(() { + _selectedUsers.remove(user); + }); + } + }, + pagination: PaginationParams( + limit: 25, + ), + filter: { + if (_userNameQuery.isNotEmpty) + 'name': { + r'$autocomplete': _userNameQuery, + }, + 'id': { + r'$ne': StreamChat.of(context).user.id, + } + }, + sort: [ + SortOption( + 'name', + direction: 1, + ), + ], + emptyBuilder: (_) { + return LayoutBuilder( + builder: (context, viewportConstraints) { + return SingleChildScrollView( + physics: AlwaysScrollableScrollPhysics(), + child: ConstrainedBox( + constraints: BoxConstraints( + minHeight: viewportConstraints.maxHeight, + ), + child: Center( + child: Column( + children: [ + Padding( + padding: const EdgeInsets.all(24), + child: StreamSvgIcon.search( + size: 96, + color: StreamChatTheme.of(context) + .colorTheme + .grey, + ), + ), + Text( + 'No user matches these keywords...', + style: StreamChatTheme.of(context) + .textTheme + .footnote + .copyWith( + color: StreamChatTheme.of(context) + .colorTheme + .grey, + ), + ), + ], + ), + ), + ), + ); + }, + ); + }, ), ), ), - ); - }), + ), + ); + }, + ), ); } } diff --git a/packages/flutter_widgets/lib/src/channel_header.dart b/packages/flutter_widgets/lib/src/channel_header.dart index fb681d59..954734f9 100644 --- a/packages/flutter_widgets/lib/src/channel_header.dart +++ b/packages/flutter_widgets/lib/src/channel_header.dart @@ -9,6 +9,7 @@ import 'package:stream_chat_flutter/src/stream_chat_theme.dart'; import '../stream_chat_flutter.dart'; import './channel_name.dart'; import 'channel_image.dart'; +import 'connection_status_builder.dart'; /// ![screenshot](https://raw.githubusercontent.com/GetStream/stream-chat-flutter/master/screenshots/channel_header.png) /// ![screenshot](https://raw.githubusercontent.com/GetStream/stream-chat-flutter/master/screenshots/channel_header_paint.png) @@ -85,11 +86,9 @@ class ChannelHeader extends StatelessWidget implements PreferredSizeWidget { @override Widget build(BuildContext context) { final channel = StreamChannel.of(context).channel; - final _client = StreamChat.of(context).client; - return ValueListenableBuilder( - valueListenable: _client.wsConnectionStatus, - builder: (context, status, _) { + return ConnectionStatusBuilder( + statusBuilder: (context, status) { String statusString = ''; bool showStatus = true; diff --git a/packages/flutter_widgets/lib/src/channel_info.dart b/packages/flutter_widgets/lib/src/channel_info.dart index b1ab568d..88739bb3 100644 --- a/packages/flutter_widgets/lib/src/channel_info.dart +++ b/packages/flutter_widgets/lib/src/channel_info.dart @@ -2,6 +2,8 @@ import 'package:flutter/material.dart'; import 'package:jiffy/jiffy.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; +import 'connection_status_builder.dart'; + class ChannelInfo extends StatelessWidget { final Channel channel; @@ -25,9 +27,8 @@ class ChannelInfo extends StatelessWidget { stream: channel.state.membersStream, initialData: channel.state.members, builder: (context, snapshot) { - return ValueListenableBuilder( - valueListenable: client.wsConnectionStatus, - builder: (context, status, child) { + return ConnectionStatusBuilder( + statusBuilder: (context, status) { switch (status) { case ConnectionStatus.connected: return _buildConnectedTitleState(context, snapshot.data); diff --git a/packages/flutter_widgets/lib/src/channel_list_header.dart b/packages/flutter_widgets/lib/src/channel_list_header.dart index 8ced0422..29126402 100644 --- a/packages/flutter_widgets/lib/src/channel_list_header.dart +++ b/packages/flutter_widgets/lib/src/channel_list_header.dart @@ -6,6 +6,7 @@ import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; import 'package:stream_chat_flutter/src/stream_neumorphic_button.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; +import 'connection_status_builder.dart'; import 'info_tile.dart'; import 'stream_chat.dart'; @@ -79,9 +80,8 @@ class ChannelListHeader extends StatelessWidget implements PreferredSizeWidget { Widget build(BuildContext context) { final _client = client ?? StreamChat.of(context).client; final user = _client.state.user; - return ValueListenableBuilder( - valueListenable: _client.wsConnectionStatus, - builder: (context, status, child) { + return ConnectionStatusBuilder( + statusBuilder: (context, status) { String statusString = ''; bool showStatus = true; @@ -130,9 +130,8 @@ class ChannelListHeader extends StatelessWidget implements PreferredSizeWidget { actions: [ StreamNeumorphicButton( child: IconButton( - icon: ValueListenableBuilder( - valueListenable: _client.wsConnectionStatus, - builder: (context, status, child) { + icon: ConnectionStatusBuilder( + statusBuilder: (context, status) { var color; switch (status) { case ConnectionStatus.connected: diff --git a/packages/flutter_widgets/lib/src/connection_status_builder.dart b/packages/flutter_widgets/lib/src/connection_status_builder.dart new file mode 100644 index 00000000..25f9a0b6 --- /dev/null +++ b/packages/flutter_widgets/lib/src/connection_status_builder.dart @@ -0,0 +1,55 @@ +import 'package:flutter/material.dart'; +import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; +import 'stream_chat.dart'; + +class ConnectionStatusBuilder extends StatelessWidget { + /// Creates a new ConnectionStatusBuilder + const ConnectionStatusBuilder({ + Key key, + @required this.statusBuilder, + this.initialStatus = ConnectionStatus.disconnected, + this.connectionStatusStream, + this.errorBuilder, + this.loadingBuilder, + }) : assert(statusBuilder != null), + super(key: key); + + /// The connection status that will be used to create the initial snapshot. + final ConnectionStatus initialStatus; + + /// The asynchronous computation to which this builder is currently connected. + final Stream connectionStatusStream; + + /// The builder that will be used in case of error + final Widget Function(BuildContext context, Object error) errorBuilder; + + /// The builder that will be used in case of loading + final WidgetBuilder loadingBuilder; + + /// The builder that will be used in case of data + final Widget Function(BuildContext context, ConnectionStatus status) + statusBuilder; + + @override + Widget build(BuildContext context) { + final stream = connectionStatusStream ?? + StreamChat.of(context).client.wsConnectionStatusStream; + return StreamBuilder( + initialData: initialStatus, + stream: stream, + builder: (context, snapshot) { + if (snapshot.hasError) { + if (errorBuilder != null) { + return errorBuilder(context, snapshot.error); + } + return Offstage(); + } + if (!snapshot.hasData) { + if (loadingBuilder != null) return loadingBuilder(context); + return Offstage(); + } + return statusBuilder(context, snapshot.data); + }, + ); + } +} diff --git a/packages/flutter_widgets/lib/src/message_list_view.dart b/packages/flutter_widgets/lib/src/message_list_view.dart index 9ce29117..86c1445c 100644 --- a/packages/flutter_widgets/lib/src/message_list_view.dart +++ b/packages/flutter_widgets/lib/src/message_list_view.dart @@ -14,6 +14,7 @@ import 'package:stream_chat_flutter/src/system_message.dart'; import 'package:visibility_detector/visibility_detector.dart'; import '../stream_chat_flutter.dart'; +import 'connection_status_builder.dart'; import 'date_divider.dart'; import 'swipeable.dart'; import 'extension.dart'; @@ -301,197 +302,193 @@ class _MessageListViewState extends State { } _messageListLength = newMessagesListLength; - final _client = StreamChat.of(context).client; return Stack( alignment: Alignment.center, children: [ - ValueListenableBuilder( - valueListenable: _client.wsConnectionStatus, - builder: (context, status, _) { - String statusString = ''; - bool showStatus = true; + ConnectionStatusBuilder( + statusBuilder: (context, status) { + String statusString = ''; + bool showStatus = true; + switch (status) { + case ConnectionStatus.connected: + statusString = 'Connected'; + showStatus = false; + break; + case ConnectionStatus.connecting: + statusString = 'Reconnecting...'; + break; + case ConnectionStatus.disconnected: + statusString = 'Disconnected'; + break; + } - switch (status) { - case ConnectionStatus.connected: - statusString = 'Connected'; - showStatus = false; - break; - case ConnectionStatus.connecting: - statusString = 'Reconnecting...'; - break; - case ConnectionStatus.disconnected: - statusString = 'Disconnected'; - break; - } + return InfoTile( + showMessage: widget.showConnectionStateTile ? showStatus : false, + tileAnchor: Alignment.topCenter, + childAnchor: Alignment.topCenter, + message: statusString, + child: LazyLoadScrollView( + onStartOfPage: () async { + _inBetweenList = false; + if (!_upToDate) { + _topPaginationActive = false; + _bottomPaginationActive = true; + return _paginateData( + streamChannel, + QueryDirection.bottom, + ); + } + }, + onEndOfPage: () async { + _inBetweenList = false; + _topPaginationActive = true; + _bottomPaginationActive = false; + return _paginateData( + streamChannel, + QueryDirection.top, + ); + }, + onInBetweenOfPage: () { + _inBetweenList = true; + }, + child: ScrollablePositionedList.separated( + key: ValueKey(initialIndex + initialAlignment), + itemPositionsListener: _itemPositionListener, + addAutomaticKeepAlives: true, + initialScrollIndex: initialIndex ?? 0, + initialAlignment: initialAlignment ?? 0, + physics: widget.scrollPhysics, + itemScrollController: _scrollController, + reverse: true, + itemCount: + messages.length + 2 + (_isThreadConversation ? 1 : 0), + separatorBuilder: (context, i) { + if (i == messages.length) return Offstage(); + if (i == 0) return SizedBox(height: 30); + if (i == messages.length + 1) { + final replyCount = widget.parentMessage.replyCount; + return Container( + decoration: BoxDecoration( + gradient: + StreamChatTheme.of(context).colorTheme.bgGradient, + ), + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Text( + '$replyCount ${replyCount == 1 ? 'Reply' : 'Replies'}', + textAlign: TextAlign.center, + style: StreamChatTheme.of(context) + .channelTheme + .channelHeaderTheme + .lastMessageAt, + ), + ), + ); + } - return InfoTile( - showMessage: - widget.showConnectionStateTile ? showStatus : false, - tileAnchor: Alignment.topCenter, - childAnchor: Alignment.topCenter, - message: statusString, - child: LazyLoadScrollView( - onStartOfPage: () async { - _inBetweenList = false; - if (!_upToDate) { - _topPaginationActive = false; - _bottomPaginationActive = true; - return _paginateData( + final message = messages[i]; + 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(), + ) + : DateDivider( + dateTime: nextMessage.createdAt.toLocal(), + ); + return Padding( + padding: const EdgeInsets.symmetric(vertical: 12.0), + child: divider, + ); + } + 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; + final isDeleted = message.isDeleted; + if (timeDiff >= 1 || + !isNextUserSame || + isThread || + isDeleted) { + return SizedBox(height: 8); + } + return SizedBox(height: 2); + }, + itemBuilder: (context, i) { + if (i == messages.length + 2) { + if (widget.parentMessageBuilder != null) { + return widget.parentMessageBuilder( + context, + widget.parentMessage, + ); + } else { + return buildParentMessage(widget.parentMessage); + } + } + if (i == messages.length + 1) { + return _buildLoadingIndicator( + streamChannel, + QueryDirection.top, + ); + } + if (i == 0) { + return _buildLoadingIndicator( streamChannel, QueryDirection.bottom, ); } - }, - onEndOfPage: () async { - _inBetweenList = false; - _topPaginationActive = true; - _bottomPaginationActive = false; - return _paginateData( - streamChannel, - QueryDirection.top, - ); - }, - onInBetweenOfPage: () { - _inBetweenList = true; - }, - child: ScrollablePositionedList.separated( - key: ValueKey(initialIndex + initialAlignment), - itemPositionsListener: _itemPositionListener, - addAutomaticKeepAlives: true, - initialScrollIndex: initialIndex ?? 0, - initialAlignment: initialAlignment ?? 0, - physics: widget.scrollPhysics, - itemScrollController: _scrollController, - reverse: true, - itemCount: - messages.length + 2 + (_isThreadConversation ? 1 : 0), - separatorBuilder: (context, i) { - if (i == messages.length) return Offstage(); - if (i == 0) return SizedBox(height: 30); - if (i == messages.length + 1) { - final replyCount = widget.parentMessage.replyCount; - return Container( - decoration: BoxDecoration( - gradient: StreamChatTheme.of(context) - .colorTheme - .bgGradient, - ), - child: Padding( - padding: const EdgeInsets.all(8.0), - child: Text( - '$replyCount ${replyCount == 1 ? 'Reply' : 'Replies'}', - textAlign: TextAlign.center, - style: StreamChatTheme.of(context) - .channelTheme - .channelHeaderTheme - .lastMessageAt, - ), - ), - ); - } + final message = messages[i - 1]; - final message = messages[i]; - 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(), - ) - : DateDivider( - dateTime: nextMessage.createdAt.toLocal(), - ); - return Padding( - padding: const EdgeInsets.symmetric(vertical: 12.0), - child: divider, - ); - } - final timeDiff = - Jiffy(nextMessage.createdAt.toLocal()).diff( - message.createdAt.toLocal(), - Units.MINUTE, + Widget messageWidget; + + if (i == 1) { + messageWidget = _buildBottomMessage( + context, + message, + messages, + streamChannel, ); - - final isNextUserSame = - message.user.id == nextMessage.user?.id; - final isThread = message.replyCount > 0; - final isDeleted = message.isDeleted; - if (timeDiff >= 1 || - !isNextUserSame || - isThread || - isDeleted) { - return SizedBox(height: 8); - } - return SizedBox(height: 2); - }, - itemBuilder: (context, i) { - if (i == messages.length + 2) { - if (widget.parentMessageBuilder != null) { - return widget.parentMessageBuilder( - context, - widget.parentMessage, - ); - } else { - return buildParentMessage(widget.parentMessage); - } - } - if (i == messages.length + 1) { - return _buildLoadingIndicator( - streamChannel, - QueryDirection.top, - ); - } - if (i == 0) { - return _buildLoadingIndicator( - streamChannel, - QueryDirection.bottom, - ); - } - final message = messages[i - 1]; - - Widget messageWidget; - - if (i == 1) { - messageWidget = _buildBottomMessage( - context, - message, - messages, - streamChannel, - ); - } else if (i == messages.length - 1) { - messageWidget = _buildTopMessage( - context, - message, - messages, - streamChannel, + } else if (i == messages.length - 1) { + messageWidget = _buildTopMessage( + context, + message, + messages, + streamChannel, + ); + } else { + if (widget.messageBuilder != null) { + messageWidget = Builder( + key: ValueKey('MESSAGE-${message.id}'), + builder: (context) => widget.messageBuilder( + context, + MessageDetails( + context, + message, + messages, + i, + ), + messages), ); } else { - if (widget.messageBuilder != null) { - messageWidget = Builder( - key: ValueKey('MESSAGE-${message.id}'), - builder: (context) => widget.messageBuilder( - context, - MessageDetails( - context, - message, - messages, - i, - ), - messages), - ); - } else { - messageWidget = buildMessage(message, messages, i); - } + messageWidget = buildMessage(message, messages, i); } - return messageWidget; - }, - ), + } + return messageWidget; + }, ), - ); - }), + ), + ); + }, + ), if (widget.showScrollToBottom) _buildScrollToBottom(), Positioned( top: 20.0, diff --git a/packages/flutter_widgets/lib/stream_chat_flutter.dart b/packages/flutter_widgets/lib/stream_chat_flutter.dart index 3f52c8c6..fa296075 100644 --- a/packages/flutter_widgets/lib/stream_chat_flutter.dart +++ b/packages/flutter_widgets/lib/stream_chat_flutter.dart @@ -40,4 +40,5 @@ export 'src/channel_file_display_screen.dart'; export 'src/channel_media_display_screen.dart'; export 'src/info_tile.dart'; export 'src/stream_chat.dart'; +export 'src/connection_status_builder.dart'; export 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; diff --git a/packages/flutter_widgets/pubspec.yaml b/packages/flutter_widgets/pubspec.yaml index 93e84f07..9321f992 100644 --- a/packages/flutter_widgets/pubspec.yaml +++ b/packages/flutter_widgets/pubspec.yaml @@ -32,8 +32,6 @@ dependencies: image_picker: ^0.6.7+17 flutter_keyboard_visibility: ^4.0.2 mime: ^0.9.7 - stream_chat: - path: ../dart_client video_compress: ^2.1.1 visibility_detector: ^0.1.5 http_parser: ^3.1.4 diff --git a/packages/stream_chat_flutter_core/pubspec.yaml b/packages/stream_chat_flutter_core/pubspec.yaml index 19dd8eb0..61c3528e 100644 --- a/packages/stream_chat_flutter_core/pubspec.yaml +++ b/packages/stream_chat_flutter_core/pubspec.yaml @@ -10,8 +10,8 @@ environment: flutter: ">=1.17.0" dependencies: - stream_chat: ^0.2.23+3 - rxdart: ^0.24.1 + stream_chat: + path: ../dart_client flutter: sdk: flutter From e6241aca39787f0cbe306f06658d1c57d2a75d65 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Fri, 29 Jan 2021 09:30:22 +0100 Subject: [PATCH 1080/1140] fix recconection bug while using tokenprovider --- packages/dart_client/lib/src/client.dart | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/dart_client/lib/src/client.dart b/packages/dart_client/lib/src/client.dart index 09ea4232..5f534864 100644 --- a/packages/dart_client/lib/src/client.dart +++ b/packages/dart_client/lib/src/client.dart @@ -278,8 +278,6 @@ class Client { httpClient.lock(); final userId = state.user.id; - _ws.connectionStatus.removeListener(_connectionStatusListener); - await _disconnect(); final newToken = await tokenProvider(userId); From 89a901f335c8df2d9e3cfed0c77ec982989490b0 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Fri, 29 Jan 2021 09:52:55 +0100 Subject: [PATCH 1081/1140] bump version --- packages/dart_client/CHANGELOG.md | 4 ++++ packages/dart_client/lib/version.dart | 2 +- packages/dart_client/pubspec.yaml | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/packages/dart_client/CHANGELOG.md b/packages/dart_client/CHANGELOG.md index 4019cf06..fdaee098 100644 --- a/packages/dart_client/CHANGELOG.md +++ b/packages/dart_client/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.2.24+2 + +- Fix reconnection bug while using tokenProvider + ## 0.2.24+1 - Stop ws reconnection after calling disconnect diff --git a/packages/dart_client/lib/version.dart b/packages/dart_client/lib/version.dart index cf6b0a93..1d13b723 100644 --- a/packages/dart_client/lib/version.dart +++ b/packages/dart_client/lib/version.dart @@ -2,4 +2,4 @@ import 'package:stream_chat/src/client.dart'; /// Current package version /// Used in [Client] to build the `x-stream-client` header -const PACKAGE_VERSION = '0.2.24+1'; +const PACKAGE_VERSION = '0.2.24+2'; diff --git a/packages/dart_client/pubspec.yaml b/packages/dart_client/pubspec.yaml index f9c22db0..55a1f5ec 100644 --- a/packages/dart_client/pubspec.yaml +++ b/packages/dart_client/pubspec.yaml @@ -1,7 +1,7 @@ name: stream_chat homepage: https://getstream.io/ description: The official Dart client for Stream Chat, a service for building chat applications. -version: 0.2.24+1 +version: 0.2.24+2 repository: https://github.com/GetStream/stream-chat-dart issue_tracker: https://github.com/GetStream/stream-chat-dart/issues From 4b9a7d68372d272e52e117c306f9631e5e97d818 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Fri, 29 Jan 2021 15:22:19 +0530 Subject: [PATCH 1082/1140] [Core -> LazyLoadScrollView] Remove `isLoading` property Signed-off-by: Sahil Kumar --- .../lib/src/lazy_load_scroll_view.dart | 4 ---- 1 file changed, 4 deletions(-) diff --git a/packages/stream_chat_flutter_core/lib/src/lazy_load_scroll_view.dart b/packages/stream_chat_flutter_core/lib/src/lazy_load_scroll_view.dart index bc1f4d1b..d74c1d98 100644 --- a/packages/stream_chat_flutter_core/lib/src/lazy_load_scroll_view.dart +++ b/packages/stream_chat_flutter_core/lib/src/lazy_load_scroll_view.dart @@ -27,9 +27,6 @@ class LazyLoadScrollView extends StatefulWidget { /// The offset to take into account when triggering [onEndOfPage]/[onStartOfPage] in pixels final double scrollOffset; - /// Used to determine if loading of new data has finished. You should use set this if you aren't using a FutureBuilder or StreamBuilder - final bool isLoading; - /// Initiates a LazyLoadScrollView widget const LazyLoadScrollView({ Key key, @@ -39,7 +36,6 @@ class LazyLoadScrollView extends StatefulWidget { this.onPageScrollStart, this.onPageScrollEnd, this.onInBetweenOfPage, - this.isLoading = false, this.scrollOffset = 100, }) : assert(child != null), super(key: key); From 5310287fdd2d29943af152b0c7c6585fde044c5f Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Fri, 29 Jan 2021 17:23:00 +0530 Subject: [PATCH 1083/1140] Transfer `showLocalNotification`, `backgroundKeepAlive` from LLC to Core Signed-off-by: Sahil Kumar --- packages/dart_client/lib/src/client.dart | 10 --- .../example/lib/advanced_options_page.dart | 3 - .../flutter_widgets/example/lib/main.dart | 3 +- .../example/lib/notifications_service.dart | 46 ++++++------- .../flutter_widgets/lib/src/stream_chat.dart | 14 +++- .../lib/src/stream_chat_core.dart | 66 +++++++------------ .../test/stream_chat_core_test.dart | 28 +++----- 7 files changed, 72 insertions(+), 98 deletions(-) diff --git a/packages/dart_client/lib/src/client.dart b/packages/dart_client/lib/src/client.dart index 988f0f8f..381d1cd6 100644 --- a/packages/dart_client/lib/src/client.dart +++ b/packages/dart_client/lib/src/client.dart @@ -79,8 +79,6 @@ class Client { Duration connectTimeout = const Duration(seconds: 6), Duration receiveTimeout = const Duration(seconds: 6), Dio httpClient, - this.showLocalNotification, - this.backgroundKeepAlive = const Duration(minutes: 1), RetryPolicy retryPolicy, }) { _retryPolicy ??= RetryPolicy( @@ -110,14 +108,6 @@ class Client { /// The retry policy options getter RetryPolicy get retryPolicy => _retryPolicy; - /// Method used to show a local notification while the app is in background - /// Switching to another application will not disconnect the client immediately - /// So, use this method to show the notification when receiving a new message via events - final void Function(Message, ChannelModel) showLocalNotification; - - /// The amount of time that will pass before disconnecting the client in the background - final Duration backgroundKeepAlive; - /// This client state ClientState state; diff --git a/packages/flutter_widgets/example/lib/advanced_options_page.dart b/packages/flutter_widgets/example/lib/advanced_options_page.dart index 25cbf51c..0b55212c 100644 --- a/packages/flutter_widgets/example/lib/advanced_options_page.dart +++ b/packages/flutter_widgets/example/lib/advanced_options_page.dart @@ -277,9 +277,6 @@ class _AdvancedOptionsPageState extends State { final client = Client( apiKey, logLevel: Level.INFO, - showLocalNotification: (!kIsWeb && Platform.isAndroid) - ? showLocalNotification - : null, )..chatPersistenceClient = chatPersistentClient; try { diff --git a/packages/flutter_widgets/example/lib/main.dart b/packages/flutter_widgets/example/lib/main.dart index caa11198..a44a8692 100644 --- a/packages/flutter_widgets/example/lib/main.dart +++ b/packages/flutter_widgets/example/lib/main.dart @@ -33,8 +33,6 @@ void main() async { final client = Client( apiKey ?? kDefaultStreamApiKey, logLevel: Level.INFO, - showLocalNotification: - (!kIsWeb && Platform.isAndroid) ? showLocalNotification : null, )..chatPersistenceClient = chatPersistentClient; if (userId != null) { @@ -73,6 +71,7 @@ class MyApp extends StatelessWidget { builder: (context, child) { return StreamChat( client: client, + onBackgroundEventReceived: showLocalNotification, child: Builder( builder: (context) => AnnotatedRegion( child: child, diff --git a/packages/flutter_widgets/example/lib/notifications_service.dart b/packages/flutter_widgets/example/lib/notifications_service.dart index 0eeb9cc0..e74a2a5a 100644 --- a/packages/flutter_widgets/example/lib/notifications_service.dart +++ b/packages/flutter_widgets/example/lib/notifications_service.dart @@ -1,12 +1,14 @@ import 'dart:io'; import 'package:example/main.dart'; +import 'package:firebase_messaging/firebase_messaging.dart'; import 'package:flutter_apns/flutter_apns.dart'; import 'package:flutter_local_notifications/flutter_local_notifications.dart' hide Message; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; -void showLocalNotification(Message message, ChannelModel channel) async { +void showLocalNotification(Event event) async { + if (event.message == null) return; final flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin(); final initializationSettingsAndroid = AndroidInitializationSettings('launch_background'); @@ -17,9 +19,9 @@ void showLocalNotification(Message message, ChannelModel channel) async { ); await flutterLocalNotificationsPlugin.initialize(initializationSettings); await flutterLocalNotificationsPlugin.show( - message.id.hashCode, - '${message.user.name} @ ${channel.name}', - message.text, + event.message.id.hashCode, + event.message.user.name, + event.message.text, NotificationDetails( android: AndroidNotificationDetails( 'message channel', @@ -35,24 +37,24 @@ void showLocalNotification(Message message, ChannelModel channel) async { Future backgroundHandler(Map notification) async { print('new notification ${notification}'); - final messageId = notification['data']['id']; - - final notificationData = await NotificationService.getAndStoreMessage( - messageId: messageId, - storeMessageHandler: (messageResponse) { - return chatPersistentClient.updateChannelState( - ChannelState( - messages: [messageResponse.message], - channel: messageResponse.channel, - ), - ); - }, - ); - - showLocalNotification( - notificationData.message, - notificationData.channel, - ); + // final messageId = notification['data']['id']; + // + // final notificationData = await NotificationService.getAndStoreMessage( + // messageId: messageId, + // storeMessageHandler: (messageResponse) { + // return chatPersistentClient.updateChannelState( + // ChannelState( + // messages: [messageResponse.message], + // channel: messageResponse.channel, + // ), + // ); + // }, + // ); + // + // showLocalNotification( + // notificationData.message, + // notificationData.channel, + // ); } void initNotifications(Client client) { diff --git a/packages/flutter_widgets/lib/src/stream_chat.dart b/packages/flutter_widgets/lib/src/stream_chat.dart index 37a163ec..0ea5efb2 100644 --- a/packages/flutter_widgets/lib/src/stream_chat.dart +++ b/packages/flutter_widgets/lib/src/stream_chat.dart @@ -34,11 +34,21 @@ class StreamChat extends StatefulWidget { final Widget child; final StreamChatThemeData streamChatThemeData; + /// The amount of time that will pass before disconnecting the client in the background + final Duration backgroundKeepAlive; + + /// Handler called whenever the [client] receives a new [Event] while the app + /// is in background. Can be used to display various notifications depending + /// upon the [Event.type] + final EventHandler onBackgroundEventReceived; + StreamChat({ Key key, @required this.client, @required this.child, this.streamChatThemeData, + this.onBackgroundEventReceived, + this.backgroundKeepAlive = const Duration(minutes: 1), }) : super( key: key, ); @@ -82,8 +92,10 @@ class StreamChatState extends State { scaffoldBackgroundColor: streamTheme.colorTheme.white, ), child: StreamChatCore( - child: widget.child, client: client, + child: widget.child, + onBackgroundEventReceived: widget.onBackgroundEventReceived, + backgroundKeepAlive: widget.backgroundKeepAlive, ), ); }, diff --git a/packages/stream_chat_flutter_core/lib/src/stream_chat_core.dart b/packages/stream_chat_flutter_core/lib/src/stream_chat_core.dart index 73f5eb61..1d2d4736 100644 --- a/packages/stream_chat_flutter_core/lib/src/stream_chat_core.dart +++ b/packages/stream_chat_flutter_core/lib/src/stream_chat_core.dart @@ -4,6 +4,8 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:stream_chat/stream_chat.dart'; +typedef EventHandler = void Function(Event event); + /// Widget used to provide information about the chat to the widget tree /// /// class MyApp extends StatelessWidget { @@ -28,17 +30,26 @@ import 'package:stream_chat/stream_chat.dart'; class StreamChatCore extends StatefulWidget { // ignore: public_member_api_docs final Client client; + // ignore: public_member_api_docs final Widget child; + /// The amount of time that will pass before disconnecting the client in the background + final Duration backgroundKeepAlive; + + /// Handler called whenever the [client] receives a new [Event] while the app + /// is in background. Can be used to display various notifications depending + /// upon the [Event.type] + final EventHandler onBackgroundEventReceived; + // ignore: public_member_api_docs StreamChatCore({ Key key, @required this.client, @required this.child, - }) : super( - key: key, - ); + this.onBackgroundEventReceived, + this.backgroundKeepAlive = const Duration(minutes: 1), + }) : super(key: key); @override StreamChatCoreState createState() => StreamChatCoreState(); @@ -82,56 +93,28 @@ class StreamChatCoreState extends State WidgetsBinding.instance.addObserver(this); } - StreamSubscription _newMessageSubscription; + StreamSubscription _eventSubscription; @override void didChangeAppLifecycleState(AppLifecycleState state) { if (client.state?.user != null) { if (state == AppLifecycleState.paused) { - if (client.showLocalNotification != null) { - _newMessageSubscription = client - .on(EventType.messageNew) - .where((e) => e.user?.id != user.id) - .where((e) => e.message.silent != true) - .where((e) => e.message.shadowed != true) - .listen((event) async { - final channel = client.channel( - event.channelType, - id: event.channelId, - ); - - client.showLocalNotification( - event.message, - ChannelModel( - id: channel.id, - createdAt: channel.createdAt, - extraData: channel.extraData, - type: channel.type, - memberCount: channel.memberCount, - frozen: channel.frozen, - cid: channel.cid, - deletedAt: channel.deletedAt, - config: channel.config, - createdBy: channel.createdBy, - updatedAt: channel.updatedAt, - lastMessageAt: channel.lastMessageAt, - ), - ); - }); - _disconnectTimer = Timer(client.backgroundKeepAlive, () { - client.disconnect(); - }); + if (widget.onBackgroundEventReceived != null) { + _eventSubscription = + client.on().listen(widget.onBackgroundEventReceived); + _disconnectTimer = Timer( + widget.backgroundKeepAlive, + client.disconnect, + ); } else { client.disconnect(); } } else if (state == AppLifecycleState.resumed) { - _newMessageSubscription?.cancel(); + _eventSubscription?.cancel(); if (_disconnectTimer?.isActive == true) { _disconnectTimer.cancel(); } else { - if (client.wsConnectionStatus.value == - ConnectionStatus.disconnected) { - NotificationService.handleIosMessageQueue(client); + if (client.wsConnectionStatus == ConnectionStatus.disconnected) { client.connect(); } } @@ -142,6 +125,7 @@ class StreamChatCoreState extends State @override void dispose() { WidgetsBinding.instance.removeObserver(this); + _eventSubscription?.cancel(); _disconnectTimer?.cancel(); super.dispose(); } diff --git a/packages/stream_chat_flutter_core/test/stream_chat_core_test.dart b/packages/stream_chat_flutter_core/test/stream_chat_core_test.dart index 714375de..a8d7e227 100644 --- a/packages/stream_chat_flutter_core/test/stream_chat_core_test.dart +++ b/packages/stream_chat_flutter_core/test/stream_chat_core_test.dart @@ -9,7 +9,7 @@ import 'package:mockito/mockito.dart'; import 'mocks.dart'; class MockShowLocalNotifications extends Mock { - void call(Message m, ChannelModel cm); + void call(Event event); } void main() { @@ -97,14 +97,8 @@ void main() { ), ); final showLocalNotificationMock = MockShowLocalNotifications().call; - when(client.showLocalNotification) - .thenReturn(showLocalNotificationMock); - when(client.backgroundKeepAlive).thenReturn(Duration( - seconds: 4, - )); final eventStreamController = StreamController(); - when(client.on(EventType.messageNew)) - .thenAnswer((_) => eventStreamController.stream); + when(client.on()).thenAnswer((_) => eventStreamController.stream); when(client.channel('test', id: 'testid')).thenReturn(channel); @@ -113,6 +107,8 @@ void main() { StreamChatCore( key: scKey, client: client, + onBackgroundEventReceived: showLocalNotificationMock, + backgroundKeepAlive: const Duration(seconds: 4), child: Builder( builder: (context) { return Container(); @@ -144,13 +140,8 @@ void main() { ), ); final showLocalNotificationMock = MockShowLocalNotifications().call; - when(client.showLocalNotification).thenReturn(showLocalNotificationMock); - when(client.backgroundKeepAlive).thenReturn(Duration( - seconds: 4, - )); final eventStreamController = StreamController(); - when(client.on(EventType.messageNew)) - .thenAnswer((_) => eventStreamController.stream); + when(client.on()).thenAnswer((_) => eventStreamController.stream); when(client.channel('test', id: 'testid')).thenReturn(channel); @@ -159,6 +150,8 @@ void main() { StreamChatCore( key: scKey, client: client, + onBackgroundEventReceived: showLocalNotificationMock, + backgroundKeepAlive: const Duration(seconds: 4), child: Builder( builder: (context) { return Container(); @@ -178,12 +171,9 @@ void main() { ); eventStreamController.add(event); - await untilCalled(showLocalNotificationMock(any, any)); + await untilCalled(showLocalNotificationMock(event)); - verify(showLocalNotificationMock( - event.message, - any, - )).called(1); + verify(showLocalNotificationMock(event)).called(1); }, ); } From 0013cb98fd6a5a1607f78f25fd8588f2135d4267 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Fri, 29 Jan 2021 17:31:43 +0530 Subject: [PATCH 1084/1140] Ran formatter Signed-off-by: Sahil Kumar --- .../stream_chat_persistence/lib/src/mapper/reaction_mapper.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/stream_chat_persistence/lib/src/mapper/reaction_mapper.dart b/packages/stream_chat_persistence/lib/src/mapper/reaction_mapper.dart index 407816be..8f9b99e7 100644 --- a/packages/stream_chat_persistence/lib/src/mapper/reaction_mapper.dart +++ b/packages/stream_chat_persistence/lib/src/mapper/reaction_mapper.dart @@ -19,7 +19,7 @@ extension ReactionEntityX on ReactionEntity { /// Useful mapping functions for [Reaction] extension ReactionX on Reaction { - ReactionEntity toEntity() { + ReactionEntity toEntity() { return ReactionEntity( extraData: extraData, type: type, From 1c54b3f36ffcd006bf61d267f34fbcf6a6a0bd08 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Fri, 29 Jan 2021 17:32:29 +0530 Subject: [PATCH 1085/1140] [Persistence] Doc Signed-off-by: Sahil Kumar --- .../stream_chat_persistence/lib/src/mapper/reaction_mapper.dart | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/stream_chat_persistence/lib/src/mapper/reaction_mapper.dart b/packages/stream_chat_persistence/lib/src/mapper/reaction_mapper.dart index 8f9b99e7..d265fcb7 100644 --- a/packages/stream_chat_persistence/lib/src/mapper/reaction_mapper.dart +++ b/packages/stream_chat_persistence/lib/src/mapper/reaction_mapper.dart @@ -19,6 +19,7 @@ extension ReactionEntityX on ReactionEntity { /// Useful mapping functions for [Reaction] extension ReactionX on Reaction { + /// Maps a [Reaction] into [ReactionEntity] ReactionEntity toEntity() { return ReactionEntity( extraData: extraData, From 5954dfa2b222dbd9d4770ef0a11eff36a3ab77cc Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Fri, 29 Jan 2021 17:38:11 +0530 Subject: [PATCH 1086/1140] [Persistence] Analyzer warning Signed-off-by: Sahil Kumar --- .../lib/src/stream_chat_persistence_client.dart | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/packages/stream_chat_persistence/lib/src/stream_chat_persistence_client.dart b/packages/stream_chat_persistence/lib/src/stream_chat_persistence_client.dart index 49a59423..d36ed1b2 100644 --- a/packages/stream_chat_persistence/lib/src/stream_chat_persistence_client.dart +++ b/packages/stream_chat_persistence/lib/src/stream_chat_persistence_client.dart @@ -28,19 +28,6 @@ class StreamChatPersistenceClient extends ChatPersistenceClient { final Logger _logger; final ConnectionMode _connectionMode; - bool get _debugAssertConnected { - assert(() { - if (_db == null) { - throw Exception( - 'A $runtimeType was used after being disconnected.\n' - 'Once you have called disconnect() on a $runtimeType, it can no longer be used.', - ); - } - return true; - }()); - return true; - } - @override Future connect(String userId) async { if (_db != null) { From 5ce0bd50b2c6e4c9d88565662f189c67e1d725a6 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Fri, 29 Jan 2021 18:11:28 +0530 Subject: [PATCH 1087/1140] feat: Added new screenshots --- .../screenshots/channel_header.png | Bin 20184 -> 40991 bytes .../screenshots/channel_header_paint.png | Bin 23665 -> 50024 bytes .../screenshots/channel_list_view.png | Bin 214440 -> 284581 bytes .../screenshots/channel_list_view_paint.png | Bin 301565 -> 398294 bytes .../screenshots/channel_preview.png | Bin 26812 -> 38717 bytes .../screenshots/channel_preview_paint.png | Bin 29952 -> 50487 bytes .../screenshots/message_input.png | Bin 13408 -> 20441 bytes .../screenshots/message_input2.png | Bin 13157 -> 17480 bytes .../screenshots/message_input2_paint.png | Bin 15998 -> 25576 bytes .../screenshots/message_input_paint.png | Bin 15156 -> 32207 bytes .../screenshots/message_listview.png | Bin 230154 -> 652108 bytes .../screenshots/message_listview_paint.png | Bin 344947 -> 607204 bytes .../screenshots/message_widget.png | Bin 67903 -> 347568 bytes .../screenshots/message_widget_paint.png | Bin 65445 -> 320357 bytes .../screenshots/reaction_picker.png | Bin 46037 -> 36147 bytes .../screenshots/reaction_picker_paint.png | Bin 49343 -> 48701 bytes .../screenshots/thread_header.png | Bin 8500 -> 18964 bytes .../screenshots/thread_header_paint.png | Bin 10616 -> 26620 bytes 18 files changed, 0 insertions(+), 0 deletions(-) diff --git a/packages/flutter_widgets/screenshots/channel_header.png b/packages/flutter_widgets/screenshots/channel_header.png index 41b2b77a776c00f23782e0bea44fb33c4f208b0c..c0a2e29f460d978b2026ad28349ab15b4e29c0e8 100644 GIT binary patch literal 40991 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 literal 20184 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

C^L-J@ZPP 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

K0| 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œz&}?~UJYeRfDq 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 literal 214440 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 z�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 z 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%0Dj}2{Nfp~SGqVx3Q}hM4 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

    g|BiSO-GY65$M2 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

    6dgtn{98W46F-U+*_3T$ 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

    6O=& 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 literal 301565 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

    ^=N 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 diff --git a/packages/flutter_widgets/screenshots/channel_preview.png b/packages/flutter_widgets/screenshots/channel_preview.png index 0405838751ce82c1686c4d79cc2dbee58677be3d..c98d4c08b4695aab6709e464b5d70ee387885538 100644 GIT binary patch literal 38717 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 EFX)U?<^TWy diff --git a/packages/flutter_widgets/screenshots/channel_preview_paint.png b/packages/flutter_widgets/screenshots/channel_preview_paint.png index c2f822a311088e4e52a4d2c0c66d8c0066dff65e..eda9f14f4e5d084ee29a2107f27ed18ba6350340 100644 GIT binary patch literal 50487 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 z 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 diff --git a/packages/flutter_widgets/screenshots/message_input.png b/packages/flutter_widgets/screenshots/message_input.png index 9dab6cce6c5be9ae872b889982b9234bd2f4998d..00331e5ec02dc78127327c0c9536fff989163c39 100644 GIT binary patch literal 20441 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%0A6kDwm;?q@ziAU6jH^3?xj;Y zU4Xg97TsV)c46MaZG1d#J~xkaHgDx?!?d}~Qmspo$aHcT!On0T$6f5D05W?n6v|WYM2Y^Xcv#092 zeq*TViAo5&y~2{NmMDrB?Hx93Wp=H#q)+s_C*xt^KH-^)If(cB1$X3hNOuQ$foRBh z%qWaAQslTq1r+-kg#5?fiuzukE-qkKR*;ewc1AA(KeCTJlplKpY=!JtXUr9hoB+J zkoo`4kM=$v_BeU{eMaSD4fA?2@6O?Y+!8AS3hn%~V)aE^(fzO>!ZuEn;NioEzpw%z zK{SRjXJgnV;K|JSaIcSBJ?_Zcy0|UGh5<>%Oqr`i7@JYDi%E7rAyp|c6&5Zukms|X z5fquQofB-5G8j;*?VAx^AU?1G2zSooamq!0u+7$#!xhANTl3mLb?UqfXE~L9#TDVO zZrhG#SPi2O;K9GBRMWmbAv8LR_a>{P>tR#quSC6p3goLqU1KU9qy&yByN@pW->r4r zl&@Gjij9wt3nPc38*(S37D?YtyrJC{(&c*h?G)tZ`kuEjZ^IXLx-0#Cm@P2~=#|g2 zAFJ&2x|~WAswGAH^Y>~yuYJg&;UwT_TR&;_Q!d*3FSwxaAq#%}F-WVw@%f}`YJL4Y zLlQ*nxn!~x1dRqlie$klY6o)}e!rV}Eysd*aZ*5FFDzbY*X^<$`N_|q;ql0u^0Hhc zk!O&^w4Its-FB|q1YdV;(V-a5W4*tEueIUqDbM>tpIS>%{3VJnS~Z4eC)5*y*JD5w zsXEY4mY&eEynyAZcPJ<|?Z+Ry20wV7f-8=p-w(W={%YtS#4}nw5v=EV?MD|mZNSz> zQ5Jdm?fiT>d|(it@wJEN#i65rzfbb|BI}!s@xkRZ+22IoMF-UUGIqGLtgEHPvq{VMFD6y6>C+>T*Uk-SdlX1 zeFpV=0f$ce6j-|Oh3`QUUdVk0h$lWy&>_Ww+Lv%=Y^^=RL0tbnepr>B5 zvtf%yfgQ8JE43eOW6l?*0$W?A*$b+9RV_ZAf13^8U*Y-KY@cpdQknI43Y8e!tn&Pu zFIf8zT^_FX&IthwsN!sJACNSCn=@nk$apfT;(00Oi)zzf`|k1r9!CwtoQvM$&TKy^ zFK>?9BU%h8aV)LK&>DP_{mIm_`bA4imcyp&Zr#^^A*ctD@q@{fR(e1w3783~O;Wvj z@ND?Gtz(^;`h#b6-s-sbS3-qW4jA7!;3my_UbjMTM)qE{d&L2*i9|8`Fl|$=o3HvU z=Bb|FQ{l~E&t`N=dmT**!2OhBX^vIW1)Po<=B#)a5PmzeH*0^3u?w7_Ie*Poadm48 zd{I^?j~Kj~O$|R2@zfF?oS63llfw}OMoaR*l(dnit-wMSv2mzWXM>|XE3`DbCE-lF zmf+|9%)O(eYG)t1sH)9g|p>L}!vJ)$Ka$P7Dv+9(K zB*}X@fYo2#sy)(;$g0uvd!2 zo!^X7;7`kAg!X#0^&i1TzOgf+Gy3e;*+rMhySeb+TqTUUdxVXE5Q0MqwjtC~8Bvvo zI|FN!=|ty(f=ZExT{EvdFZjbiU@+D7DRglgReSHU*ZZ$pmEA{akN04gNu!Wiy&M$f5>0Dr1rT$xkE z70#87I#5P(%kH%op6uRzgMgb}@U?ZPU6R7bl>FxLq^9GWrP`^>bGL!uH2J#6q5-p` z%MJhF@#>cn1^+wh37P<0f*rjC1mCMsx)&aN1Ftm?ll`#_lMuw6VTY|V720jg^t!Dg z$mm5AigU1Wv_XT<2RGgAeQBD2-kTb`l zcaeO1T5!bR5$DW+pNaLwv53N_={CxAw_+*0k>^>MlwVYo-0vSA zpT6-8ABG=;pMw8F8?roI`=eHs?%uGout3-*-FjBJr-%>6TT!wkXBU{@rCQ?MncrXe z!{eMQXdlWFX(~Bp_M#zRdlrcSjYqrpGws?XNjKQCLTUuJQ86F3V_4c@@zun;qLBSC zhUO}qx*vwT!rJDZH||#5CaX^=WG`BG(C|PA>V|V-$262V;UNHOQwANGsJCz;M`y^% zyPD1`d1Ec&0at8;$brL-N%F5!HAzgSWL`v)OfznD4V)NsrkDzRF3x$Z*P^dTVWwJe z(SE?-s~B2l&V@$5>L(%$>!|7%ynAYyOpkuXn zHoAJHr{Fz}tM~@?78o3rk^;l+G`LgP_T<{5LY|o6EETjRBnd}&ETr4z;4P%PGuHB} zH{(az5bpcd5?h5Y2c9xdlH&29r_=0 zIlX^}A)L(&AYye@ovY{%^v7~?e6>L)IC-)afc0DO+a#L(+Wlo#BH}k#pmq#$>Q)3z zpfR}Dx`+P}N?IlP99>t@3=*_imv*YaNJD=65A={OLDmxFA2srmhc@`pB#~z05#;*2 zFGk%5rA=Vsf|V|Y#Xeo7%Lhsyf{`nVepApg@^2!;x|RsRffbB{^>MPcMtC~!s6keJm3~$w>%am<3Wwrs zBiOyEH*8|zo$%m)dx!B;ZOlw*Xr2*?6^>rJ!o_BjF!FO{1?Lmx+dh59H36&dy<20(&32jf1& z+9WaCY0nRBw2AMDR_h88hL2xv1)QGjB_^&|XLA*tgHws_utN~wu$+x7Z_FxQlu69O z*%y$nQ1PymyGpBB?ZrnNd$IujIv8b zUs=26%o{TF&CE11XBH|NjeQ3C;s>Kex27+rk4zB@ISMck-M?wCCkMljY29Aal0t1q zD5u50kJF&b9dUd$Th4{oHj!dN**#&kq*1TE@MU*E;m4qL-%njK;`TW^7oJsBqjSy^ z6|8ep^kWwNZBv$8H$|WoX%VTJbwf_=zyBV6VAT>!K$|Ek;@VUe$-8?8f7Juu95?(N z#_y_C-LpVUdut~_JDbbyE3$0sa1g=)r1coP^Tw2F?XdrQO@vUgyHyp-t+H-Rk*9S! zXrBO3FT8;)N4_~Nz%J$87pUAFf_&$^VFGl?Q?Q)zn~DcY?owi4g4D>r^r#3w6#ra9 zYr%kfnnsEjwOW8F7zakNue&7(U0ZJ7$9aZvhuCo}<#E|H@9}xVyKng4`Q+^TEtxdM z_cA;AIH9zDO~j2waSq0V7QTHv2p|`#?X?nui+7yyR)O=fTm zw_WL>px8Ut6jhmr2j80+?1(X;3;#|`L#~Wxy9}tWQ)mVV)|gyr|;1@9CA$fat zn+D0gnC8Ged$L`ULLcptZU+?P6rOIuGl2D9!0&g)oAHpLp5Iu|sZQTpO(za>JrY@` zS-bg^q4zt_X<;T<4n*Ria=s|(wM``WTYl=8Qazj$dFxb3)+k3XA8UCf5}^=$(l4u! z2$hzRvx+N83EJG0E4lxEl>v0hRvFe-f}D;D>KDh=p`KNdi5*N=79psu-a1GK?#JZefyq4#5NG`Tj?9}yWskNF^3UA% zP-KJ!KRC@@x0=Uv}+MRvewPuG3u(q5+@3zgXe@}F+f1isDiu~yL@*d2C z2N;dG|@P2uzFzvE17>FcXWN%26Rk1W>dEf>JZ>XrLd=)}S3_8;S5? zSqZ0>W@&{$KxpRrQ8H-u)rZY=b4-C0YO1S<6I@3zVwD_|ppl#819sIdqbvQHMUJOz zFY|#(2(SW2^0oC25rsRi8L$S|pv&ggSE-@y{UmlvX2-n00uk0LS`Z{N$3Y}TG~na{ zUu(V`1>fAbBDfjr8RcpYEC5F;z%jH&feIq6Clq3b4-OyOp#15=lUzgTH*I)qtS~P- zO|w>3?2J$I1L^IDKNG3&CCD7;Ug)j~gS4{`5w;tVzf$=LxRB+$0nxFLSpX9$5oc5H zhlBH}`c30DZ~zwvzf#^tZ{=4~qUdTP-VRlFJi`XjsGN3&w$PtyVDSyL=`j(L7CNhnJ`?wh!1;qHm{6+u(%8SRR88o|(R%tivisLYxKa3Cjc;o+zBER( ztbevk3mWc%^OCp<>6pIRUzQ9&f({Y2bWYDH9GBJItoz2{CiSwd?|Jpz%5yMY0SBEV;g5*!f`O9<&XO8C7Z`ky0W-DjBBrwhn%oT2Si-?afNOCJi;H432vbG^`_Mt1H*WYOMb50x(?VEi{Ib( zYy^<*-n+xS16Zn#Zl(`mxe!8Mz7wIWuYn>}u6!SfyNmBt5CnE8uXrtGHfjJjEcRNb zt(FUeWIAVPH%%qzQ_+!=2^1yOlmpuETyQ8hc5x<(9BPMkk>F5UaWA9K)D%Sy*cJK+ z!#dr@m!)!d+8XR>t3dk8Lg@_%I9lXO8VSj>GsF_~*q}zTF?v;Q#`T`V?U?8V)CsGg zU@~8@9E7$ElFgw@w2FU^Yx+{C?81`cJ|ig5yp;6EHX=ubfl~+08cIpnzxO$-HrUc% zCb2{?^&RtSv}>&DH0>F>D}h=5)!2GB^xG7_&XMMs376as>R=}#E_EXOA? zWxj1_l01t%>j(RqeY7bA9=47?MOa~}Gjxk~rf4dUT4hSA{9eMY=2~&(Nteg>qxN9;RTY*-vIwG;%AZucRPOF>_$K)_ zd~@&kE_`~T6={?8x;{54XpEjsw(+?gw5Az;9z9#{TG8q<8;(CeuBh>ZhDUP;E7+yJ zXHAQ%xkA3rRt6oO9^g=&Gc+8^H=F&wFyu9kNx_|Fhn4-e#Zo0AaF{5qZL2?`L$gYE z-j4;9rP*=qm=vu2wfH?;!D+QPtTa1cCR+kGgn6#p4pzb1+{to_(?!7JY+m~xO<&0BO#tlqUHxAIEK|IomyysoIYNw6vEweX4u!VkitLMb0rM4A#4K_W5 zcikpjE{rZbi~_Hl1bz(NyWHx%Y?ww&o{>&BXuVWRo5>- zw-(2>)vA{Dy?|AKP!BS5W3uO(>rW=G zd$x(Zz*nCZuM5KsGM;tsqKlemPmPGO+|NJ8^F%iCF1{!*yMX=n-EYg`s6?y3k7oTh zt`opl=<#(zMCMAUx%snSTrD;# zH+k3le6e^i!cl8~V&7&7Li^xrzc)+?XIYvg7Q33NWq35IE9^P0wAuTZBtv>R@Wlnq zNBF2X`Ksck>rP(+mEuB<4!X!|=%}niLq%Xb*$jc|ZATwnnkw|zcA8#cp^L)BH^Vs+m+PlNcNcEJMd=DhRHR% z`&FmNy+jpn(B@h~cN>XooKb1?MR3PC*JD8kEi2r+*S9;tENHEtZ-fpMgUjUlM@8l1 zS`jMGU?Suxq-LauA)=Yt`jE)2`ZOKh}E&W>h?>FyH=4 zNA>uyk{8Ro^QFy^r5sWKi-nCG6u$y$8YZVcj>T?25KN;;uSz2o0#6#DuSmY*^m1vtTdB1Ltz&fN3t%40eZ`5Dpnia5e|T>giDX`%$w)6L02jljoK^Ijjz zCIm|4s8~6`!Q<9);8qx3rvm_{A#)}@it^V!DD%2#pa<-zJ?GM+FdxgdL_JKlAM7%_L2gD54tTj)e2UsjRuR7Z!MoIegjl`QWZoME^x5Xi12%lPoRUEIv4VUG z+5}vG$!`315e$ngD6HS|07F`4zTd#H27fIA8fNPT)7q`j0ksZY7cP`IISB%GGLXs- zR#=maP>BMxWV}xfv(AZiA6tb0T>TI`dhq?b=3;~nXI_zE!BxJuIw*c9mS9JEMg2D( z?od#)Bz)K;LX6yZYehr)-;7Ec_$YrI*d4!T6kY~~+8)qguLjlGZEY*Vn#K9W=~e4< z^)cvk6q`rcy+Oua^PjZ%zAovt*V@BfhH%y@&d;Dpy+c2SD;KLX&t}v7W@HfkS@pD+ zWE!wBwejf(@$e*OOaL(iAs z!nHN=SX#yG`z}=)lt9&fo7pJ3+{2#!dr>AC04+>~#=(Rk?4%b2LW`+Bn=;U*@CDA6 zCmD%C7Q>=1@SZU+gRq47xpm#;1D#6l=`i6yW}@iODmVyroKr^qP%2EO6N!48^g2!l zdPW}(QzcwpEK$HCyS)h^dj>92EWI1jR;{siQU}2IfPdDoArLhOEd~Q0=|+Q`XOaet zcH0~v@B4-TNrAxvwM4UTo10N_?Vw?17vHtji2#B6ekt}bpog0jP&MR8scAe(s9Rf9 z*-m$6Bay(gaQFFcVp;G)!n(c`sD*Rlh4k4FVZMP|&Oco>OYJcoLWkDU)GQbo_6p{g zDM3abFl+qX!-~_Qw^5>dyi5Td9JU9$x1~pULxMP?~hj zE7Wd{Ie0k4L_=K2hQCSB2+ecuh+{;>M7BAfcgWsA@t9}?Z^HpE2T!M8c!bsh??!cBw&Io_2O+IZr_gMezIh4hN~1p8fj_C^oSzzBN;a3=E1* zz!>{yIFyZvtK2(AS~*$V1L+JDd2VRxaHZUW^Ee;r@uDshsbENSO^o|x?5&|^ zX^jL#nA{j#Hy|G{a4Nohe4CVL5 z^&563umJ@TGW1Z5To;2bMU{I7ZZNb?xfMO0#0=_7LT`w%IFQ^&UxpYRkuD|lwY+93 z4IH>D?7?;U+6EUzG611YH-W4c(t0Vt_Rf1*_7Gd1%bOhz$jY0hui&Sw*Nf%)L;B;g zEF@2geTwxE%0Sl)tpMu~g)x*l2j~4Jwlh=s_(-BT=n2R@4fmW*uU5wQb;p^|d%Q06 zWy@HN_x7kP&ogue#ODuxJC`&M^GHY$!uI3I4>s3rN^?1OwtZDoqc7bm_Fir}!0q?p zbT=Ar)3Zn(@Oq`PzV;1T;HOI@bz|Oj#HG}eGa(--Y&XSD4F7j9QBJWVz(7rUBnUC$ z19&=u?y>f(N}JL2zQiUCpL0t4px=m!_O1_^7qR0)Z~S;HpwzI@v0fM;6Yn43{Yg92 z);ypPp-O&$;VmrTFaA=<3XJTM3`4?Vz#>){Gq*(;zH6beW?vNLBn^CasX=+bS|UrS zLA)jSxoN{hQ4C!#W|BeL#F`OTR1d3v29o8{?>)W7B z5XtCwgdSwL>jM^$j$xk*^y@yhig9vay z9D3qsxf7%9KcrPF;wN1o%u5@~(&ryanCErs6#;}KwFx^ zrVl5UNbJ}~Mgxh1-4Ae$PS#nR zA%bJ0Z=x^tYpK4y;F7Vb!{kW$h=4KB-pojmc+KT0<-&Y9!;ORC>khVaD4PnJQ0@t9chJ)(#GNQ5t_mo)pipXWRoL!aFG1L903 zxo}2!f?;;>h9TgKs=7#Rn^}(hjOoO;R^`gV?ga5wD%~e?1QuIJh<=b3J@?hkk-#IM zJm1&v2zVXaA1Nf*&D{TZW9q_#63@R!u;(Ibo{)sHXQ4=axR%qf4RS!Qh*9E0ABKZU zSQ|cPwW7r4E_JRZ<@RD@8T$DAqk>Nuhj#EFJ>Qfit9xblJma&9R*r8#_f=Ty9Aa_s3CL&iRm$@Om<&uvvYHv*5ANFvmkllPFZWb<|#o zD6NZapQ}IPSukflu_MQ}OQ!)n1+Ku?$C5VEM0(O20^Jcy)u=YhW6BblXxM{LP?B4B zb7B#dkdcCa9`_XP(1-h70hpWln4Nx@zB(CK!C_Y>v$XhK?SKR`qR%J}dY#^NbZf*R z$w9NJM&x^^6*`U-+=+pqXxX*x(WoL7GA=_}20i6($dDAO-Y^(`=Fw`{zI{2LZ%+4|euq=Zo(fX% z+80{%3H6@R5w+XtAx1ald`|=00y6Osiy{@Jkp+o&?S0}2&tvcjLD0r#_f@6X_h|aT z?Qj!|OVX z!$qW+6=Uyse(=k4QYVQY9S)G|E&9E?L0erkhAHc|Woj%zLqG!} zchLqzzs|W}8otuImJ_ci8I#KKdol(+Hq=-K_`d_cO~UC-mc&!IX~p|uw6~@G4=rL{@j+}VFutKz#j_Q7Szx0j<6L#Y+M4|5y9 zUr@;MLx>Y9+m}`zXcm`^Dlf*+`bqnVTRdqdR;f~vxq$T&LfEBs^iASkV!8g{tdyHf zo6(;9HK@-DO)YHrkLl@J| zjJ}ew4-eDdi~$kKi4F8#b@SK2UG!jE1kpSMeb)8}_Ur^UrMS8F`k+Q-g(!+zoOB%V z9&SMWRM`yGTxg#aFAP<90!U%VBZrFV&B~3EZ&Ym~%D;vwm+NaYMqrE!xn_AZ5*`E9%TxhE+Bxtr{@eCoRnw(#9s{R3x(1mPD5=)4<3>LUPX( z0XcX$WbjUwht)*=LXjKI0qFHJ7$?HAWa4H~c^X*a5?1>RXF;*`V^wDq+r<}D@GcHH z8|&ClCSRo;Vh4vB8v97JlCyMwMM@d&sgoxt_ECftPg*!#UJSNxBDo~NPG+UPGd+o{ z(*Ubr`4*U)?Zu%7wnXCGnP02Y0t~>I-IoYD$&iqxOBn+6X3>TG$UK8u_t30 z%kQ)FyH4kP|9#hYUGH+g&vJjy{XU~al6Hv#br=aL=r}RTtAUtB%k}tM*1e%q&TP(l zB2ZNSmjDd|-@vT7N+s*=<+Gr-tckTn*e9NhdI}rOT~P?<@w*F+hhA@5nJYOpWJsCr zGL1c&6clw#*~ch+6}FmsJ=uV$Cxpq(kBMM>KMw(R4+lr++Ct$()){a@n5F8{gE+o~ z=j;y&Z3nZv)VeR~4PCMs(r1>QZ`Q6OolBp*N?2&#OOj!KLRrsS01^N&6Toh`!HpAEdRHihlruNs z#Y@mY35CYmX1(%lGVf2#0y zzZxa7yceMY4ag+R@H+>)gxWl{CRlKzs+IK=w`2ip+lhnKs+#HSksmM46(f_X%D9D< z-+on*@v@gz0N3U;2B;jYCH?4Y?lsMe-y7S!J4ArWcXTy{AA`t)FBo9BRS$9&A& z=N4uAL&3&|PCOS9U0yqin0iajq4`N*0*_dI63_e$msU?;>WyV_oZa|ODI{KS;kE74 zGP2%r({#pWBOutMLw#3npWD69u(WC)v20#XAv=| z`)wr-Tw^`_L%-h7?US)sY@hA(;Sk3N@jFrb`5FQFe#zu z)@Axysd-jb(xgb~fpazHhe0E$twIO7ZHnV;WCgLB!RT_JP@@aPqB908%4W_wXEd{| zvuovgjupb*pGQn3BoYDjf;aF9jaYCzjm-@>E4X7RN2I}!48-hl zbZynsEOT<`Ws_WS?tTHUo`LsX-RB!J&Q;zyAgV(aX~(~gqL*Hitk?a^I}7FUgiyUy zbo@zq-@CDE0eNn_PWCsV=+kJ+z6{63^s+noA@04$-+28f-UwwbmQxVC%gfgdRW-q^ zaU4Vz;Ydg}LcRJyhd#VpbY~?{P`p9dDJw?C9dJa?;CP75H?!=KqjbVgtIs#qFT8LA zJ?tnrSFB}aJavnB+Z-ka@_2SanBubM)h*g^Y`iMR3b8Q#EMjLYBVo{GZ^T4KqLp%4 zB1)nnU*(VRvgf@tcULlVan>PJGRH$L*{-%7QmuD@$nnN}C=eX;UNVkNvWblw64I~m z7fHN!K9O#;i;*w*o`t#>^&8o%v?R1Tvg2A=ySMDTM15$&swg36S!fw3h=0F*7skCF zdyt?zdVV5XcXVIw9X@gQgk1Zr69S4ea-bu#RK@6gmGJX4XE1Ox|_k1FFm2y0jIJq~Gh%kzh4C}X!VHgad}5Lif&WIE>9 zQTE45*n2VYhNONroBh1Ir)LAEs7KZB4f<*?n}140=f^3EtEOS|>f$8ryUPQdQvCSZ z3g=n@ojh=;_YIY|-iTMQ?n4~^e5i-p$yl9t-Hyd(&x`I~6-T($ZN-X5AyBOOWrc{> z>^RQyjP;8|KpQ)DuFAhaRBb9By60g>NBUA`+hyhNUL-dM1_WC~vFZ$W(o_3}%?I7N zE8)P9fB^{OIJJF5{Wil}M zww{|MhG9w~sT|>~my+esnO!1{Zj^7W!MQ)2bk2geGaS4Zk{BC7i);6t+Be3Ei*709 ziw|pdL(!`ys?P@aVZPYppBwq8v2>`vwJ}RpnUqEq^{yRZ;}SZxu(t*Zay5kKqOms_g_8 z*}ILLRVvduwI-u7gPdbkEjxHY(GpPpTe{;Pum@7O_?O4SC7YP~osR={j2sRo-eLh~ zvP)NUcgC1P%wsH|0kCTBQA?crv(i^mAWng!K4b3_0yOxS&1BMpL*8+zU+rm0%}>5z z2SLe!g!Fpiihc^E?9Z&pbM*K9yb-F(R(4)4NBqD}^er)9Vf_Pom7h_hM}6ie%DL$= zHmFCLE>B_n5Rviy`Vn{Fu)X^fO|9747Si$45QY=9HQPeP27I%GH&v zfqUcxEmC!~`J0YC#3g0_qEVhKh+L-w_0k!y>UjePY0F_bUp(_u=#~^v?5g!!I1SBspMU{_Sau&6L^6lKy`o!^M-w<>NAe>CDF`DM%{7LYNiuk`zhxLv8XmL>Hn#G8;m1% zU?b1t(Dtvoto>7HDTpr3VV^UI|U+YwlzH=MD%ZC$T`|tXFHwCtA99%?NT1Ij0}Zy$G(g zc&P2f87HFfJCGOA*e|UlgW;UlJUSPK8FtX>!*hGgMX(5zC2hDN{8D}?{a?_x3J^}- z5~%zXUym>T$=NilD{vnWLeoI_1X1Kg^Z+P3>KEtR!IU7x8@NOZpn1MB#{p_^IkRXL zlTWJT7SmjX-Uphr-ko#lHU8ZcQslQ9;~5ClrwUIM5FQ@!tdXyA^8;U##XY6dxl(QZ zSN;VQQbGx6?F)D>7I3WF*jgxj2|33YTxY1);dJU2zZPQB)sTI5ete+c&~=KgAF2ta zmAR6sc-rFUkLAkUFo>2B^%@y76Hv#@07Pc}0oH7`|7?d+d?~sLxU5gx!$b9^)-?JC zS`L?Hwk8ONW>vY+QT>&^Uxg+M|8p?<*tS%8?TvLnNUf-_V-sOAHxHYZMJRTi9AW_; NQ3 literal 13408 zcmeHucT`hL*FFS-7zDfuC37RO<0VWjs7W ze&8BIOay%T<*?cUfAH;Sa{@SwmoF&+s25+1=x6W|x`wHY4a zpVxSJcYwcmcmzrKzn><7{(efxpG5HYH6G@qq3?^f0H701GgS=-4LMmsLu)J8lV{dX zjbJWTHYW}6gk1!IODiLXCk!rDmPmU+7m=HPwh#oaPj0i{Wcag*gN4XV4LL;yacesx z1|AqU?A}dL2m=Fyu-!9bLFI=M|9KtwCUVo%!NEq5o!!~l8RpCdv$iu~=MWGOV86%7 z&dJFJv|zJ$MLIljVME&A`m2+_`*~<&Z)j&`<6vfuWH{;f$x~}b2a%gMPX_w+^Vd8b z%#44JgtY&USb%`+Cr{WpVE5R6^$ol#d~#P%!OqMG82O}sQ4ZlhTmI|bf5s7JKN1Kkovfib90he=VCRM7I8}CLSKArqsjxsxJ6Tqa^PljOd!y&S|_Do&JWb$oD28 z%$gRduVfhOlx<+))G&-RHoyGHe6UA0Mw9D@Y>ap}!;|PJsmq@$UbslM$&4vO2?^D( zG8b9%E|%{g1-imV8@Ic>*n$3?As7)P!rZ0`vtZjaI>9PjItFOG#>IFClNe!|)K>|5S=AYz7peW-ckog)XGzDs;t&l^wjoAnLwsh)tZAX;I9Q=JeqymJBW zzpZ&m@$Z38-X^wLz3}fbfw$q`z{EDUkEoRK&P3^ z91s9^My&r6;2-Py|H}^e_@_l0GzHUTq^CDn4(2x$78l1X4VPTY8Lo13Rt|Vr{l_V7 zd?S}669vmiNvU^O85>nqQ;R{Pq1_eE))lZ~*{QV$Zy`38W0iy1x)pud`ZZ%jd_U)E zQD+p$AjI33mWPKY1B>lYRad{;nAVy=Mb0=r^`t$9$G8`bF#hz4l=?}9(~^0)XHH-tTM|Q4UykO3FugK`k zpKr{)&#$Ja4%hJ(A624a(+a=Dru^cuSURx=gzvrZ=@Y9+jL!pCT!9>xrs+`v>%mfn zWMQP7&?t96X%<^Xa}|s#?rpDFOWKjD<)2<1JkUpoDN%O>i~7(q%W}OR5hylE9l9g@)bl&^A=H%UYdqvE*!C;ald(LNfd`b=ua5fO6dF!df^HSC0p$z zpV3$El)y5jY)S8h)6F|M@O!5bnd-{Ul)ak)5&oAZIuFV$`mseu%iWpe1?dzE%l5jb zmram4iCPg+qOPo~?|AeyErpOjCML!=-@FiU>5Q`7RI<>{nKu{)L7uwfA^4w_&>94^3;nqzM(C_8VhN3))OR`rr#2a%5W=1`sH!@v zZpYzWufKV${)VkKdDli;OKTA^y1`*f8M<&<{k`GBAZ$nORqvPT3BhaFG5|t z2_cI0JEabIAPzuaPcbURIo8iq69f51GK!HcEiDGo;L}@lalno6K(L0MgvsH&A&CuO z?}&_k3>KK=wVn0Iiy|P;`0)@hMfr=5VE$t3ab#;(k%fA9j&{j|sDSk|t{wgdAt2$X z{+9;Ow`K`Td@{Z~;<_MyBuoG49ZGTmVV73`!KQ8(<25ahR#>@~JN&pLSyoDPX5%TO zYI_fLSs8*Y0ny&1-uo|$+oA%54z6R)(m|&drdE#;?roS`9#3)R*!`qns8veXj#oY{ zMxOe4)kQ=)v+@&8(wJ{V2xjHtQr6S6GP(u#PK__ostat7<%PH90}rz?m|Fwy{X{BGE6uwAJp5o* zX^3T3dLse3utA1GVuBH_n2(v^XFUn~0R57P=Yb2?lX^n?TKsbt=S*WmL{4jVGZgN9 ziy)*tUN)Mup)F2;>(ljk?ZXK_a+*UOn>z3e8iVB|B_)j)x*>Ub=@c75Z7G+^cZHmn z3v+mS>TmW>ylU)yvv)pT@aKX!xyUnE<>~`2!^R7#7GbA{g(n??3MW?Ecr6DEkY&?U z>jQ=%t`^-_DBC(2QfO2RcUC8jj}N!`JoYv?A|fK3X8Zco3T(eitbdiHj|L3-&_^L| zVzZ1vwZfGkzA@9W=L>A>e)I>m8%x7{hbh_jPe+M9fgnPD(TuN_O#OOpIniQXo)WC! z>m4H7I`%EhnIC}J_AD0QM5(to`7DQv+bfTc_Gbo75_v*|f4)&-V1$b7&86}({KV)V zwscfqDk5JvBM^gbQfq=5xT0Hq)~mf@rP_jJ3j(3FYre5t1HapmrA8HYM=rm+S|UEf zd1Y+oXDd73Y`k*<3Wa(*#5n5+SQI{Tv4gy5UaJ^0GqbnC$kmCunc`t&L5}!MX9LF5 z8p+6-6m@WXxZ-6+{_+#Km~doVc~|gr);{g?_DzNOAa>T&Z_vA z;$;W|=SP&jOq&hn8!5$VzCLw$@IW_w^2uznH47Sb?Av*a8~iD6P#FSF{0Xvjl4w0Z z|Db+jWn9e4%|!je)qAxG`+EzyCH;^@1y|*N z4#UHzvQ}0(W#5B^+DdJ|FD^2f2~C;3Bx32k04?vU-d~P&>H`kffG{-o_L;t#Srv=% zgT)Re$!F4|^rXX3xw(8Q8L}L=Bmy4~t7TD^_w}Gug0OV*?3Js&WeeDfddzO{85tAc znne6ZN82^A;|DW**FPO!!C)}$xn74B>(My(J677s>T@wP8ihcZx1=0)SE0BdFU`u} z5kt~PyI~_*m0S_V&10|UL##T=jD+? zl)hvzt=Zn@LeysIszea0TelqF;1Bap!^o;lwc(aj?GogqoYC>&(f$fK2;M~RRVi?| z(LK!l)wH_iV46K>;b{F6{ZZ$}NsRIxIOE7M*IBxXagHWh!w$iPY~GMBg`d7P1hijP z5Prh9AT0ixti90UVx>~aol}k&UJf4w^C!5@P_H*$vrdyTH4fu2Y)s3+88uXGk68e= zCn|p--g#_r8Sk~c&5&7Ubgsve#Y~9Tfnm$8p4XvcYNgj&fWE9I?usFI4mN{9S-F!T zY6Ccv;5yQ!+!d>$k-;L1sITGmFj5-sW;Ule`;IsP34&3m$Yzhq%<%Y;)0FE0UNGne zB>Qv_sSIvG2efp=3k5Zf5oaoR?RC%ivtWsHVME(2xs_cPs5x&h?X^_2z@;g#^4l2X zJt)9g4iz%*B$!PC2S9d^;wT}1?K}H1u($1iAbxW3@wz679$V)-dJ9Z&XMCg27D+h5 z`#Z4nm=kLd)77i4Z^eBifx7J&(Mj=fGEEHvC16G*B`4RZs=9YwH3PzQl+cT6v$i0w zqxD2)i{rHrud79!&5;M|TT8?J?(-^%EyZrJ!yUrwvg>6ykB*}_kF7zgWgOY5Ts9iq z0=(XEKQ?)NjT@?}^{QvN$-@BvIjCX!WZ^y*%*!;db5AP^;tO}n^_O~P|;R3oKv z+@>J^AzhqVMx<<0>84VX(J+;xRS9ff2dSMbO5!MI@{W0YsS4?~jdRe=VUMzJK*;N6 z-s+!k<``UN8UAe~rS&JmoDS0y`{kziFG-a{S zm*WI)Hw+Qs)oAkN*k7sfs!f8wSS}K4e3WO4^A%H^1J0J~dfhqtf%X6@Hcm-8$M719 zylh*MgUA~ML>GvQ%_f&h#(BAn+wvC3L^c#pd|xVu(3tzWoSO*g9W50V!|MIf6{04Q ztpUTCqJF)C@!qGB1Z_}edgoEcC|$DSR894fHkP3+z_gBMRmiF;gB9*yb8HQLtA)+l zR{^Y-)mqAZgwSw%V+|I2_m<=FS4YPxz&UkiD$w7`o&5BA*hfc5Xso#|L@ig(Y6Y<} zRu$A}FEE$n*R@4X7O2sjSTdz0fK=}QI)cepJ~emBDpZXck2>^A}>A};#s{^_uCmx9@CxD(rOm#7@q0L*YxsbX}&y!{K}65 z8z*g~BGkbY2T8AoGiqO7^Ae}DLbN$#muF|y7g-JS0^v7#iQDQAXS1&^Y-k%}>GEn2 z1UT1;mf-QFD<(2G5P`izcMnD|?vP5RtW-@`3e~UKtnu-lYWPW-1;${NxpK}066oo3&i@s#qa|D^2le}LePA2d<&TY9&phT^8)}uMn zx%hXk9$pL|B;+6S*d8quN-o(>Pml<_`Umv{)24ek9P~y zxwJQac>K6+)?*dd`WvNy|0Ha=S(}{EY7U{3f9|F~FGV?I1F1ogS+n=AczTOd7O=Zd zl9*ATUzDX8uS!3!I6hd%4I3eDr-EpYc4(hhB(jy=*+fs#du)6yPRUiffxb8s>M%0* zHPufS;p&V}Mw)@9x)L18wK~{{MO+B_G(jY`j?3f?g=uuF94+DH}Q&A9&n|#8oLp(N7tEM(!5`2 z#Z+!|$rvvVe8loIC*nl+EmyNm{g$IWB`KaMcO8b85vgqX2|5{m7Tc{P|0C0c@>eJc zuP2nYc4!CTp}k5l4ttsE#|M^D$F8{PyWIkI0&4ruWRzT08-jc!x_dW_2N@Bes+vE; zvJc@=7+NUtM5Bo!pSMldHKQQ031yc9(vq=b)zvA$W#{R>RgLcB@N6aV8h3|bTx+yY zOepY6A~a%G$3}dicgU#i1IJABt&kq|g^d=L+=1z>qttO0$7nk#!;ptXHcGp_k3KV2 zp|-UfN;m0tg@H(_?d27{56Ww5t_V*@uCJwJFw`~wMuxJvlz>GMTiBi|i|;y4Y}`q~ zc7H*@UwYS}k4MMia!_WvV!FqjhOLxh7X_y| zggdi%vt(&1-*3G2rgwQ464Qa{nhza=RYYDiPoIRUnbYJ(a-y>^={_-)3)Q7*eHS5i zOejVPZ8kazR;8B;+iV?aEfr%46=@vCoYVIyyMcJRgDe<*$nzLoF8pk0Jf7t+_`A^^5U5}C&*`5PCfNmoE^Z0|MON7We?xU%)-Kv zZaXT5(xp=&3ln{gQ{7@FJ!_Nj42!bMMY(;u1zit|!dprT=sP>PFa|LeN)#Qb<=Ut#tXRk)4tXL3oPAuhUW-lj|`$(y0hr?4-2d_(imVI_#bZ6F>`d3205Dgl%F#p1; zqJl?8&}fGqd)-h5qoImnSHzF{pFcU5;Zubi6(( zr?SjYaG#ot>fxd2ZvQHQhLX=`cOeW(n9O{6D)ke2!5?Yi6LG^>HO@g0!LD#rMaD5I zDO`)6883T(vE1k7iqTF*@cQV_HMgn6+z+^le?rA@TQFdR|G-YX8L9dKgLxs<)s1e( zrL<6tWzyE{>t3hGvXP>+;^W6?(Yq z=~&ak$P|mSA8cFPmArqUsJe52=IAOf(hZh4S@Xn`1f>%kGIV!*`^G#?w)n4v|8XQ- zlaRl@J<~B@gGxCf%5qdS-)i03UX}6ju)WBbn7WJRteV~@RDM2ZrT+>5k8v>cjOgbO z_wKOfQ^Bx$ zwvPOw2VXV?UzU=W>BS!Y4!WdOPL9VU^?3)D4SHvU9#@rAPwfl9V>-(_FGXr2&o^4z zoIBWQ5-X-O-WKULDfagdR=S?575gxPxtpiOtjd@A`S4OqE{kHa_jeLZa6#@#P;c1c2L91~G34!Wy?4z-^j%diN=*(;v=eg(PwSk*Zv`{-if%tSWxRp)YHuj zZWV9w2(H7a&=jIi*LW>I2z+~U%T7ReL3G&)TN4(O%;o3L9$L=oc4eY76LcACRt25# zP3??^}oq}!AUy1^W!Y`Kc&R%VT&bg9~e zDXP`9$3L<0_GmGojdZnV*GjJZ6y526@{eOL0MZQ$>kXdmaTFs?ywM*mU*FWQJDTWP ztIIdc3PC2?9c>U?HTOwYy9ZOeEmZS#N(fayZOP;LdI9}yi+OsDFI-ZrGXu+Od%I?# z{=MY&vi@^?-yHhJ*}$4S_ATHmItF*-11vn@B5jR7gc!~pnF$=q~X zyisMnb$M>d_@tR$!PmL=G8ss4DHW}Gykg6DYbKm$8BdbANfVO|*`Vm5&vl`p2FBrC z8Cz}9cpjO6^0ZQVJ{Bp}GM@Amv&?uZOXbz>#9*F3(-Io)zI0i((UGlUQA$-+66UCp zft$;2lA`Ob^n!LC!M`y&CJ~?f^EPvAru;xXtTnjd4?TV8IFEeu;$T5{{&xkBnBw=8 zPVRUJq6k&|ZEfnpUXS|3YUNQaUgU@=F4b0uv*;jCh+;KSr-@~?HKPS<%=LxwWd(BD zE^xSs{#;!msLyI!j3-P&MJ22T`o4A7A@Xf`Y-wV#7H^hYOyWVE(7G!O%-@4(WjthS ziPTY#wA{}c4wr$9?9Dna9O8;ufduJbAwTdJn)FV`Cm&+-V&4ZtQV#&PI{D5Dt|a95 z(9*@mDhx(fIt_wgW&YJ;JAHk9<-P9{=Pyn8-tr`&CxvTePmx>B*L)=1C6L4?|HdSn7ku$Ny z+<Xl|Ngk69IFapV2O(}Q zlix*%ar`mFe{!^dR} zFj0L0ywu9p9qkr)%&W_GOLY>#sBFmiBJ5`_^TR`Y6~vk<38W}v)$iKSHUQIRkb1tr zg)MBWD2VjZI*-_zRqWT14qC)0A!2m9YGWp;n2_3+MAxUYBd?f8I|68a8ilq`()Kuj z-)z1(-j>o8ft5{#Hk)uJ&ML#D>o|`El!++4ZSE6$sC!l)ZRTbQiyz^o4>d7@s~qI{ zwBPqt%xX53uFuB-=z;TVqrc~HK9l_?WI!{>6= zx2w0S!Z#cCI34GECP*_AUjypGoi0^g6Ev-g@5u9&pB9@~LloV6?VC<0^vV45+UXo^kc|_VR{6+RVJAs&>`W2XnJoR=Y6jxw4tC z-OXLQ$jL8v6D>g690(bJ@Dot>JYkB|ulaOgrI zi++7Cj}}=v!MYI7jnrn8*|1<4(W}a>A&YJ&mFfFF5&ptk&-e!z(@3GJKF_a=%q{%hEG66DIV=ahSp731H%)i#uGsF|C6Y0{ zgT%u{6SLX*W=K`M`t_79o_-y1n_G}qj>HUk>X0nTcQWRi_ia9zt-k$j`lXVx8z*dt z=dt%}zdhXM+36X$GM{lNVd=&|vNwtOkq2O6&-rcaMk(tB49+*;NLqmj!zIBz28uo- zIy7V*iDF`)*cMe}#v{C*ywQ&lZ;USnF!)6zGV$V^rBZ z8q<}b)kDdXlhQcGaDq8WU2$0|>Td&Jf%cIy`vM{Xif4T;FqoMR**|e$tCJFpxS`L8 z%lDv}S^{!et}cT>bsgK6(Hw>n_f1?o7xDLS)gY)+_l^0SX#jRti80O`y`ct7x{Hvz zbP=crSr!8%6075Cb6y59vl%+l3kN_ygczPuEYWAi-{==ZXC!=(l#_<&gswq)?^#Tr z4FF2a2#xQ`cc=uu!X^HwFedvT?3(ZT?d{#0&eZ%iNhg&c8bEJp3jW?`Xh0U@t++XIz z`jt=$iK2g1*W&Dh56PW-M9Z+Kk3=a-9c*u7fd@T0|k zp6FPh^rp+XgzUGtCn6V=8oNJYkBg4xGBLhjIfr+csn^|0cJ&^^g6rTLK$C7G;G^pR zSEB7Ty{Bm;tLD?bY)!+aDaC-G8{)67I^rxWEiKnqER@EW1PgPU`+y;99 zSBO1HI@;ry1~|-nn1=au>WDpZv$G4Eii(Se7+(3_A)#Wuw?5O}O4DO=rF*yqD2D~l z43NDzMSTIh{ly6;pWzI?0COYTg`AR@$jC?yyR@U}m;|*P@p31&VOxE}k25!aufv~L zFRw63c>4`G%vD2c?;%I{g(|)PaF=%Hov!(@6pIsIwiQFj_khnY_tcBTQ%s8Qzk3>$ zXdfRPw#)I2K7&>7JQXrZ&Is&vq1k;5v1EF~31Ifa{lfIKQ?#ew4llqf$eME5j*X2y z(fM{D5;oLxou(`>YzmGexDGK@RaN}}ln?rV2%|CZy2y}xz=!YYgQUN*^S`o0pNHou zQUf4t{C4gSPq6f>)HHVufgr(YRZ)(m0x0VXjVAY50sOFp95lKGD7&?Cb8~<2Avi}P zw~yAuM`JMdl{6Lq(EPv1H*hzgpkFAt@ZE#5@+!yE7l%J;CuvV}dGJ84R0i+93j5g! z{tCMOp57aMfY@*_qw~k#H+~T*ezF2pdR$W6iMIZ_`RCO)fVTKYjez>YUkUJkp8E)s z01S#wRg`pv^Gb*PAN+K`fWN7X1_uMPU{-LR;#46c6?qNpqNqr@4Sq;v8oC- z99Fj?kj0c1JVkSQpBOGCde0xA_gTt-&ecPJ&NVfu!%YAWRmVwkrg7dj@qg$nml~-i zve0NqOV`j44Qs(EP80CeEyP=YcH0pDCG3eMe(+e8+c~4bN>}^;ozB9Y_l9MlG3XkJ zF03QuZ~1@uj7Jx396cNGwp#8>7@gFJ%$yeop6K`l7_>9~PNM#^@JV-(vzeAN4 z@q-VyhS}eI%UabgwtS1p);V`ZX&?+qVI+w}DJpCbr1f6?2EQE$>T#=bnWoUWG?=(LRq5v+NR3 zX>V~bouGs1J^E#UVb}JG^qRktC-%2X{d=3~C=_+|9G|EA`$M$*S0+$`9vT48P2~B; zJ)m|)0?B*!0KxRLNsK+R(SyF4IZAMpOlf0=ePxQFc# z8=sC%s@L(6F+g02CVyilBSpxsswUQ)yaJRZ?;Y-KcHcZpo0f*d3H-}B_`>6r&m)=G z881&L8b`u(%_G^gGakk6ZTv9&h(@DFprU7#kipmosL~E3TtOC7=<1Cs6Omu1wU_7A z$EJa3TV`T-EZR~Y1+)Q#1YaEsf9gXD`@B#Ft}`2}cn1V1AQzxhTTPUj1?i^nuTMkD zCVzexm4VeJ2cB2-i#TDnPIr3(i7eo+Xi_8T&Jr`20=>1&PuQ>7+9j}QkfWoc6Ldh? z(pxbUpDZ(zNl8UTWvC76PsQAbpahGBUvzNIh-^o9+j>|7Kj~Cyk_i%WlNqh zgCSsU6x#P1k~f^`!(X)7SD_2Rmm>Nf67uUb^5C%LIa$%NGBN?$?RU>u$SJ8LfUV=? zLhLB1)EbnQ_7KePuF4ao^iKR%8JfBsDEwPprg@Zf5|sX1uiojxMHsjVA8s#?0{q&T zI@LPT9GR!mmfpAC4ov-qjsBi3*d?02;E_v9!Z10Kf5K!ELxq@V8s9!AsxdzR!1z63-b3>xyMPYxbv?fk`w zH@Fy zB18&K_GXqgreI)_5y|S%8p=ahIob(vagz{VC1E>Yr^}O2v>?Gt17qSK(WIkch5EmQ z!&T{u*5;R!L{>q?iHRMXDjxgP=GE0PU}1>u$Vv(>`0RM?J?)PBO=LaDx3Ju;f(zEC z(#CJ+Yk_S?ToqlQ5|7rFTFNLv3xdH7`a?#y@TLc2Vq+ubA>8_<-f?_oOR|=OtMdEu zrarX+Z^8=}cY$JlZraWpo(T@*I47I-1`CJl*qQZ?fS3r;P=|XL3}}Ebr@ml-8dumX z2G8sRu=lBhDHJ%hOw)m}o{I3*`=>&Au=0x>lk7(IfmtAhamG<@UlObJ@$)j;*FmTY z+CZO>qx1s&<$t(mY5HwV;B4+W)rZzFSA#3UV-AtEtQ@?VTfR1J?+iox`~-?)N|SD3 zKJ??$jU);QO!su-i4J{zF7~;aY8nZR^=iWFH*@FigO~9h5BJn-?NP zhi|ZfV+0Biqk%0>w#Nl1f>ZfFGKy&J%)y!9>ka?fCuzhvMZnSX&e4w-S1-uW zx!1>Gt(&)V5j_WW2__bn1Lh={Cs9;vnlS$(;u5i6a~al$wFQW#fUFz<3<208G0QkG z#vlC@{H5lcXnzsiYO$;tQ`PVl_|k;X>4i(fQwRTn{3tPK$W35;)?xDeqmkn5w#kGZ_LNntui6vDyoJcwKcM**Ilo!LJYM}>O5OhPoj6g>}y${sff*MB3eY-|jB}^WM+^BOEG%2va6l6|2XU0ZO@B<`Z&~KXc8; z3h<+Dvl_%>2(NB%1>_7MtiyX9NOd5h19DXk(m9$-&|My~5DJ>G$bLAnQK$y#mvFqz zAV?BJNmjJjLXrbXEE4hUK^YT%rO*n|c~b3ot8MIU7$*p>*zd&daT1c0m+v2fji@l^ z#AFrlTp$mF>L#gJQM3KczA8@&f5*{{RLfJ{C-{!U7oaC(0Eqt(0Pt__O3iv*{|?5zD&e5udZ~f)ag*^P|k|w2I+=A zM!fzj)XcQS!}p@^R!dS#B3jk&b$c~~3c4543KUBfOB_|Vk|{K2v=WQB6zdi0b*}Pu zO~)AM>r!H{w4=(|w9A!_!sqEL32a*%%iSv6a&FO1el6`a=&n%-*lOD9<*M!4cH?r*d!2Aoe4u)WKWA-jfPnWt zEPh1e2Pd$3=)TZCe_|SYpK-o=uB+^=+aOJ-CIFZ>YmnQG7$hGm)BCCSV=rdtO(=4- z11WR?lelsW`-g1yL)>DXQ9m4ejf0wZy{EVZKahT0{9uW0`k>Ez%EZJL@hLv7f`!X+ z+I096BKsJ-uC3?j_nBxrEDH)|ZCkgMW8`9j#QsrJwNLU)ZDTQGq+>g~+GE;dPjoi) z33QQkx0<{)g&L0G3@pq$FX0j=AuHtsEZWn0|C z4TB9+H!+z(coUV=C#^hVd@DX*yn>#rktL7=1}I{eb6h5-a^U&2dAk4}UQ!)a9o!w2 z?K2%5fVIo1n}{pTP3Q5{b-YcUfu^Cmg4|U7&Nc9^uIKD$=V$k)E*wi9rB6;zgOuP{ z;4A)>;3om2z-u6Vz=_bV&`Mre-avOs_wzb__k`wch0Q#{d^t)gisj%&9I}nTEuEV) z6&5b47VZ*mF?tF{Bmc2svlu`PAPaC0Ht&lL-<1?LQQ3|h)c%N$6stUTK(NDSHUCXn zarRsAw;RRS0{r}nYRioX`xbx5Mm)J9ILfS~4Kqz_ z>Ta3;$d%2bl#%|Kea_EB=BT;ZLDoj*q4c@V?DBs5a2uKWD>be1(!duS9_!!w- zD-m33dM;ZDt%>FuN9!N1(RUy9nO}DymtkipvT`k0ncO$0q%snl6OoG1rO@0%1@m{egs*$XZpc4JO+oH?m_aR#}38{!epUAZ&Hs#hL#c6zI zQFfvExN3O6L&l+#ZTRh2I0$$ec+V0Fc|J~AuMEIa(E-v7w!EJnj^6zhg7Mi#TdkBqgKb{)7La?lz5x&hXTW) z*vN6orxUc{U$E`;f*H~1t#pq&0lzk@i=L<9O&LsgOmkDuQ*`c!Zb~9^A5+a3Y;|`V zY-XG`oh~jjX#>@cwMskc9Ci{_3)JT-&8ir5U+l&T+4e^GhB>N>Dw3;htHY}-G|U_9 z9$F`kLXPZJLRC(e4cZMaLXq(v@T%?LR#n;-O`I2Z<+Vk%?d)TIYN?wlt9HgTR~jtW zpA0QeydGaU-yjv>oAPuXW1QKnVRjvl{?18g+ z&qNmQ2)Ea>4zQ*8%6BhT=e$M1Z|cbC7x~2JFu$wk6Nhqj>tCj4BZ%tW)vS#%Hau=@ z`-c(MUl+!8_H?=cq`TtFV}+Sb_Ay;^zL|bc{n;x#)n`~MCv6;e{2RUp?<%2pkYfnd zUhLkUI^C*o3u1){bv?7r?^n@R6I10)a+mz<0H$|`llt9$x`zbIzb>>MTi?bKnnLZ}JFfr>)94FV=RT`XoybKUp&f1f zkKVjb)H^d*ou#=_xwM@>{VbnxZ*F}3^!&PlX?KvG;S6fNrl*6oFT#S+V}fz>HYxs~ zo(OywNHtOY4(6G%f|n5~92=~mM)~BN9oV?Rh5n1v&8FvnH zY|NZsn2whhds#3dHi&bvrM0!D+OD?|H=JX9u#6I_i99&s9+qA#Y^YYN#y8A+p`^W; zGpFZT=tvk|VC+j5Sa*NyX6`!g2}t{hG}VwYla&Rd0fk|}Ai;6LpgVb# zOh{QoN($sF8#|er+BsX;yKHot+JIibI!J0dgMnd@|K-4?l*mBp68OBOiiV4ZtPHoY zy)A>GiM^321HjhduX4b60oS$;6CXNmTrIcF-?A5(^g>2X012cXxLNcNPYFCv!$7 zE-o&{Pt1(W%=DlX^v)i3E`|VlJ7>~=3i(rxsHwBDlcj@;rM(@|U*#Ga*}J;%k&ygV z(Z8R6+Gz@~{9jFW&cC|_>LBA^F^o(MpBVow8SYWz=5jsNB3U}OGo&i};xzd2Q%O`SySZ9!GK@c&O-zcc?g@^?mF#=m<0 zpON@ynE!qY8fShuUdDfA#t+9lO$-AP<3~$Tc@>Zknq+@}ctGD&AorIKa@adK?_?c8 zeyx+-kw}xw%bvGuP*Lw`pF7lY8CBD{bhvi@`bwk;BD!i{LQlcZKgM}@ee|Wvy2|*F2 zNLDG*D|)?CP${}R?0E9M>zIA>z4Pljf`be!t<-)~*O2sw{O^TIxSzkR=DyuyDbmrDv71r=E}fKdnv@6r`*@{HSK~RS{k`4GUKf z^M6%>>Rva2khLVEr3oyR4A!*BTG9A_nhhBQj@V^Pt~Mqtg3QYZ^M3}-fjuBj%OXKb zOg&E+$~zdIi>s|ggXcd<0)#0IWQ}B*A@ujLAtrMF(=H+b7~ng5S)-y53IVO?2D1N% zipm0_TVXOwfbSg2=fnB-fBShEA}9&vtt5MnasDuE#P!XbCOIhRGVXVW6xJbGhhX4g zze@u_okd54@-7F!ZH*PWZ5&I`VI=~18617&_MfO#L7Gm_bLS_EbGqM!13y5n*fjxo z3C6JY(b{hxyf<$=$5?zD3CF+DTTdlJ3U|j<^;%KX9tz7P>kO9CZtPuZpd2G2BFe^E zuv!K4tlC!!4%YuW8C>YW!|zg{dhmri2ldHbNxCpFG1H+}&8ZO}()!>`f53Qye|J|R zJz$EdT3A@fgw8(+uPVq3vwst+@w#)XUVGIAC)%V=_-AhU8^aKN3q7;+Vr{of(&-w> zjQz6Zg*)|-kbrgtw2t%`U^P~wF{+#V7Fgmx0jFnvjKT3>h-elklXoFX{@4n*IZWOGZ)biOlt)au@p?P zxtgtn;E5rj5S>qKbmK63x4mJ=pKWa`QBRv6eDuO^NvP@R*?MiGtK26V_cY`GZZXDt za2{!7Z5v(VJfyWZn89u>=V>X*4@~mJYaLZ#{#q6*DgMZ1(EKYM<5hwa?}hQ%(}SRq z*vei3k%k1ZjzWnnOPrlz-*m7trR$ zL9pykhX#e@tr4rWU0oY4+C?h1%(fBJo5qGB|5QH@^AlVE#zV$8q^MXvm!ASpcOGdN z-#kPR#$!D_go4(lzEc^nbbGRF?m2VbdiNtPO-{vhmhWia1MK%I9sCSIPv3;oaJJmU zDCV8hKrth^s~NO7*WZUBx=OrBy!v!^HX%jL{*nK8onWw8abP4(h=>vVKTeqyUD4553yyRd%YXX;504s7-^8BQ+I3&R)KA+jPt2yz%7!lwC z`_uV=XcILcEPP;ziEf+%1&+;Qy(KQOK66-06LS+kisdKAhhrAH|3TfPB1CxKvKuZW zwBd-UTgI2^$fB zP5Lru7Iw^P*Yvdi-g}1%0{jNp#`cs)tAHx0D&CA%UZ7P{%bdofr>$*GQMqZ>bB^UX z_@5TUQA6C^+=%y)TEIjxU(J%O|_Hzd#oVxI*S{~ zXieBX7SxY<4rCsXJP4-Z{p<;upkd39lMu|GdauK6%+oR9Z2h}HDp82=PSWsj55S;g zkQgb~+c=lHFbjA!0YH2me}*}{6EriI5%dkwVC%;V*H|@ZJk4!|-3X=O^zP^#KYv>x zB{1ukCZrG$`UeagAZtz$b~lLq!>M?&0Z!xO26U|4Q4PzQ7APJe7QOGPPx7f*DvQi- zJ{-tq^?&XHB1JRdidyBG{3k~ zmzGHlrDRJzY-Sb)mn+vf`$-?-RVW{6k|<3rlLtMvZjUOjFmIbQW$BzI|HQBNGP2+hU4Obm zDaPnNjyE^XtE{7A<5a`FV>aZ-E8f|7*t5wR#2T(>)~_DxQwsX(}aUaPZaL{I{gCuH>6A^_}d=Q)6%k#5R~`0 zy9Vqo`+TA<=a(PU_LCk=scEG}a<9PZ$4wU~>LK^@`l3ydb*8E=ej3ztkRv5Y&$?u; z2(JGXfNbhvPOlRGvrgL)7Sg|$?mjmJ zA};=~7UvSKy!YO1-psVDtCY)V%x4{G-tAoEigW&x&e`<7xr3UdI+q0_9TX(`6^nsM$UI84P@R1a~uR`A8Ep)GxY9S~hIMLN|l< z%Zbdd_lym9Sc+XLw%O$SC*nctguDvdluOl! z>Sm^;Wrp!;@Vb_tn(=^pY@watpfePjfNcy9Ubf*e$G3r(hIXEON0Oy2T7q<^`;}yC z!fE7g{CfBUaT7-Q`R)E|gH z5_TO+3*?D9iq*f`+@*ANv#&=kdSuf)I&GKPSsbA}^uv$|t6UG)cAvqvtB}KbcLNrJ z-XkU`P!;A5jg1L{=bq-ivy=ag-2>?U{G~$vwVu^d6#>`tx{7%-zE{g>bXwW_HM+$e zH*}X#I$iWsHB4bBBTKXp70HHM_vgM!86LL#VN*@}W1)XxQB?=e?Yv^-)qv(j|_JAi>EO z#=`w+9w*GK4%KlSM&K!#!k}vvI-KKmtJ(6HVZDU0h4RAK^<2k$`_njZp=r&x&10Je ziUP{Js)~Rh_3te)uMJg@M#=)iq#!_i=+>R5@2O`l1yF50N|R_?T%#!eT%~QMd&ZG& zRp-+_ek@Q3LEz>v01qgH@ZQZ%YtQef2^GKi0z9pW8?;>j>`2G7rn)H^ELd>obMQxw zkl+_bsNnZ66=;~uBX=;LDCOSQH{;NVvZ(RZW6PXB%w{DQ1Sep}y&6jIsolAJkdF293wG9D`(hNIT#Je>Wn1Y$;A>gz0z+`y&>#- zDh<-T1e)aPeClz|0u00n>ktkK&&1O)Hv?9m=on(@qNGe>p-=|euVqqs`6~zMo@d$T zul?XBIMwt*!rg@*2dmJ|?}PlEB?8n}iz2kTTTN@(Ya4sdmM-U(pQ4V?+Wl6O<47Hk zoI#2Zx$3LT@5y~aX;6}Q3_1W$(b)Q6H~Cc$*tIzODVZ^T87AzKH1+N|td-!tke?)8 znG^4iOuEZ#;sx-7qKBV5)&RV6y>Ta?k2la>rQ< zz1$~_xn^Gx^O;fC(t4>#kIQ`jg5-@Va9+Rvx;ctJe3<1eC$3kb!uC@Ivsb>v>nn5D zJ#&^GnlKh^_9D7Qn^UN}HDn$AdM!~O=rnBF8;Yo;scGr`hU1FEWE31tz^8RS@b!W4 zy^Gy^rM9_R2|XiYDwFY#@7&(d7oCn<;`L|2dW)SvssjOsI4&```+2R5vwyUmIKd~F zpYXCNDJf>;guJXPw1nSW#qqJZ@jsRH7qq?nYZ0kk~DoJfgU_o(z9XQ$nT_KVf$u5Kef8^ zQF^^ZB*0*xM|DBZt8&F{+1BZH(VQdVzEZns_`BuIcA`8#)1vLF@00BZHmh03@S1HF ziU|hII#Frqk?qdC)ZvgdeDlTve*q-ywcmtFfEzkchp#ZPPgKn!S*9AJtAN{*bxpsK zv~lIasG0>zLfm{9=u5)*GRnC2A*nO;c+_$EN;5I!M=1n>(b-f}{^hVey6n{58G`eW zGsjU}D1+a!7OeG_yl4JbOEenXi);H*b>Dn-25x$v>SsTD*}+Qq0;PrtZd{7*t2~Re z%8ZKoD%P0$>t1Oe0~ddV_wg8lm)O7pwwrT#+^dGvf^vA3WJ&NbDO!8px}42Ld6<}5 zwi7;Y4^ieO)sJ(Jgabx>b6L#4jOKF4KZ}Xg8FWLW^ZSIpo@%V?`#u!OWOJ+XgI4$l z=Z*f$5p%51Yv5{SBXPf1kxWIHjFghMpDPYJ~Jw;5*-tIqOn> z3PL^{fX}b9%$!$%cj}l(-;O6N4S^EDt4t=HN@~AvOQQocX^u~dGtLCzhxd`jO!bcB zU;gmxDYwOUd|qqb9{M2mLH5=j9-txUpq%HPIpS2|e>d`(v4d{G=Z)LZ(5M?0j^qFy zn<44xv`w8yM=CL(*aHiww4^;Uf^v3ivbHH+EkCt<(gB$9r{XkQRGnVvXK*i(3c;)84|^&FWjRT>KRW zu4@4)eDpHtc#%#PODd2BN`e?}2;t8o$e#LlH=}(L8GqFMDffg3K63-Ya#p<2V|8OC z=fR~#1;oPf%!387j3t8MZ|X-QJwH~yYM5dcvBcjav-j^*iPaV(aGtMsUB>$A?lhcu zYDn0vy){#>LrGL)#UvaUmfp^7?yHSK@!HK2i-Zoo?Ttw6y;F3d+YO#(jxixai^sEX zSLA=(C;h-~lNOP$@7RwiyXZD4v{bu=*K#$^WBPEpBi_uY-6-?p3%>Pjm;f$1rCd^j z^};ZSiGgCr1?-*#4g&e^R!HRqUcPGzT5Z5HO7*9w!Yjq)D*%@Z@Be`50lHuwk`~n3 zUALfuw=bfi`8Oc5&((9mmoOLisKKZH0v+bP_qpCY76u(ygv2vRUfnac{dMKzBy`Jh+zzPtZ!&%G||w=cO`#{w@1*`asR6A%Qv=G6_SB8 z&%wTQ78~0qP#AxIHGSUK3-32mk9fI=g&FvW?CN1voU8|fA0&eT1Ax(oaj($J7{N&3 z%-w|`5NK-RZ!WzMw4`2Fuhz5mK2EEE&xFVFv9i6l?T^G{cHWf<=--W(Ac$`}>s-FR z?S_dGBvN}V4 zn(iQN?;X_*QX5Lr2CFmde@t7s5MHt9bg_mF3&r;!oF}nHn7{Y9co`SlJZtVI6=>tW zf|Z%(o7i0j@i5T40oAJOlBC}+jji89aC^AZ070fNFY{ED#j_5 zYGKfmT%z}vYqbjseNzgd(Ezs;tH7-NrXi?87wJS6>`#^zK<0JhW5&WoG+?$UOR@dn zYvabk!}2ud=QeoNan*iieg#Vhvwl{q5R&(arRr3 z1bootj{$xUt91EGq$Ing8wqv~gJ9*yEIUSBjsEfwLJ!kneIF$i46TDeJ$8@XVt|y( zV%blc=cY)P0ZmQKO$SagK6+gn$Eij8dp@czGhg4%6~_Vm%N}?}NpJ6VI*l5^P$YaB zcI};)%cqyiQI?6pLa9W^>JpiBBi>`Twu`62wzHIhTtLr#UUM_2<4;=tR3X^NiKDq( zl6TNZNy)V8ks~|IjZYh4gxkBB_9;c5Q>7j7y!aT!oZepUMz&%F7(ja} zd&=GEj5_-cpa_Wfh_sk&$~Z!;{$`O}o^!sN z{((JRfL~9Gz442$ZD%+!Jcu`Dkc}dE-njZ z%J_vaZ<+=vFPj?lJgiFPZ%>dbzdkDZu8dP8R=W(#^DGu|ceJ1Kbm`og#A9FtHwqL4 z$-cTtw3CsG?wM%m0=sUPteqZqQq`%~9fbs5u4kAXH~Y|`+B@Bw;GQTWp}fP8@C(JF zurRZ$oJKsa_la4|$CHACA&otVP~!G-yvA|J3=I5zb-ge81J6$PrwVp{xvwRcSG7um zj_&lb8SEwgj1q}mf9TO|NF(y~E4H89oAM!-JMJ6sfUw9r=kdCsLfWipa<+DZm`(OPWwM zF9skjvv4&1q`go)UCZDBAIbB#5-H{9)rCCnH$E_%jp7KAb+(#Cx;uBsX0i{Nrs`5G zE-pIlWxEdtA@fs}t5>JcR<|pC!RMg>ZJ===6gg;Gk^{FF-eUQESCmB-paFZ|i;Ld{ z@C-274PFpR1NVHxiFYqCA*#_9k0j?DdCqTRIqS*v;xC-K!)8P4TKDmbC}vqJKmNcF z=O+`9`WM;$HQ``1zmTkR0ds>jh>L{ zN^On{=wJwbx_q68-^^+mCCX>;w-IP~GHdx8A0RHuxom=%78`9BzYZ#ky^~a13h`H; zLcvNdXE<`&CU29sZ{lkk=l<*nCFJG)ZzcVZ?Gp5?3VrOVm)#X~M;aD&R}jqGUwhEj zJV$m(MowdnZ$q>iw^Kz)lKESt@puf>e}Ocz4%V10_F`^858dJJBI_2(&Eeutf+%3D(A&w4dOqsQ}HgtC+>phTq2(z{li&xS`H+3urX z`s;ChDi0w?jfm@sMvLd!lwKu>Ayy$M^o^QLn?;tMwV&W#XpnY6{N2DTw=qTECLaQf9o}Xf>Pt2np*RX)(VYLG z_p=@~otzP0b*8MI!jbIv1dWc2@35a?GImMBSpo;Y*E%No_6Y+;;sihx!R4d~@_~Pm zg6~C?kkgvaozy~=Zp>E53)Ch7|HIvypS~Q=32Qp&u#JGrx*uGyRA(9`SYhmQK0GwU zbbGNG#W>uspl4kn5AFxS&hSUS2!|#5+3a;^XZ&Pgg^BU8#nkPq_xDoH9$Z6YWAb&L zrlukNxk|$#GPPJr*`Q3JBad}ti~R2UmXNyQdlL#Pq^)gKq?X(EPqS_p5n=vb<^}R* zbQjXat0~lY9$h})M0|a!l(P)KKoj`ZOYXkTF!Fbu>YQmtB*}2b(H*9#ji5-EuyyeWy!V&{HOa3_}d_fy@SQ?)$@N$>3nUw@7m6UiKcC2L= ztk&}~6f$WBfR)6A>(x0&M58ymN~@q?HBpF3gUoJU7G~z?HR^Rlgy(VgopU zN@0*%gj!AQWI3+A;n(&~t&n9Yi+d0hfb-d0UdLQae^)eNKm7(2u%jfn0S+8^)Of6D zg-|SWW8sqF^FH2@cpTvKr7y)D0mddo@>^OXnKTHEd=~wDF7LJV7C+$989By~p8b5E z?{i%bRks^u^c0iRWl4(9tOSj2xNTsBJ;$!%AcXN@f+{F2?b}_zVNJg@(Ad8Y#B&wY zjZQbE43CdylS6zAgRe#M8gpIHr7RGSNl3yN)2k}%=iZ0k{oymyXPfu@o2&QM*7{- zIcLeM_CMN@g}L>x*L)(z2BwsmlGW3xh@ycB)E^=z84Wj^9yxF}S~hCWqg?1MYnIL{gH zhffBATyL!{?+{Q>Y~L2TUdg@gPT8EmP+SMh4S15$E9^{=@y5ikb;*{S>^aiDx{#I4 zq%|B;ugflZQ~bV2Nu+cTjgk~BCsKHyY0Y|dGjDq{g2)nOrBl#xtk^FMr0k25=~^Z3 zeF{ATqh2o2=m_;kPL7`?o7csXHtGlWOT>@M%w?pD$QwA);YW^j8Z`CEGO8BsHQv5O z#yn$Lr6cr^fanRv1+2=h^W!7%zQmGv*rn^YYsnKJ7Dbt@YP<-Ne0Ku~#4mO*y61l6 zb{YH@i^Q~yf_u!^Ode)V*2|gAU@WTntClpO%cvi&;FgEv9K@@2Dki^21+P~GW|IA@ zrBKSR0|VYAWMWZj&>j#B4-WfxB4EA1P(bKSB_OKNJ{g5Tt|^?f?>hG)N_;6 z66M@}<%A~v8eP?bAy*N{5ffKKCG#g~Zc-?hvWO7aU(Z7^VC5f*pGJ_-}6l#H;$A2jrUdW-%4|U90EQq@I35 zhc50UIFG9nRiy&HqV;spUJ)nFsQ6Icu-u)0_JKqau#GQH3vO+EWtbMjZg5aC#f;PmP~{Mm z$)j3sx$&Li*FFxpoF31f>a)Ag5#JdxZPmqr<o&NbSn+b|?>1?Zc` zq3sO@OKsj|wZ$M2zA0S~p#o8pGKzL?QXEd7&R>joZ)3E%e%e<32eac8ey!cq=EV{M zk6&K5ZZV{#NJj7qmVd;!?hmL5gS~l-<_fGyYW16_hc~+~pe5a-sV7N_fa?c-Vf?ML zt{1`>V7Z8{#{(n1>n$GFM%<3!V|v!unw} zPu5IQ5sheB0KtS2A`0u(?u!IVy2P9K{aEzn!I;(PVC{dp_!Oxx!b54>9r;x;V#ULyz-b~=2 zPzkUqu(X+2qJD1@B)&SdG-&@>T?yz*6%}w7yR-A zP2nK?%;jv{(ed%f+t-5Dt}#vDhploe>qRY^&5h3jd}9<%2z7W;?`0ENnYDZ6LncRf z(2|OdyqWL#^jnrLaLBTpQ)G+ZmdGvXjr>R)9Sss7VII`9B8nXoDcE>%tL)H#9xo&V zv;(usVY>>k&zg2&WSmxyh)j2b=D(4}0syJt@gCEHXvOeCERJd3R$Wi#E>C)a^jx~eT%z(|ZED;~69SMBubDplTn;k&7N5T~N$sg2IWAfsh|W9v z9`pZ36JRUc69UangT<7vm2(bm(q&Gk#xLyL)K(HBSMj_D-{~ncje0Lv&RR+73Vx31 zm*Ucp_lG}r9n1YERxuBJt!#P10iv6^I;Y8V`jD<@dDF3>KsgzdgR-Gwl#6UW_JjQ| zEM|7Lg^7Y+@f8EUDE?|Xbbj;1?(Q2>ac0Y)Y4^7+5^Oo9`U|+e^Ks z>cl<4?=ja%^-phygGV&euPm3MFm%?tk5|X?Ugw}Njr?BaC03|i6pnCapBn$}V**xx zJ{6{q8f$9zJ7ig9Mmp93Le4%;X_;5o26_IuQg4ipzZ`bLb?^y<~sUXfvc zgALA=Mfdu)c_MMmk<;;N)5Kx1P^KNbBApH6jJdX|nHA%xD(rr> zG#|OAI=}|YB0g0^LWT#s)G$ivrUl%fFMWBs=PsjOhLF5o(+$~5IENQXtO-U66gWO*VAUPu2 zF3SDwm#ZojNi!k%BMppeX*DcRLIgaozp={M(NWVY^=&xxZ5A}k|Aug)fcN5Ho$e}K zz0u`^Z6agtTILlGMb@Cnh7 zR$j_EUv}{yIK*2{b8T1}lJr|8!BjKw{Tz`^7*%$DWv!rPH0EV}c3c zVESDhJl0IZqS1C)+`b{8w^blcB@hz*r=`P`5U{r-H0sO0yrVy454pbqQ7}*0I1vua zG6J0G?mReeNuVEy%oI;B`Q;Lpi^~8W4p`ak3I9OSS!)(v&_~91 zv4OVj`CE3AHLySlMEn40ca*b9)S5k|cI`JW#k`vb7P+%;`1Dopx?GRk6VlQwUUKTg z#62iQH?N$o`i`!o>sC*D`UehKpPl}-m{k!2n=>O?H5?H;N1ijo@u-eWYgi3>Jz6PE zwCXm3A4{RvMj*DRw5#JtM*VccD#;r_2#3xf*hlJ>MY=!y&5`Rjl(Nb|Od@_WgT6q* zdmrdaJ&E{zY_^;cQU^!3)s32-w8i7ftXE#Q`b%Io8-s8-Kqu+Erx$%q)RxUHC4IXo z=nwJ;!UE5bHlQbX^hke(S-HWy*3L0PK)Zms{YW>rC_zMS=eh4MW{i2gzjC#hwu?6@Bk~y|nYXZnSq%%p&A8Xgvs_-B zRMY9N&m)pm`dvbwMkuvk$o!))I;o3i>dD&7|Sbi2j2-$IOx{Vtx4B{)%^xP876fdsVt^ zAfl_&lY<$&2 zkEf@3fge8}rw#H%Mnyt+&LrE*n7i zcAuj;m=+tEuE}|I6}PQ7_b#U)$ss?LKc!Y^c(iU2MGQ%TsQvy z)U#8n;jS<)R{>oIfOUH=+*h;AfEEP@Bvkh;`d7|=m^`cPJfWb-5y@iDKzl}Q20q`* zMCId89-IT{KtGTns>rBu-4=%2FrETv1{0Vl>d+fAOJ@MhXL?TjxOx7 z1X{y16E7ice1X<8=2|Y5H2@heFq;gbz>+|mT@=1grPHJH@mso^<+mcx<$}161>3|g z04NVW`OuuZx~VHqikxS@1tcw}{bAI>VEdx|J+MC#`opw&gsmJnM9%DBU_-WbnicYy zl>ifXUhlUWn7!{+%U0PU<|?r=LaIAy-pwla&O5-Sk$Ne&2L-oOY$$ES|1m;7L7#lu z*pU{@oL7VKY7G6n4x+l_tgBjnfaReA+#OciADlKqu-SD;c%A-0?BCt2`4j-UTp0%4 z0K^cK`QJgBPh^mbFm%lJ=$bA3Yd!f_Aa4UrqtT@_y2CXKf~s+n_ojq$N1fDn&LQG_ z@W1~KkOcNXV$thRHLZD+C}OSbO1VOp$feUXJ@0a0oiewH|F%^5M~aB4z~jYw)1~j0 zUzro^+^x=UmnjGPBGB;|PznB^$v^8?BMnFz%TL4d_Kb1pT@YPJ3FzI&GkFY}pmd*8r-cJ;t9>Tg{8rzNZg5Ft=dPDjm-mmoR{gR-_P zWOv1RB3V;Qy3XTj7ZC>$Is5;qfQXS%{zuGHrFXMg!xUHVJCI#JvIwxGq~!l^={)YI zD&PWg>~fb2>8ps#J3#cb-8lQYA>>U^1IzH zankdNkwx=d+YW+yiQoA0&o(yc59 z28etmqN21^hO!5&-!!avP4F?B9pgB1XCvYu|G&c{0^GYA0!@RRuLsCceWex)es9pR Y8#F9=km~E8t5Yy3F*(sHVS~W`59vG}*Z=?k literal 13157 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 diff --git a/packages/flutter_widgets/screenshots/message_input_paint.png b/packages/flutter_widgets/screenshots/message_input_paint.png index 555ce9413852c93f708ba2e91041f268eb6309db..d6cc494760d2fe9ce3f53c2c4544b141bceac98c 100644 GIT binary patch literal 32207 zcmZU41z23W)+kV%;_mM54#lCxr8u;>ySpC3S47a_n21TUW<|gC(`AAp2p_ch`IWac|OpD)U~cmGgET@bloo=Gi;JB5{>DG$mN$<($yyPy%0Kp1 zb9xKOLviGL5LHM;*}KkI!BksUxwp>m%**ECh0Per0b$tZUkcV2W; zaz>?h8}Kkh*rLTMbn^0nsZg~Vfpq+^M#z9HQ+@;$h74e+xZ8Mcj5xa{<=sV}UJWA@JELX13>hJza4M1^ z8bR?mu{SvyE%kQ~FY0^pi_um-sRY83x*=xhR&>Npn0}JFAn18LA%0R8MQYJ(`jNO# z>VpxuX3jDL^gF#N!4^HRc>xHZ8q>?a9~m>0&6LK1ZHjQ2#&qY3#>Q`yed$n~5tYFR z5osR-zP|p(evT}Lhud`!xekfeb9Q!S|4lZ8lOavLWe250l4_6i#wO)BP)T9888lnow zqh7NbDc*pmANe^~<2OkIig2KTqrSSmRcK^a#Lo6qxMK+C+@)Pjny=fys$s?OohyKNony z@-8>k_e>{P znCrg9;OIt`bL*C?9sw4ZD@knIn#$cO+_G;lPS%$98x4QQyV$t=aJds05Lj_hJQT_^ zcKIZbFiO=n*WNFwVl{z1xpQA~dXa;b!sPqd`iT0l!>+?nqa7&W z3fQI9VtDYgcn%4Q1;_pI?6nSR-u0al6bzyaUJP(TrXG}-g zka;F}^liPy8)l>Ja4cvzbZy;Mk5P+B5(majKeH*Zw@<`OP)_Xb=}zcQJTloZCon}a z-DnHd6ly(andwwD+0-64anuvoa?h3x9#(NLEf48fbS^wpT*DFSW?*H6@?7(<+92ET zH-$EFH{G6CxQV%`9hV(ftze$`9y=fNE*m<2AQmDHK}kkQAy$!Ll>zQZ4>fItY<2Yw z^p%HgIOPk}W+G-l7W)@^cWgcZ2#?%l1d5i`C^^{$09&MmD8~4`zvK@iZ#^J{4 z>zIsS!l}xclQzK#;Z@&Q@8CykR2kI3A)2_AY?rC&Y$Rb_p>7XPZ@EsZPJzzKj@eFL zj}7qjb;PCiw)14lCgHZ=Q1i%bK~9Qc*9K&F_fyuB^OO5yH=d=SDx1^eFfAkwtkMG|Sbg5QIvfN6)CXJQRy3Xnj1OUZAdGB|$*X z%x^2BGu2Y#Xg%l}eM@A>@v;ZKf-p;ynPb7l?!G-Om!8;?h*FF>qc-DS;=ecORNf+t zpBasezb3?E&wNHLn%bSdK@X2sfh9EcepoNfo4L(Cz`BeoD< zjpTpGI&uO+0>vRhAu%9%mCz^&^C@_zdn^|npv>Yb`5WLF++Du+fwh+&lfO*6G!sc5 zNN;rI;Se--8zUOyA8;1flOA8=j^ki8U$>WHkz$NmpHNEM(6Uh#YQ7r@0>E%n6Hw12 z=psGi+8KnfVlZ3jA9s1IZC4jP%^;bwnC_b9q?~`#yBoPKiOhLOF=MgS-)pp)b=r2i z0B0};eLmJH?W}XyP1GpRoUb&iV$pxLn<(Vo9}^zstuCrauC}cPR9R@5H`?8|O&x_E z*{g@CpRRoA_<9kBN_bCLZHKt7-o9kwytJpJE2(Q|AM;B`(^O5PE2gFL%S!#p$ja2q z@ul-MN&&H{VAnC$nau`v_mO&|yX&>x&f1vOPXbSc{p<_xs$=A}73CxKc2`nk!zI5O z!>-pj!x{fpPqM=gV`4eMjo}rjwtVuUdOG2A3e`tdxC_m^g**+!_^yRT)7=;6)sx+) zHXQb4LS^nQOYEby+s4mBNO8AZpVHeEO|m>@I7)ZdM`~%Sa|oQvu3hF1oXvksWeSZ6 zct7d&v=(3b?Z@ezw<`Nj9~rGtPkjpazkE7zDA%-JGd&wa*7T|7YKpNDbmRVg7-5~a zIH|X<*X=>MC%rOJn9*z>(>?E(;r}?0wJKPBhO>Io&U-7e<#+I|5^fhYhV=8Z-RonQ zTlGyroH(hzSLXTMI_7#}ijt|4s5_QufiR=L-A%_s=t@-aqJ6xn7w<~rN`n7=HlhK@A_jGYEfrcXS>LQkI*Ci z?(Ah(X^vbDW7jW#%O`^CYd?Pj|LzdRU6d!pFEx2-X%HPt2oTKJ5CTHYDueV>LGOa- zrmEk;KhahQv7!KQAsTDco(AhPAb+7|Oy~_0zYo~P6=BEAJw26Bpstg5=cUHQ&JKa^ ze15i9fFR?BI+t4B*l4cpejRheJ0^xmFQJ>tMI`^h*@uG*(`ME5ihU=Rv_E_1^i&HM z2`|(W_uLK9I}o>>vnh1)W_?7OYRQ=?C_pg0mEj?vAqgO0-b#>fNd%JcpRzP09mKnT z)k8r*gj+&D|GSUkTmI*Xe@lO0{>tAagh9Z){lj=m9=T9|_l5%JzWcij;rG@CA*LoF zC-;`C89SMp+BsX;yA*vy&3LOoaFEq@hJe7K{*xf(RH@G2@Gn@ZYq@AC$O{H$ zu{Sbh@vwFHg9k#$L*T7wYwGfq%){2k&RM`inBreO1m4Pjs#z(>{?*0BT9`shL77a# z-pQ1VhlP!WjY0&GjEqdk$;3=RRZ{xj;BWtgDJ)!E90XWd-QC?;+&Nk7oy=L;`T6-- z**I7^IGEphFgttNxqS6twsWTZ3(4PjBu$--oh%((EbZ;c{^0#;Wbf)COhNHypnsmf z=4t9-`Ja*Ood3P7w*|8PX<=n&VPpLV_Zz6tpIQNBOAk{UZAnYpH=4bTA;QkVBlNHS z|EJ|YBmNhp)_)**xw-xu^1oXC7gEF7)JekL_H9TPk^gMhzk&a|@!x<#tbbPiUzGTZ z%>Sx=qq7L25bHmCCW4ri$|?G`jYO7`O6qU<+adec^QVsPE&a*g(udi5+CGoB970Y~ zOx*+W*cZV=V<>IcGs+Di5G{%d&8WHe3!B0DsYe{9&5)bTPQTo;Bdzd(OL4uMzzVPM z+QDgB_QAo3ym`WlKt$GnM^v+it>AhMGLIR1xi(C~2eJunk(ho7@vtGi#oNhz9C5HBSaLdsE+e9?>x-EsM{zn*xO{S`r=%`DS>O7y5L zt35_h0^$>8|k=yTadR`(?BzSaJk@#t3Iy6`!; zsC%-#`l#LSlIF@AoI3f*&#meRR)?20tSma|BN4_8?Edth92sLhg4 zG#S*$DZi(LucDu(%<18aLU=W0DY0+Dp}XO}%k3%3#=%3Peusc>_@rP~7cH>xtQ1;g zY2Mxa{Itp+n!K*L?q6#t!G;>~TODz7N6nh4r|j)oJ6KE{#4pKF>S7Ev(HZG}IKApq ztj_W|qdFaYKWm#RM_@S@?tXhZ>H6{0c45ks*{cq;G-@CZ#@+lF%Wn$sXhcazv}Cre z7V`D!J8s$j`=4Aq;P|cEf|Qj>LD~+HyN@4JtMM*fjmAONbAk7==DF>*G@`ElXLik} z8_=H*Z(ShVFr9?aW6M(nw{{`KH9~TgXDJo=4V7rp3z!9Zy>U&FL0jw6>VXuK{ z`0p|P0A)_XSEQ@R5hxkEj>(v4^1`52ohSVnWgNAQd6sP33{b?{ik zSdB&g&uB96fi0wfL`?6I7}By##Y4pmA5TyGi3^e)FF#a$>usuY7(%1r$Y^BqD~DLP z-Xf8(9Oy`%!OghX7$4t||DQF4d_bi*ldP0$Tfk$m=LxC9xleSc7yZ}E@fS7!B9An7V1r~=M^F{F9INLi zkW8c3@dWdqE&W6AzbSZtF8c{IHp+nE^erVP#A?pVohOW=n@}iFoQuPHyPS z7^oV_(nkh1N9oJd`yF@wAB2|Z4w#;yIU(d=Q@!I+Ja9xvN)c#M+hbYm(lIiN? zjP=Qjq4Y1?YC6#U>%jiKx@a~iGv@`r)1}1WF^Ua*ne|pXHc63jt4Ajbpy{eN+`m3CcVXKEN;c|BpI<&VQ*y&;I4+swD}?aetwUDtUOemgYdm_{j>Z z(G0DM`$T0kOW(2o&X0k*{b%ri`#n19yA0Bp_~D$<_N9jZLmtZTfH>%v1kZIb^!xA@ z@}!EpK^X%Qu-<8;_uGEA>eRdc#UlQp)ZH*88y3Z@!@LV@89R=r9lR-@FDw)Io#Q#a ziR`S9A8yZ25%IWL=g;g@bcH7+0ClXUg9TuJP*^3I|TaNruURN=9JM z>V^|rD^?8!O`X-CDLOqjl42G?Ty6eLf!|UXLcGfEXcK4lA6nW7E^gfVoxt&~H`=KUPf%FjzMYS< zL@s_}xY^Gmt4Y!52t&1IVeQJg&a_OTl)q)0t={r>RU$?W40cq1^2XvP?okoJt(+AG zOq~Dd1IQVe(b<>buKRsXKrI@-A^7JYnP5Q1WI5l-jFHiD%F51mhoUcKedt9bMP$9{ z{p7y81)tcT2r`LucA_4#LP;x8&+jEmZ?=OrHNvENti!^w86hQDGtO~zhBnThgPZ;*kSU5xIvu31meo&i=yhA{$1ieHa;M@Z33R__&syia@ z2Cw0HNu&x3i2Xk6xJ`RBJUDH39)6VX-ZQ4UT>97+PW8R1>0~{sr+%tWtutIlmCy)? zR_CJ)0O92OF6bp~IMYTljB+Y+c$>d^Y((H!QOoL*GdD z$3G&*$*g4aVSHskpY_~evV2gd`aQF&er0JpGE5fBL;r6|;yuCxXgnzqRxc9i$_!?D zhDa@n&Bv{q1jj39vN&2hLfSJ_gx(8dybx*ijV;M9n z``|bswh{*+s4g4H6c&ly%A5~&IvhD4YEIE~h7W3t35_5L-1^Ax(l$KS`5F`|dqBzV z`6e%V=HE%72!gvo(B(Th!*U$rAVxWmFlY!Hdl$ip2#1QZio1&m^+&t$V4dh4MYfMr zP(On`i#GNpo>3b@X<(-;6PEO2tuesWB^5DhXnT;7hE|lcAK5YCVcT-|{GorwD^kx< zTpjvH3@uumG@7yAgd`IzYu43s!?w(K7@UOueXN_j=WF>HKSF3I5*-AvnJ4E*P{A}^ z(A=JTbK@5L(Ts%j=@gifmlpTl=lt1nxtFZYMyc^{(b1FoApk34;gAlB=u!ZR7`_s0 zJW>y1_N|>U*yzs1dbn#ODrn{DTq%E~0(Hk?(X|Q{1$ahQa`@{LB_8uw$;WMw{)tQ+ zg|s*;28(saRoJnfVsc`J)OTep=iU<03`uq=*#opZn691Q?BHp(MQ!PkcOwY*tcMT(nl;+ zzmq1@X0`d1X_eNNs^;I})PmzlZwe{WGvQK?7%FboDT$I?`{Rc=7NAEh@6#eIY^J4m z{y$=HkPM38^+yakv;lzPNtI|lxS?xEO$+(H-5n?X)l?MxZCYIvK<~f{tlq$q;ETUX z9p=J%cH~)`+OjczJvJ$Ui$?u?v)4Cui8diG=O>M>@L>YVZ4P<0`R!+<1sMv0&l`eJVptQ|Qe$m& z#;PWss3byw55B^PW)tGQg>sYRmn<9iHxk$I#G)vyjm?g;j4_W=af!z%Qt)YNN95O?pa$pgH%=eMCw0mR{@PJq$|6A#$E=^FVf@; zZPAx~&jU5Br}mbG6j9`WwC2o*0T>rQtYlJ$kD>*CKNwXHldkyXX~~?j`TIWNhzC^= z8NcE8B5cp(*?7Zz?&vIv$%UT*A8eWHiWPfXEcMto-5@Ene_s5o-2pg%^LwgT(t~ra zD+x=~quIc`(z!^O9pn%L9Z*&aPy;oIJSVC=4k!&dj|ZwKz%W#++V~XUuNe1VXo0Lo zZ7&7@pWk=v4YNa?p&`D9;N6i@T-=AUtDY|3iVowWgyrf(z6}rpi!sw1qO%wxz9EfTXIh?@< z4jZ0rl-5aq)2r|SI-EL^BH|dhtF4&KF%xtKJ}8WKb?v1yXTl$&e38YAXU5q42BWKX zzH+DPx1-yj8c{@a_#CboJym?aZ=5yC;WYm|Lvbe3>qo)?l|}{zho%t5FkN_kxO|H? z4#kD9T6$S*NlX@X{`^NBD`ADYKtoO-`~m+YfHQ>dCWp26GV@U5x=_L2QkGTTbq)04kcX-4Ys^j#mSD8G*6x_rH| zH`0RI7}&hPq}NBWQ9dAryBa*OoQRE^=Z4FO9~V*9GD!fRWg&Uqr*C0x+jn>Qjbj`n z=`6o!=|xMY=b@MyMLo!>zud=M!in(6BMBY$3AFoeo&zn-9Ag6>C2IC;ysW8jKC88{_`2_R+S9lyA-S( zZql7%c_WAflWgOwy7(i7V-Lz@ON|_#Q=`6H=Uag&TS4z5 zF$$s3_9=cj$e@KrO^Utr&!CrwM`PT7Z1ePP3DB(KM$iG_O9865OIU%L%){ZGS=gjj zR$?KAEZ$%$&`e2|nNI(2r!C_F>uYB|R#Z%F&&V&^^0f_T%fYdGpZocI)nxq{>&sf1 z1HM0PTb9PL$7Gh_({bqJ6+lI6t>x765-4<>ky1qAK<|dk@DmSq$60;&g6! z4kAC(h+PaMx7SJK<%rS4wq_#m@gshx8A(2~g6!O}%(vLtW&uT`?;cmnSi@5mw0=5Q z&NPaWZeM|xTy5dWpP9ZU-nkc%RczqehYA7KFfjD>|v z7o}7pli`{yYUEZM561;O*<<+WHVcj^16^vO!+MrBAO9n3gwcMA|JsyJxc4_^i%;M& z@uiQH+buHl)wZX`lcP8TiNP+iMfen!BB)e_s~3tr%n&H1kf8#&NMzWmAz&_X170`) zryJo+IFp*n!`DEr-!lP>7wk_iIGrqY_**m?XOxx^?xP8o6!sR;J|Ne3+MqN331%>g z@(8#_o+=oDB_yfHU^z7$o76aT;ir39TDtz$977n7mAF{`yX1Pa_zGN_Y8A@7;(h8? z-o;i;trmMDQB=Y}7s;3KOaTN3!QIUad-A4kf(Wu^jlDh8JfEs4LnoG}PdMaa6K#M| z4TO>jerw5ZlTJ=xIF$%leitdxJ+UHKwuLKieVe{}w2l1rZSV zUs|Yxb|$F$fFCwES0ydD038g2Xc|s!eD`TBS?`^;T_~=@TSdS>r+4V8GK0TZqb=p( zjHmL)WC$y4wwg3^z2GaBz`NCr#!-}vaRG68vcVh}o(iSs8wW&ws-gG*Nv#8!xU3Jk ztr3T5IY?Ta!>mk${YHa?Q<_PMfrUm>BUn(Sl3f8G7n^U6rH7DMDH`l~#i_0xMJie= zQi)iM>`b+03uYNqUP`g)c5eF94V*tkbFwH@cLkmwRXa89Lgz>86|j(nBNF@YTQH}E zBzT`nmo}L;C7*;%`ZfKff(FLXK_L?5rJbTkyG##8B(~(lLdh16TA<(0`S5KRQ(e>Y zS^H-?Zar%+S)dL9HTg)W2R!Lm#t(ELjxt4;&q_juHC?1D(bGr|&J)#>9pR1@8E8s?%dkK;O&ho$(F!_Kr77^d6bw>748O?g%LS6&d(QoWO-L0kv4@5? zahDL(q1LyiC{0 zXvFj1J{Fw7Swu+SU4cv-LG!#(TXxbLkDGrs;gj?u%d}?;7~tP)j+%wR4|?F+8F7{- z?{0yPICgB<@Knw`>uY%euE48`89yYdiG#)%@%$2gGsy4AN>?7_2D)InLq$5dmv>Q> z_XM}{It%J%ckidsP$<_y~&kz7_4oc0gXlbqQ&fP>FrMpwnE*e>yw&zoP7jJ zZFtITH_&l)Uty$Y`{U$Me_}gwHe?gI5U46`SwI!}a2K;Ut*#k|VAz3*iSNGf-`+Dh zXsox`tU(5oBB+fk)Y)yy05y3y>d=;I{|Fv6tFLGQ*mtlEa$%orW8^4`6KolZ9wZY@ zluX!14){`1Ed1*X@rq(nqBBov&3Q3}D)LJ{ezDGy(VEEGQKaj^nisOIlJ^WRYz?BJ^>h4erv8A}T-HRKAlt1#o|6(6+N>)5J zq_wBjbDn`{sSd$(%I>v_KH`l6h#8cXQlXNAQ1T~n?1>W%Weo9$prt7!2e~b-=C(vUcl9hxPCG^+? zinS|X@Pst~%kCPT=RT0F2Iw79_{Zu+K45zk9O4Q$1Ud2 zeM-eTpa~PC%FA^uTbgj3duNfXhGBb8A9$SmDs7@FJsN&>G0ccWTn7(dq0Mx^X&UXw z`gDfU`%l6mzs}MjM+&3OUW8b*!WBWN+q&J4%qS=P0r}o%TZ8&YjzORAh*)&8ezd$I zxG~vQcZV$?XKc1!z{+3?oG*I?mEkjL=k9Rjo6tp@BU;Tg~>mY`DA zS>o)959wtpddA79`TdN0hgBW4Q>0gQo)sGn3pCW=UUSgFxG((6VJmHCzNk(?YX458 zohPuldt86un~V2nZ%~=qM^%L$C>j0l{J*a+vMu6vD7rct_IRAQ-6q23>3(HIU0PR5 z7!=kVjkd7HHbuojX@*auU6a4J!i-r;y^$mtB;KWwD4vFpK?=ZqO}N+nmDOD(8Fo&t zmD3aYDjdl#6XxKU{s|?ax$6d*6mj2-#y{}cQSV07IMq>TVnWq#S=uJMMR6-P0WRz# zsJ?Y)nK#=X<>aiYkDSHmLeGyraxy!d9(z`~C#E%s^i_??O@`kCb;Dg)g?(79W#($)K z4g8g4k7MohU{ox*g330B6lj;l_iPMd+yrn-M!%?bJHx!IlfqqN?l#VgI&{zP(v&mz zD-bhUM61~oIW|OR>#-jZ65L(kcG7ip2>P?{`Ja`mgtTe^P1FHGydeoLZ40s!KPRgSWI$rwrS)b`$rq7K z39N~{mnDf38B_G5%C~ZsB2t1FeEte}QRagxD^5g>8H@QBoiQy&QiCwzC91`SRR+y2k3xJ#osM>BbQtS&)RFM?n7nnlwv zi~5EmrMJci>EeF{QP{z z&LcYJ%Iz1AW#WO>;)1uElDWj>BDqqlfy_}z98L!$i8+ZeD0W!$T%8!4XWdgaokT^X zzDR3kKdOJ~_+R1aw4h6_2i4=(hD|;o%K%qA-mlBT2^4GOUUA;ixCeYv!+K2o$Nj+s z#kSxv)Tn`OGdQcSaYX4aFES_AZuMM@M-d2JHmv;+1(|Y4NlLr_SRzWLJfh6{`ht*q zUB0wx+GszAw8OrN1<0$t;X8D<>+OoM&)-V7R(4pz9<(Sa$Hp_A5e;*^O?PWpRSE9l zkLDzulz#6?=Ov1|-@%5mRGaNRb>*tbukdtK`C%xfzO`8yEPui6I6e^v7(QB|!@LJa za!e{wrR`W?+}lW(Oy@7yNDHJS8?KrRHPC);Zw2-m)?fX8+;tNcxbcS2^ClU~{M=ZT(J6m7TBFivD@Y%R8 zP9tcPcMCd<&}^cEEN;WIvWG&dlv1e0Jq z&_#I0r;WB9ai;oQIJq3Jhr;{r8^g7J$@unUQA3Qbi2P9Zs~8apZFjOts|JF4Q7U=2tk8Sd;9lO2g|+E*7``!u=# zl6#Gks18e#4sMTR9|?aOF&d)gOx`vOSg9Ce&5v6EoRVS&urF8Xv8 zU3u02lgW48k;qCUfRdP`fd&jv5SfgPlQF$$G2jnKjJ+hGZC&XeKKf}g4DkwmuVcZ4 zeqUD?8IrlXE5eap#f<`-A_u;bxUVyuHhd&C>v~Dc3%#0uZhz-we|ECk>Z&Ob5K@El zsJ)elSnqhL?_S{XBV?V0ecAlFN}o^5A8W`07{}T5Q~^fN;xI>i8dno2H8Z}aM`&5z zygkTRTg#luT6?tjPMw@ei&c*%Wy_i!I4JPd$FkjsFiRTt57rXJgWn8WCIHo8j-WP> z=R0U!&0jj)>WkubhP7I%UuW2VnHmqJ>)iHg@UKBh_U0|Hd2dM!Utz1&)t_`cRc@Y3VB zS_dXcQYavlDxtDn`nS|2Ackolr>`!}qur~xRK6)kn!DT$p*5z4@5*>Pqt3TFTeiOGvfUoT&}%q> z7eBYz9T%eBZ0(`x_)5{Jjuu5RsOTlFFW5!+>_t3z9s?H~_4{yRdA=}681Bw)iS&kR z#g&BnDR{ZYZ+4&mI-8cK7B+uq<&#Bv;m00m0Uz!T@4zZAH?>+5n(JV!Iyxv-U7s2* zB=n2EVdN#d`J2l`dqPWsUPBBZk?uwt8nP`0YIC5K&%M}}`O#kQ{84j;8QF&N1?%FK zI9{Jst&ayQ&2;znDI|ld2Mq~fNSzqa)Rn+G zw^X65h;BB174^9fZE^UDT~?e@RB84J#Q6!tU7#}QXCWH#wAga)il{ke-CL%66+mK* zVzg65z;(O?OK-TOw*LiuRnPA3#IvWsXr^D1Bj#9=cv>$3;uhu?y?p-Krn|iHubBJ4 zBH~ogCY#G6qWP62k;5_s2PrSlZXWJ;2Qwdem(gj!Dg=90v5iK3-}Jw)oa5|GRsKj` z+~|qP**43;5AQ+x;Mk&WNxLtosusS3PHMz2mCD-*?R@Z!k}?nH97TE%=gkehs2J4| z$vnw{;{)Q{(wSYx>3JZAtMOeUkk8Npl#BXdiUZkh*k(p1vjiQ3>~Ik)sd88~@^Ku; z(>USk&8MVCLNKJ6BaLsHY=5=c^6FstG3oOW?z8B88TPXZ)uqVMrl@wKLpSN(NFZfhC$<*e52Skxn0&Bp%ARs|x9fiU5<&Vyp8%S|CsCU;g;Quv2GVhUFM z=WrLt|6+Evkr2TpoAw2c7QTz66yS6e`zKp8prPZm`6}nOWLMS^i07z$=e{@5mWbo5I-Aq&t_`{ zS}1cwpnZPm&Aez=Xp`}E%bUfHzRfkpSltm642L>Hp_CHEMUWx;JXfmbI4y;{mFYam zKFfaexjXcvz1;CdYRsWG6t~cIijNr3F}h-Cyl4|*Mh(lDb^~-j&6%1%*w|0WJkDNr z^5zRl-=n)Bw)&Bmm7#L^Lh5*Zy=c51B=yTxC>oPkWI+vQvT|Hz9@JZ{^#|9X8tZ(T z!RLP;jW?e`4*<$nT+NO?Ti-2V0f<=)w0tLEy z-xw`+5y-P-jJx2t$K-iljnfrRE8{%849?X`fdu=M7-Bo#4W@~MC|xSGANO?W()b{? zD^gPoyhfN7@MH&YRXN*1+flWd)tGu;S_3b}Q&_suOtG<1ND4NHaqBWgt%+!2jmLk94QtVYmmTfh_s3_TSyn~PIxfd2 zy@ToUh5x>yFo^~&9XZUnx^2CI{B^Pz`sHhgzIFe>y0{pU3_@r?)(LV;7~p`DhN##zH-7_SSu_FHlOPX*c# z+guj6?MW$uXC1RGIIaGq!{*_`)muSPuT4gGj-V`W0t%%?9P`)@yB1%yMo>}VRQzio z9~ZhpR%Mawx^FL2RSg0mo)6+U4SXcnVuKs-`s0H~b}nW2qJSx!=K*?evbEUgy!9dY zs_`~(O19cWTg^NDz)`Q!Y&>k(Z@_Xrc0v|Q5C<_2S!MdJkim5b{-ZAWAwcgqm@|`sx)5UO`;*|vGxo27^9`_T=Y04jMLu*Ci@toOz24i#%6jB3}I2O$iKAp2n<^Nv}1WaEfoQ9bS~X$xcEewcFB-ZAGuqjWO!*gj>P zkWmAluja0v$5v>|&9XJQKV9>%yA|!u&=`!2PL3qBW*4}5)d#6y`ATTR_e6^Z>_ooO zWLr)SrieR`M83IMvFDBQoh3dyYi?WSd$D7ckeIwNdYttkr2(R{bq4Jh&~-2(i85T{ zM|FIzAVrb9_-c!Za<&%nY;Ex49+#z$JLisyd3i0vTkdOlb)^)ggz0?aW9uC)9E|6E zi-X-rfW8e8#m2|m-f@4TrUV)=)M>?y=39~ldX&gn94E1Bo|cz> zd#sfNX--qH9yAOe83(CYw=mMgEdJ{*7utY`^MqMN?L1TFJ{4~`^tLcNW#3Fu7L^}M4 zgE0qpZzV`H)Kn6t1j^Wm$hYAxnd(ZmWdf5d7&7wSE{k>F2{cVTpLGSz_=tX9?Zlui zDxx)I|G6ASpfgLj{Nv4BmHLqqhp!e{WAYiH?&+XpbTxucvdebEK>lH(S^+K}AnhbP zbLiF#P#2ZJ=nnkm7O^~+K>f*K#kTp{LRX+TjdUXVIR6J-#aYV^3X@)oayTq=TeaQ~ zP<8=NI)ke0#-0rpCnP<2-SR&dH91iO-y$CVD?|xj) zKnJTY7MgW@8es={9e=Bp0SWqo23(~MCqwwa3}aRLg2;icIPRm12Ro#%EfKN>#G_5@ z4TTJHEIfAB#RSn6cZeznbP!I}t(!qeiZi2`k;G$?exmMNiK30G)-xjxK08@gZw?1% zL?JrCscb5Bf-+n_XcCzO_t`oUvUr^2SM;8Bm+76epFAUp!J2UoYK1i@xlLwgEa;?b;%QNbl^{xYM-u4R1TI62Y6Gf}seBr-Xy6tU3YD`SwSW z&fV@I{>+H0_ePgk%^Cnrl*8q!M;gHuu`R(&Ywt~tLT{wSQ~Hy@28lIJjkeLBp1I8r za-EZYe{K>!NPnS!!9>bKTkvWSc}RV$W1s6DlP zQ;SZm7+==08^hi`jXpP)bV?auzm9WG;pMoOK#pe#;x;>&YXaT1ze~-T3U>mkcox}R z@>U3*AC9UCyS=!nMzA&Y0*kL`zRR-wd5;-#vVLr+qYkb5)f_+Q{E*v(dFi7crWl*JRSD*@p34%tQaFeYLBM?_Hr(gK9qr zlNGAey4aD?Dyw|MbW4*kTfy)VO6R>xrJp7V$gSW?eMn~~&zd@&MxDU!xc?-mH=s3c zb-FNr_;A zOl0!UesS6Cft+*Xl-4WXtJ?d)A%C`+J@DXPIl4YpvB-{PRVJGWB$cEz@aWzBEDH_D9m&dHqF_ zGMVQsuh~hLO14Bu@x`0Qw1`Ce%95Xqc<%{1xY+2=+PV+hcvadzXD8o&Zi>=tnxOA6 zhgpe_h7h3X14trPj3z0nn-%4yETU@(RgvOT>4|R1ZKlWa{)zf#Ie=~-V><0 z9Rhq7w?88*7tj$%m?o+Dmro_IOTFFnU?m4ulc^$pN$goGX|;|y^daVbAFmq&>l^`? zu54b9te+Agw0^s;Rn6uVWJrcz#=}Q!<2_^zqlw_?UvA-rIN|#rD;Qokg4L-GG$vnz8DvBcS8dVJV|p zA~K6)gYmaHOXwteW89^mcZ^IY&fkXD&6g?wAirP(J zSGk^!L~aTeYEfkhm`eWBFMg{HSo$Oi&^zp+$0NhnWi%((8Xar0T`5-Kl}TYqrbdwu zEbcVxJ^b;YS_bf~8iMsg~ha!DHT}Civ3!_oMZzRq81eMIWb_%LM7wBMGRf zbHk-__9K&6_1osYkQp7}FfVLOO5NFaKR0=XWxdGm{}yTc+=3wL{#vv%T7VVXXcI^J zvr_S6l;DOH>JMq#&sASaBe7WbuZI-cP-c`^lIu>*Er|xr)@6!U&%}ufdRVFok*0ev%f*v?2lc;dwy| z?b?$dC5wHO9Nha2x=9#ciZA|n77Mhu?WykIW#{XxicX%Zb^Q=-ZL}Y!t6$)ba0AnEUaw=tPrxBQ~7j2 zg|QVG1~L^vG#5bdU7BnHQ$@S`8PEQ2FDV=#si(c#`8-kTV7in+aMAGW+d;NwYAI%` z5`|6q`YDKPjIrk3Mu8?QZnzK)yd-2agdw^=~QHo}Ch)T|DQ-F5y9LIZ5enC*G&6 zB~ix*yc4H%%Rt%8VUY8busPEY3R)}P$$Tqxlg4sX(Wjr1z}Bpni_5)vPNI~gun zZpbxz5*VtB7%SVVnQL8K{5hfGv@H(H z0$KT^?yj^n+|Qbt zn(n*0Cm(+OUN0k@uRT<||4eX*Ni=;N5lucCJX$HB)|HGppEg>#gwlxJN`I*H7P0;< z*Va7)q&C?9?Kc{p7&e+O#B9)k#|!qFVAB2*>4OdLk;S~jypY)y zrO(aQc`-;hD1N9_4c$diXOTOfdw1G?=B7Qs^?luSU!Sg;jyJg=66b!thk2VCT@K9? zQ{}fpS;UGKC77UMH|~Uvs?>8T#J(fZY%s!yFhXeLDG8DF1ruQ?{kD1g=Z!+k-Aq&s z$R{kFC`74#xp$qI)M$2a!Xm=c@#6or_0~~sc1!zkks<|(wNRi~(Bh>?aSEYWaf%kV zB8B2^rNN;DcemhPG(fT7E=3CjD4G&9=$Gd?=Q-y+zxDl;~9Q9%4n{sZP}4r9&*I!!fRiykcyZ21fNupbo>tJ{j=E& zE1MG6QLAz1c6EVhdb_L=h|8rgVr74FlCK|@L!TAr>_>;t?IiC z=Z!{$w&P5b#y=?MSG0mNl4bj?lDs!Zg+~rT%z1QOOhShBovhr7!2FCwGR;n=*Wt&_ zi>cOJSsr;V1e8feTNEC3%bfmM1s(;TJ2={gN}-zWaZ2!6il?KBJJeR7p9X_fHzk0jNw}OL2*rNMT1jveDSqdDK_iutAr$5Ar}aQZ)pb> zVp`CADK@M5>dOA5&FZowuQNHSGg4k9BhC<{kO&xkef{XQB*Ma0ej{M$CU~K^dj?_re3>lzmsL&LL7#} zF6plF?C0K$$A|*^V4f9ZW8S-~au3c%4omt>#=%p%%YNTWM>=m0orv<1%^_(IS1cGd zSdpS8k&)T1HaI}b^V>57&6W{R%TgDp0bFH_&fsEX2~&Rp!rQvHE@+;9XEU=i|} z%vkfLK{p7m4awvHpFRp7qa>y12kgIZSDoKCAks-^iT{%CGM+85^sCGwR-qfbly#*v zs>kkMQrW0Jcy)*fu-TK-GkQmM|I&Qt2#aYQ@8Y-Kr|{-Pvc@fKK(&It=95`yL#*s& zQhcvizTY0z)JgtN`q_>@*@c{d`n$p-S6*R8}M8 z#NmQd?#@YHu@O)AFm+wDQL88%5vzMoW1;M$N767}f}mh%MoKxb1-2i!Vv zV9>(!3mRn#Z@E=cFj{$``$twF5v-2E{*Px=#U~`zNi&Y$#qp{naSDvmX=gE7Ua_p- z_1dO&j_-98sY+d7O09~g>mKw=fa$J`%6W3h%$mv*8nR+ggV(lt{gLuA@b3Cl!Z&43 z8BDYer~^!~f3T`ee6LN>-*(hG%;odM+b1a5T%VkW#kM_|hnOs@Q3IgZ+^;O=Fp-uz~*5Sn$o@Vd{siJ*V z!*3tO>0SYi1LgqTN@DK8pPe9W5$&+DeC#4)&Zsu)BFkV3syTx%+VhlIC(2`q3f)t& z?LMn=%t@VR+SuA2X1R?I>kRgd9W_u5JTga$d%~8_gG({$02%eAcNf=V{vf@UAPaFEN#bfMl=QXQD|xMr40u=q4w( z#KD;ezwfTWt04{hZKKVeIum*4HC@+Vn=>(%3_xQFb|Snnw`eX!$2Ma!z2TPXfq) zP2oxg5IklbtG!!QLpP>hDvsULaQ-$u*&6$fmjcLo?MQxP0m)fGcLuh1F7_in<~<44 z$pBkv><*f9l@DMm&OcEy-;q#i#Uc{T>XJ-scnQ1OY&9W=iJ}ysMU$157F?Y z!e|E6<_nB7$Ay3_B3VI1Q9gHO{Se(}wl7>EyaPG#2bl}972Rl10~&|EugW2TzY=j@ zkO8KBSQ~#YryVLNZWLBK0;;Jn*AKE)CLU^*X;b>7Xx_Sw%}W)nVkS1%h2@D)a)TSUX^?Vo~EhzwcRBRN+g&an4{Z6}VclDntZ!aDj%>-PbL8r9=@y{_6xLe2)t9i^CZdG2*A# zz;!jPFQct56mT zQ4yga)X$U~vUEODv*dPsy=dxJSoA?jQHPBqelL9L{Z$Vm@`s}R2x8i+Z{^3GIY9)9MkG7(AO)GnseHlpZUJG6>Wdz&yXK5 z_bfWS!y*hulcGc|HatAMkmAB%vm=rYlw2je*-OG!a*<%y7vux**40=aQoqteM<+0! zqHsoPZL7(6t6@gsbPDj&m!&KAsQ3z$CLVK{o61At8KmB5w?5D~-s0}@A@RyUE*X1F z9+|hqgF2Z=x5wH7?$w_ohI#YtLBsc+x$`-@K;tN^RKn1G;}#5t7ho@+h9qB`Vtn)g2Y5ygSwSW4J|U$39u%aHwV60C9}g z1xWZy3qVJ2Sjs3*NbZ+lDnu=DKQg4_h*M5}>m3WyZl?|wbz1V)&Sgi%d*bRrC4q*I zV^n*EUHVh)73IPQZMa&VqGL8&uYN*#8i1=9edumEoS?4VckuD6X8L-%*bRG6Yo_my zigUE+g-JAW7zw;h{G)t7eM>05;vq$KUybZb@*{l={47FYQowm?(YasuXr+w%``4-D z^A8?ycmDNyhgtZU+Ot`R`^GaR;p?dt_V6H55;^eun71tH&z2whzwD1lQ#6;f&QxTT z++oQP_GV2>gR>-1%8wpFe^o^&FHbZFv15Oh14LCs;;oz-4Ex_BAW(H9?djRs*_GMR zdujLgE573`J9lFc*MJ?*yPZHxLBZK;J_u72n!kBT(-2x zT9N|uMlAY82X8Odco7{J+1Fz^=(3IGn8d}07d$*3w#;PsR3heuz{q&#bK`|8v#gy# zB4=E)D@Z1k(!S#U>0>3^$F;guA6|TuyebtC60)Yf{?kL862;T1fJ68!&OLL6K$lIt zMb5;xi3L6yX1>7^Z!_E=IYLFBXu8)&B}wczoB)av*B62%>`**a&K1OLK|wbrG;RnL zJ$5I^{FARw1=Y1s*{eAXGDjiH|1b_uxmTyamiCURY? z_CK`$G!zjfb$4mevRiC|R-x?ZiCe>%?>B$xy$30Q%kjTGIx`Ct#nO2GHrfx9jdM^y{p_+j&Cu34Pi zS=e!zeSfYpAvu|1KDlVyX=g0UTYg;uow$M++&PH&&3+(gj3XsqFVvpYmY>D@8ih*X!7xv|F-mH{UyN zM0DDXU_mkB#c;xq_la*&+*kzEzm1#l)&^tdC z>+s=W^D-p-03W_c{xu*XRRJk8Q&<>j>AUmUzozfv|MdskU}=JTE7!nbEjrF#TI5BAFlF`nGLD%lad z6$?p1R}GYlRWh3BgB3cPIuN*6;4twOmtpSMkKbs;=13)APq2EtmAW+dAG(8Ga_Ze{N7Gu6ul%IX~~;U7eks zA@|Cwhc^16RwQDlf*)f^)Vx;z;}+Lqqn6cPfjU`|>_(X?MpPrycR z#ADsX#+feZ#5Ye6yTI)3(Zla+M>s?c#CY_C=9;+dGsjOkbzb{@^qh(i4@r=^Jyt_r zA?J<6_vW1kXj5Ei64E`d9q^uEej@!{4wTIMddK$7hyUgCxS@=AARWfYj>V@OmwP88 zMr1?x=^MNb|14O~=OkD;pc+F36)#x`E3nSH$_*lW#+~Jd97OIWsK#H+Rk@duJ>1F> zI~jSkRBGpD&VFv#STQG=BSM`<{1_g4RjMkN~uYCbcG3@aE1}k>ng2a@1wy4w(nwEHN5Vm0U6&{JTiio zzT%TFN2_t9!S4ti88T;En?U)a5g(TGz?^6T*d>0C|@>c@xBHTq6U z3LN)R^o<=~CBMRG*Z9LIimmXO)oM9wMheA>jN{wmJ2QjBz>c3IA&*1w@C0LMim6kR z%#3A2U=@VLv`I>$_=Hys$EhiCQq=DP=+kiOd1Qv@!+#?J?|nUqkHUW9mA$k~T;pLz z@dl!zd`ng-0N@LJ?lO_XF0(LNR%C1ok3(ei@AdvhqzofVMS0 zPAvbq_@X3p1MgEB#}VN|_Y;S-7RDfnS8Q?qIJhG^0v~O(%69W3r$di39`X*w22&Si zA$sLXbDvX*FZ&`o9D{nhqBk2%;A#9;e2>ngUI${6CIro$!vNbsSAgufDN-Pl<}7*k`8YSzmViI85zjhD?FtN2~Vda|Ae?8x*@ z+FV?xbPNYlHC`9f=lBY0W)Kp2(sfI$kfr*PoPnKPQfrnXC3ceSWoALon@>QMQ!F@0 zl{M+(q`pj(0!`7BZWDyvt)||3O!NBiR{u&=ju`N5a z4pHhWUM(g2rVp1h+>aIXT8sLSb{{>yUU31B&LFS*$%b?nWtg0YO@d_MsN>G^M@S<( zU&3xC>35XoW4XPY64E-gTIch|LB~HH5?F1Jl27xxubrsC)6f!gGM9KHJa|ur*o97@ zt;$9Ngy9%;?wECIJ@UQ}NJ9=@K4Xxyd`?bIJrIi-IfTyeZ7vKgCq|q|mSm`9kib?F zA-v}oFMxpYSLT|aj@MqAxLt9f&#gk&$aef`JQem7MQLEK$hwHEXspsjv4X2L>pA$W zO&{p5HhszA=UF=hyg>*9=YryLvCh*C>5P+HVw=gh3W@7a1)vb>1a7q*NY-qLz z8zsx?IIhg2!^-cR>Rv#o0cD%HC)G^9ml=Hxm^VspOYx8)rF2iBn}lJP#9LHthJA() zla{b4tyD7rS6O~w=7b~5_fI9#aEX7AK!It2+cf^= zC!BFv2~%m8kxBXC4w*{kyCcoKW$wkz zrZ};#+au1b5)fxdc@!mYvZsKf){ubU*4PN><7uPA$~toPbGZ?vF8tyIu6kISROcjV*K)tT&mZjafp#9W_BeUnRL`yYE| zUqA+u`tpasQBeait%CrK2?l=bAe&%L;0iH`*E=V_DH*@^WoZ}n@jsXAp0C|Lc-3?# zXO3}b>6I)z6$RT+)A2qpwbVY^9oRJpdNuyLj+&TG61>*&=4tbQ7^0E2wI^XSupFhy zNDeURlw^!h!G}n`_@EAyTqH~Sz8WwLNsZIk>kS@xz{mUMX%WU7MXMV8>ssA<2XfWP3R||C7qT>*0(Ivdbw(U=V9h=rV|WyqjblH%EgT-Fy#ABCM3xf)z5aIhN|cT!}(n_^%fCEKWmPkWhB9|alwL< z#)0j)A6YEln_H`(F6jaVDf)s>CVLEDJ$?`us?eTet$AzYq@q65Sw{GJEUHuV72|Hi zd*aBL{@P3FudXOf%z!!sbVqhU>0+~SJM_;dc%yC{jZ>?$Qwh#sSHEkVNAEa9 z^mN&Eyu~HIKF`AJn1hxQV~d=eoFWZnwx^-BRl%FNrGT;X+YP^0ew0lz%hWe-B0}6U z=rN_C31(q@cZ^ib+N!IS?{mQY8e%WM-9&B+^m1|VyUTm8k3vUmXBRBw0hB2kL$nM? zcc-%bDNl0#n=cAzIV^``_TGI4t@bH=KObYpEU4XxQ?Z0gI$d=Eq7eU>z}6yl@Cl^g z66BI?^Glzh^;d!<-*5Ju-U~6Z4G&gHXB77|k2@>R1(RcwvsV*38yW^XZSd)t{z;-^ z*r{mKuPzoQ#3T`a7TrksjNsSXda*rS-;0J#bSf0|SBTR{&Uv+Y4x$0M^Ly?~-DczvCvBIP zrm1MUG+QrbeS&*1b?{j9i&dL!Z)+!;$htmEsB>AQMCCvl&bRMn8l@pzP?e@GEvlTNkA z+q~fV3=7!to?1EJ~)%Wvu z?@TP>djzB~W`~I|8?Xp=gMLZ>Wg=3KD2z9PzmT$EQ5J8VJf%+QvmEd2wM^5=rQeo@ zJJY3mG4rrF&Jg`L;u;~!LxPfuEbyL)VxD5r`_)XQ(dS1`QkZ)H!@_@(TC0>Ew=*2$ z(Q#>KiF-%x!ynzExB^3^17&kNNxk1;yktAzKow__a*?vNk|~79RY6|7LVtS8=C+aM z()L=0KAhfnI|ORux2*}eIQbA@Kep!F*)v}{-g9}C^GV55DyPT^@01PuiUwR#`R4Ok z$D?x({g=~tCcqn(C(PjLDu^bQLHahdw%)$Qr_x*J@YgMo6HGX2=MR@wMI>qQt9RE| zO{tk`#0%f^0qdGBXEfzm1d{L6@iHw;`8F@9s8&>pOWywmX3Iri3dqL{2uUV%*k8SJ z-}aRZziBmaUxO(9N*zbIZo#JdRs|}%?_nu2gKKg&e`@TBg71PJ4Ec5Nr1oKz8+p{gBANa+MkqOI&%F5j*9yw+l2*LZmU+P%}GZgK3@ z){n1}n^ZQrQ;wlOlpq#*FBBgRM_i?3$y2P!1_LIj?NeTYV$^vlEj9L$TAmRN5kYzEh z{hc6L8k*1`b{OU6fmSgR?)e|-Q1%+T)Y`k)=*q*dyUcaN#UJjA*Ou~n2Rd_1(=Rk` zz9kc+yKrkxxAeg=jkO{R=CK@cl&H zTfItQ0|VUS6$mUugswsFG*VF@-%<@HT+A^z43g4$>K;#mayPL{-dCg4FN(BKo=TM+ zCGgFLZ3bvQ2Ukz^Rqe^Ho_w)mGPyirV?<&X8`XpjoUagDS#8;IN*P&?r9x<4zi*Dw zUg*NreM@o+W_qinXd6-fBsH@J%Y1J`_u$}VOZSoFk~;dxi1g_uN2@;z4nAOY*G@Y; zad$KFBt@BLX}0x8DT7*@_6KX^XrgW0A5HufnEt(-30)FtWO~WQ{De+yBEm1Q@DWOl zNiH5wJ~O4~h!qK^*PwV$H@%b1e3Ck48XEl|lP>+j3mH;UP`C4nQQzO`U4)-Y+@u&V zyRT~Ow(#hnjQ+)S)O9$3xF&i|efed9qET;T8c|dYLsh%%uc#>H#NNoIXP`&jtb&*C z!{FD!4{I-Fj$kW=fgSh8=oO^lSkuPpY5|1!f5*l-0lp2~y)n=cqt1ZS)9hO{$A;g^ zv95pvm8VJgun93_yU-tt@(-Ymij=v=CdP~fQBjuV@%_n;4PdoVd~uxaMmCtZIU6(G zKImNrR($o!)qzxGd1Yt%Tt#ci_Xxi-TNO?_kThI*7)#UDxAto&b6C>SlZKoZAN|^d zo;)!Dvkgn84QyFnJ+f(M|K%PkmwlPOW8fhM99*lait$T$K4mroB9oH+u8-id<+22P zE1^CZ>BO7l*2sA4YY~%rXFsr_(_Q>S)%?K|`!!j{(wmJ}FOKgd2%=!$TXTB9wdZuNvLdCt z#}Z1Q)QRPk6bP0BTmTZDfoWaOBtGk)X>ts~UJ0zi>d-PxovG0ia?e0w^(ji|!hn+K znZq9qGtYM}Ts=up)#cw)4fko_nTJc3;g5e@nz_$QGk1Q}v-`K1hf3eSc|aF@!ST*M zyR;0ftQ587V^sPx0Z1pHPlFF0!0a)ZPvuSgDV?a2<8_QeJE`z?>N#fNuP!d%r%z7}-XmJS;S{r+HEw20^Uoa&l{Umq{pm>~u)BU(P-baR zqYzNI&v7CLCw|Y%!{ivPfQ~qtL_S`}+{_$RC0&JH@%T1$yI^Ti*=B5F16d1H3Lr7!r%-0Az%kHeZSQNCE zD6V?D*c!5w0Qb_fc4J<>vX!0FSn=n9`Pv9Ia54h|FBW9oNNcpMaa`~P zK_r9$kKrkaJG7~3uF|W2jyfmz^(B325`Sqgw7fgq?}EhpT;2ZT$AvbAv_4pLD))bo zEmZn~sS8u9g0{x=nX#lydLU)uTdU~KW)8s1M(N$5Q1$#V1RJ3iuNVQqr6~Tg$E5}% zbiXhE;hHvpAA=CnQjtP4H>F7Y_FhU z5q2^nzWn2Czc1>cZx+lXYa`1#!}{p0ksih=WMG;gzj?h2>)YwR*wyNXWFs@DiJM#1 zlL2IS;GADMNWFhTP6OZ@K1ULH@buh-`N$03n=6cvstik`)Zat-nhA zwA(!y&%E{-FOn}O62|WtIC2)_eFQGX>C5uYY45eDcEPk6tCmTfD)=Hht*OtUZP&4gpwa+7J@~49583OR2aTUP#To*;rZsvWO2rQ5i7j;&ue=&5{XJ$q z+#uwR3*Ld!ceWZ*-)q&{a>OI;W%z%6JrF*y6JGQ9@n66{mwk{xEk4`3Pp)|y7OaW% zNyBD?kjDpd#+Rn|e4rer2lKv{qgzdg5>F{Tu^bBoTAdqSOUS6=+9eq*UybGhcjy*e zRicXN_R-3ev9ND6o7q|seleN~Pn^^!DnejkJ}TfGmjFEm6p7?}S=%-(VjZ-?<5E*9W`eUl}1w0C-CMm{M zB{u$%TvC0k(^YMk9SdLt>xhVOceyon~jM@y(bmamn z$V~k2($npD^R$g$q;eqlXP~8?;o?0n-&*hHDX0jr`U!ExT{Z^BDmJtnKFy|c^5*?U zgUv3*l^rMdqG|MP+nRVKEw}x3;9bLF_-}<3ViaFxp2LMWSyJ)-`*SDIM8VY9x#h%c z9~sr^adbouy|3^;ew#4(oV1H4+uhck{t!Ijl+;_TO;*jy+m}+-c66VIty^^BN9ygO zF(h=Ep7 zwry?y3ZtY=4zqy~`>93Soh1?N z?BGuM2=S`T3sP_Hf`|6=kh3r7rsyBF<1LJFynykQjI}x1m8z)7@7^ZH3@3RgKu8sP z@d8UBi&FIsjcouCrfqJX0-TreiU_O~4(9(*9t`EVp@nR{IwI zYCe^Y4cY2*nvK8tLF5H^;G1}{;G33@hX%KW1dn`Sw{T5Ck>eFL>(IBZ1(7$21PPHh zG#6=rH9A$0NBg^uyAf*nO3}~1VfHamm0C72%CnlXb$N&NcoV6n~+Q#ges$t$`tEQ0Vd0H_o@1r>bJ-`3kI15f##{(U>Z z?mY%L2a3*6GiDzX+YWp>7PV?rey-jpAp@t9m|+$EAYrN!mGnEd zqW;Gog%%r0axY8ahcTITrd(@xO)$tcts-3fTe&549h5qAFCH^uVf|`8A=u8^Lg)l! z!pjx*Z)X7tejs$re%weu*Ql|mOu6EBz#Q|8ToPo zAAY+UB|MnV#QK_x7L2PqwD-kxPJ!>kA`?(@Dc<45V}%eN!ar^u79dA~r~PULpnwqR zIiPXQ0(XGFHf86X5~u7C1Ieq5pm&^-{vk&Q<%{d&biJG^W=UC-bWZTNR@1c~KMH`1NcL&DfHAq#%3{hvmHh9^ z@xM|mpqx6m^8iMWWvpVspUI(UE(pArG4CDEriu%_yk<2>w*SwIcw#RcK+t^!;LBp8J@csx)dF!67U-${o;C7`yVFW+V;L!G zxt7fu8t&H)(K*WE|49VRyjCVesXj3-3n1BL7N zkhIaNnGEkK@h1JDzzVGoOdQN#C(|GP^M|`gCIlm#A(fTxLdUg>&Dc(yYvsLSuIY$| z^l3}=4gbq%*tG)uJewClU%tk2LGPcKA)p~A*~0ilU(~5jDMFj@B_PKTrC0Hs1O|e& zE!8~mNLw7a=TAPhE(n<-;%s34B4wG1-{5fTlC>WGZFG?K zjVurl#t|YFM23(GA@!z@SYAa3y&0a4DPh*{Jk#*Bb>HtRy&2+VI7#73iZ^@z7VgSP zAC-iKX#_x4UPR6NklimNjbg43hj7tzAeSz#a z1>oVm()$Q?*NmwtO_ob**&KW^G3$S!$;1UoSC*xP#pbH6I7LdGx;lq8jDwg^{hQO9 z2&r{6>_GWv=OC*i6W*H}?1T=slrna*UH#6YpMOP&X<-m)swgTjS>V zI@S`thJR*4URyZHx8esM0gwS68mtuZ7RYocqBl1CXNk1>N=4{0S7KmR$A7X7e=3Z3 zh2%=Bq;+4esEcn`J{U0xF;OHh=DcOOYhvr$`C53|Q1ewJO_mRkgZ1%+22u`w;qZa; zoBy^YxAS+#L>>>h1YMJ58_DBDZMp!OjluqZyP*8Lx8Cm0E0;2Rwkl2i0sFA^d$rQ#uZu)N>ov=cX1cJ@-x9m#@ z?bA4G|3QUD+6wjW6$bZ8p%0hb`;wBQ{RRIqZ=a{Z)Q3O%KR({JlQ*c^o6Qa@ATvye zLlX383aHxTw@q{k+1{gGWvx3-3EC~`4zL&?20uRif_u70evy?i;8vdTcB|pInXUXN zLaBix;?!eng=Ohq3vn}5{>pSxn}oWF!5o5>&Q@g)Un17!E&mi+v;yHw zMHmsn)}~5ET_T0HWXLQ>$~sGpldlg1L6rOIJuHJRJVRQGY4MXy^87Im$wmKEnB>Ie z9x*?k@%x(Cg?olOP|aMC5$|5KKAcGWk6oDJx#41dezS%mytThQ|N4ZOP@%B#+u@Le z;`qF+#n9el@NP>&ho`Qlq}Rp|+k&BlHW|2-w<}0oBoOMtHVa3~9s+Vdt9D*UQi*=D z9s>ppd6S;W=G<=(z9|*xyf>kCfpZY!+npLl?AM690v~zZr~N z8W!m6{;bc(IJEL46 zRL*i1(0F1u_W$=lPm05*p%DT7;L`3wE-sfKbn&$s@ae zT=n0X-{&~S34K84?x6fu5ohPR`XlZ4vtG}JEtsWFZ0>dYv;8&ZfC0OUUrU#!9EsSG zT5d&xe}xI<0HKqHd>DFR9Q2bv5 zxO#vo2{t))y63QWY~${0C>A`i7#GpCzJpV0LII56k7n#^#juOubSr&{C~I66z`NDlLWP>sNub} z=QOlklHFSqnq_ps?LjMYft_}1A`FXjPkIaYZK*jp|9@5&^z8vKU}s^a4xUq$Sjh|h zJ+fi=6ctqGqZUf*AI*ehk}MMfAPTGz|IhEFd6^!7*CZY4$xu$Pu_Vq}jhKH^3vwL9 z^lbHk0R=Mxv}QnP3c;|W)Bl{hDc&WXG+g*;CsXy!v~bapll{v26B=(dCHZKV$eV>f z&TrxVGY2dG&Ex*HGgjCP$o>54!Kw1<#8Bez_KpUh;1U8TX=xcN7XF=1$3*8IRUN?E zaLcC-e`T=3-#A$}dkN-^_S5J2`w{GuUYnSTWeAvCDDzACsh?I34$ zN}AMl%X63h7BajIeJGzyDRWwimzG&`FBhRU7v=x%0xmfw4ZW|ramN)sOI}+m*-S(6 zTdDP~{^^i6B3C9*PIBJsGHfOe5TycMqczK_CIeNS!+!~szs&5p8{TE+OyHkvcyWZD z_S`CxMjwTcngdm(W3ikB|DA7{sBemhZnrBJ`du})8fvHI3>f?Ka!{suS?iJ6?bUBb zr1qx!3W|BS{tsXThmZt+u63Du^+QvD!S)52{ki4n=1W@$f{G7wiv6tmUQcK_@OqWz z$nYRtATh;kS}h)f?N$a8Jk&vXwvF4B-YOl@UUpngAr}L?ur^!h_`e4JT7fhOrY0&3 z=#vENCLo0Azrxr?KeW;&FVI1Jj}4K>Q#-Sd$KP%M!C%|8JCvJ$_{ zDu%5aL)PlFD2kcit76#F>Hb9(9t=(p|1X?bn^_X6yZ(1IK z*m{jZ;!%5hcC*`OhU)T9t~yH{az{{CyhYYS5fT|~9!C_jw$WW9HD1nwzfJ6p*p`9^ zAOG(YPc5*8DnD>l-)wUTZb6o=6JueoUXaXCBETD(X|;da_^np0e0ldqiMjhQY*Uj@ znM`Ui0ct$|hdui@S`lNG=UjGhbzDm^)6IekQfINrkoOp;WfrM+GzvxNPV)zfa;m^8 I8PhNSAG%>#KmY&$ literal 15156 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 diff --git a/packages/flutter_widgets/screenshots/message_listview.png b/packages/flutter_widgets/screenshots/message_listview.png index adf3f0873e7554fa144027914d01f2ecf635d233..b4ca5e7e136d0eced297987c77f8c0d36893be54 100644 GIT binary patch literal 652108 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%0AmY}+PhXC_4{i_b8aitXQFA(t#S_+XQ@}li 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�-{ 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�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 +L?qr(e$*ey1#|C;d2R@LaMkoc2?z3f`z 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�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 z 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 z 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

  1. hf3R`Ksf?S3ND}q67N40f|0bt^_IgkNrV?7Ul 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⪚F3p_ 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%0DyzcQS@J`(<2Y(K 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

    ##s?`Y=tt)1M|*uD>lC}Y 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

    2fS!SOY&Rs+(QV)uGo_%@?!o&RyBdL|Tkr!E~n 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ν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 z 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

    TO={MAp&|;)4(%RzCb$r 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 diff --git a/packages/flutter_widgets/screenshots/message_widget_paint.png b/packages/flutter_widgets/screenshots/message_widget_paint.png index 4eee610bf0961e1c3cfe0ae9aba287ee5cfb76a1..802deb6270682c040dc70af2f5af6488e3039f60 100644 GIT binary patch literal 320357 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 z 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≤AWe+zk{U4(A(J3dtb#OuCg>&0VFy6wpuGq8>=DwhU$gba2askL**YNa zVe>C5y!2G(@hpWu@y$~cf7gKKPcGq3sufY)@yr;fJJ`6%M7^Ids!O=p0S4BN| zkRU>Pw)71ly+L=F%!>C-Fnh}DK;pEZte&KNqkE^m4~+n8$E<4|^VEyM{9MJmUQgNZ*;RJ6=7(vNg3 z{(k|k15x}(0tLaO!LH*&hEFSTYjUe82zo*E2-u1r{IG?CYi@Vci7f}UhZnsa*CRyy zYGZ;ipm>u#oZQ6kVKL1Nt|@!Q+f9cbX^Uf$4K2N7y8yx+t!^P?HF$lzJ#u-h@-XQ@ zYb*UkM84cFiOM^;avrfWsmK`$(!e%I<>8j>JTAMf>Q(T6nJ!6M;s{bd!xWS?2@BCQ z>`CkAoc@N-XWHSecoC}343bhs6C`_I6k(cpwt1*NucMn1zjCi*xUbOSBXyQ-fSTPV z#_JkKZL4O0@I8IS*z~<`Brq5|9;A^x`rK3GjuT5V~1l9v$EX4&e|V2daOBi z)Xv27RKl;mpov74SZ;_xK?rYu-FG*RyEUdKIx(1TP6RYBxAn@E3u?)Dne1FJSBqY3 z#0*^VqDTkq;EY!Q@7y0BkM07V@tb=0b5hzAujpX7jkr&xk;}+$*Ly0S=sITjD@=>E zM7I?+c!9Kd@y}DJ#thCQTOvBSNJe2qZ!jYWkZ)- zc}0jWo?GPS{G{}KlBv!qV}1XQtp@AtT8A>4%elGTf&_~5i0GjnCnoQw&t1^jL+;B^~GjF5c@+tA0l^io*3&FqCxi+cn7%sc_C zQLJ-8Dn&dWcX>q9ci6{ZZii#1?BfNESCbgb$BW?p%HqYZTg?|oZ>@x?#HdgXiafD9 z$^C;9{`g^Y4H-$8>+%ay@SWvjw&O$`_YD`eZf>#A8P9DIGC01?_QEM$SQ2$kQE4nk zuFe^pHHBxL6}ROI`K%f>{QLmdDhW}4UvU-M$5=3pNbjadHUeNgZ6sOb!tV9kJY^OV literal 46037 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 Pux3;z diff --git a/packages/flutter_widgets/screenshots/reaction_picker_paint.png b/packages/flutter_widgets/screenshots/reaction_picker_paint.png index 20028f4c38853a5b0363b2370b6cb64ac4af9c46..f70ed795f1c43e04930c3501399ac901ec837a3a 100644 GIT binary patch literal 48701 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 a$ne8j>^o~yhHQ3#Qj$}bZIrh7`hNhU>P=$+ literal 49343 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 literal 8500 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 N#pi0!5?Ql={{o1>;_(0g literal 10616 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 X4dJq1GR}1_?lDTfloKs_q38R5xo;IH From da8301eceabbf684b6ebce38618af3c38799784a Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Fri, 29 Jan 2021 18:18:50 +0530 Subject: [PATCH 1088/1140] Fix action for non flutter projects Signed-off-by: Sahil Kumar --- .github/workflows/stream_flutter_workflow.yml | 23 ++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/.github/workflows/stream_flutter_workflow.yml b/.github/workflows/stream_flutter_workflow.yml index 8ced7815..35b16c59 100644 --- a/.github/workflows/stream_flutter_workflow.yml +++ b/.github/workflows/stream_flutter_workflow.yml @@ -1,4 +1,3 @@ - name: stream_flutter_workflow env: @@ -70,7 +69,25 @@ jobs: find . -maxdepth 12 -name "*.java" -print0 \| xargs -0 java -jar $HOME/google-java-format.jar --replace ./.github/workflows/scripts/validate-formatting.sh - test: + test_dart: + runs-on: ubuntu-latest + timeout-minutes: 5 + steps: + - uses: actions/checkout@v1 + with: + fetch-depth: 0 + - name: 'Install Flutter' + run: ./.github/workflows/scripts/install-flutter.sh stable + - name: 'Install Tools' + run: ./.github/workflows/scripts/install-tools.sh + - name: 'Bootstrap Workspace' + run: melos bootstrap + - name: 'Flutter Test' + run: | + melos exec -c 1 --no-flutter --dir-exists=test --ignore="*example*" --ignore="*web*" -- \ + flutter pub run test + + test_flutter: runs-on: ubuntu-latest timeout-minutes: 15 steps: @@ -85,5 +102,5 @@ jobs: run: melos bootstrap - name: 'Flutter Test' run: | - melos exec -c 3 --dir-exists=test --ignore="*example*" --ignore="*web*" -- \ + melos exec -c 3 --flutter --dir-exists=test --ignore="*example*" --ignore="*web*" -- \ flutter test \ No newline at end of file From ab9266bfeb9d2265fc1553b388e37aa1d00e14a4 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Fri, 29 Jan 2021 18:37:42 +0530 Subject: [PATCH 1089/1140] [Action] Increase dart test timeout Signed-off-by: Sahil Kumar --- .github/workflows/stream_flutter_workflow.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/stream_flutter_workflow.yml b/.github/workflows/stream_flutter_workflow.yml index 35b16c59..06a8a2ec 100644 --- a/.github/workflows/stream_flutter_workflow.yml +++ b/.github/workflows/stream_flutter_workflow.yml @@ -71,7 +71,7 @@ jobs: test_dart: runs-on: ubuntu-latest - timeout-minutes: 5 + timeout-minutes: 15 steps: - uses: actions/checkout@v1 with: From e85a4326d682d17523065d967d1873ce8b4642e5 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Fri, 29 Jan 2021 19:17:07 +0530 Subject: [PATCH 1090/1140] [Persistence] Delete members, read data before adding new one Signed-off-by: Sahil Kumar --- .../lib/src/db/chat_persistence_client.dart | 21 ++++++++++++++++++- .../lib/src/dao/member_dao.dart | 12 ++++++++++- .../lib/src/dao/message_dao.dart | 12 +++++------ .../lib/src/dao/reaction_dao.dart | 16 +++++++++++--- .../lib/src/dao/read_dao.dart | 2 +- .../src/stream_chat_persistence_client.dart | 10 +++++++++ 6 files changed, 61 insertions(+), 12 deletions(-) diff --git a/packages/dart_client/lib/src/db/chat_persistence_client.dart b/packages/dart_client/lib/src/db/chat_persistence_client.dart index 19a9164e..070bf37f 100644 --- a/packages/dart_client/lib/src/db/chat_persistence_client.dart +++ b/packages/dart_client/lib/src/db/chat_persistence_client.dart @@ -129,6 +129,12 @@ abstract class ChatPersistenceClient { /// Future updateReactions(List reactions); + /// + Future deleteReactionsByMessageId(List messageIds); + + /// + Future deleteMembersByCids(List cids); + /// Future updateChannelState(ChannelState channelState) { return updateChannelStates([channelState]); @@ -181,13 +187,26 @@ abstract class ChatPersistenceClient { return updateMembers(cid, members.toList(growable: false)); }).toList(growable: false); + final deleteReactions = deleteReactionsByMessageId(channelStates + .expand((it) => it.messages) + .map((m) => m.id) + .toList(growable: false)); + + final deleteMembers = deleteMembersByCids( + channelStates.map((it) => it.channel.cid).toList(growable: false), + ); + + await Future.wait([ + deleteReactions, + deleteMembers, + ]); await Future.wait([ ...updateMessagesFuture, ...updateReadsFuture, ...updateMembersFuture, + updateUsers(users.toList(growable: false)), updateChannels(channels.toList(growable: false)), updateReactions(reactions.toList(growable: false)), - updateUsers(users.toList(growable: false)), ]); } } diff --git a/packages/stream_chat_persistence/lib/src/dao/member_dao.dart b/packages/stream_chat_persistence/lib/src/dao/member_dao.dart index c535af9a..ed30a931 100644 --- a/packages/stream_chat_persistence/lib/src/dao/member_dao.dart +++ b/packages/stream_chat_persistence/lib/src/dao/member_dao.dart @@ -16,7 +16,7 @@ class MemberDao extends DatabaseAccessor /// Creates a new member dao instance MemberDao(MoorChatDatabase db) : super(db); - /// Get all members where [members.channelCid] matches [cid] + /// Get all members where [Members.channelCid] matches [cid] Future> getMembersByCid(String cid) async { return (select(members).join([ leftOuterJoin(users, members.userId.equalsExp(users.id)), @@ -40,4 +40,14 @@ class MemberDao extends DatabaseAccessor ), ); } + + /// Deletes all the members whose [Members.channelCid] is present in [cids] + Future deleteMemberByCids(List cids) async { + return batch((it) { + it.deleteWhere( + members, + (m) => m.channelCid.isIn(cids), + ); + }); + } } diff --git a/packages/stream_chat_persistence/lib/src/dao/message_dao.dart b/packages/stream_chat_persistence/lib/src/dao/message_dao.dart index 57aa055d..8acdbfd4 100644 --- a/packages/stream_chat_persistence/lib/src/dao/message_dao.dart +++ b/packages/stream_chat_persistence/lib/src/dao/message_dao.dart @@ -16,7 +16,7 @@ class MessageDao extends DatabaseAccessor final MoorChatDatabase _db; - /// Removes all the messages by matching [messages.id] in [messageIds] + /// Removes all the messages by matching [Messages.id] in [messageIds] /// /// This will automatically delete the following linked records /// 1. Message Reactions @@ -24,7 +24,7 @@ class MessageDao extends DatabaseAccessor return (delete(messages)..where((tbl) => tbl.id.isIn(messageIds))).go(); } - /// Removes all the messages by matching [messages.channelCid] in [cids] + /// Removes all the messages by matching [Messages.channelCid] in [cids] /// /// This will automatically delete the following linked records /// 1. Message Reactions @@ -52,7 +52,7 @@ class MessageDao extends DatabaseAccessor ); } - /// Returns a single message by matching the [messages.id] with [id] + /// Returns a single message by matching the [Messages.id] with [id] Future getMessageById(String id) async { return await (select(messages).join([ leftOuterJoin(users, messages.userId.equalsExp(users.id)), @@ -63,7 +63,7 @@ class MessageDao extends DatabaseAccessor } /// Returns all the messages of a particular thread by matching - /// [messages.channelCid] with [cid] + /// [Messages.channelCid] with [cid] Future> getThreadMessages(String cid) async { return Future.wait(await (select(messages).join([ leftOuterJoin(users, messages.userId.equalsExp(users.id)), @@ -76,7 +76,7 @@ class MessageDao extends DatabaseAccessor } /// Returns all the messages of a particular thread by matching - /// [messages.parentId] with [parentId] + /// [Messages.parentId] with [parentId] Future> getThreadMessagesByParentId( String parentId, { PaginationParams options, @@ -97,7 +97,7 @@ class MessageDao extends DatabaseAccessor } /// Returns all the messages of a channel by matching - /// [messages.channelCid] with [parentId] + /// [Messages.channelCid] with [parentId] Future> getMessagesByCid( String cid, { PaginationParams messagePagination, diff --git a/packages/stream_chat_persistence/lib/src/dao/reaction_dao.dart b/packages/stream_chat_persistence/lib/src/dao/reaction_dao.dart index 249bd011..99053fca 100644 --- a/packages/stream_chat_persistence/lib/src/dao/reaction_dao.dart +++ b/packages/stream_chat_persistence/lib/src/dao/reaction_dao.dart @@ -15,7 +15,7 @@ class ReactionDao extends DatabaseAccessor ReactionDao(MoorChatDatabase db) : super(db); /// Returns all the reactions of a particular message by matching - /// [reactions.messageId] with [messageId] + /// [Reactions.messageId] with [messageId] Future> getReactions(String messageId) { return (select(reactions).join([ leftOuterJoin(users, reactions.userId.equalsExp(users.id)), @@ -31,8 +31,8 @@ class ReactionDao extends DatabaseAccessor /// Returns all the reactions of a particular message /// added by a particular user by matching - /// [reactions.messageId] with [messageId] and - /// [reactions.userId] with [userId] + /// [Reactions.messageId] with [messageId] and + /// [Reactions.userId] with [userId] Future> getReactionsByUserId( String messageId, String userId, @@ -51,4 +51,14 @@ class ReactionDao extends DatabaseAccessor ); }); } + + /// Deletes all the reactions whose [Reactions.messageId] is present in [messageIds] + Future deleteReactionsByMessageIds(List messageIds) { + return batch((it) { + it.deleteWhere( + reactions, + (r) => r.messageId.isIn(messageIds), + ); + }); + } } diff --git a/packages/stream_chat_persistence/lib/src/dao/read_dao.dart b/packages/stream_chat_persistence/lib/src/dao/read_dao.dart index 00af6b6d..c78cab07 100644 --- a/packages/stream_chat_persistence/lib/src/dao/read_dao.dart +++ b/packages/stream_chat_persistence/lib/src/dao/read_dao.dart @@ -13,7 +13,7 @@ class ReadDao extends DatabaseAccessor with _$ReadDaoMixin { /// Creates a new read dao instance ReadDao(MoorChatDatabase db) : super(db); - /// Get all reads where [reads.channelCid] matches [cid] + /// Get all reads where [Reads.channelCid] matches [cid] Future> getReadsByCid(String cid) async { return (select(reads).join([ leftOuterJoin(users, reads.userId.equalsExp(users.id)), diff --git a/packages/stream_chat_persistence/lib/src/stream_chat_persistence_client.dart b/packages/stream_chat_persistence/lib/src/stream_chat_persistence_client.dart index d36ed1b2..ebad74f8 100644 --- a/packages/stream_chat_persistence/lib/src/stream_chat_persistence_client.dart +++ b/packages/stream_chat_persistence/lib/src/stream_chat_persistence_client.dart @@ -193,6 +193,16 @@ class StreamChatPersistenceClient extends ChatPersistenceClient { return _db.userDao.updateUsers(users); } + @override + Future deleteReactionsByMessageId(List messageIds) { + return _db.reactionDao.deleteReactionsByMessageIds(messageIds); + } + + @override + Future deleteMembersByCids(List cids) { + return _db.memberDao.deleteMemberByCids(cids); + } + @override Future disconnect({bool flush = false}) async { if (_db != null) { From 8195bfd3c9f3712e09159ee72901593e2246489a Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Fri, 29 Jan 2021 19:47:21 +0530 Subject: [PATCH 1091/1140] fix: pagination hotfix --- packages/flutter_widgets/lib/src/channel_list_view.dart | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/flutter_widgets/lib/src/channel_list_view.dart b/packages/flutter_widgets/lib/src/channel_list_view.dart index 84eb1298..a0514f87 100644 --- a/packages/flutter_widgets/lib/src/channel_list_view.dart +++ b/packages/flutter_widgets/lib/src/channel_list_view.dart @@ -224,6 +224,7 @@ class _ChannelListViewState extends State itemBuilder: (context, index) { return _listItemBuilder(context, index, channels); }, + controller: _scrollController, ); } } From b08940bd61d5eaf3ea094af639bc095aea6f55c4 Mon Sep 17 00:00:00 2001 From: Neevash Ramdial Date: Fri, 29 Jan 2021 10:18:41 -0400 Subject: [PATCH 1092/1140] extract typedef to file --- .../lib/src/message_list_core.dart | 7 ------- packages/stream_chat_flutter_core/lib/src/typedef.dart | 7 +++++++ 2 files changed, 7 insertions(+), 7 deletions(-) create mode 100644 packages/stream_chat_flutter_core/lib/src/typedef.dart diff --git a/packages/stream_chat_flutter_core/lib/src/message_list_core.dart b/packages/stream_chat_flutter_core/lib/src/message_list_core.dart index 697e7e39..2b9e5c0e 100644 --- a/packages/stream_chat_flutter_core/lib/src/message_list_core.dart +++ b/packages/stream_chat_flutter_core/lib/src/message_list_core.dart @@ -5,12 +5,6 @@ import 'package:flutter/material.dart'; import 'package:stream_chat/stream_chat.dart'; import 'stream_channel.dart'; -/// A signature for a callback which exposes an error and returns a function. -/// This Callback can be used in cases where an API failure occurs and the widget -/// is unable to render data. -typedef StreamErrorBuilder = Widget Function( - BuildContext context, Object error); - /// [MessageListCore] is a simplified class that allows fetching a list of messages while exposing UI builders. /// A [MessageListController] is used to paginate data. /// @@ -89,7 +83,6 @@ class MessageListCore extends StatefulWidget { /// Callback triggered when an error occurs while performing the given request. /// This parameter can be used to display an error message to users in the event /// of a connection failure. - final StreamErrorBuilder errorWidgetBuilder; /// If true will show a scroll to bottom message when there are new messages and the scroll offset is not zero final bool showScrollToBottom; diff --git a/packages/stream_chat_flutter_core/lib/src/typedef.dart b/packages/stream_chat_flutter_core/lib/src/typedef.dart new file mode 100644 index 00000000..6cbc25a6 --- /dev/null +++ b/packages/stream_chat_flutter_core/lib/src/typedef.dart @@ -0,0 +1,7 @@ +import 'package:flutter/widgets.dart'; + +/// A signature for a callback which exposes an error and returns a function. +/// This Callback can be used in cases where an API failure occurs and the widget +/// is unable to render data. +typedef ErrorBuilder = Widget Function( + BuildContext context, Object error); \ No newline at end of file From c09f24d94577bf58bb94d02bb387ece1a12d23b3 Mon Sep 17 00:00:00 2001 From: Neevash Ramdial Date: Fri, 29 Jan 2021 10:19:18 -0400 Subject: [PATCH 1093/1140] migrate error builder callback using typedef --- packages/flutter_widgets/lib/src/channel_list_view.dart | 2 +- .../flutter_widgets/lib/src/message_search_list_view.dart | 2 +- packages/stream_chat_flutter_core/example/lib/main.dart | 2 +- .../stream_chat_flutter_core/lib/src/channel_list_core.dart | 5 +++-- .../stream_chat_flutter_core/lib/src/message_list_core.dart | 2 ++ .../lib/src/message_search_list_core.dart | 5 +++-- 6 files changed, 11 insertions(+), 7 deletions(-) diff --git a/packages/flutter_widgets/lib/src/channel_list_view.dart b/packages/flutter_widgets/lib/src/channel_list_view.dart index 84eb1298..aebb6f37 100644 --- a/packages/flutter_widgets/lib/src/channel_list_view.dart +++ b/packages/flutter_widgets/lib/src/channel_list_view.dart @@ -167,7 +167,7 @@ class _ChannelListViewState extends State emptyBuilder: (BuildContext context) { return _buildEmptyWidget(); }, - errorBuilder: (Error error) { + errorBuilder: (BuildContext context, dynamic error) { return _buildErrorWidget(context); }, loadingBuilder: (BuildContext context) { diff --git a/packages/flutter_widgets/lib/src/message_search_list_view.dart b/packages/flutter_widgets/lib/src/message_search_list_view.dart index 2cbea145..dd7232f9 100644 --- a/packages/flutter_widgets/lib/src/message_search_list_view.dart +++ b/packages/flutter_widgets/lib/src/message_search_list_view.dart @@ -148,7 +148,7 @@ class _MessageSearchListViewState extends State { }, ); }, - errorBuilder: (error) { + errorBuilder: (BuildContext context, dynamic error) { if (error is Error) { print((error).stackTrace); } diff --git a/packages/stream_chat_flutter_core/example/lib/main.dart b/packages/stream_chat_flutter_core/example/lib/main.dart index 3a86850f..845510f2 100644 --- a/packages/stream_chat_flutter_core/example/lib/main.dart +++ b/packages/stream_chat_flutter_core/example/lib/main.dart @@ -89,7 +89,7 @@ class HomeScreen extends StatelessWidget { ), ); }, - errorBuilder: (Error error) { + errorBuilder: (BuildContext context, dynamic error) { return Center( child: Text( 'Oh no, something went wrong. Please check your config.'), diff --git a/packages/stream_chat_flutter_core/lib/src/channel_list_core.dart b/packages/stream_chat_flutter_core/lib/src/channel_list_core.dart index d60292d1..7a9e7e41 100644 --- a/packages/stream_chat_flutter_core/lib/src/channel_list_core.dart +++ b/packages/stream_chat_flutter_core/lib/src/channel_list_core.dart @@ -5,6 +5,7 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:stream_chat/stream_chat.dart'; import 'package:stream_chat_flutter_core/src/channels_bloc.dart'; +import 'package:stream_chat_flutter_core/src/typedef.dart'; import 'stream_chat_core.dart'; @@ -72,7 +73,7 @@ class ChannelListCore extends StatefulWidget { final ChannelListController channelListController; /// The builder that will be used in case of error - final Widget Function(Error error) errorBuilder; + final ErrorBuilder errorBuilder; /// The builder that will be used in case of loading final WidgetBuilder loadingBuilder; @@ -162,7 +163,7 @@ class _ChannelListCoreState extends State print((snapshot.error as Error).stackTrace); } - return widget.errorBuilder(snapshot.error); + return widget.errorBuilder(context, snapshot.error); } void loadData() { diff --git a/packages/stream_chat_flutter_core/lib/src/message_list_core.dart b/packages/stream_chat_flutter_core/lib/src/message_list_core.dart index 2b9e5c0e..b8d5c8da 100644 --- a/packages/stream_chat_flutter_core/lib/src/message_list_core.dart +++ b/packages/stream_chat_flutter_core/lib/src/message_list_core.dart @@ -3,6 +3,7 @@ import 'dart:async'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:stream_chat/stream_chat.dart'; +import 'package:stream_chat_flutter_core/src/typedef.dart'; import 'stream_channel.dart'; /// [MessageListCore] is a simplified class that allows fetching a list of messages while exposing UI builders. @@ -83,6 +84,7 @@ class MessageListCore extends StatefulWidget { /// Callback triggered when an error occurs while performing the given request. /// This parameter can be used to display an error message to users in the event /// of a connection failure. + final ErrorBuilder errorWidgetBuilder; /// If true will show a scroll to bottom message when there are new messages and the scroll offset is not zero final bool showScrollToBottom; diff --git a/packages/stream_chat_flutter_core/lib/src/message_search_list_core.dart b/packages/stream_chat_flutter_core/lib/src/message_search_list_core.dart index cfdfb0ae..1eefc3a0 100644 --- a/packages/stream_chat_flutter_core/lib/src/message_search_list_core.dart +++ b/packages/stream_chat_flutter_core/lib/src/message_search_list_core.dart @@ -2,6 +2,7 @@ import 'dart:convert'; import 'package:flutter/material.dart'; import 'package:stream_chat/stream_chat.dart'; +import 'package:stream_chat_flutter_core/src/typedef.dart'; import 'message_search_bloc.dart'; /// @@ -82,7 +83,7 @@ class MessageSearchListCore extends StatefulWidget { final WidgetBuilder emptyBuilder; /// The builder that will be used in case of error - final Widget Function(Error error) errorBuilder; + final ErrorBuilder errorBuilder; /// The builder that will be used in case of loading final WidgetBuilder loadingBuilder; @@ -125,7 +126,7 @@ class _MessageSearchListCoreState extends State { print((snapshot.error as Error).stackTrace); } - return widget.errorBuilder(snapshot.error); + return widget.errorBuilder(context, snapshot.error); } if (!snapshot.hasData) { From 1628a7f4d7c2e0835114606751732ab7679fae4a Mon Sep 17 00:00:00 2001 From: Neevash Ramdial Date: Fri, 29 Jan 2021 10:19:57 -0400 Subject: [PATCH 1094/1140] Lint fix --- .../flutter_widgets/lib/src/message_search_list_view.dart | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/flutter_widgets/lib/src/message_search_list_view.dart b/packages/flutter_widgets/lib/src/message_search_list_view.dart index dd7232f9..8a22bf00 100644 --- a/packages/flutter_widgets/lib/src/message_search_list_view.dart +++ b/packages/flutter_widgets/lib/src/message_search_list_view.dart @@ -159,9 +159,8 @@ class _MessageSearchListViewState extends State { var message = error.toString(); if (error is DioError) { - final dioError = error as DioError; - if (dioError.type == DioErrorType.RESPONSE) { - message = dioError.message; + if (error.type == DioErrorType.RESPONSE) { + message = error.message; } else { message = 'Check your connection and retry'; } From e5829c3c83faecd12e62f944c22f155c46e33b30 Mon Sep 17 00:00:00 2001 From: Neevash Ramdial Date: Fri, 29 Jan 2021 10:34:18 -0400 Subject: [PATCH 1095/1140] update formatting --- packages/stream_chat_flutter_core/lib/src/typedef.dart | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/stream_chat_flutter_core/lib/src/typedef.dart b/packages/stream_chat_flutter_core/lib/src/typedef.dart index 6cbc25a6..3077574e 100644 --- a/packages/stream_chat_flutter_core/lib/src/typedef.dart +++ b/packages/stream_chat_flutter_core/lib/src/typedef.dart @@ -3,5 +3,4 @@ import 'package:flutter/widgets.dart'; /// A signature for a callback which exposes an error and returns a function. /// This Callback can be used in cases where an API failure occurs and the widget /// is unable to render data. -typedef ErrorBuilder = Widget Function( - BuildContext context, Object error); \ No newline at end of file +typedef ErrorBuilder = Widget Function(BuildContext context, Object error); From c0e4b51a3b001380afb558d87b9fe97d65cf91a2 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Fri, 29 Jan 2021 20:11:51 +0530 Subject: [PATCH 1096/1140] Fix action Signed-off-by: Sahil Kumar --- .github/workflows/stream_flutter_workflow.yml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/.github/workflows/stream_flutter_workflow.yml b/.github/workflows/stream_flutter_workflow.yml index 06a8a2ec..240c0310 100644 --- a/.github/workflows/stream_flutter_workflow.yml +++ b/.github/workflows/stream_flutter_workflow.yml @@ -71,7 +71,7 @@ jobs: test_dart: runs-on: ubuntu-latest - timeout-minutes: 15 + timeout-minutes: 5 steps: - uses: actions/checkout@v1 with: @@ -83,9 +83,7 @@ jobs: - name: 'Bootstrap Workspace' run: melos bootstrap - name: 'Flutter Test' - run: | - melos exec -c 1 --no-flutter --dir-exists=test --ignore="*example*" --ignore="*web*" -- \ - flutter pub run test + run: cd packages/dart_client && flutter pub run test test_flutter: runs-on: ubuntu-latest From f69821b813f28d6b89f7bba842090aef7d8ff274 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Fri, 29 Jan 2021 20:15:29 +0530 Subject: [PATCH 1097/1140] [Persistence] Update changelog, pubspec Signed-off-by: Sahil Kumar --- packages/stream_chat_persistence/CHANGELOG.md | 4 ++-- packages/stream_chat_persistence/pubspec.yaml | 9 +++++---- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/packages/stream_chat_persistence/CHANGELOG.md b/packages/stream_chat_persistence/CHANGELOG.md index ac071598..ba22fd4f 100644 --- a/packages/stream_chat_persistence/CHANGELOG.md +++ b/packages/stream_chat_persistence/CHANGELOG.md @@ -1,3 +1,3 @@ -## [0.0.1] - TODO: Add release date. +## 1.0.0-rc -* TODO: Describe initial release. +* Initial release \ No newline at end of file diff --git a/packages/stream_chat_persistence/pubspec.yaml b/packages/stream_chat_persistence/pubspec.yaml index a0c97c89..b8e49170 100644 --- a/packages/stream_chat_persistence/pubspec.yaml +++ b/packages/stream_chat_persistence/pubspec.yaml @@ -1,8 +1,9 @@ name: stream_chat_persistence -description: A new Flutter package. -version: 0.0.1 -author: -homepage: +homepage: https://github.com/GetStream/stream-chat-flutter +description: Official Stream Chat Persistence library. Build your own chat experience using Dart and Flutter. +version: 1.0.0-rc +repository: https://github.com/GetStream/stream-chat-flutter +issue_tracker: https://github.com/GetStream/stream-chat-flutter/issues environment: sdk: ">=2.7.0 <3.0.0" From 74707093b67ff804056193f86a786673a9801bca Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Fri, 29 Jan 2021 20:22:04 +0530 Subject: [PATCH 1098/1140] [Persistence] Update LICENSE Signed-off-by: Sahil Kumar --- packages/stream_chat_persistence/LICENSE | 220 ++++++++++++++++++++++- 1 file changed, 219 insertions(+), 1 deletion(-) diff --git a/packages/stream_chat_persistence/LICENSE b/packages/stream_chat_persistence/LICENSE index ba75c69f..49088d47 100644 --- a/packages/stream_chat_persistence/LICENSE +++ b/packages/stream_chat_persistence/LICENSE @@ -1 +1,219 @@ -TODO: Add your license here. +SOURCE CODE LICENSE AGREEMENT + +IMPORTANT - READ THIS CAREFULLY BEFORE DOWNLOADING, INSTALLING, USING OR +ELECTRONICALLY ACCESSING THIS PROPRIETARY PRODUCT. + +THIS IS A LEGAL AGREEMENT BETWEEN STREAM.IO, INC. (“STREAM.IO”) AND THE +BUSINESS ENTITY OR PERSON FOR WHOM YOU (“YOU”) ARE ACTING (“CUSTOMER”) AS THE +LICENSEE OF THE PROPRIETARY SOFTWARE INTO WHICH THIS AGREEMENT HAS BEEN +INCLUDED (THE “AGREEMENT”). YOU AGREE THAT YOU ARE THE CUSTOMER, OR YOU ARE AN +EMPLOYEE OR AGENT OF CUSTOMER AND ARE ENTERING INTO THIS AGREEMENT FOR LICENSE +OF THE SOFTWARE BY CUSTOMER FOR CUSTOMER’S BUSINESS PURPOSES AS DESCRIBED IN +AND IN ACCORDANCE WITH THIS AGREEMENT. YOU HEREBY AGREE THAT YOU ENTER INTO +THIS AGREEMENT ON BEHALF OF CUSTOMER AND THAT YOU HAVE THE AUTHORITY TO BIND +CUSTOMER TO THIS AGREEMENT. + +STREAM.IO IS WILLING TO LICENSE THE SOFTWARE TO CUSTOMER ONLY ON THE FOLLOWING +CONDITIONS: (1) YOU ARE A CURRENT CUSTOMER OF STREAM.IO; (2) YOU ARE NOT A +COMPETITOR OF STREAM.IO; AND (3) THAT YOU ACCEPT ALL THE TERMS IN THIS +AGREEMENT. BY DOWNLOADING, INSTALLING, CONFIGURING, ACCESSING OR OTHERWISE +USING THE SOFTWARE, INCLUDING ANY UPDATES, UPGRADES, OR NEWER VERSIONS, YOU +REPRESENT, WARRANT AND ACKNOWLEDGE THAT (A) CUSTOMER IS A CURRENT CUSTOMER OF +STREAM.IO; (B) CUSTOMER IS NOT A COMPETITOR OF STREAM.IO; AND THAT (C) YOU HAVE +READ THIS AGREEMENT, UNDERSTAND THIS AGREEMENT, AND THAT CUSTOMER AGREES TO BE +BOUND BY ALL THE TERMS OF THIS AGREEMENT. + +IF YOU DO NOT AGREE TO ALL THE TERMS AND CONDITIONS OF THIS AGREEMENT, +STREAM.IO IS UNWILLING TO LICENSE THE SOFTWARE TO CUSTOMER, AND THEREFORE, DO +NOT COMPLETE THE DOWNLOAD PROCESS, ACCESS OR OTHERWISE USE THE SOFTWARE, AND +CUSTOMER SHOULD IMMEDIATELY RETURN THE SOFTWARE AND CEASE ANY USE OF THE +SOFTWARE. + +1. SOFTWARE. The Stream.io software accompanying this Agreement, may include +Source Code, Executable Object Code, associated media, printed materials and +documentation (collectively, the “Software”). The Software also includes any +updates or upgrades to or new versions of the original Software, if and when +made available to you by Stream.io. “Source Code” means computer programming +code in human readable form that is not suitable for machine execution without +the intervening steps of interpretation or compilation. “Executable Object +Code" means the computer programming code in any other form than Source Code +that is not readily perceivable by humans and suitable for machine execution +without the intervening steps of interpretation or compilation. “Site” means a +Customer location controlled by Customer. “Authorized User” means any employee +or contractor of Customer working at the Site, who has signed a written +confidentiality agreement with Customer or is otherwise bound in writing by +confidentiality and use obligations at least as restrictive as those imposed +under this Agreement. + +2. LICENSE GRANT. Subject to the terms and conditions of this Agreement, in +consideration for the representations, warranties, and covenants made by +Customer in this Agreement, Stream.io grants to Customer, during the term of +this Agreement, a personal, non-exclusive, non-transferable, non-sublicensable +license to: + +a. install and use Software Source Code on password protected computers at a Site, +restricted to Authorized Users; + +b. create derivative works, improvements (whether or not patentable), extensions +and other modifications to the Software Source Code (“Modifications”) to build +unique scalable newsfeeds, activity streams, and in-app messaging via Stream’s +application program interface (“API”); + +c. compile the Software Source Code to create Executable Object Code versions of +the Software Source Code and Modifications to build such newsfeeds, activity +streams, and in-app messaging via the API; + +d. install, execute and use such Executable Object Code versions solely for +Customer’s internal business use (including development of websites through +which data generated by Stream services will be streamed (“Apps”)); + +e. use and distribute such Executable Object Code as part of Customer’s Apps; and + +f. make electronic copies of the Software and Modifications as required for backup +or archival purposes. + +3. RESTRICTIONS. Customer is responsible for all activities that occur in +connection with the Software. Customer will not, and will not attempt to: (a) +sublicense or transfer the Software or any Source Code related to the Software +or any of Customer’s rights under this Agreement, except as otherwise provided +in this Agreement, (b) use the Software Source Code for the benefit of a third +party or to operate a service; (c) allow any third party to access or use the +Software Source Code; (d) sublicense or distribute the Software Source Code or +any Modifications in Source Code or other derivative works based on any part of +the Software Source Code; (e) use the Software in any manner that competes with +Stream.io or its business; or (e) otherwise use the Software in any manner that +exceeds the scope of use permitted in this Agreement. Customer shall use the +Software in compliance with any accompanying documentation any laws applicable +to Customer. + +4. OPEN SOURCE. Customer and its Authorized Users shall not use any software or +software components that are open source in conjunction with the Software +Source Code or any Modifications in Source Code or in any way that could +subject the Software to any open source licenses. + +5. CONTRACTORS. Under the rights granted to Customer under this Agreement, +Customer may permit its employees, contractors, and agencies of Customer to +become Authorized Users to exercise the rights to the Software granted to +Customer in accordance with this Agreement solely on behalf of Customer to +provide services to Customer; provided that Customer shall be liable for the +acts and omissions of all Authorized Users to the extent any of such acts or +omissions, if performed by Customer, would constitute a breach of, or otherwise +give rise to liability to Customer under, this Agreement. Customer shall not +and shall not permit any Authorized User to use the Software except as +expressly permitted in this Agreement. + +6. COMPETITIVE PRODUCT DEVELOPMENT. Customer shall not use the Software in any way +to engage in the development of products or services which could be reasonably +construed to provide a complete or partial functional or commercial alternative +to Stream.io’s products or services (a “Competitive Product”). Customer shall +ensure that there is no direct or indirect use of, or sharing of, Software +source code, or other information based upon or derived from the Software to +develop such products or services. Without derogating from the generality of +the foregoing, development of Competitive Products shall include having direct +or indirect access to, supervising, consulting or assisting in the development +of, or producing any specifications, documentation, object code or source code +for, all or part of a Competitive Product. + +7. LIMITATION ON MODIFICATIONS. Notwithstanding any provision in this Agreement, +Modifications may only be created and used by Customer as permitted by this +Agreement and Modification Source Code may not be distributed to third parties. +Customer will not assert against Stream.io, its affiliates, or their customers, +direct or indirect, agents and contractors, in any way, any patent rights that +Customer may obtain relating to any Modifications for Stream.io, its +affiliates’, or their customers’, direct or indirect, agents’ and contractors’ +manufacture, use, import, offer for sale or sale of any Stream.io products or +services. + +8. DELIVERY AND ACCEPTANCE. The Software will be delivered electronically pursuant +to Stream.io standard download procedures. The Software is deemed accepted upon +delivery. + +9. IMPLEMENTATION AND SUPPORT. Stream.io has no obligation under this Agreement to +provide any support or consultation concerning the Software. + +10. TERM AND TERMINATION. The term of this Agreement begins when the Software is +downloaded or accessed and shall continue until terminated. Either party may +terminate this Agreement upon written notice. This Agreement shall +automatically terminate if Customer is or becomes a competitor of Stream.io or +makes or sells any Competitive Products. Upon termination of this Agreement for +any reason, (a) all rights granted to Customer in this Agreement immediately +cease to exist, (b) Customer must promptly discontinue all use of the Software +and return to Stream.io or destroy all copies of the Software in Customer’s +possession or control. Any continued use of the Software by Customer or attempt +by Customer to exercise any rights under this Agreement after this Agreement +has terminated shall be considered copyright infringement and subject Customer +to applicable remedies for copyright infringement. Sections 2, 5, 6, 8 and 9 +shall survive expiration or termination of this Agreement for any reason. + +11. OWNERSHIP. As between the parties, the Software and all worldwide intellectual +property rights and proprietary rights relating thereto or embodied therein, +are the exclusive property of Stream.io and its suppliers. Stream.io and its +suppliers reserve all rights in and to the Software not expressly granted to +Customer in this Agreement, and no other licenses or rights are granted by +implication, estoppel or otherwise. + +12. WARRANTY DISCLAIMER. USE OF THIS SOFTWARE IS ENTIRELY AT YOURS AND CUSTOMER’S +OWN RISK. THE SOFTWARE IS PROVIDED “AS IS” WITHOUT ANY WARRANTY OF ANY KIND +WHATSOEVER. STREAM.IO DOES NOT MAKE, AND HEREBY DISCLAIMS, ANY WARRANTY OF ANY +KIND, WHETHER EXPRESS, IMPLIED, STATUTORY OR OTHERWISE, INCLUDING WITHOUT +LIMITATION, THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +PURPOSE, TITLE, NON-INFRINGEMENT OF THIRD-PARTY RIGHTS, RESULTS, EFFORTS, +QUALITY OR QUIET ENJOYMENT. STREAM.IO DOES NOT WARRANT THAT THE SOFTWARE IS +ERROR-FREE, WILL FUNCTION WITHOUT INTERRUPTION, WILL MEET ANY SPECIFIC NEED +THAT CUSTOMER HAS, THAT ALL DEFECTS WILL BE CORRECTED OR THAT IT IS +SUFFICIENTLY DOCUMENTED TO BE USABLE BY CUSTOMER. TO THE EXTENT THAT STREAM.IO +MAY NOT DISCLAIM ANY WARRANTY AS A MATTER OF APPLICABLE LAW, THE SCOPE AND +DURATION OF SUCH WARRANTY WILL BE THE MINIMUM PERMITTED UNDER SUCH LAW. +CUSTOMER ACKNOWLEDGES THAT IT HAS RELIED ON NO WARRANTIES OTHER THAN THE +EXPRESS WARRANTIES IN THIS AGREEMENT. + +13. LIMITATION OF LIABILITY. TO THE FULLEST EXTENT PERMISSIBLE BY LAW, STREAM.IO’S +TOTAL LIABILITY FOR ALL DAMAGES ARISING OUT OF OR RELATED TO THE SOFTWARE OR +THIS AGREEMENT, WHETHER IN CONTRACT, TORT (INCLUDING NEGLIGENCE) OR OTHERWISE, +SHALL NOT EXCEED $100. IN NO EVENT WILL STREAM.IO BE LIABLE FOR ANY INDIRECT, +CONSEQUENTIAL, EXEMPLARY, PUNITIVE, SPECIAL OR INCIDENTAL DAMAGES OF ANY KIND +WHATSOEVER, INCLUDING ANY LOST DATA AND LOST PROFITS, ARISING FROM OR RELATING +TO THE SOFTWARE EVEN IF STREAM.IO HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. CUSTOMER ACKNOWLEDGES THAT THIS PROVISION REFLECTS THE AGREED UPON +ALLOCATION OF RISK FOR THIS AGREEMENT AND THAT STREAM.IO WOULD NOT ENTER INTO +THIS AGREEMENT WITHOUT THESE LIMITATIONS ON ITS LIABILITY. + +14. General. Customer may not assign or transfer this Agreement, by operation of +law or otherwise, or any of its rights under this Agreement (including the +license rights granted to Customer) to any third party without Stream.io’s +prior written consent, which consent will not be unreasonably withheld or +delayed. Stream.io may assign this Agreement, without consent, including, but +limited to, affiliate or any successor to all or substantially all its business +or assets to which this Agreement relates, whether by merger, sale of assets, +sale of stock, reorganization or otherwise. Any attempted assignment or +transfer in violation of the foregoing will be null and void. Stream.io shall +not be liable hereunder by reason of any failure or delay in the performance of +its obligations hereunder for any cause which is beyond the reasonable control. +All notices, consents, and approvals under this Agreement must be delivered in +writing by courier, by electronic mail, or by certified or registered mail, +(postage prepaid and return receipt requested) to the other party at the +address set forth in the customer agreement between Stream.io and Customer and +will be effective upon receipt or when delivery is refused. This Agreement will +be governed by and interpreted in accordance with the laws of the State of +Colorado, without reference to its choice of laws rules. The United Nations +Convention on Contracts for the International Sale of Goods does not apply to +this Agreement. Any action or proceeding arising from or relating to this +Agreement shall be brought in a federal or state court in Denver, Colorado, and +each party irrevocably submits to the jurisdiction and venue of any such court +in any such action or proceeding. All waivers must be in writing. Any waiver or +failure to enforce any provision of this Agreement on one occasion will not be +deemed a waiver of any other provision or of such provision on any other +occasion. If any provision of this Agreement is unenforceable, such provision +will be changed and interpreted to accomplish the objectives of such provision +to the greatest extent possible under applicable law and the remaining +provisions will continue in full force and effect. Customer shall not violate +any applicable law, rule or regulation, including those regarding the export of +technical data. The headings of Sections of this Agreement are for convenience +and are not to be used in interpreting this Agreement. As used in this +Agreement, the word “including” means “including but not limited to.” This +Agreement (including all exhibits and attachments) constitutes the entire +agreement between the parties regarding the subject hereof and supersedes all +prior or contemporaneous agreements, understandings and communication, whether +written or oral. This Agreement may be amended only by a written document +signed by both parties. The terms of any purchase order or similar document +submitted by Customer to Stream.io will have no effect. From 00b24113c364dedd9102d4093585af75f68079b3 Mon Sep 17 00:00:00 2001 From: Neevash Ramdial Date: Fri, 29 Jan 2021 21:02:31 -0400 Subject: [PATCH 1099/1140] [Core] Update documentation with API links --- .../lib/src/channel_list_core.dart | 9 ++++++--- .../lib/src/channels_bloc.dart | 20 ++++++++++++++++++- .../lib/src/lazy_load_scroll_view.dart | 6 +++--- .../lib/src/message_list_core.dart | 7 +++---- .../lib/src/message_search_bloc.dart | 11 +++++++++- .../lib/src/message_search_list_core.dart | 7 ++++++- .../lib/src/stream_channel.dart | 3 ++- .../lib/src/stream_chat_core.dart | 7 +++++++ .../lib/src/users_bloc.dart | 7 +++++++ 9 files changed, 63 insertions(+), 14 deletions(-) diff --git a/packages/stream_chat_flutter_core/lib/src/channel_list_core.dart b/packages/stream_chat_flutter_core/lib/src/channel_list_core.dart index 7a9e7e41..393c3686 100644 --- a/packages/stream_chat_flutter_core/lib/src/channel_list_core.dart +++ b/packages/stream_chat_flutter_core/lib/src/channel_list_core.dart @@ -257,11 +257,14 @@ class _ChannelListCoreState extends State } } -/// Controller used for paginating data in [ChannelListCore] +/// Controller used for loading more data and controlling pagination in [ChannelListCore]. class ChannelListController { - /// Call this function to reload data + /// This function calls Stream's servers to load a list of channels. If there is existing data, + /// calling this function causes a reload. VoidCallback loadData; - /// Call this function to load further data + /// This function is used to load another page of data. Note, [loadData] should be + /// used to populate the initial page of data. Calling [paginateData] performs a query + /// to load subsequent pages. VoidCallback paginateData; } diff --git a/packages/stream_chat_flutter_core/lib/src/channels_bloc.dart b/packages/stream_chat_flutter_core/lib/src/channels_bloc.dart index 2eef0f8a..1c30ad65 100644 --- a/packages/stream_chat_flutter_core/lib/src/channels_bloc.dart +++ b/packages/stream_chat_flutter_core/lib/src/channels_bloc.dart @@ -3,10 +3,28 @@ import 'dart:async'; import 'package:flutter/material.dart'; import 'package:rxdart/rxdart.dart'; import 'package:stream_chat/stream_chat.dart'; +import 'package:stream_chat_flutter_core/src/channel_list_core.dart'; import 'package:stream_chat_flutter_core/src/stream_chat_core.dart'; /// Widget dedicated to the management of a channel list with pagination +/// [ChannelsBloc] is used together with [ChannelListCore] to manage a list of +/// [Channel]s with pagination, re-ordering, querying and other operations +/// associated with [Channel]s. +/// +/// [ChannelsBloc] can be access at anytime by using the static [of] method +/// using Flutter's [BuildContext]. +/// +/// API docs: https://getstream.io/chat/docs/flutter-dart/query_channels/ class ChannelsBloc extends StatefulWidget { + /// Creates a new [ChannelsBloc]. The parameter [child] must be supplied and not null. + const ChannelsBloc({ + Key key, + @required this.child, + this.lockChannelsOrder = false, + this.channelsComparator, + this.shouldAddChannel, + }) : super(key: key); + /// The widget child final Widget child; @@ -45,7 +63,7 @@ class ChannelsBloc extends StatefulWidget { } } -/// The current state of the [ChannelsBloc] +/// The current state of the [ChannelsBloc]. class ChannelsBlocState extends State with AutomaticKeepAliveClientMixin { @override diff --git a/packages/stream_chat_flutter_core/lib/src/lazy_load_scroll_view.dart b/packages/stream_chat_flutter_core/lib/src/lazy_load_scroll_view.dart index bc1f4d1b..0e118420 100644 --- a/packages/stream_chat_flutter_core/lib/src/lazy_load_scroll_view.dart +++ b/packages/stream_chat_flutter_core/lib/src/lazy_load_scroll_view.dart @@ -3,8 +3,8 @@ import 'package:flutter/widgets.dart'; enum _LoadingStatus { LOADING, STABLE } -/// A widget that wraps a [Widget] and will trigger [onEndOfPage]/[onStartOfPage] when it -/// reaches the bottom/start of the list +/// Wrapper around a [Scrollable] which triggers [onEndOfPage]/[onStartOfPage] the Scrollable +/// reaches to the start or end of the view extent. class LazyLoadScrollView extends StatefulWidget { /// The [Widget] that this widget watches for changes on final Widget child; @@ -27,7 +27,7 @@ class LazyLoadScrollView extends StatefulWidget { /// The offset to take into account when triggering [onEndOfPage]/[onStartOfPage] in pixels final double scrollOffset; - /// Used to determine if loading of new data has finished. You should use set this if you aren't using a FutureBuilder or StreamBuilder + /// Used to determine if loading of new data has finished. You should use set this if you aren't using a [FutureBuilder] or [StreamBuilder]. final bool isLoading; /// Initiates a LazyLoadScrollView widget diff --git a/packages/stream_chat_flutter_core/lib/src/message_list_core.dart b/packages/stream_chat_flutter_core/lib/src/message_list_core.dart index b8d5c8da..5856575c 100644 --- a/packages/stream_chat_flutter_core/lib/src/message_list_core.dart +++ b/packages/stream_chat_flutter_core/lib/src/message_list_core.dart @@ -53,10 +53,8 @@ import 'stream_channel.dart'; /// Make sure to have a [StreamChannel] ancestor in order to provide the information about the channels. /// The widget uses a [ListView.custom] to render the list of channels. /// -/// The widget components render the ui based on the first ancestor of type [StreamChatTheme]. -/// Modify it to change the widget appearance. class MessageListCore extends StatefulWidget { - /// Instantiate a new MessageListView + /// Instantiate a new [MessageListView] MessageListCore({ Key key, this.showScrollToBottom = true, @@ -89,7 +87,8 @@ class MessageListCore extends StatefulWidget { /// If true will show a scroll to bottom message when there are new messages and the scroll offset is not zero final bool showScrollToBottom; - /// Parent message in case of a thread + /// If the current message belongs to a `thread`, this property represents the + /// first message or the parent of the conversation. final Message parentMessage; @override diff --git a/packages/stream_chat_flutter_core/lib/src/message_search_bloc.dart b/packages/stream_chat_flutter_core/lib/src/message_search_bloc.dart index ca6a983d..615f5374 100644 --- a/packages/stream_chat_flutter_core/lib/src/message_search_bloc.dart +++ b/packages/stream_chat_flutter_core/lib/src/message_search_bloc.dart @@ -4,7 +4,13 @@ import 'package:stream_chat/stream_chat.dart'; import 'stream_chat_core.dart'; -/// Widget dedicated to the management of a message list with pagination +/// [MessageSearchBloc] is used to manage a list of messages with pagination. +/// This class can be used to load messages, perform queries, etc. +/// +/// [MessageSearchBloc] can be access at anytime by using the static [of] method +/// using Flutter's [BuildContext]. +/// +// API docs: https://getstream.io/chat/docs/flutter-dart/send_message/ class MessageSearchBloc extends StatefulWidget { /// The widget child final Widget child; @@ -15,6 +21,9 @@ class MessageSearchBloc extends StatefulWidget { @required this.child, }) : super(key: key); + /// The widget child + final Widget child; + @override MessageSearchBlocState createState() => MessageSearchBlocState(); diff --git a/packages/stream_chat_flutter_core/lib/src/message_search_list_core.dart b/packages/stream_chat_flutter_core/lib/src/message_search_list_core.dart index 1eefc3a0..26ee58c1 100644 --- a/packages/stream_chat_flutter_core/lib/src/message_search_list_core.dart +++ b/packages/stream_chat_flutter_core/lib/src/message_search_list_core.dart @@ -32,7 +32,12 @@ import 'message_search_bloc.dart'; /// The widget uses a [ListView.separated] to render the list of messages. /// class MessageSearchListCore extends StatefulWidget { - /// Instantiate a new MessageSearchListView + /// Instantiate a new [MessageSearchListView]. + /// The following parameters must be supplied and not null: + /// * [emptyBuilder] + /// * [errorBuilder] + /// * [loadingBuilder] + /// * [childBuilder] const MessageSearchListCore({ Key key, @required this.emptyBuilder, diff --git a/packages/stream_chat_flutter_core/lib/src/stream_channel.dart b/packages/stream_chat_flutter_core/lib/src/stream_channel.dart index 85f7ecca..af5502ae 100644 --- a/packages/stream_chat_flutter_core/lib/src/stream_channel.dart +++ b/packages/stream_chat_flutter_core/lib/src/stream_channel.dart @@ -17,7 +17,8 @@ enum QueryDirection { /// /// Use [StreamChannel.of] to get the current [StreamChannelState] instance. class StreamChannel extends StatefulWidget { - // ignore: public_member_api_docs + /// Creates a new instance of [StreamChannel]. Both [child] and [client] must + /// be supplied and not null. const StreamChannel({ Key key, @required this.child, diff --git a/packages/stream_chat_flutter_core/lib/src/stream_chat_core.dart b/packages/stream_chat_flutter_core/lib/src/stream_chat_core.dart index 3d23eb08..a37dfd54 100644 --- a/packages/stream_chat_flutter_core/lib/src/stream_chat_core.dart +++ b/packages/stream_chat_flutter_core/lib/src/stream_chat_core.dart @@ -49,6 +49,13 @@ class StreamChatCore extends StatefulWidget { @required this.child, }) : super(key: key); + /// Instance of Stream Chat Client containing information about the current + /// application. + final Client client; + + /// Widget descendant. + final Widget child; + @override StreamChatCoreState createState() => StreamChatCoreState(); diff --git a/packages/stream_chat_flutter_core/lib/src/users_bloc.dart b/packages/stream_chat_flutter_core/lib/src/users_bloc.dart index 5ada9d90..bef0cead 100644 --- a/packages/stream_chat_flutter_core/lib/src/users_bloc.dart +++ b/packages/stream_chat_flutter_core/lib/src/users_bloc.dart @@ -5,11 +5,18 @@ import 'package:stream_chat/stream_chat.dart'; import 'stream_chat_core.dart'; /// Widget dedicated to the management of a users list with pagination. +/// +/// [UsersBloc] can be access at anytime by using the static [of] method +/// using Flutter's [BuildContext]. +/// +/// API docs: https://getstream.io/chat/docs/flutter-dart/init_and_users/ class UsersBloc extends StatefulWidget { /// The widget child final Widget child; /// Instantiate a new UsersBloc + /// Instantiate a new [UsersBloc]. The parameter [child] must be supplied and + /// not null. const UsersBloc({ Key key, @required this.child, From f7d1e480c7eb94099fa73eccd5bcf21907a8c93b Mon Sep 17 00:00:00 2001 From: Neevash Ramdial Date: Fri, 29 Jan 2021 21:04:14 -0400 Subject: [PATCH 1100/1140] [Core] sort constructor first across package --- .../lib/src/channels_bloc.dart | 9 ------ .../lib/src/lazy_load_scroll_view.dart | 28 ++++++++++--------- .../lib/src/message_search_bloc.dart | 3 -- .../lib/src/stream_chat_core.dart | 7 ----- .../lib/src/users_bloc.dart | 7 ++--- 5 files changed, 18 insertions(+), 36 deletions(-) diff --git a/packages/stream_chat_flutter_core/lib/src/channels_bloc.dart b/packages/stream_chat_flutter_core/lib/src/channels_bloc.dart index 1c30ad65..987e06f9 100644 --- a/packages/stream_chat_flutter_core/lib/src/channels_bloc.dart +++ b/packages/stream_chat_flutter_core/lib/src/channels_bloc.dart @@ -37,15 +37,6 @@ class ChannelsBloc extends StatefulWidget { /// Function used to evaluate if a channel should be added to the list when a message.new event is received final bool Function(Event) shouldAddChannel; - /// Instantiate a new ChannelsBloc - const ChannelsBloc({ - Key key, - this.child, - this.lockChannelsOrder = false, - this.channelsComparator, - this.shouldAddChannel, - }) : super(key: key); - @override ChannelsBlocState createState() => ChannelsBlocState(); diff --git a/packages/stream_chat_flutter_core/lib/src/lazy_load_scroll_view.dart b/packages/stream_chat_flutter_core/lib/src/lazy_load_scroll_view.dart index 0e118420..1ba9ca7b 100644 --- a/packages/stream_chat_flutter_core/lib/src/lazy_load_scroll_view.dart +++ b/packages/stream_chat_flutter_core/lib/src/lazy_load_scroll_view.dart @@ -6,6 +6,21 @@ enum _LoadingStatus { LOADING, STABLE } /// Wrapper around a [Scrollable] which triggers [onEndOfPage]/[onStartOfPage] the Scrollable /// reaches to the start or end of the view extent. class LazyLoadScrollView extends StatefulWidget { + /// Creates a new instance of [LazyLoadScrollView]. The parameter [child] must be + /// supplied and not null. + const LazyLoadScrollView({ + Key key, + @required this.child, + this.onStartOfPage, + this.onEndOfPage, + this.onPageScrollStart, + this.onPageScrollEnd, + this.onInBetweenOfPage, + this.isLoading = false, + this.scrollOffset = 100, + }) : assert(child != null), + super(key: key); + /// The [Widget] that this widget watches for changes on final Widget child; @@ -30,19 +45,6 @@ class LazyLoadScrollView extends StatefulWidget { /// Used to determine if loading of new data has finished. You should use set this if you aren't using a [FutureBuilder] or [StreamBuilder]. final bool isLoading; - /// Initiates a LazyLoadScrollView widget - const LazyLoadScrollView({ - Key key, - @required this.child, - this.onStartOfPage, - this.onEndOfPage, - this.onPageScrollStart, - this.onPageScrollEnd, - this.onInBetweenOfPage, - this.isLoading = false, - this.scrollOffset = 100, - }) : assert(child != null), - super(key: key); @override State createState() => _LazyLoadScrollViewState(); diff --git a/packages/stream_chat_flutter_core/lib/src/message_search_bloc.dart b/packages/stream_chat_flutter_core/lib/src/message_search_bloc.dart index 615f5374..a6a73012 100644 --- a/packages/stream_chat_flutter_core/lib/src/message_search_bloc.dart +++ b/packages/stream_chat_flutter_core/lib/src/message_search_bloc.dart @@ -12,9 +12,6 @@ import 'stream_chat_core.dart'; /// // API docs: https://getstream.io/chat/docs/flutter-dart/send_message/ class MessageSearchBloc extends StatefulWidget { - /// The widget child - final Widget child; - /// Instantiate a new MessageSearchBloc const MessageSearchBloc({ Key key, diff --git a/packages/stream_chat_flutter_core/lib/src/stream_chat_core.dart b/packages/stream_chat_flutter_core/lib/src/stream_chat_core.dart index a37dfd54..d454d8c9 100644 --- a/packages/stream_chat_flutter_core/lib/src/stream_chat_core.dart +++ b/packages/stream_chat_flutter_core/lib/src/stream_chat_core.dart @@ -32,13 +32,6 @@ import 'package:stream_chat/stream_chat.dart'; /// ``` /// class StreamChatCore extends StatefulWidget { - /// Instance of Stream Chat Client containing information about the current - /// application. - final Client client; - - /// Widget descendant. - final Widget child; - /// Constructor used for creating a new instance of [StreamChatCore]. /// /// [StreamChatCore] is a stateful widget which reacts to system events and updates diff --git a/packages/stream_chat_flutter_core/lib/src/users_bloc.dart b/packages/stream_chat_flutter_core/lib/src/users_bloc.dart index bef0cead..359985b3 100644 --- a/packages/stream_chat_flutter_core/lib/src/users_bloc.dart +++ b/packages/stream_chat_flutter_core/lib/src/users_bloc.dart @@ -11,10 +11,6 @@ import 'stream_chat_core.dart'; /// /// API docs: https://getstream.io/chat/docs/flutter-dart/init_and_users/ class UsersBloc extends StatefulWidget { - /// The widget child - final Widget child; - - /// Instantiate a new UsersBloc /// Instantiate a new [UsersBloc]. The parameter [child] must be supplied and /// not null. const UsersBloc({ @@ -22,6 +18,9 @@ class UsersBloc extends StatefulWidget { @required this.child, }) : super(key: key); + /// The widget child + final Widget child; + @override UsersBlocState createState() => UsersBlocState(); From a4b7a4441aefd39f248e5e4f0e1ed7ff876d9a32 Mon Sep 17 00:00:00 2001 From: Neevash Ramdial Date: Fri, 29 Jan 2021 21:16:07 -0400 Subject: [PATCH 1101/1140] Add assert checks for required parameters. --- .../lib/src/channel_list_core.dart | 6 +++++- .../lib/src/channels_bloc.dart | 3 ++- .../lib/src/message_list_core.dart | 12 ++++++++---- .../lib/src/message_search_bloc.dart | 3 ++- .../lib/src/message_search_list_core.dart | 6 +++++- .../lib/src/stream_chat_core.dart | 4 +++- .../lib/src/user_list_core.dart | 7 +++++-- .../stream_chat_flutter_core/lib/src/users_bloc.dart | 3 ++- 8 files changed, 32 insertions(+), 12 deletions(-) diff --git a/packages/stream_chat_flutter_core/lib/src/channel_list_core.dart b/packages/stream_chat_flutter_core/lib/src/channel_list_core.dart index 393c3686..b77ef394 100644 --- a/packages/stream_chat_flutter_core/lib/src/channel_list_core.dart +++ b/packages/stream_chat_flutter_core/lib/src/channel_list_core.dart @@ -66,7 +66,11 @@ class ChannelListCore extends StatefulWidget { this.sort, this.pagination, this.channelListController, - }) : super(key: key); + }) : assert(errorBuilder != null), + assert(emptyBuilder != null), + assert(loadingBuilder != null), + assert(listBuilder != null), + super(key: key); /// A [ChannelListController] allows reloading and pagination. /// Use [ChannelListController.loadData] and [ChannelListController.paginateData] respectively for reloading and pagination. diff --git a/packages/stream_chat_flutter_core/lib/src/channels_bloc.dart b/packages/stream_chat_flutter_core/lib/src/channels_bloc.dart index 987e06f9..7009234b 100644 --- a/packages/stream_chat_flutter_core/lib/src/channels_bloc.dart +++ b/packages/stream_chat_flutter_core/lib/src/channels_bloc.dart @@ -23,7 +23,8 @@ class ChannelsBloc extends StatefulWidget { this.lockChannelsOrder = false, this.channelsComparator, this.shouldAddChannel, - }) : super(key: key); + }) : assert(child != null), + super(key: key); /// The widget child final Widget child; diff --git a/packages/stream_chat_flutter_core/lib/src/message_list_core.dart b/packages/stream_chat_flutter_core/lib/src/message_list_core.dart index 5856575c..64e8f255 100644 --- a/packages/stream_chat_flutter_core/lib/src/message_list_core.dart +++ b/packages/stream_chat_flutter_core/lib/src/message_list_core.dart @@ -54,17 +54,21 @@ import 'stream_channel.dart'; /// The widget uses a [ListView.custom] to render the list of channels. /// class MessageListCore extends StatefulWidget { - /// Instantiate a new [MessageListView] + /// Instantiate a new [MessageListView]. MessageListCore({ Key key, - this.showScrollToBottom = true, - this.parentMessage, @required this.loadingBuilder, @required this.emptyBuilder, @required this.messageListBuilder, @required this.errorWidgetBuilder, + this.showScrollToBottom = true, + this.parentMessage, this.messageListController, - }) : super(key: key); + }) : assert(loadingBuilder != null), + assert(emptyBuilder != null), + assert(messageListBuilder != null), + assert(errorWidgetBuilder != null), + super(key: key); /// A [MessageListController] allows pagination. /// Use [ChannelListController.paginateData] pagination. diff --git a/packages/stream_chat_flutter_core/lib/src/message_search_bloc.dart b/packages/stream_chat_flutter_core/lib/src/message_search_bloc.dart index a6a73012..6458bebf 100644 --- a/packages/stream_chat_flutter_core/lib/src/message_search_bloc.dart +++ b/packages/stream_chat_flutter_core/lib/src/message_search_bloc.dart @@ -16,7 +16,8 @@ class MessageSearchBloc extends StatefulWidget { const MessageSearchBloc({ Key key, @required this.child, - }) : super(key: key); + }) : assert(child != null), + super(key: key); /// The widget child final Widget child; diff --git a/packages/stream_chat_flutter_core/lib/src/message_search_list_core.dart b/packages/stream_chat_flutter_core/lib/src/message_search_list_core.dart index 26ee58c1..e3d98426 100644 --- a/packages/stream_chat_flutter_core/lib/src/message_search_list_core.dart +++ b/packages/stream_chat_flutter_core/lib/src/message_search_list_core.dart @@ -50,7 +50,11 @@ class MessageSearchListCore extends StatefulWidget { this.paginationParams, this.messageFilters, this.messageSearchListController, - }) : super(key: key); + }) : assert(emptyBuilder != null), + assert(errorBuilder != null), + assert(loadingBuilder != null), + assert(childBuilder != null), + super(key: key); /// A [MessageSearchListController] allows reloading and pagination. /// Use [MessageSearchListController.loadData] and [MessageSearchListController.paginateData] respectively for reloading and pagination. diff --git a/packages/stream_chat_flutter_core/lib/src/stream_chat_core.dart b/packages/stream_chat_flutter_core/lib/src/stream_chat_core.dart index d454d8c9..fbdc6d86 100644 --- a/packages/stream_chat_flutter_core/lib/src/stream_chat_core.dart +++ b/packages/stream_chat_flutter_core/lib/src/stream_chat_core.dart @@ -40,7 +40,9 @@ class StreamChatCore extends StatefulWidget { Key key, @required this.client, @required this.child, - }) : super(key: key); + }) : assert(client != null), + assert(child != null), + super(key: key); /// Instance of Stream Chat Client containing information about the current /// application. diff --git a/packages/stream_chat_flutter_core/lib/src/user_list_core.dart b/packages/stream_chat_flutter_core/lib/src/user_list_core.dart index a9398d89..23140258 100644 --- a/packages/stream_chat_flutter_core/lib/src/user_list_core.dart +++ b/packages/stream_chat_flutter_core/lib/src/user_list_core.dart @@ -50,7 +50,6 @@ import 'package:stream_chat_flutter_core/src/users_bloc.dart'; /// [UsersBloc] must be the ancestor of this widget. This is necessary since /// [UserListCore] depends on functionality contained within [UsersBloc]. /// -/// The widget uses a [ListView.separated], [GridView.builder] to render the list, grid of channels. /// The parameters [listBuilder], [loadingBuilder], [emptyBuilder] and [errorBuilder] must all be supplied /// and not null. class UserListCore extends StatefulWidget { @@ -67,7 +66,11 @@ class UserListCore extends StatefulWidget { this.pagination, this.groupAlphabetically = false, this.userListController, - }) : super(key: key); + }) : assert(errorBuilder != null), + assert(emptyBuilder != null), + assert(loadingBuilder != null), + assert(listBuilder != null), + super(key: key); /// A [UserListController] allows reloading and pagination. /// Use [UserListController.loadData] and [UserListController.paginateData] respectively for reloading and pagination. diff --git a/packages/stream_chat_flutter_core/lib/src/users_bloc.dart b/packages/stream_chat_flutter_core/lib/src/users_bloc.dart index 359985b3..19c4a026 100644 --- a/packages/stream_chat_flutter_core/lib/src/users_bloc.dart +++ b/packages/stream_chat_flutter_core/lib/src/users_bloc.dart @@ -16,7 +16,8 @@ class UsersBloc extends StatefulWidget { const UsersBloc({ Key key, @required this.child, - }) : super(key: key); + }) : assert(child != null), + super(key: key); /// The widget child final Widget child; From eb070cb97355e8cbd3cacaf2c48c184cb5830ea5 Mon Sep 17 00:00:00 2001 From: Neevash Ramdial Date: Fri, 29 Jan 2021 21:24:14 -0400 Subject: [PATCH 1102/1140] remove extra newline --- .../stream_chat_flutter_core/lib/src/lazy_load_scroll_view.dart | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/stream_chat_flutter_core/lib/src/lazy_load_scroll_view.dart b/packages/stream_chat_flutter_core/lib/src/lazy_load_scroll_view.dart index 1ba9ca7b..85e313fb 100644 --- a/packages/stream_chat_flutter_core/lib/src/lazy_load_scroll_view.dart +++ b/packages/stream_chat_flutter_core/lib/src/lazy_load_scroll_view.dart @@ -45,7 +45,6 @@ class LazyLoadScrollView extends StatefulWidget { /// Used to determine if loading of new data has finished. You should use set this if you aren't using a [FutureBuilder] or [StreamBuilder]. final bool isLoading; - @override State createState() => _LazyLoadScrollViewState(); } From 992a0f5569280e43eb79c5a007c0a27587300b83 Mon Sep 17 00:00:00 2001 From: Neevash Ramdial Date: Fri, 29 Jan 2021 21:24:49 -0400 Subject: [PATCH 1103/1140] remove new line --- .../stream_chat_flutter_core/lib/src/lazy_load_scroll_view.dart | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/stream_chat_flutter_core/lib/src/lazy_load_scroll_view.dart b/packages/stream_chat_flutter_core/lib/src/lazy_load_scroll_view.dart index 1ba9ca7b..85e313fb 100644 --- a/packages/stream_chat_flutter_core/lib/src/lazy_load_scroll_view.dart +++ b/packages/stream_chat_flutter_core/lib/src/lazy_load_scroll_view.dart @@ -45,7 +45,6 @@ class LazyLoadScrollView extends StatefulWidget { /// Used to determine if loading of new data has finished. You should use set this if you aren't using a [FutureBuilder] or [StreamBuilder]. final bool isLoading; - @override State createState() => _LazyLoadScrollViewState(); } From b8e9d8efdc5758314ac287b2b6dca7178b41d4be Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Mon, 1 Feb 2021 13:55:29 +0530 Subject: [PATCH 1104/1140] [Persistence] Add more docs Signed-off-by: Sahil Kumar --- .../lib/src/db/shared/native_db.dart | 16 +++++++++++++--- .../lib/src/db/shared/unsupported_db.dart | 14 ++++++++++---- .../lib/src/db/shared/web_db.dart | 16 ++++++++++++---- .../lib/src/stream_chat_persistence_client.dart | 2 +- packages/stream_chat_persistence/pubspec.yaml | 1 + 5 files changed, 37 insertions(+), 12 deletions(-) diff --git a/packages/stream_chat_persistence/lib/src/db/shared/native_db.dart b/packages/stream_chat_persistence/lib/src/db/shared/native_db.dart index 90f19de6..74cf91f8 100644 --- a/packages/stream_chat_persistence/lib/src/db/shared/native_db.dart +++ b/packages/stream_chat_persistence/lib/src/db/shared/native_db.dart @@ -1,5 +1,3 @@ -//ignore_for_file: public_member_api_docs - import 'dart:io'; import 'dart:isolate'; import 'package:moor/ffi.dart'; @@ -7,10 +5,18 @@ import 'package:moor/isolate.dart'; import 'package:moor/moor.dart'; import 'package:path/path.dart'; import 'package:path_provider/path_provider.dart'; +import 'package:stream_chat_persistence/src/stream_chat_persistence_client.dart'; +import 'package:stream_chat_persistence/stream_chat_persistence.dart'; import '../moor_chat_database.dart'; +/// A Helper class to construct new instances of [MoorChatDatabase] specifically +/// for native platform applications class SharedDB { + /// Returns a new instance of [VmDatabase] created using [userId] + /// on a regular isolate. + /// + /// Generally used with [ConnectionMode.regular]. static Future constructDatabase( String userId, { bool logStatements = false, @@ -62,7 +68,11 @@ class SharedDB { return (await receivePort.first as MoorIsolate); } - static Future constructOfflineStorage( + /// Returns a new instance of [MoorChatDatabase] using the factory constructor + /// [MoorChatDatabase.connect] created on a background isolate. + /// + /// Generally used with [ConnectionMode.background]. + static Future constructMoorChatDatabase( String userId, { bool logStatements = false, }) async { diff --git a/packages/stream_chat_persistence/lib/src/db/shared/unsupported_db.dart b/packages/stream_chat_persistence/lib/src/db/shared/unsupported_db.dart index b014c833..303d925f 100644 --- a/packages/stream_chat_persistence/lib/src/db/shared/unsupported_db.dart +++ b/packages/stream_chat_persistence/lib/src/db/shared/unsupported_db.dart @@ -1,15 +1,21 @@ -//ignore_for_file: public_member_api_docs -//ignore_for_file: always_declare_return_types +import 'package:stream_chat_persistence/stream_chat_persistence.dart'; +/// A Helper class to construct new instances of [MoorChatDatabase] class SharedDB { - static constructDatabase( + /// Returns a new instance of database. + /// + /// Generally used with [ConnectionMode.regular]. + static dynamic constructDatabase( String userId, { bool logStatements = false, }) { throw 'Unsupported Platform'; } - static constructOfflineStorage( + /// Return a new instance of moor chat database. + /// + /// Generally used with [ConnectionMode.background]. + static dynamic constructMoorChatDatabase( String userId, { bool logStatements = false, }) { diff --git a/packages/stream_chat_persistence/lib/src/db/shared/web_db.dart b/packages/stream_chat_persistence/lib/src/db/shared/web_db.dart index e30d08ea..6f4360c0 100644 --- a/packages/stream_chat_persistence/lib/src/db/shared/web_db.dart +++ b/packages/stream_chat_persistence/lib/src/db/shared/web_db.dart @@ -1,11 +1,15 @@ -//ignore_for_file: public_member_api_docs -//ignore_for_file: always_declare_return_types import 'package:moor/moor_web.dart'; +import 'package:stream_chat_persistence/src/stream_chat_persistence_client.dart'; import '../moor_chat_database.dart'; +/// A Helper class to construct new instances of [MoorChatDatabase] specifically +/// for Web applications class SharedDB { - static constructDatabase( + /// Returns a new instance of [WebDatabase] created using [userId]. + /// + /// Generally used with [ConnectionMode.regular]. + static Future constructDatabase( String userId, { bool logStatements = false, }) async { @@ -13,7 +17,11 @@ class SharedDB { return WebDatabase(dbName, logStatements: logStatements); } - static Future constructOfflineStorage( + /// Returns a new instance of [MoorChatDatabase] creating using the + /// default constructor. + /// + /// Generally used with [ConnectionMode.background]. + static Future constructMoorChatDatabase( String userId, { bool logStatements = false, }) async { diff --git a/packages/stream_chat_persistence/lib/src/stream_chat_persistence_client.dart b/packages/stream_chat_persistence/lib/src/stream_chat_persistence_client.dart index ebad74f8..0962c9ac 100644 --- a/packages/stream_chat_persistence/lib/src/stream_chat_persistence_client.dart +++ b/packages/stream_chat_persistence/lib/src/stream_chat_persistence_client.dart @@ -43,7 +43,7 @@ class StreamChatPersistenceClient extends ChatPersistenceClient { return; case ConnectionMode.background: _logger.info('Connecting on background isolate'); - _db = await SharedDB.constructOfflineStorage(userId); + _db = await SharedDB.constructMoorChatDatabase(userId); return; } } diff --git a/packages/stream_chat_persistence/pubspec.yaml b/packages/stream_chat_persistence/pubspec.yaml index b8e49170..0702431b 100644 --- a/packages/stream_chat_persistence/pubspec.yaml +++ b/packages/stream_chat_persistence/pubspec.yaml @@ -20,3 +20,4 @@ dev_dependencies: test: ^1.15.7 build_runner: ^1.11.0 moor_generator: ^3.4.1 + pedantic: ^1.9.2 From e68a512a3bee4330ca5c1142d8da1b0553fb8b9d Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Mon, 1 Feb 2021 13:58:45 +0530 Subject: [PATCH 1105/1140] Fix analyzer warnings Signed-off-by: Sahil Kumar --- packages/dart_client/lib/src/client.dart | 11 ++--- packages/dart_client/pubspec.yaml | 2 +- .../example/lib/advanced_options_page.dart | 11 ----- .../example/lib/choose_user_page.dart | 6 --- .../flutter_widgets/example/lib/main.dart | 4 -- .../example/lib/notifications_service.dart | 44 ------------------- packages/flutter_widgets/pubspec.yaml | 3 +- .../stream_chat_flutter_core/pubspec.yaml | 1 + 8 files changed, 9 insertions(+), 73 deletions(-) diff --git a/packages/dart_client/lib/src/client.dart b/packages/dart_client/lib/src/client.dart index 381d1cd6..67b3f444 100644 --- a/packages/dart_client/lib/src/client.dart +++ b/packages/dart_client/lib/src/client.dart @@ -8,7 +8,6 @@ import 'package:logging/logging.dart'; import 'package:rxdart/rxdart.dart'; import 'package:stream_chat/src/api/retry_policy.dart'; import 'package:stream_chat/src/event_type.dart'; -import 'package:stream_chat/src/models/channel_model.dart'; import 'package:stream_chat/src/models/own_user.dart'; import 'package:stream_chat/version.dart'; import 'package:uuid/uuid.dart'; @@ -460,10 +459,12 @@ class Client { _connectionStatusHandler = (ConnectionStatus status) async { _wsConnectionStatus = status; - handleEvent(Event( - type: EventType.connectionChanged, - online: status == ConnectionStatus.connected, - )); + handleEvent( + Event( + type: EventType.connectionChanged, + online: status == ConnectionStatus.connected, + ), + ); if (status == ConnectionStatus.connected && state.channels?.isNotEmpty == true) { diff --git a/packages/dart_client/pubspec.yaml b/packages/dart_client/pubspec.yaml index 9cdc130f..e9036a09 100644 --- a/packages/dart_client/pubspec.yaml +++ b/packages/dart_client/pubspec.yaml @@ -17,10 +17,10 @@ dependencies: async: ^2.4.1 rxdart: ^0.24.1 collection: ^1.14.12 - pedantic: ^1.9.2 dev_dependencies: build_runner: ^1.10.0 json_serializable: ^3.3.0 test: ^1.15.7 mockito: ^4.1.1 + pedantic: ^1.9.2 diff --git a/packages/flutter_widgets/example/lib/advanced_options_page.dart b/packages/flutter_widgets/example/lib/advanced_options_page.dart index 0b55212c..35e2af7f 100644 --- a/packages/flutter_widgets/example/lib/advanced_options_page.dart +++ b/packages/flutter_widgets/example/lib/advanced_options_page.dart @@ -1,19 +1,12 @@ -import 'dart:io'; - -import 'package:example/routes/app_routes.dart'; import 'package:example/routes/routes.dart'; import 'package:example/stream_version.dart'; -import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_secure_storage/flutter_secure_storage.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; -import 'package:stream_chat_persistence/stream_chat_persistence.dart'; -import 'package:streaming_shared_preferences/streaming_shared_preferences.dart'; import 'choose_user_page.dart'; import 'main.dart'; -import 'notifications_service.dart'; class AdvancedOptionsPage extends StatefulWidget { @override @@ -287,10 +280,6 @@ class _AdvancedOptionsPageState extends State { userToken, ); - if (!kIsWeb) { - initNotifications(client); - } - final secureStorage = FlutterSecureStorage(); secureStorage.write( key: kStreamApiKey, diff --git a/packages/flutter_widgets/example/lib/choose_user_page.dart b/packages/flutter_widgets/example/lib/choose_user_page.dart index 8e36e748..02852c64 100644 --- a/packages/flutter_widgets/example/lib/choose_user_page.dart +++ b/packages/flutter_widgets/example/lib/choose_user_page.dart @@ -1,11 +1,9 @@ import 'package:example/stream_version.dart'; -import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_secure_storage/flutter_secure_storage.dart'; import 'package:flutter_svg/flutter_svg.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; -import 'notifications_service.dart'; import 'routes/routes.dart'; const kStreamApiKey = 'STREAM_API_KEY'; @@ -187,10 +185,6 @@ class ChooseUserPage extends StatelessWidget { key: kStreamToken, value: token, ); - - if (!kIsWeb) { - initNotifications(client); - } Navigator.pushNamedAndRemoveUntil( context, Routes.HOME, diff --git a/packages/flutter_widgets/example/lib/main.dart b/packages/flutter_widgets/example/lib/main.dart index a44a8692..93c7b082 100644 --- a/packages/flutter_widgets/example/lib/main.dart +++ b/packages/flutter_widgets/example/lib/main.dart @@ -1,5 +1,4 @@ import 'dart:async'; -import 'dart:io'; import 'package:example/chat_info_screen.dart'; import 'package:example/choose_user_page.dart'; @@ -41,9 +40,6 @@ void main() async { User(id: userId), token, ); - if (!kIsWeb) { - initNotifications(client); - } } runApp(MyApp(client)); diff --git a/packages/flutter_widgets/example/lib/notifications_service.dart b/packages/flutter_widgets/example/lib/notifications_service.dart index e74a2a5a..246923df 100644 --- a/packages/flutter_widgets/example/lib/notifications_service.dart +++ b/packages/flutter_widgets/example/lib/notifications_service.dart @@ -1,8 +1,3 @@ -import 'dart:io'; - -import 'package:example/main.dart'; -import 'package:firebase_messaging/firebase_messaging.dart'; -import 'package:flutter_apns/flutter_apns.dart'; import 'package:flutter_local_notifications/flutter_local_notifications.dart' hide Message; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; @@ -34,42 +29,3 @@ void showLocalNotification(Event event) async { ), ); } - -Future backgroundHandler(Map notification) async { - print('new notification ${notification}'); - // final messageId = notification['data']['id']; - // - // final notificationData = await NotificationService.getAndStoreMessage( - // messageId: messageId, - // storeMessageHandler: (messageResponse) { - // return chatPersistentClient.updateChannelState( - // ChannelState( - // messages: [messageResponse.message], - // channel: messageResponse.channel, - // ), - // ); - // }, - // ); - // - // showLocalNotification( - // notificationData.message, - // notificationData.channel, - // ); -} - -void initNotifications(Client client) { - final connector = createPushConnector(); - connector.configure( - onBackgroundMessage: backgroundHandler, - ); - - connector.requestNotificationPermissions(); - connector.token.addListener(() { - if (connector.token.value != null) { - client.addDevice( - connector.token.value, - Platform.isAndroid ? PushProvider.firebase : PushProvider.apn, - ); - } - }); -} diff --git a/packages/flutter_widgets/pubspec.yaml b/packages/flutter_widgets/pubspec.yaml index 9321f992..af2e39f4 100644 --- a/packages/flutter_widgets/pubspec.yaml +++ b/packages/flutter_widgets/pubspec.yaml @@ -58,8 +58,7 @@ flutter: - animations/ dev_dependencies: - flutter_test: sdk: flutter mockito: ^4.1.3 - pedantic: ^1.9.2 + pedantic: ^1.9.2 \ No newline at end of file diff --git a/packages/stream_chat_flutter_core/pubspec.yaml b/packages/stream_chat_flutter_core/pubspec.yaml index 61c3528e..6dbde76e 100644 --- a/packages/stream_chat_flutter_core/pubspec.yaml +++ b/packages/stream_chat_flutter_core/pubspec.yaml @@ -20,4 +20,5 @@ dev_dependencies: flutter_test: sdk: flutter fake_async: ^1.1.0 + pedantic: ^1.9.2 \ No newline at end of file From e03f50ae5abde62ef201ec07b48e652be43bf26e Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Mon, 1 Feb 2021 14:06:30 +0530 Subject: [PATCH 1106/1140] [StreamChatFlutter -> ConnectionStatusBuilder] Add docs Signed-off-by: Sahil Kumar --- .../flutter_widgets/lib/src/connection_status_builder.dart | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/packages/flutter_widgets/lib/src/connection_status_builder.dart b/packages/flutter_widgets/lib/src/connection_status_builder.dart index 25f9a0b6..ebb12cd5 100644 --- a/packages/flutter_widgets/lib/src/connection_status_builder.dart +++ b/packages/flutter_widgets/lib/src/connection_status_builder.dart @@ -2,6 +2,11 @@ import 'package:flutter/material.dart'; import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; import 'stream_chat.dart'; +/// Widget that builds itself based on the latest snapshot of interaction with +/// a [Stream] of type [ConnectionStatus]. +/// +/// The widget will use the closest [Client.wsConnectionStatusStream] in case no +/// stream is provided. class ConnectionStatusBuilder extends StatelessWidget { /// Creates a new ConnectionStatusBuilder const ConnectionStatusBuilder({ From 0d4db879060d5915d30dc0ddf87f691b08d62638 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Mon, 1 Feb 2021 09:55:53 +0100 Subject: [PATCH 1107/1140] check messagePagination nullability --- .../stream_chat_persistence/lib/src/dao/message_dao.dart | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/stream_chat_persistence/lib/src/dao/message_dao.dart b/packages/stream_chat_persistence/lib/src/dao/message_dao.dart index 8acdbfd4..97122232 100644 --- a/packages/stream_chat_persistence/lib/src/dao/message_dao.dart +++ b/packages/stream_chat_persistence/lib/src/dao/message_dao.dart @@ -112,7 +112,7 @@ class MessageDao extends DatabaseAccessor .map(_messageFromJoinRow) .get()); - if (messagePagination.lessThan != null) { + if (messagePagination?.lessThan != null) { final lessThanIndex = msgList.indexWhere( (m) => m.id == messagePagination.lessThan, ); @@ -120,7 +120,7 @@ class MessageDao extends DatabaseAccessor msgList.removeRange(lessThanIndex, msgList.length); } } - if (messagePagination.greaterThanOrEqual != null) { + if (messagePagination?.greaterThanOrEqual != null) { final greaterThanIndex = msgList.indexWhere( (m) => m.id == messagePagination.greaterThanOrEqual, ); @@ -128,7 +128,7 @@ class MessageDao extends DatabaseAccessor msgList.removeRange(0, greaterThanIndex); } } - if (messagePagination.limit != null) { + if (messagePagination?.limit != null) { return msgList.take(messagePagination.limit).toList(); } return msgList; From 62ed7246d449bdb58dac6730dab599a7be369597 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Mon, 1 Feb 2021 10:06:34 +0100 Subject: [PATCH 1108/1140] bummp version --- .../flutter_widgets/example/ios/fastlane/report.xml | 10 +++++----- packages/flutter_widgets/example/pubspec.yaml | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/flutter_widgets/example/ios/fastlane/report.xml b/packages/flutter_widgets/example/ios/fastlane/report.xml index 69eca3e6..b6e7bdcb 100644 --- a/packages/flutter_widgets/example/ios/fastlane/report.xml +++ b/packages/flutter_widgets/example/ios/fastlane/report.xml @@ -5,27 +5,27 @@ - + - + - + - + - + diff --git a/packages/flutter_widgets/example/pubspec.yaml b/packages/flutter_widgets/example/pubspec.yaml index d3116148..4814f3b0 100644 --- a/packages/flutter_widgets/example/pubspec.yaml +++ b/packages/flutter_widgets/example/pubspec.yaml @@ -1,7 +1,7 @@ name: example description: A new Flutter project. publish_to: 'none' -version: 1.2.0 +version: 1.2.0+1 environment: sdk: ">=2.2.2 <3.0.0" From dcdaefe76e289c61964930ac6a5a66aafef8d006 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Mon, 1 Feb 2021 14:42:34 +0530 Subject: [PATCH 1109/1140] [StreamChat -> ChatPersistenceClient] Add doc comments Signed-off-by: Sahil Kumar --- .../lib/src/db/chat_persistence_client.dart | 55 +++++++++++-------- 1 file changed, 33 insertions(+), 22 deletions(-) diff --git a/packages/dart_client/lib/src/db/chat_persistence_client.dart b/packages/dart_client/lib/src/db/chat_persistence_client.dart index 070bf37f..c4ce6cd2 100644 --- a/packages/dart_client/lib/src/db/chat_persistence_client.dart +++ b/packages/dart_client/lib/src/db/chat_persistence_client.dart @@ -8,7 +8,7 @@ import 'package:stream_chat/src/models/reaction.dart'; import 'package:stream_chat/src/models/read.dart'; import 'package:stream_chat/src/models/user.dart'; -/// +/// A simple client used for persisting chat data locally. abstract class ChatPersistenceClient { /// Creates a new connection to the client Future connect(String userId); @@ -38,22 +38,25 @@ abstract class ChatPersistenceClient { /// Get the channel cids saved in the offline storage Future> getChannelCids(); - /// + /// Get stored [ChannelModel]s by providing channel [cid] Future getChannelByCid(String cid); - /// + /// Get stored channel [Member]s by providing channel [cid] Future> getMembersByCid(String cid); - /// + /// Get stored channel [Read]s by providing channel [cid] Future> getReadsByCid(String cid); + /// Get stored [Message]s by providing channel [cid] /// + /// Optionally, you can [messagePagination] + /// for filtering out messages Future> getMessagesByCid( String cid, { PaginationParams messagePagination, }); - /// Get channel data by cid + /// Get [ChannelState] data by providing channel [cid] Future getChannelStateByCid( String cid, { PaginationParams messagePagination, @@ -73,14 +76,18 @@ abstract class ChatPersistenceClient { ); } - /// Get list of channels by filter, sort and paginationParams + /// Get all the stored [ChannelState]s + /// + /// Optionally, pass [filter], [sort], [paginationParams] + /// for filtering out states. Future> getChannelStates({ Map filter, List sort = const [], PaginationParams paginationParams, }); - /// Update list of channel queries + /// Update list of channel queries. + /// /// If [clearQueryCache] is true before the insert /// the list of matching rows will be deleted Future updateChannelQueries( @@ -89,53 +96,57 @@ abstract class ChatPersistenceClient { bool clearQueryCache, ); - /// Remove a message by message id + /// Remove a message by [messageId] Future deleteMessageById(String messageId) { return deleteMessageByIds([messageId]); } - /// Remove a message by message ids + /// Remove a message by [messageIds] Future deleteMessageByIds(List messageIds); - /// Remove a message by channel cid + /// Remove a message by channel [cid] Future deleteMessageByCid(String cid) { return deleteMessageByCids([cid]); } - /// Remove a message by message cids + /// Remove a message by message [cids] Future deleteMessageByCids(List cids); - /// Remove a channel by cid + /// Remove a channel by [cid] Future deleteChannels(List cids); - /// Update messages data from a list + /// Updates the message data of a particular channel [cid] with + /// the new [messages] data Future updateMessages(String cid, List messages); - /// Get the info about channel threads + /// Returns all the threads by parent message of a particular channel by + /// providing channel [cid] Future>> getChannelThreads(String cid); - /// + /// Updates all the channels using the new [channels] data. Future updateChannels(List channels); - /// + /// Updates all the members of a particular channle [cid] + /// with the new [members] data Future updateMembers(String cid, List members); - /// + /// Updates the read data of a particular channel [cid] with + /// the new [reads] data Future updateReads(String cid, List reads); - /// + /// Updates the users data with the new [users] data Future updateUsers(List users); - /// + /// Updates the reactions data with the new [reactions] data Future updateReactions(List reactions); - /// + /// Deletes all the reactions by [messageIds] Future deleteReactionsByMessageId(List messageIds); - /// + /// Deletes all the members by channel [cids] Future deleteMembersByCids(List cids); - /// + /// Update the channel state data using [channelState] Future updateChannelState(ChannelState channelState) { return updateChannelStates([channelState]); } From 206f63ff8419b85429600f21e78dce2032b4ab07 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Mon, 1 Feb 2021 14:50:01 +0530 Subject: [PATCH 1110/1140] [StreamChatCore] Move `EventHandler` into typedef.dart Signed-off-by: Sahil Kumar --- .../stream_chat_flutter_core/lib/src/stream_chat_core.dart | 2 +- packages/stream_chat_flutter_core/lib/src/typedef.dart | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/stream_chat_flutter_core/lib/src/stream_chat_core.dart b/packages/stream_chat_flutter_core/lib/src/stream_chat_core.dart index e17fe708..78cae0ba 100644 --- a/packages/stream_chat_flutter_core/lib/src/stream_chat_core.dart +++ b/packages/stream_chat_flutter_core/lib/src/stream_chat_core.dart @@ -4,7 +4,7 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:stream_chat/stream_chat.dart'; -typedef EventHandler = void Function(Event event); +import 'typedef.dart'; /// Widget used to provide information about the chat to the widget tree. /// This Widget is used to react to life cycle changes and system updates. diff --git a/packages/stream_chat_flutter_core/lib/src/typedef.dart b/packages/stream_chat_flutter_core/lib/src/typedef.dart index 3077574e..29fb2d31 100644 --- a/packages/stream_chat_flutter_core/lib/src/typedef.dart +++ b/packages/stream_chat_flutter_core/lib/src/typedef.dart @@ -1,6 +1,10 @@ import 'package:flutter/widgets.dart'; +import 'package:stream_chat/stream_chat.dart'; /// A signature for a callback which exposes an error and returns a function. /// This Callback can be used in cases where an API failure occurs and the widget /// is unable to render data. typedef ErrorBuilder = Widget Function(BuildContext context, Object error); + +/// A Signature for a handler function which will expose a [event]. +typedef EventHandler = void Function(Event event); From e05097a91424f2693b90afee1a90b2c333c710c6 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Mon, 1 Feb 2021 14:58:46 +0530 Subject: [PATCH 1111/1140] fix tests Signed-off-by: Sahil Kumar --- .../stream_chat_flutter_core/lib/stream_chat_flutter_core.dart | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/stream_chat_flutter_core/lib/stream_chat_flutter_core.dart b/packages/stream_chat_flutter_core/lib/stream_chat_flutter_core.dart index 623c4424..48d31b45 100644 --- a/packages/stream_chat_flutter_core/lib/stream_chat_flutter_core.dart +++ b/packages/stream_chat_flutter_core/lib/stream_chat_flutter_core.dart @@ -10,4 +10,5 @@ export 'src/stream_channel.dart'; export 'src/stream_chat_core.dart'; export 'src/user_list_core.dart'; export 'src/users_bloc.dart'; +export 'src/typedef.dart'; export 'package:stream_chat/stream_chat.dart'; From b791040960039e7f36ad703fdc8e8f0bc472fc74 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Mon, 1 Feb 2021 12:17:02 +0100 Subject: [PATCH 1112/1140] await deleting actions before update --- .../lib/src/db/chat_persistence_client.dart | 27 ++++++++++--------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/packages/dart_client/lib/src/db/chat_persistence_client.dart b/packages/dart_client/lib/src/db/chat_persistence_client.dart index c4ce6cd2..e240f9e6 100644 --- a/packages/dart_client/lib/src/db/chat_persistence_client.dart +++ b/packages/dart_client/lib/src/db/chat_persistence_client.dart @@ -164,6 +164,20 @@ abstract class ChatPersistenceClient { ]; }).where((it) => it != null); + final deleteReactions = deleteReactionsByMessageId(channelStates + .expand((it) => it.messages) + .map((m) => m.id) + .toList(growable: false)); + + final deleteMembers = deleteMembersByCids( + channelStates.map((it) => it.channel.cid).toList(growable: false), + ); + + await Future.wait([ + deleteReactions, + deleteMembers, + ]); + final users = channelStates .map((cs) => [ cs.channel?.createdBy, @@ -198,19 +212,6 @@ abstract class ChatPersistenceClient { return updateMembers(cid, members.toList(growable: false)); }).toList(growable: false); - final deleteReactions = deleteReactionsByMessageId(channelStates - .expand((it) => it.messages) - .map((m) => m.id) - .toList(growable: false)); - - final deleteMembers = deleteMembersByCids( - channelStates.map((it) => it.channel.cid).toList(growable: false), - ); - - await Future.wait([ - deleteReactions, - deleteMembers, - ]); await Future.wait([ ...updateMessagesFuture, ...updateReadsFuture, From c8319004843adcd3b3ce563dbc9d9a249d164b79 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Mon, 1 Feb 2021 18:32:22 +0530 Subject: [PATCH 1113/1140] [Persistence] Minor refactoring Signed-off-by: Sahil Kumar --- .../lib/src/db/chat_persistence_client.dart | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/packages/dart_client/lib/src/db/chat_persistence_client.dart b/packages/dart_client/lib/src/db/chat_persistence_client.dart index e240f9e6..a2a4d313 100644 --- a/packages/dart_client/lib/src/db/chat_persistence_client.dart +++ b/packages/dart_client/lib/src/db/chat_persistence_client.dart @@ -153,17 +153,6 @@ abstract class ChatPersistenceClient { /// Update list of channel states Future updateChannelStates(List channelStates) async { - final channels = channelStates.map((it) { - return it.channel; - }).where((it) => it != null); - - final reactions = channelStates.expand((it) => it.messages).expand((it) { - return [ - ...it.ownReactions.where((r) => r.userId != null), - ...it.latestReactions.where((r) => r.userId != null) - ]; - }).where((it) => it != null); - final deleteReactions = deleteReactionsByMessageId(channelStates .expand((it) => it.messages) .map((m) => m.id) @@ -178,6 +167,17 @@ abstract class ChatPersistenceClient { deleteMembers, ]); + final channels = channelStates.map((it) { + return it.channel; + }).where((it) => it != null); + + final reactions = channelStates.expand((it) => it.messages).expand((it) { + return [ + ...it.ownReactions.where((r) => r.userId != null), + ...it.latestReactions.where((r) => r.userId != null) + ]; + }).where((it) => it != null); + final users = channelStates .map((cs) => [ cs.channel?.createdBy, From fe45b2ef6e21b8a36934591abf314522137c238b Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Mon, 1 Feb 2021 19:11:57 +0530 Subject: [PATCH 1114/1140] Update README.md Signed-off-by: Sahil Kumar --- packages/flutter_widgets/README.md | 2 +- packages/stream_chat_flutter_core/README.md | 2 +- packages/stream_chat_persistence/README.md | 59 +++++++++++++++++---- 3 files changed, 51 insertions(+), 12 deletions(-) diff --git a/packages/flutter_widgets/README.md b/packages/flutter_widgets/README.md index 8104e83a..b99a8f29 100644 --- a/packages/flutter_widgets/README.md +++ b/packages/flutter_widgets/README.md @@ -1,7 +1,7 @@ # Official Flutter SDK for [Stream Chat](https://getstream.io/chat/)

    - Flutter Chat + Flutter Chat

    > The official Flutter components for Stream Chat, a service for diff --git a/packages/stream_chat_flutter_core/README.md b/packages/stream_chat_flutter_core/README.md index a62da863..6fe86329 100644 --- a/packages/stream_chat_flutter_core/README.md +++ b/packages/stream_chat_flutter_core/README.md @@ -1,7 +1,7 @@ # Official Flutter SDK Core for [Stream Chat](https://getstream.io/chat/)

    - Flutter Chat + Flutter Chat

    > The official Flutter core components for Stream Chat, a service for diff --git a/packages/stream_chat_persistence/README.md b/packages/stream_chat_persistence/README.md index 3e3f0c7c..6d9c21cf 100644 --- a/packages/stream_chat_persistence/README.md +++ b/packages/stream_chat_persistence/README.md @@ -1,14 +1,53 @@ -# stream_chat_persistence +# Official Chat Persistence Client for [Stream Chat](https://getstream.io/chat/) -A new Flutter package. +

    + Flutter Chat +

    -## Getting Started +> The official Chat Persistence Client for Stream Chat, a service for +> building chat applications. -This project is a starting point for a Dart -[package](https://flutter.dev/developing-packages/), -a library module containing code that can be shared easily across -multiple Flutter or Dart projects. +[![Pub](https://img.shields.io/pub/v/stream_chat_persistence.svg)](https://pub.dartlang.org/packages/stream_chat_persistence) +![](https://img.shields.io/badge/platform-flutter%20%7C%20flutter%20web-ff69b4.svg?style=flat-square) +[![Gitter](https://badges.gitter.im/GetStream/stream_chat_persistence.svg)](https://gitter.im/GetStream/stream-chat-flutter?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) +![CI](https://github.com/GetStream/stream-chat-flutter/workflows/CI/badge.svg?branch=master) + -For help getting started with Flutter, view our -[online documentation](https://flutter.dev/docs), which offers tutorials, -samples, guidance on mobile development, and a full API reference. +This package provides a persistence client for fetching and saving chat data locally. +Stream Chat Persistence uses [Moor](https://github.com/simolus3/moor) as a disk cache. + +## Add dependency +Add this to your package's pubspec.yaml file, use the latest version [![Pub](https://img.shields.io/pub/v/stream_chat_persistence.svg)](https://pub.dartlang.org/packages/stream_chat_persistence) +```yaml +dependencies: + stream_chat_persistence: ^latest_version +``` + +You should then run `flutter packages get` + +## Usage +The usage is pretty simple. +1. Create a new instance of StreamChatPersistenceClient providing `logLevel` and `connectionMode`. +```dart +final chatPersistentClient = StreamChatPersistenceClient( + logLevel: Level.INFO, + connectionMode: ConnectionMode.background, +); +``` +2. Pass the instance to the official Stream chat client. +```dart + final client = Client( + apiKey ?? kDefaultStreamApiKey, + logLevel: Level.INFO, + )..chatPersistenceClient = chatPersistentClient; +``` + +And you are ready to go... + +## Contributing + +We welcome code changes that improve this library or fix a problem, +please make sure to follow all best practices and add tests if applicable before submitting a Pull Request on Github. +We are pleased to merge your code into the official repository. +Make sure to sign our [Contributor License Agreement (CLA)](https://docs.google.com/forms/d/e/1FAIpQLScFKsKkAJI7mhCr7K9rEIOpqIDThrWxuvxnwUq2XkHyG154vQ/viewform) first. +See our license file for more details. From 4e6d64064e6ab9aaff1185a45da8125f0798125b Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Mon, 1 Feb 2021 15:13:59 +0100 Subject: [PATCH 1115/1140] [llc] update changelog and readme --- packages/dart_client/CHANGELOG.md | 9 +++++ packages/dart_client/README.md | 43 +++++++++++++--------- packages/stream_chat_persistence/README.md | 18 +++++++++ 3 files changed, 52 insertions(+), 18 deletions(-) diff --git a/packages/dart_client/CHANGELOG.md b/packages/dart_client/CHANGELOG.md index fdaee098..c51f9a5f 100644 --- a/packages/dart_client/CHANGELOG.md +++ b/packages/dart_client/CHANGELOG.md @@ -1,3 +1,12 @@ +## 0.1.0-beta + +- 🛑 **BREAKING** Renamed `Client` to less generic `StreamChatClient` +- 🛑 **BREAKING** Segregated the persistence layer into separate package (stream_chat_persistence)[https://pub.dev/packages/stream_chat_persistence] +- 🛑 **BREAKING** Moved `Client.backgroundKeepAlive` to (core package)[https://pub.dev/packages/stream_chat_core] +- 🛑 **BREAKING** Moved `Client.showLocalNotification` to (core package)[https://pub.dev/packages/stream_chat_core] and renamed it to `StreamChatCore.onBackgroundEventReceived` +- Removed `flutter` dependency. This is now a pure Dart package 🥳 +- Minor improvements and bugfixes + ## 0.2.24+2 - Fix reconnection bug while using tokenProvider diff --git a/packages/dart_client/README.md b/packages/dart_client/README.md index 241c2f4e..4d3ca397 100644 --- a/packages/dart_client/README.md +++ b/packages/dart_client/README.md @@ -14,7 +14,7 @@ You can sign up for a Stream account at https://getstream.io/chat/ ```yaml dependencies: - stream_chat: ^0.2.0 + stream_chat: ^1.0.0-beta ``` You should then run `flutter packages get` @@ -57,27 +57,34 @@ final client = Client("stream-chat-api-key", logHandlerFunction: myLogHandlerFun ### Offline storage -By default the library saves information about channels and messages in a SQLite DB. +To add data persistance you can extend the class `ChatPersistenceClient` and pass an instance to the `StreamChatClient`. -Set the property `persistenceEnabled` to false if you don't want to use the offline storage. +```dart +class CustomChatPersistentClient extends ChatPersistenceClient { +... +} -## Flutter Web - -Due to Moor web (for offline storage) you need to include the sql.js library: - -```html - - - - - - - - - +final client = Client( + apiKey ?? kDefaultStreamApiKey, + logLevel: Level.INFO, +)..chatPersistenceClient = CustomChatPersistentClient(); ``` -You can grab the latest version of sql-wasm.js and sql-wasm.wasm [here](https://github.com/sql-js/sql.js/releases) and copy them into your `/web` folder. +We provide an official persistent client in the (stream_chat_persistence)[https://pub.dev/packages/stream_chat_persistence] package. + +```dart +import 'package:stream_chat_persistence/stream_chat_persistence.dart'; + +final chatPersistentClient = StreamChatPersistenceClient( + logLevel: Level.INFO, + connectionMode: ConnectionMode.background, +); + +final client = Client( + apiKey ?? kDefaultStreamApiKey, + logLevel: Level.INFO, +)..chatPersistenceClient = chatPersistentClient; +``` ## Contributing diff --git a/packages/stream_chat_persistence/README.md b/packages/stream_chat_persistence/README.md index 6d9c21cf..d53d51e4 100644 --- a/packages/stream_chat_persistence/README.md +++ b/packages/stream_chat_persistence/README.md @@ -44,6 +44,24 @@ final chatPersistentClient = StreamChatPersistenceClient( And you are ready to go... +## Flutter Web + +Due to Moor web (for offline storage) you need to include the sql.js library: + +```html + + + + + + + + + +``` + +You can grab the latest version of sql-wasm.js and sql-wasm.wasm [here](https://github.com/sql-js/sql.js/releases) and copy them into your `/web` folder. + ## Contributing We welcome code changes that improve this library or fix a problem, From 1751cd6092bc3f96ee0dd74a1159016aa95070d3 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Mon, 1 Feb 2021 15:15:28 +0100 Subject: [PATCH 1116/1140] change rc to beta --- packages/dart_client/CHANGELOG.md | 2 +- packages/stream_chat_flutter_core/CHANGELOG.md | 2 +- packages/stream_chat_flutter_core/pubspec.yaml | 2 +- packages/stream_chat_persistence/CHANGELOG.md | 2 +- packages/stream_chat_persistence/pubspec.yaml | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/dart_client/CHANGELOG.md b/packages/dart_client/CHANGELOG.md index c51f9a5f..98730359 100644 --- a/packages/dart_client/CHANGELOG.md +++ b/packages/dart_client/CHANGELOG.md @@ -1,4 +1,4 @@ -## 0.1.0-beta +## 1.0.0-beta - 🛑 **BREAKING** Renamed `Client` to less generic `StreamChatClient` - 🛑 **BREAKING** Segregated the persistence layer into separate package (stream_chat_persistence)[https://pub.dev/packages/stream_chat_persistence] diff --git a/packages/stream_chat_flutter_core/CHANGELOG.md b/packages/stream_chat_flutter_core/CHANGELOG.md index ec6ae55e..819c0e5a 100644 --- a/packages/stream_chat_flutter_core/CHANGELOG.md +++ b/packages/stream_chat_flutter_core/CHANGELOG.md @@ -1,3 +1,3 @@ -## 1.0.0-rc +## 1.0.0-beta * First release diff --git a/packages/stream_chat_flutter_core/pubspec.yaml b/packages/stream_chat_flutter_core/pubspec.yaml index 6dbde76e..cf7fb31d 100644 --- a/packages/stream_chat_flutter_core/pubspec.yaml +++ b/packages/stream_chat_flutter_core/pubspec.yaml @@ -1,7 +1,7 @@ name: stream_chat_flutter_core homepage: https://github.com/GetStream/stream-chat-flutter description: Stream Chat official Flutter SDK Core. Build your own chat experience using Dart and Flutter. -version: 1.0.0-rc +version: 1.0.0-beta repository: https://github.com/GetStream/stream-chat-flutter issue_tracker: https://github.com/GetStream/stream-chat-flutter/issues diff --git a/packages/stream_chat_persistence/CHANGELOG.md b/packages/stream_chat_persistence/CHANGELOG.md index ba22fd4f..72eec406 100644 --- a/packages/stream_chat_persistence/CHANGELOG.md +++ b/packages/stream_chat_persistence/CHANGELOG.md @@ -1,3 +1,3 @@ -## 1.0.0-rc +## 1.0.0-beta * Initial release \ No newline at end of file diff --git a/packages/stream_chat_persistence/pubspec.yaml b/packages/stream_chat_persistence/pubspec.yaml index 0702431b..06015495 100644 --- a/packages/stream_chat_persistence/pubspec.yaml +++ b/packages/stream_chat_persistence/pubspec.yaml @@ -1,7 +1,7 @@ name: stream_chat_persistence homepage: https://github.com/GetStream/stream-chat-flutter description: Official Stream Chat Persistence library. Build your own chat experience using Dart and Flutter. -version: 1.0.0-rc +version: 1.0.0-beta repository: https://github.com/GetStream/stream-chat-flutter issue_tracker: https://github.com/GetStream/stream-chat-flutter/issues From 23feabe85ec18dc09eb7feb1ac31325e438b0b03 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Mon, 1 Feb 2021 15:30:46 +0100 Subject: [PATCH 1117/1140] rename Client to StreamChatClient --- melos.yaml | 8 +- packages/dart_client/README.md | 10 +-- packages/dart_client/example/lib/main.dart | 12 +-- packages/dart_client/lib/src/api/channel.dart | 6 +- .../dart_client/lib/src/api/responses.dart | 22 +++--- .../dart_client/lib/src/api/retry_policy.dart | 11 +-- packages/dart_client/lib/src/client.dart | 25 +++--- packages/dart_client/lib/version.dart | 2 +- .../test/src/api/channel_test.dart | 66 ++++++++-------- .../dart_client/test/src/client_test.dart | 78 +++++++++---------- packages/flutter_widgets/README.md | 4 +- .../example/lib/advanced_options_page.dart | 2 +- .../example/lib/custom_message.dart | 4 +- .../example/lib/custom_theme.dart | 4 +- .../lib/customize_channel_preview.dart | 4 +- .../example/lib/customize_message_widget.dart | 4 +- .../flutter_widgets/example/lib/main.dart | 4 +- .../example/lib/multiple_conversation.dart | 4 +- .../example/lib/single_conversation.dart | 12 +-- .../example/lib/split_view.dart | 4 +- .../flutter_widgets/example/lib/threads.dart | 4 +- .../lib/src/channel_header.dart | 6 +- .../lib/src/channel_image.dart | 4 +- .../flutter_widgets/lib/src/channel_info.dart | 3 +- .../lib/src/channel_list_header.dart | 19 ++--- .../lib/src/connection_status_builder.dart | 3 +- .../flutter_widgets/lib/src/stream_chat.dart | 8 +- packages/flutter_widgets/test/src/mocks.dart | 2 +- .../example/lib/main.dart | 12 +-- .../lib/src/message_search_bloc.dart | 4 +- .../lib/src/stream_chat_core.dart | 6 +- .../stream_chat_flutter_core/test/mocks.dart | 2 +- packages/stream_chat_persistence/README.md | 2 +- 33 files changed, 185 insertions(+), 176 deletions(-) diff --git a/melos.yaml b/melos.yaml index 7e02909f..6a6c74dc 100644 --- a/melos.yaml +++ b/melos.yaml @@ -33,8 +33,12 @@ scripts: flutter build macos - test: > - melos exec -c 1 --fail-fast --dir-exists=test --ignore="*example*" --ignore="*web*" -- \ + test:dart: > + melos exec -c 1 --fail-fast --no-flutter --dir-exists=test --ignore="*example*" --ignore="*web*" -- \ + flutter pub run test + + test:flutter: > + melos exec -c 1 --fail-fast --flutter --dir-exists=test --ignore="*example*" --ignore="*web*" -- \ flutter test test:web: > diff --git a/packages/dart_client/README.md b/packages/dart_client/README.md index 4d3ca397..e0ed18bf 100644 --- a/packages/dart_client/README.md +++ b/packages/dart_client/README.md @@ -28,7 +28,7 @@ There is a detailed Flutter example project in the `example` folder. You can dir First you need to instantiate a chat client. The Chat client will manage API call, event handling and manage the websocket connection to Stream Chat servers. You should only create the client once and re-use it across your application. ```dart -final client = Client("stream-chat-api-key"); +final client = StreamChatClient("stream-chat-api-key"); ``` ### Logging @@ -40,7 +40,7 @@ By default the Chat Client will write all messages with level Warn or Error to s During development you might want to enable more logging information, you can change the default log level when constructing the client. ```dart -final client = Client("stream-chat-api-key", logLevel: Level.INFO); +final client = StreamChatClient("stream-chat-api-key", logLevel: Level.INFO); ``` #### Custom Logger @@ -52,7 +52,7 @@ myLogHandlerFunction = (LogRecord record) { // do something with the record (ie. send it to Sentry or Fabric) } -final client = Client("stream-chat-api-key", logHandlerFunction: myLogHandlerFunction); +final client = StreamChatClient("stream-chat-api-key", logHandlerFunction: myLogHandlerFunction); ``` ### Offline storage @@ -64,7 +64,7 @@ class CustomChatPersistentClient extends ChatPersistenceClient { ... } -final client = Client( +final client = StreamChatClient( apiKey ?? kDefaultStreamApiKey, logLevel: Level.INFO, )..chatPersistenceClient = CustomChatPersistentClient(); @@ -80,7 +80,7 @@ final chatPersistentClient = StreamChatPersistenceClient( connectionMode: ConnectionMode.background, ); -final client = Client( +final client = StreamChatClient( apiKey ?? kDefaultStreamApiKey, logLevel: Level.INFO, )..chatPersistenceClient = chatPersistentClient; diff --git a/packages/dart_client/example/lib/main.dart b/packages/dart_client/example/lib/main.dart index ed21df76..769e6d44 100644 --- a/packages/dart_client/example/lib/main.dart +++ b/packages/dart_client/example/lib/main.dart @@ -2,9 +2,9 @@ import 'package:flutter/material.dart'; import 'package:stream_chat/stream_chat.dart'; Future main() async { - /// Create a new instance of [Client] passing the apikey obtained from your + /// Create a new instance of [StreamChatClient] passing the apikey obtained from your /// project dashboard. - final client = Client('b67pax5b2wdq'); + final client = StreamChatClient('b67pax5b2wdq'); /// Set the current user. In a production scenario, this should be done using /// a backend to generate a user token using our server SDK. @@ -48,9 +48,9 @@ class StreamExample extends StatelessWidget { @required this.channel, }) : super(key: key); - /// Instance of [Client] we created earlier. This contains information about + /// Instance of [StreamChatClient] we created earlier. This contains information about /// our application and connection state. - final Client client; + final StreamChatClient client; /// The channel we'd like to observe and participate. final Channel channel; @@ -242,7 +242,7 @@ class _MessageViewState extends State { } } -/// Helper extension for quickly retrieving the current user id from a [Client]. -extension on Client { +/// Helper extension for quickly retrieving the current user id from a [StreamChatClient]. +extension on StreamChatClient { String get uid => state.user.id; } diff --git a/packages/dart_client/lib/src/api/channel.dart b/packages/dart_client/lib/src/api/channel.dart index 45dd5da8..449a5267 100644 --- a/packages/dart_client/lib/src/api/channel.dart +++ b/packages/dart_client/lib/src/api/channel.dart @@ -160,8 +160,8 @@ class Channel { state?.channelStateStream?.map((cs) => cs.channel?.extraData); /// The main Stream chat client - Client get client => _client; - final Client _client; + StreamChatClient get client => _client; + final StreamChatClient _client; String get _channelURL => '/channels/$type/$id'; @@ -722,7 +722,7 @@ class Channel { }); } - /// Hides the channel from [Client.queryChannels] for the user until a message is added + /// Hides the channel from [StreamChatClient.queryChannels] for the user until a message is added /// If [clearHistory] is set to true - all messages will be removed for the user Future hide({bool clearHistory = false}) async { _checkInitialized(); diff --git a/packages/dart_client/lib/src/api/responses.dart b/packages/dart_client/lib/src/api/responses.dart index 919a875b..e27ac2c9 100644 --- a/packages/dart_client/lib/src/api/responses.dart +++ b/packages/dart_client/lib/src/api/responses.dart @@ -17,7 +17,7 @@ class _BaseResponse { String duration; } -/// Model response for [Client.resync] api call +/// Model response for [StreamChatClient.resync] api call @JsonSerializable(createToJson: false) class SyncResponse extends _BaseResponse { /// The list of events @@ -28,7 +28,7 @@ class SyncResponse extends _BaseResponse { _$SyncResponseFromJson(json); } -/// Model response for [Client.queryChannels] api call +/// Model response for [StreamChatClient.queryChannels] api call @JsonSerializable(createToJson: false) class QueryChannelsResponse extends _BaseResponse { /// List of channels state returned by the query @@ -39,7 +39,7 @@ class QueryChannelsResponse extends _BaseResponse { _$QueryChannelsResponseFromJson(json); } -/// Model response for [Client.queryChannels] api call +/// Model response for [StreamChatClient.queryChannels] api call @JsonSerializable(createToJson: false) class TranslateMessageResponse extends _BaseResponse { /// List of channels state returned by the query @@ -50,7 +50,7 @@ class TranslateMessageResponse extends _BaseResponse { _$TranslateMessageResponseFromJson(json); } -/// Model response for [Client.queryChannels] api call +/// Model response for [StreamChatClient.queryChannels] api call @JsonSerializable(createToJson: false) class QueryMembersResponse extends _BaseResponse { /// List of channels state returned by the query @@ -61,7 +61,7 @@ class QueryMembersResponse extends _BaseResponse { _$QueryMembersResponseFromJson(json); } -/// Model response for [Client.queryUsers] api call +/// Model response for [StreamChatClient.queryUsers] api call @JsonSerializable(createToJson: false) class QueryUsersResponse extends _BaseResponse { /// List of users returned by the query @@ -94,7 +94,7 @@ class QueryRepliesResponse extends _BaseResponse { _$QueryRepliesResponseFromJson(json); } -/// Model response for [Client.getDevices] api call +/// Model response for [StreamChatClient.getDevices] api call @JsonSerializable(createToJson: false) class ListDevicesResponse extends _BaseResponse { /// List of user devices @@ -141,7 +141,7 @@ class SendReactionResponse extends _BaseResponse { _$SendReactionResponseFromJson(json); } -/// Model response for [Client.setGuestUser] api call +/// Model response for [StreamChatClient.setGuestUser] api call @JsonSerializable(createToJson: false) class SetGuestUserResponse extends _BaseResponse { /// Guest user access token @@ -155,7 +155,7 @@ class SetGuestUserResponse extends _BaseResponse { _$SetGuestUserResponseFromJson(json); } -/// Model response for [Client.updateUser] api call +/// Model response for [StreamChatClient.updateUser] api call @JsonSerializable(createToJson: false) class UpdateUsersResponse extends _BaseResponse { /// Updated users @@ -166,7 +166,7 @@ class UpdateUsersResponse extends _BaseResponse { _$UpdateUsersResponseFromJson(json); } -/// Model response for [Client.updateMessage] api call +/// Model response for [StreamChatClient.updateMessage] api call @JsonSerializable(createToJson: false) class UpdateMessageResponse extends _BaseResponse { /// Message returned by the api call @@ -188,7 +188,7 @@ class SendMessageResponse extends _BaseResponse { _$SendMessageResponseFromJson(json); } -/// Model response for [Client.getMessage] api call +/// Model response for [StreamChatClient.getMessage] api call @JsonSerializable(createToJson: false) class GetMessageResponse extends _BaseResponse { /// Message returned by the api call @@ -208,7 +208,7 @@ class GetMessageResponse extends _BaseResponse { } } -/// Model response for [Client.search] api call +/// Model response for [StreamChatClient.search] api call @JsonSerializable(createToJson: false) class SearchMessagesResponse extends _BaseResponse { /// List of messages returned by the api call diff --git a/packages/dart_client/lib/src/api/retry_policy.dart b/packages/dart_client/lib/src/api/retry_policy.dart index 270d558c..2c59ec48 100644 --- a/packages/dart_client/lib/src/api/retry_policy.dart +++ b/packages/dart_client/lib/src/api/retry_policy.dart @@ -15,17 +15,18 @@ class RetryPolicy { int attempt = 0; /// This function evaluates if we should retry the failure - final bool Function(Client client, int attempt, ApiError apiError) + final bool Function(StreamChatClient client, int attempt, ApiError apiError) shouldRetry; /// In the case that we want to retry a failed request the retryTimeout method is called to determine the timeout - final Duration Function(Client client, int attempt, ApiError apiError) - retryTimeout; + final Duration Function( + StreamChatClient client, int attempt, ApiError apiError) retryTimeout; /// Creates a copy of [RetryPolicy] with specified attributes overridden. RetryPolicy copyWith({ - bool Function(Client client, int attempt, ApiError apiError) shouldRetry, - Duration Function(Client client, int attempt, ApiError apiError) + bool Function(StreamChatClient client, int attempt, ApiError apiError) + shouldRetry, + Duration Function(StreamChatClient client, int attempt, ApiError apiError) retryTimeout, int attempt, }) => diff --git a/packages/dart_client/lib/src/client.dart b/packages/dart_client/lib/src/client.dart index 67b3f444..7f9f560a 100644 --- a/packages/dart_client/lib/src/client.dart +++ b/packages/dart_client/lib/src/client.dart @@ -3,15 +3,15 @@ import 'dart:convert'; import 'dart:io'; import 'package:dio/dio.dart'; -import 'package:meta/meta.dart'; import 'package:logging/logging.dart'; +import 'package:meta/meta.dart'; +import 'package:pedantic/pedantic.dart' show unawaited; import 'package:rxdart/rxdart.dart'; import 'package:stream_chat/src/api/retry_policy.dart'; import 'package:stream_chat/src/event_type.dart'; import 'package:stream_chat/src/models/own_user.dart'; import 'package:stream_chat/version.dart'; import 'package:uuid/uuid.dart'; -import 'package:pedantic/pedantic.dart' show unawaited; import 'api/channel.dart'; import 'api/connection_status.dart'; @@ -64,12 +64,12 @@ extension on PushProvider { /// websocket connection to Stream Chat servers. /// /// ```dart -/// final client = Client("stream-chat-api-key"); +/// final client = StreamChatClient("stream-chat-api-key"); /// ``` -class Client { +class StreamChatClient { /// Create a client instance with default options. /// You should only create the client once and re-use it across your application. - Client( + StreamChatClient( this.apiKey, { this.tokenProvider, this.baseURL = _defaultBaseURL, @@ -81,9 +81,10 @@ class Client { RetryPolicy retryPolicy, }) { _retryPolicy ??= RetryPolicy( - retryTimeout: (Client client, int attempt, ApiError error) => + retryTimeout: (StreamChatClient client, int attempt, ApiError error) => Duration(seconds: 1 * attempt), - shouldRetry: (Client client, int attempt, ApiError error) => attempt < 5, + shouldRetry: (StreamChatClient client, int attempt, ApiError error) => + attempt < 5, ); state = ClientState(this); @@ -94,7 +95,7 @@ class Client { logger.info('instantiating new client'); } - /// Client chat persistence client + /// Chat persistence client ChatPersistenceClient chatPersistenceClient; /// Whether the chat persistence is available or not @@ -110,11 +111,11 @@ class Client { /// This client state ClientState state; - /// By default the Chat Client will write all messages with level Warn or Error to stdout. + /// By default the Chat client will write all messages with level Warn or Error to stdout. /// During development you might want to enable more logging information, you can change the default log level when constructing the client. /// /// ```dart - /// final client = Client("stream-chat-api-key", logLevel: Level.INFO); + /// final client = StreamChatClient("stream-chat-api-key", logLevel: Level.INFO); /// ``` final Level logLevel; @@ -133,7 +134,7 @@ class Client { /// // do something with the record (ie. send it to Sentry or Fabric) /// } /// - /// final client = Client("stream-chat-api-key", logHandlerFunction: myLogHandlerFunction); + /// final client = StreamChatClient("stream-chat-api-key", logHandlerFunction: myLogHandlerFunction); ///``` LogHandlerFunction logHandlerFunction; @@ -1337,7 +1338,7 @@ class ClientState { })); } - final Client _client; + final StreamChatClient _client; /// Update user information set user(OwnUser user) { diff --git a/packages/dart_client/lib/version.dart b/packages/dart_client/lib/version.dart index 1d13b723..3f084128 100644 --- a/packages/dart_client/lib/version.dart +++ b/packages/dart_client/lib/version.dart @@ -1,5 +1,5 @@ import 'package:stream_chat/src/client.dart'; /// Current package version -/// Used in [Client] to build the `x-stream-client` header +/// Used in [StreamChatClient] to build the `x-stream-client` header const PACKAGE_VERSION = '0.2.24+2'; diff --git a/packages/dart_client/test/src/api/channel_test.dart b/packages/dart_client/test/src/api/channel_test.dart index 3897eb04..4b274a94 100644 --- a/packages/dart_client/test/src/api/channel_test.dart +++ b/packages/dart_client/test/src/api/channel_test.dart @@ -1,6 +1,5 @@ import 'package:dio/dio.dart'; import 'package:dio/native_imp.dart'; -import 'package:test/test.dart'; import 'package:mockito/mockito.dart'; import 'package:stream_chat/src/api/requests.dart'; import 'package:stream_chat/src/client.dart'; @@ -8,6 +7,7 @@ import 'package:stream_chat/src/event_type.dart'; import 'package:stream_chat/src/models/event.dart'; import 'package:stream_chat/src/models/message.dart'; import 'package:stream_chat/src/models/reaction.dart'; +import 'package:test/test.dart'; class MockDio extends Mock implements DioForNative {} @@ -22,7 +22,7 @@ void main() { when(mockDio.options).thenReturn(BaseOptions()); when(mockDio.interceptors).thenReturn(Interceptors()); - final client = Client( + final client = StreamChatClient( 'api-key', httpClient: mockDio, tokenProvider: (_) async => '', @@ -51,7 +51,7 @@ void main() { when(mockDio.options).thenReturn(BaseOptions()); when(mockDio.interceptors).thenReturn(Interceptors()); - final client = Client( + final client = StreamChatClient( 'api-key', httpClient: mockDio, tokenProvider: (_) async => '', @@ -83,7 +83,7 @@ void main() { when(mockDio.options).thenReturn(BaseOptions()); when(mockDio.interceptors).thenReturn(Interceptors()); - final client = Client( + final client = StreamChatClient( 'api-key', httpClient: mockDio, tokenProvider: (_) async => '', @@ -108,7 +108,7 @@ void main() { when(mockDio.options).thenReturn(BaseOptions()); when(mockDio.interceptors).thenReturn(Interceptors()); - final client = Client( + final client = StreamChatClient( 'api-key', httpClient: mockDio, tokenProvider: (_) async => '', @@ -149,7 +149,7 @@ void main() { when(mockDio.options).thenReturn(BaseOptions()); when(mockDio.interceptors).thenReturn(Interceptors()); - final client = Client( + final client = StreamChatClient( 'api-key', httpClient: mockDio, tokenProvider: (_) async => '', @@ -173,7 +173,7 @@ void main() { when(mockDio.options).thenReturn(BaseOptions()); when(mockDio.interceptors).thenReturn(Interceptors()); - final client = Client( + final client = StreamChatClient( 'api-key', httpClient: mockDio, tokenProvider: (_) async => '', @@ -198,7 +198,7 @@ void main() { when(mockDio.options).thenReturn(BaseOptions()); when(mockDio.interceptors).thenReturn(Interceptors()); - final client = Client( + final client = StreamChatClient( 'api-key', httpClient: mockDio, tokenProvider: (_) async => '', @@ -223,7 +223,7 @@ void main() { when(mockDio.options).thenReturn(BaseOptions()); when(mockDio.interceptors).thenReturn(Interceptors()); - final client = Client( + final client = StreamChatClient( 'api-key', httpClient: mockDio, tokenProvider: (_) async => '', @@ -247,7 +247,7 @@ void main() { when(mockDio.options).thenReturn(BaseOptions()); when(mockDio.interceptors).thenReturn(Interceptors()); - final client = Client( + final client = StreamChatClient( 'api-key', httpClient: mockDio, tokenProvider: (_) async => '', @@ -272,7 +272,7 @@ void main() { when(mockDio.options).thenReturn(BaseOptions()); when(mockDio.interceptors).thenReturn(Interceptors()); - final client = Client( + final client = StreamChatClient( 'api-key', httpClient: mockDio, tokenProvider: (_) async => '', @@ -306,7 +306,7 @@ void main() { when(mockDio.options).thenReturn(BaseOptions()); when(mockDio.interceptors).thenReturn(Interceptors()); - final client = Client( + final client = StreamChatClient( 'api-key', httpClient: mockDio, tokenProvider: (_) async => '', @@ -340,7 +340,7 @@ void main() { when(mockDio.options).thenReturn(BaseOptions()); when(mockDio.interceptors).thenReturn(Interceptors()); - final client = Client( + final client = StreamChatClient( 'api-key', httpClient: mockDio, tokenProvider: (_) async => '', @@ -375,7 +375,7 @@ void main() { when(mockDio.options).thenReturn(BaseOptions()); when(mockDio.interceptors).thenReturn(Interceptors()); - final client = Client( + final client = StreamChatClient( 'api-key', httpClient: mockDio, tokenProvider: (_) async => '', @@ -414,7 +414,7 @@ void main() { when(mockDio.options).thenReturn(BaseOptions()); when(mockDio.interceptors).thenReturn(Interceptors()); - final client = Client( + final client = StreamChatClient( 'api-key', httpClient: mockDio, tokenProvider: (_) async => '', @@ -448,7 +448,7 @@ void main() { when(mockDio.options).thenReturn(BaseOptions()); when(mockDio.interceptors).thenReturn(Interceptors()); - final client = Client( + final client = StreamChatClient( 'api-key', httpClient: mockDio, tokenProvider: (_) async => '', @@ -475,7 +475,7 @@ void main() { when(mockDio.options).thenReturn(BaseOptions()); when(mockDio.interceptors).thenReturn(Interceptors()); - final client = Client( + final client = StreamChatClient( 'api-key', httpClient: mockDio, tokenProvider: (_) async => '', @@ -501,7 +501,7 @@ void main() { when(mockDio.options).thenReturn(BaseOptions()); when(mockDio.interceptors).thenReturn(Interceptors()); - final client = Client( + final client = StreamChatClient( 'api-key', httpClient: mockDio, tokenProvider: (_) async => '', @@ -527,7 +527,7 @@ void main() { when(mockDio.options).thenReturn(BaseOptions()); when(mockDio.interceptors).thenReturn(Interceptors()); - final client = Client( + final client = StreamChatClient( 'api-key', httpClient: mockDio, tokenProvider: (_) async => '', @@ -845,7 +845,7 @@ void main() { when(mockDio.options).thenReturn(BaseOptions()); when(mockDio.interceptors).thenReturn(Interceptors()); - final client = Client( + final client = StreamChatClient( 'api-key', httpClient: mockDio, tokenProvider: (_) async => '', @@ -1159,7 +1159,7 @@ void main() { when(mockDio.options).thenReturn(BaseOptions()); when(mockDio.interceptors).thenReturn(Interceptors()); - final client = Client( + final client = StreamChatClient( 'api-key', httpClient: mockDio, tokenProvider: (_) async => '', @@ -1474,7 +1474,7 @@ void main() { when(mockDio.options).thenReturn(BaseOptions()); when(mockDio.interceptors).thenReturn(Interceptors()); - final client = Client( + final client = StreamChatClient( 'api-key', httpClient: mockDio, tokenProvider: (_) async => '', @@ -1789,7 +1789,7 @@ void main() { when(mockDio.options).thenReturn(BaseOptions()); when(mockDio.interceptors).thenReturn(Interceptors()); - final client = Client( + final client = StreamChatClient( 'api-key', httpClient: mockDio, tokenProvider: (_) async => '', @@ -1815,7 +1815,7 @@ void main() { when(mockDio.options).thenReturn(BaseOptions()); when(mockDio.interceptors).thenReturn(Interceptors()); - final client = Client( + final client = StreamChatClient( 'api-key', httpClient: mockDio, tokenProvider: (_) async => '', @@ -1842,7 +1842,7 @@ void main() { when(mockDio.options).thenReturn(BaseOptions()); when(mockDio.interceptors).thenReturn(Interceptors()); - final client = Client( + final client = StreamChatClient( 'api-key', httpClient: mockDio, tokenProvider: (_) async => '', @@ -1863,7 +1863,7 @@ void main() { when(mockDio.options).thenReturn(BaseOptions()); when(mockDio.interceptors).thenReturn(Interceptors()); - final client = Client( + final client = StreamChatClient( 'api-key', httpClient: mockDio, tokenProvider: (_) async => '', @@ -1885,7 +1885,7 @@ void main() { when(mockDio.options).thenReturn(BaseOptions()); when(mockDio.interceptors).thenReturn(Interceptors()); - final client = Client( + final client = StreamChatClient( 'api-key', httpClient: mockDio, tokenProvider: (_) async => '', @@ -1910,7 +1910,7 @@ void main() { when(mockDio.options).thenReturn(BaseOptions()); when(mockDio.interceptors).thenReturn(Interceptors()); - final client = Client( + final client = StreamChatClient( 'api-key', httpClient: mockDio, tokenProvider: (_) async => '', @@ -1935,7 +1935,7 @@ void main() { when(mockDio.options).thenReturn(BaseOptions()); when(mockDio.interceptors).thenReturn(Interceptors()); - final client = Client( + final client = StreamChatClient( 'api-key', httpClient: mockDio, tokenProvider: (_) async => '', @@ -1961,7 +1961,7 @@ void main() { when(mockDio.options).thenReturn(BaseOptions()); when(mockDio.interceptors).thenReturn(Interceptors()); - final client = Client( + final client = StreamChatClient( 'api-key', httpClient: mockDio, tokenProvider: (_) async => '', @@ -1993,7 +1993,7 @@ void main() { when(mockDio.options).thenReturn(BaseOptions()); when(mockDio.interceptors).thenReturn(Interceptors()); - final client = Client( + final client = StreamChatClient( 'api-key', httpClient: mockDio, tokenProvider: (_) async => '', @@ -2024,7 +2024,7 @@ void main() { when(mockDio.options).thenReturn(BaseOptions()); when(mockDio.interceptors).thenReturn(Interceptors()); - final client = Client( + final client = StreamChatClient( 'api-key', httpClient: mockDio, tokenProvider: (_) async => '', @@ -2064,7 +2064,7 @@ void main() { when(mockDio.options).thenReturn(BaseOptions()); when(mockDio.interceptors).thenReturn(Interceptors()); - final client = Client( + final client = StreamChatClient( 'api-key', httpClient: mockDio, tokenProvider: (_) async => '', diff --git a/packages/dart_client/test/src/client_test.dart b/packages/dart_client/test/src/client_test.dart index 299ccecb..a1fa2175 100644 --- a/packages/dart_client/test/src/client_test.dart +++ b/packages/dart_client/test/src/client_test.dart @@ -3,7 +3,6 @@ import 'dart:convert'; import 'package:dio/dio.dart'; import 'package:dio/native_imp.dart'; -import 'package:test/test.dart'; import 'package:logging/logging.dart'; import 'package:mockito/mockito.dart'; import 'package:stream_chat/src/api/requests.dart'; @@ -11,6 +10,7 @@ import 'package:stream_chat/src/client.dart'; import 'package:stream_chat/src/exceptions.dart'; import 'package:stream_chat/src/models/message.dart'; import 'package:stream_chat/src/models/user.dart'; +import 'package:test/test.dart'; class MockDio extends Mock implements DioForNative {} @@ -41,7 +41,7 @@ void main() { }); test('should create the object correctly', () { - final client = Client('api-key'); + final client = StreamChatClient('api-key'); expect(client.baseURL, 'chat-us-east-1.stream-io-api.com'); expect(client.apiKey, 'api-key'); @@ -55,7 +55,7 @@ void main() { print(record.message); }; - final client = Client( + final client = StreamChatClient( 'api-key', connectTimeout: Duration(seconds: 10), receiveTimeout: Duration(seconds: 12), @@ -78,7 +78,7 @@ void main() { })); test('Channel', () { - final client = Client('test'); + final client = StreamChatClient('test'); final Map data = {'test': 1}; final channelClient = client.channel('type', id: 'id', extraData: data); expect(channelClient.type, 'type'); @@ -93,7 +93,7 @@ void main() { when(mockDio.options).thenReturn(BaseOptions()); when(mockDio.interceptors).thenReturn(Interceptors()); - final client = Client( + final client = StreamChatClient( 'api-key', httpClient: mockDio, ); @@ -124,7 +124,7 @@ void main() { when(mockDio.options).thenReturn(BaseOptions()); when(mockDio.interceptors).thenReturn(Interceptors()); - final client = Client( + final client = StreamChatClient( 'api-key', httpClient: mockDio, ); @@ -175,7 +175,7 @@ void main() { when(mockDio.options).thenReturn(BaseOptions()); when(mockDio.interceptors).thenReturn(Interceptors()); - final client = Client( + final client = StreamChatClient( 'api-key', httpClient: mockDio, ); @@ -203,7 +203,7 @@ void main() { when(mockDio.options).thenReturn(BaseOptions()); when(mockDio.interceptors).thenReturn(Interceptors()); - final client = Client( + final client = StreamChatClient( 'api-key', httpClient: mockDio, ); @@ -247,7 +247,7 @@ void main() { when(mockDio.options).thenReturn(BaseOptions()); when(mockDio.interceptors).thenReturn(Interceptors()); - final client = Client( + final client = StreamChatClient( 'api-key', httpClient: mockDio, ); @@ -273,7 +273,7 @@ void main() { when(mockDio.options).thenReturn(BaseOptions()); when(mockDio.interceptors).thenReturn(Interceptors()); - final client = Client( + final client = StreamChatClient( 'api-key', httpClient: mockDio, ); @@ -292,7 +292,7 @@ void main() { when(mockDio.options).thenReturn(BaseOptions()); when(mockDio.interceptors).thenReturn(Interceptors()); - final client = Client( + final client = StreamChatClient( 'api-key', httpClient: mockDio, ); @@ -309,7 +309,7 @@ void main() { }); test('devToken', () { - final client = Client('api-key'); + final client = StreamChatClient('api-key'); final token = client.devToken('test'); expect( @@ -325,7 +325,7 @@ void main() { when(mockDio.options).thenReturn(BaseOptions()); when(mockDio.interceptors).thenReturn(Interceptors()); - final client = Client( + final client = StreamChatClient( 'api-key', httpClient: mockDio, ); @@ -353,7 +353,7 @@ void main() { when(mockDio.options).thenReturn(BaseOptions()); when(mockDio.interceptors).thenReturn(Interceptors()); - final client = Client( + final client = StreamChatClient( 'api-key', httpClient: mockDio, ); @@ -396,7 +396,7 @@ void main() { when(mockDio.options).thenReturn(BaseOptions()); when(mockDio.interceptors).thenReturn(Interceptors()); - final client = Client( + final client = StreamChatClient( 'api-key', httpClient: mockDio, ); @@ -417,7 +417,7 @@ void main() { when(mockDio.options).thenReturn(BaseOptions()); when(mockDio.interceptors).thenReturn(Interceptors()); - final client = Client( + final client = StreamChatClient( 'api-key', httpClient: mockDio, ); @@ -432,7 +432,7 @@ void main() { when(mockDio.options).thenReturn(BaseOptions()); when(mockDio.interceptors).thenReturn(Interceptors()); - final client = Client( + final client = StreamChatClient( 'api-key', httpClient: mockDio, ); @@ -453,7 +453,7 @@ void main() { when(mockDio.options).thenReturn(BaseOptions()); when(mockDio.interceptors).thenReturn(Interceptors()); - final client = Client( + final client = StreamChatClient( 'api-key', httpClient: mockDio, ); @@ -478,7 +478,7 @@ void main() { when(mockDio.options).thenReturn(BaseOptions()); when(mockDio.interceptors).thenReturn(Interceptors()); - final client = Client( + final client = StreamChatClient( 'api-key', httpClient: mockDio, ); @@ -507,7 +507,7 @@ void main() { when(mockDio.options).thenReturn(BaseOptions()); when(mockDio.interceptors).thenReturn(Interceptors()); - final client = Client( + final client = StreamChatClient( 'api-key', httpClient: mockDio, ); @@ -528,7 +528,7 @@ void main() { when(mockDio.options).thenReturn(BaseOptions()); when(mockDio.interceptors).thenReturn(Interceptors()); - final client = Client( + final client = StreamChatClient( 'api-key', httpClient: mockDio, ); @@ -550,7 +550,7 @@ void main() { when(mockDio.options).thenReturn(BaseOptions()); when(mockDio.interceptors).thenReturn(Interceptors()); - final client = Client( + final client = StreamChatClient( 'api-key', httpClient: mockDio, ); @@ -571,7 +571,7 @@ void main() { when(mockDio.options).thenReturn(BaseOptions()); when(mockDio.interceptors).thenReturn(Interceptors()); - final client = Client( + final client = StreamChatClient( 'api-key', httpClient: mockDio, ); @@ -594,7 +594,7 @@ void main() { when(mockDio.options).thenReturn(BaseOptions()); when(mockDio.interceptors).thenReturn(Interceptors()); - final client = Client( + final client = StreamChatClient( 'api-key', httpClient: mockDio, ); @@ -615,7 +615,7 @@ void main() { when(mockDio.options).thenReturn(BaseOptions()); when(mockDio.interceptors).thenReturn(Interceptors()); - final client = Client( + final client = StreamChatClient( 'api-key', httpClient: mockDio, ); @@ -636,7 +636,7 @@ void main() { when(mockDio.options).thenReturn(BaseOptions()); when(mockDio.interceptors).thenReturn(Interceptors()); - final client = Client( + final client = StreamChatClient( 'api-key', httpClient: mockDio, ); @@ -663,7 +663,7 @@ void main() { when(mockDio.options).thenReturn(BaseOptions()); when(mockDio.interceptors).thenReturn(Interceptors()); - final client = Client( + final client = StreamChatClient( 'api-key', httpClient: mockDio, ); @@ -684,7 +684,7 @@ void main() { when(mockDio.options).thenReturn(BaseOptions()); when(mockDio.interceptors).thenReturn(Interceptors()); - final client = Client( + final client = StreamChatClient( 'api-key', httpClient: mockDio, ); @@ -705,7 +705,7 @@ void main() { when(mockDio.options).thenReturn(BaseOptions()); when(mockDio.interceptors).thenReturn(Interceptors()); - final client = Client( + final client = StreamChatClient( 'api-key', httpClient: mockDio, ); @@ -727,7 +727,7 @@ void main() { when(mockDio.options).thenReturn(BaseOptions()); when(mockDio.interceptors).thenReturn(Interceptors()); - final client = Client( + final client = StreamChatClient( 'api-key', httpClient: mockDio, ); @@ -752,7 +752,7 @@ void main() { final mockHttpClientAdapter = MockHttpClientAdapter(); dioHttp.httpClientAdapter = mockHttpClientAdapter; - final client = Client( + final client = StreamChatClient( 'api-key', httpClient: dioHttp, ); @@ -771,7 +771,7 @@ void main() { when(mockDio.options).thenReturn(BaseOptions()); when(mockDio.interceptors).thenReturn(Interceptors()); - final client = Client( + final client = StreamChatClient( 'api-key', httpClient: mockDio, ); @@ -794,7 +794,7 @@ void main() { final mockHttpClientAdapter = MockHttpClientAdapter(); dioHttp.httpClientAdapter = mockHttpClientAdapter; - final client = Client( + final client = StreamChatClient( 'api-key', httpClient: dioHttp, ); @@ -813,7 +813,7 @@ void main() { when(mockDio.options).thenReturn(BaseOptions()); when(mockDio.interceptors).thenReturn(Interceptors()); - final client = Client( + final client = StreamChatClient( 'api-key', httpClient: mockDio, ); @@ -836,7 +836,7 @@ void main() { final mockHttpClientAdapter = MockHttpClientAdapter(); dioHttp.httpClientAdapter = mockHttpClientAdapter; - final client = Client( + final client = StreamChatClient( 'api-key', httpClient: dioHttp, ); @@ -855,7 +855,7 @@ void main() { when(mockDio.options).thenReturn(BaseOptions()); when(mockDio.interceptors).thenReturn(Interceptors()); - final client = Client( + final client = StreamChatClient( 'api-key', httpClient: mockDio, ); @@ -879,7 +879,7 @@ void main() { final mockHttpClientAdapter = MockHttpClientAdapter(); dioHttp.httpClientAdapter = mockHttpClientAdapter; - final client = Client( + final client = StreamChatClient( 'api-key', httpClient: dioHttp, ); @@ -898,7 +898,7 @@ void main() { when(mockDio.options).thenReturn(BaseOptions()); when(mockDio.interceptors).thenReturn(Interceptors()); - final client = Client( + final client = StreamChatClient( 'api-key', httpClient: mockDio, ); @@ -923,7 +923,7 @@ void main() { final mockHttpClientAdapter = MockHttpClientAdapter(); dioHttp.httpClientAdapter = mockHttpClientAdapter; - final client = Client( + final client = StreamChatClient( 'api-key', httpClient: dioHttp, ); diff --git a/packages/flutter_widgets/README.md b/packages/flutter_widgets/README.md index b99a8f29..3504c78a 100644 --- a/packages/flutter_widgets/README.md +++ b/packages/flutter_widgets/README.md @@ -91,7 +91,7 @@ Out of the box, all chat widgets use their default styling, and there are two wa 1. Initialize the `StreamChatTheme` from your existing `MaterialApp` style ```dart class MyApp extends StatelessWidget { - final Client client; + final StreamChatClient client; MyApp(this.client); @@ -117,7 +117,7 @@ Out of the box, all chat widgets use their default styling, and there are two wa 2. Construct a custom theme and provide all the customizations needed ```dart class MyApp extends StatelessWidget { - final Client client; + final StreamChatClient client; MyApp(this.client); diff --git a/packages/flutter_widgets/example/lib/advanced_options_page.dart b/packages/flutter_widgets/example/lib/advanced_options_page.dart index 35e2af7f..ee505148 100644 --- a/packages/flutter_widgets/example/lib/advanced_options_page.dart +++ b/packages/flutter_widgets/example/lib/advanced_options_page.dart @@ -267,7 +267,7 @@ class _AdvancedOptionsPageState extends State { ), ); - final client = Client( + final client = StreamChatClient( apiKey, logLevel: Level.INFO, )..chatPersistenceClient = chatPersistentClient; diff --git a/packages/flutter_widgets/example/lib/custom_message.dart b/packages/flutter_widgets/example/lib/custom_message.dart index 5da4541a..e2756430 100644 --- a/packages/flutter_widgets/example/lib/custom_message.dart +++ b/packages/flutter_widgets/example/lib/custom_message.dart @@ -15,7 +15,7 @@ import 'package:stream_chat_flutter/stream_chat_flutter.dart'; /// you can use [StreamChat.of], [StreamChannel.of] and [StreamChatTheme.of] to use the API client directly /// or to retrieve outer scope needed such as messages from the [Channel.state]. void main() async { - final client = Client( + final client = StreamChatClient( 's2dxdhpxd94g', logLevel: Level.INFO, ); @@ -29,7 +29,7 @@ void main() async { } class MyApp extends StatelessWidget { - final Client client; + final StreamChatClient client; MyApp(this.client); diff --git a/packages/flutter_widgets/example/lib/custom_theme.dart b/packages/flutter_widgets/example/lib/custom_theme.dart index 817d2e67..a7ad5ba0 100644 --- a/packages/flutter_widgets/example/lib/custom_theme.dart +++ b/packages/flutter_widgets/example/lib/custom_theme.dart @@ -19,7 +19,7 @@ import 'package:stream_chat_flutter/stream_chat_flutter.dart'; /// We also change the message color posted by the current user. /// You can perform these more granular style changes using [StreamChatTheme.copyWith]. void main() async { - final client = Client( + final client = StreamChatClient( 's2dxdhpxd94g', logLevel: Level.INFO, ); @@ -33,7 +33,7 @@ void main() async { } class MyApp extends StatelessWidget { - final Client client; + final StreamChatClient client; MyApp(this.client); diff --git a/packages/flutter_widgets/example/lib/customize_channel_preview.dart b/packages/flutter_widgets/example/lib/customize_channel_preview.dart index 9b7deb64..2f28fa80 100644 --- a/packages/flutter_widgets/example/lib/customize_channel_preview.dart +++ b/packages/flutter_widgets/example/lib/customize_channel_preview.dart @@ -20,7 +20,7 @@ import 'package:stream_chat_flutter/stream_chat_flutter.dart'; /// /// - We retrieve the count of unread messages from [Channel.state] void main() async { - final client = Client( + final client = StreamChatClient( 's2dxdhpxd94g', logLevel: Level.INFO, ); @@ -34,7 +34,7 @@ void main() async { } class MyApp extends StatelessWidget { - final Client client; + final StreamChatClient client; MyApp(this.client); diff --git a/packages/flutter_widgets/example/lib/customize_message_widget.dart b/packages/flutter_widgets/example/lib/customize_message_widget.dart index 14233dd7..d19d6023 100644 --- a/packages/flutter_widgets/example/lib/customize_message_widget.dart +++ b/packages/flutter_widgets/example/lib/customize_message_widget.dart @@ -15,7 +15,7 @@ import 'package:stream_chat_flutter/stream_chat_flutter.dart'; /// you can use [StreamChat.of], [StreamChannel.of] and [StreamChatTheme.of] to use the API client directly /// or to retrieve outer scope needed such as messages from the [Channel.state]. void main() async { - final client = Client( + final client = StreamChatClient( 's2dxdhpxd94g', logLevel: Level.INFO, ); @@ -29,7 +29,7 @@ void main() async { } class MyApp extends StatelessWidget { - final Client client; + final StreamChatClient client; MyApp(this.client); diff --git a/packages/flutter_widgets/example/lib/main.dart b/packages/flutter_widgets/example/lib/main.dart index 93c7b082..775b1d6e 100644 --- a/packages/flutter_widgets/example/lib/main.dart +++ b/packages/flutter_widgets/example/lib/main.dart @@ -29,7 +29,7 @@ void main() async { final apiKey = await secureStorage.read(key: kStreamApiKey); final userId = await secureStorage.read(key: kStreamUserId); - final client = Client( + final client = StreamChatClient( apiKey ?? kDefaultStreamApiKey, logLevel: Level.INFO, )..chatPersistenceClient = chatPersistentClient; @@ -46,7 +46,7 @@ void main() async { } class MyApp extends StatelessWidget { - final Client client; + final StreamChatClient client; MyApp(this.client); diff --git a/packages/flutter_widgets/example/lib/multiple_conversation.dart b/packages/flutter_widgets/example/lib/multiple_conversation.dart index b5fdd5af..f810231c 100644 --- a/packages/flutter_widgets/example/lib/multiple_conversation.dart +++ b/packages/flutter_widgets/example/lib/multiple_conversation.dart @@ -19,7 +19,7 @@ import 'package:stream_chat_flutter/stream_chat_flutter.dart'; /// In this case we are showing the list of channels the current user is a member and we order them based on the time they had a new message. /// [ChannelListView] handles pagination and updates automatically out of the box when new channels are created or when a new message is added to a channel. void main() async { - final client = Client( + final client = StreamChatClient( 's2dxdhpxd94g', logLevel: Level.INFO, ); @@ -33,7 +33,7 @@ void main() async { } class MyApp extends StatelessWidget { - final Client client; + final StreamChatClient client; MyApp(this.client); diff --git a/packages/flutter_widgets/example/lib/single_conversation.dart b/packages/flutter_widgets/example/lib/single_conversation.dart index 2093d38a..66a1091c 100644 --- a/packages/flutter_widgets/example/lib/single_conversation.dart +++ b/packages/flutter_widgets/example/lib/single_conversation.dart @@ -5,8 +5,8 @@ import 'package:stream_chat_flutter/stream_chat_flutter.dart'; /// /// There are three important things to notice that are common to all Flutter application using StreamChat: /// -/// 1. The Dart API [Client] is initialized with your API Key -/// 2. The current user is set by calling [Client.setUser] +/// 1. The Dart API [StreamChatClient] is initialized with your API Key +/// 2. The current user is set by calling [StreamChatClient.setUser] /// 3. The client is then passed to the top-level [StreamChat] widget /// [StreamChat] is an inherited widget and must be the parent of all Chat related widgets. /// @@ -15,9 +15,9 @@ import 'package:stream_chat_flutter/stream_chat_flutter.dart'; /// /// Let's have a look at what we've built: /// -/// - We set up the Chat [Client] with the API key +/// - We set up the Chat [StreamChatClient] with the API key /// -/// - We set the the current user for Chat with [Client.setUser] and a pre-generated user token +/// - We set the the current user for Chat with [StreamChatClient.setUser] and a pre-generated user token /// /// - We make [StreamChat] the root Widget of our application /// @@ -25,7 +25,7 @@ import 'package:stream_chat_flutter/stream_chat_flutter.dart'; /// /// If you now run the simulator you will see a single channel UI. void main() async { - final client = Client( + final client = StreamChatClient( 's2dxdhpxd94g', logLevel: Level.INFO, ); @@ -44,7 +44,7 @@ void main() async { } class MyApp extends StatelessWidget { - final Client client; + final StreamChatClient client; final Channel channel; MyApp(this.client, this.channel); diff --git a/packages/flutter_widgets/example/lib/split_view.dart b/packages/flutter_widgets/example/lib/split_view.dart index f99e69fc..08324759 100644 --- a/packages/flutter_widgets/example/lib/split_view.dart +++ b/packages/flutter_widgets/example/lib/split_view.dart @@ -2,7 +2,7 @@ import 'package:flutter/material.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; void main() async { - final client = Client( + final client = StreamChatClient( 's2dxdhpxd94g', logLevel: Level.INFO, ); @@ -16,7 +16,7 @@ void main() async { } class MyApp extends StatelessWidget { - final Client client; + final StreamChatClient client; MyApp(this.client); diff --git a/packages/flutter_widgets/example/lib/threads.dart b/packages/flutter_widgets/example/lib/threads.dart index f89e6fce..6a3c7766 100644 --- a/packages/flutter_widgets/example/lib/threads.dart +++ b/packages/flutter_widgets/example/lib/threads.dart @@ -10,7 +10,7 @@ import 'package:stream_chat_flutter/stream_chat_flutter.dart'; /// /// Now we can open threads and create new ones as well, if you long press a message you can tap on Reply and it will open the same [ThreadPage]. void main() async { - final client = Client( + final client = StreamChatClient( 's2dxdhpxd94g', logLevel: Level.INFO, ); @@ -24,7 +24,7 @@ void main() async { } class MyApp extends StatelessWidget { - final Client client; + final StreamChatClient client; MyApp(this.client); diff --git a/packages/flutter_widgets/lib/src/channel_header.dart b/packages/flutter_widgets/lib/src/channel_header.dart index 954734f9..27194627 100644 --- a/packages/flutter_widgets/lib/src/channel_header.dart +++ b/packages/flutter_widgets/lib/src/channel_header.dart @@ -1,13 +1,13 @@ import 'package:flutter/material.dart'; -import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; import 'package:stream_chat_flutter/src/back_button.dart'; import 'package:stream_chat_flutter/src/channel_info.dart'; import 'package:stream_chat_flutter/src/channel_name.dart'; import 'package:stream_chat_flutter/src/info_tile.dart'; import 'package:stream_chat_flutter/src/stream_chat_theme.dart'; +import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; -import '../stream_chat_flutter.dart'; import './channel_name.dart'; +import '../stream_chat_flutter.dart'; import 'channel_image.dart'; import 'connection_status_builder.dart'; @@ -18,7 +18,7 @@ import 'connection_status_builder.dart'; /// /// ```dart /// class MyApp extends StatelessWidget { -/// final Client client; +/// final StreamChatClient client; /// final Channel channel; /// /// MyApp(this.client, this.channel); diff --git a/packages/flutter_widgets/lib/src/channel_image.dart b/packages/flutter_widgets/lib/src/channel_image.dart index 18d67dfb..649a5880 100644 --- a/packages/flutter_widgets/lib/src/channel_image.dart +++ b/packages/flutter_widgets/lib/src/channel_image.dart @@ -1,8 +1,8 @@ import 'package:cached_network_image/cached_network_image.dart'; import 'package:flutter/material.dart'; -import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; import 'package:stream_chat_flutter/src/group_image.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; +import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; /// ![screenshot](https://raw.githubusercontent.com/GetStream/stream-chat-flutter/master/screenshots/channel_image.png) /// ![screenshot](https://raw.githubusercontent.com/GetStream/stream-chat-flutter/master/screenshots/channel_image_paint.png) @@ -11,7 +11,7 @@ import 'package:stream_chat_flutter/stream_chat_flutter.dart'; /// /// ```dart /// class MyApp extends StatelessWidget { -/// final Client client; +/// final StreamChatClient client; /// final Channel channel; /// /// MyApp(this.client, this.channel); diff --git a/packages/flutter_widgets/lib/src/channel_info.dart b/packages/flutter_widgets/lib/src/channel_info.dart index 88739bb3..4244c910 100644 --- a/packages/flutter_widgets/lib/src/channel_info.dart +++ b/packages/flutter_widgets/lib/src/channel_info.dart @@ -111,7 +111,8 @@ class ChannelInfo extends StatelessWidget { ); } - Widget _buildDisconnectedTitleState(BuildContext context, Client client) { + Widget _buildDisconnectedTitleState( + BuildContext context, StreamChatClient client) { return Row( mainAxisAlignment: MainAxisAlignment.center, children: [ diff --git a/packages/flutter_widgets/lib/src/channel_list_header.dart b/packages/flutter_widgets/lib/src/channel_list_header.dart index 29126402..045d24d5 100644 --- a/packages/flutter_widgets/lib/src/channel_list_header.dart +++ b/packages/flutter_widgets/lib/src/channel_list_header.dart @@ -2,9 +2,9 @@ import 'dart:ui'; import 'package:flutter/material.dart'; import 'package:flutter_svg/flutter_svg.dart'; -import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; import 'package:stream_chat_flutter/src/stream_neumorphic_button.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; +import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; import 'connection_status_builder.dart'; import 'info_tile.dart'; @@ -13,15 +13,15 @@ import 'stream_chat.dart'; typedef _TitleBuilder = Widget Function( BuildContext context, ConnectionStatus status, - Client client, + StreamChatClient client, ); /// -/// It shows the current [Client] status. +/// It shows the current [StreamChatClient] status. /// /// ```dart /// class MyApp extends StatelessWidget { -/// final Client client; +/// final StreamChatClient client; /// /// MyApp(this.client); /// @@ -42,8 +42,8 @@ typedef _TitleBuilder = Widget Function( /// Usually you would use this widget as an [AppBar] inside a [Scaffold]. /// However you can also use it as a normal widget. /// -/// The widget by default uses the inherited [Client] to fetch information about the status. -/// However you can also pass your own [Client] if you don't have it in the widget tree. +/// The widget by default uses the inherited [StreamChatClient] to fetch information about the status. +/// However you can also pass your own [StreamChatClient] if you don't have it in the widget tree. /// /// The widget components render the ui based on the first ancestor of type [StreamChatTheme] and on its [ChannelTheme.channelHeaderTheme] property. /// Modify it to change the widget appearance. @@ -59,8 +59,8 @@ class ChannelListHeader extends StatelessWidget implements PreferredSizeWidget { this.preNavigationCallback, }) : super(key: key); - /// Pass this if you don't have a [Client] in your widget tree. - final Client client; + /// Pass this if you don't have a [StreamChatClient] in your widget tree. + final StreamChatClient client; /// Use this to build your own title as per different [ConnectionStatus] final _TitleBuilder titleBuilder; @@ -215,7 +215,8 @@ class ChannelListHeader extends StatelessWidget implements PreferredSizeWidget { ); } - Widget _buildDisconnectedTitleState(BuildContext context, Client client) { + Widget _buildDisconnectedTitleState( + BuildContext context, StreamChatClient client) { return Row( mainAxisAlignment: MainAxisAlignment.center, children: [ diff --git a/packages/flutter_widgets/lib/src/connection_status_builder.dart b/packages/flutter_widgets/lib/src/connection_status_builder.dart index ebb12cd5..01632b1b 100644 --- a/packages/flutter_widgets/lib/src/connection_status_builder.dart +++ b/packages/flutter_widgets/lib/src/connection_status_builder.dart @@ -1,11 +1,12 @@ import 'package:flutter/material.dart'; import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; + import 'stream_chat.dart'; /// Widget that builds itself based on the latest snapshot of interaction with /// a [Stream] of type [ConnectionStatus]. /// -/// The widget will use the closest [Client.wsConnectionStatusStream] in case no +/// The widget will use the closest [StreamChatClient.wsConnectionStatusStream] in case no /// stream is provided. class ConnectionStatusBuilder extends StatelessWidget { /// Creates a new ConnectionStatusBuilder diff --git a/packages/flutter_widgets/lib/src/stream_chat.dart b/packages/flutter_widgets/lib/src/stream_chat.dart index 0ea5efb2..f093a81a 100644 --- a/packages/flutter_widgets/lib/src/stream_chat.dart +++ b/packages/flutter_widgets/lib/src/stream_chat.dart @@ -4,14 +4,14 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_app_badger/flutter_app_badger.dart'; import 'package:flutter_portal/flutter_portal.dart'; -import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; import 'package:stream_chat_flutter/src/stream_chat_theme.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; +import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; /// Widget used to provide information about the chat to the widget tree /// /// class MyApp extends StatelessWidget { -/// final Client client; +/// final StreamChatClient client; /// /// MyApp(this.client); /// @@ -30,7 +30,7 @@ import 'package:stream_chat_flutter/stream_chat_flutter.dart'; /// /// Use [StreamChat.of] to get the current [StreamChatState] instance. class StreamChat extends StatefulWidget { - final Client client; + final StreamChatClient client; final Widget child; final StreamChatThemeData streamChatThemeData; @@ -73,7 +73,7 @@ class StreamChat extends StatefulWidget { /// The current state of the StreamChat widget class StreamChatState extends State { - Client get client => widget.client; + StreamChatClient get client => widget.client; @override Widget build(BuildContext context) { diff --git a/packages/flutter_widgets/test/src/mocks.dart b/packages/flutter_widgets/test/src/mocks.dart index 25b438d6..0abbf3ca 100644 --- a/packages/flutter_widgets/test/src/mocks.dart +++ b/packages/flutter_widgets/test/src/mocks.dart @@ -1,7 +1,7 @@ import 'package:mockito/mockito.dart'; import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; -class MockClient extends Mock implements Client {} +class MockClient extends Mock implements StreamChatClient {} class MockClientState extends Mock implements ClientState {} diff --git a/packages/stream_chat_flutter_core/example/lib/main.dart b/packages/stream_chat_flutter_core/example/lib/main.dart index 845510f2..9199ed15 100644 --- a/packages/stream_chat_flutter_core/example/lib/main.dart +++ b/packages/stream_chat_flutter_core/example/lib/main.dart @@ -2,9 +2,9 @@ import 'package:flutter/material.dart'; import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; Future main() async { - /// Create a new instance of [Client] passing the apikey obtained from your + /// Create a new instance of [StreamChatClient] passing the apikey obtained from your /// project dashboard. - final client = Client('b67pax5b2wdq'); + final client = StreamChatClient('b67pax5b2wdq'); /// Set the current user. In a production scenario, this should be done using /// a backend to generate a user token using our server SDK. @@ -43,10 +43,10 @@ class StreamExample extends StatelessWidget { }) : super(key: key); /// Instance of Stream Client. - /// Stream's [Client] can be used to connect to our servers and set the default + /// Stream's [StreamChatClient] can be used to connect to our servers and set the default /// user for the application. Performing these actions trigger a websocket connection /// allowing for real-time updates. - final Client client; + final StreamChatClient client; @override Widget build(BuildContext context) { @@ -287,8 +287,8 @@ class _MessageScreenState extends State { } /// Extensions can be used to add functionality to the SDK. In the examples -/// below, we add two simple extensions to the [Client] and [Channel]. -extension on Client { +/// below, we add two simple extensions to the [StreamChatClient] and [Channel]. +extension on StreamChatClient { /// Fetches the current user id. String get uid => state.user.id; } diff --git a/packages/stream_chat_flutter_core/lib/src/message_search_bloc.dart b/packages/stream_chat_flutter_core/lib/src/message_search_bloc.dart index 6458bebf..9839994f 100644 --- a/packages/stream_chat_flutter_core/lib/src/message_search_bloc.dart +++ b/packages/stream_chat_flutter_core/lib/src/message_search_bloc.dart @@ -59,7 +59,7 @@ class MessageSearchBlocState extends State Stream get queryMessagesLoading => _queryMessagesLoadingController.stream; - /// Calls [Client.search] updating [messageResponses] stream + /// Calls [StreamChatClient.search] updating [messageResponses] stream Future search({ Map filter, Map messageFilter, @@ -82,7 +82,7 @@ class MessageSearchBlocState extends State } } - /// Calls [Client.search] updating [queryMessagesLoading] stream + /// Calls [StreamChatClient.search] updating [queryMessagesLoading] stream Future loadMore({ Map filter, Map messageFilter, diff --git a/packages/stream_chat_flutter_core/lib/src/stream_chat_core.dart b/packages/stream_chat_flutter_core/lib/src/stream_chat_core.dart index 78cae0ba..8a8d0185 100644 --- a/packages/stream_chat_flutter_core/lib/src/stream_chat_core.dart +++ b/packages/stream_chat_flutter_core/lib/src/stream_chat_core.dart @@ -15,7 +15,7 @@ import 'typedef.dart'; /// /// ```dart /// class MyApp extends StatelessWidget { -/// final Client client; +/// final StreamChatClient client; /// /// MyApp(this.client); /// @@ -50,7 +50,7 @@ class StreamChatCore extends StatefulWidget { /// Instance of Stream Chat Client containing information about the current /// application. - final Client client; + final StreamChatClient client; /// Widget descendant. final Widget child; @@ -85,7 +85,7 @@ class StreamChatCore extends StatefulWidget { class StreamChatCoreState extends State with WidgetsBindingObserver { /// Initialized client used throughout the application. - Client get client => widget.client; + StreamChatClient get client => widget.client; Timer _disconnectTimer; diff --git a/packages/stream_chat_flutter_core/test/mocks.dart b/packages/stream_chat_flutter_core/test/mocks.dart index 37fa5530..c23a4be4 100644 --- a/packages/stream_chat_flutter_core/test/mocks.dart +++ b/packages/stream_chat_flutter_core/test/mocks.dart @@ -1,7 +1,7 @@ import 'package:mockito/mockito.dart'; import 'package:stream_chat/stream_chat.dart'; -class MockClient extends Mock implements Client {} +class MockClient extends Mock implements StreamChatClient {} class MockClientState extends Mock implements ClientState {} diff --git a/packages/stream_chat_persistence/README.md b/packages/stream_chat_persistence/README.md index d53d51e4..77b2eea5 100644 --- a/packages/stream_chat_persistence/README.md +++ b/packages/stream_chat_persistence/README.md @@ -36,7 +36,7 @@ final chatPersistentClient = StreamChatPersistenceClient( ``` 2. Pass the instance to the official Stream chat client. ```dart - final client = Client( + final client = StreamChatClient( apiKey ?? kDefaultStreamApiKey, logLevel: Level.INFO, )..chatPersistenceClient = chatPersistentClient; From 964a428f2e4ab1d4e26de6e897b64fb145d0b73e Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Mon, 1 Feb 2021 15:45:58 +0100 Subject: [PATCH 1118/1140] rename package folders --- packages/flutter_widgets/example/ios/Podfile | 43 --- .../flutter_widgets/example/ios/Podfile.lock | 299 ------------------ .../{dart_client => stream_chat}/.gitignore | 0 .../{dart_client => stream_chat}/.metadata | 0 .../{dart_client => stream_chat}/CHANGELOG.md | 0 packages/{dart_client => stream_chat}/LICENSE | 0 .../{dart_client => stream_chat}/README.md | 0 .../analysis_options.yaml | 0 .../{dart_client => stream_chat}/build.yaml | 0 .../example/.gitignore | 0 .../example/.metadata | 0 .../example/README.md | 0 .../example/android/.gitignore | 0 .../example/android/app/build.gradle | 0 .../android/app/src/debug/AndroidManifest.xml | 0 .../android/app/src/main/AndroidManifest.xml | 0 .../com/example/example/MainActivity.kt | 0 .../main/res/drawable/launch_background.xml | 0 .../src/main/res/mipmap-hdpi/ic_launcher.png | Bin .../src/main/res/mipmap-mdpi/ic_launcher.png | Bin .../src/main/res/mipmap-xhdpi/ic_launcher.png | Bin .../main/res/mipmap-xxhdpi/ic_launcher.png | Bin .../main/res/mipmap-xxxhdpi/ic_launcher.png | Bin .../app/src/main/res/values/styles.xml | 0 .../app/src/profile/AndroidManifest.xml | 0 .../example/android/build.gradle | 0 .../example/android/gradle.properties | 0 .../gradle/wrapper/gradle-wrapper.properties | 0 .../example/android/settings.gradle | 0 .../example/ios/.gitignore | 0 .../ios/Flutter/AppFrameworkInfo.plist | 0 .../example/ios/Flutter/Debug.xcconfig | 0 .../example/ios/Flutter/Release.xcconfig | 0 .../contents.xcworkspacedata | 0 .../xcshareddata/IDEWorkspaceChecks.plist | 0 .../xcshareddata/WorkspaceSettings.xcsettings | 0 .../xcshareddata/xcschemes/Runner.xcscheme | 0 .../contents.xcworkspacedata | 0 .../xcshareddata/IDEWorkspaceChecks.plist | 0 .../xcshareddata/WorkspaceSettings.xcsettings | 0 .../example/ios/Runner/AppDelegate.swift | 0 .../AppIcon.appiconset/Contents.json | 0 .../Icon-App-1024x1024@1x.png | Bin .../AppIcon.appiconset/Icon-App-20x20@1x.png | Bin .../AppIcon.appiconset/Icon-App-20x20@2x.png | Bin .../AppIcon.appiconset/Icon-App-20x20@3x.png | Bin .../AppIcon.appiconset/Icon-App-29x29@1x.png | Bin .../AppIcon.appiconset/Icon-App-29x29@2x.png | Bin .../AppIcon.appiconset/Icon-App-29x29@3x.png | Bin .../AppIcon.appiconset/Icon-App-40x40@1x.png | Bin .../AppIcon.appiconset/Icon-App-40x40@2x.png | Bin .../AppIcon.appiconset/Icon-App-40x40@3x.png | Bin .../AppIcon.appiconset/Icon-App-60x60@2x.png | Bin .../AppIcon.appiconset/Icon-App-60x60@3x.png | Bin .../AppIcon.appiconset/Icon-App-76x76@1x.png | Bin .../AppIcon.appiconset/Icon-App-76x76@2x.png | Bin .../Icon-App-83.5x83.5@2x.png | Bin .../LaunchImage.imageset/Contents.json | 0 .../LaunchImage.imageset/LaunchImage.png | Bin .../LaunchImage.imageset/LaunchImage@2x.png | Bin .../LaunchImage.imageset/LaunchImage@3x.png | Bin .../LaunchImage.imageset/README.md | 0 .../Runner/Base.lproj/LaunchScreen.storyboard | 0 .../ios/Runner/Base.lproj/Main.storyboard | 0 .../example/ios/Runner/Info.plist | 0 .../ios/Runner/Runner-Bridging-Header.h | 0 .../example/lib/main.dart | 0 .../example/pubspec.yaml | 0 .../lib/src/api/channel.dart | 0 .../lib/src/api/connection_status.dart | 0 .../lib/src/api/requests.dart | 0 .../lib/src/api/requests.g.dart | 0 .../lib/src/api/responses.dart | 0 .../lib/src/api/responses.g.dart | 0 .../lib/src/api/retry_policy.dart | 0 .../lib/src/api/retry_queue.dart | 0 .../lib/src/api/web_socket_channel_html.dart | 0 .../lib/src/api/web_socket_channel_io.dart | 0 .../lib/src/api/web_socket_channel_stub.dart | 0 .../lib/src/api/websocket.dart | 0 .../lib/src/client.dart | 0 .../lib/src/db/chat_persistence_client.dart | 0 .../lib/src/event_type.dart | 0 .../lib/src/exceptions.dart | 0 .../lib/src/models/action.dart | 0 .../lib/src/models/action.g.dart | 0 .../lib/src/models/attachment.dart | 0 .../lib/src/models/attachment.g.dart | 0 .../lib/src/models/channel_config.dart | 0 .../lib/src/models/channel_config.g.dart | 0 .../lib/src/models/channel_model.dart | 0 .../lib/src/models/channel_model.g.dart | 0 .../lib/src/models/channel_state.dart | 0 .../lib/src/models/channel_state.g.dart | 0 .../lib/src/models/command.dart | 0 .../lib/src/models/command.g.dart | 0 .../lib/src/models/device.dart | 0 .../lib/src/models/device.g.dart | 0 .../lib/src/models/event.dart | 0 .../lib/src/models/event.g.dart | 0 .../lib/src/models/member.dart | 0 .../lib/src/models/member.g.dart | 0 .../lib/src/models/message.dart | 0 .../lib/src/models/message.g.dart | 0 .../lib/src/models/mute.dart | 0 .../lib/src/models/mute.g.dart | 0 .../lib/src/models/own_user.dart | 0 .../lib/src/models/own_user.g.dart | 0 .../lib/src/models/reaction.dart | 0 .../lib/src/models/reaction.g.dart | 0 .../lib/src/models/read.dart | 0 .../lib/src/models/read.g.dart | 0 .../lib/src/models/serialization.dart | 0 .../lib/src/models/user.dart | 0 .../lib/src/models/user.g.dart | 0 .../lib/stream_chat.dart | 0 .../lib/version.dart | 0 .../{dart_client => stream_chat}/peanut.yaml | 0 .../{dart_client => stream_chat}/pubspec.yaml | 0 .../test/src/api/channel_test.dart | 0 .../test/src/api/requests_test.dart | 0 .../test/src/api/responses_test.dart | 0 .../test/src/api/web_socket_stub_test.dart | 0 .../test/src/api/websocket_test.dart | 0 .../test/src/client_test.dart | 0 .../test/src/models/action_test.dart | 0 .../test/src/models/attachment_test.dart | 0 .../test/src/models/channel_state_test.dart | 0 .../test/src/models/channel_test.dart | 0 .../test/src/models/command_test.dart | 0 .../test/src/models/device_test.dart | 0 .../test/src/models/event_test.dart | 0 .../test/src/models/member_test.dart | 0 .../test/src/models/message_test.dart | 0 .../test/src/models/reaction_test.dart | 0 .../test/src/models/read_test.dart | 0 .../test/src/models/serialization_test.dart | 0 .../test/src/models/user_test.dart | 0 .../test/version_test.dart | 0 .../.gitignore | 0 .../CHANGELOG.md | 0 .../LICENSE | 0 .../README.md | 0 .../analysis_options.yaml | 0 .../animations/typing_dots.json | 0 .../example/.gitignore | 0 .../example/.metadata | 0 .../example/README.md | 0 .../example/android/.gitignore | 0 .../example/android/app/build.gradle | 0 .../android/app/src/debug/AndroidManifest.xml | 0 .../android/app/src/main/AndroidManifest.xml | 0 .../kotlin/com/example/example/Application.kt | 0 .../com/example/example/MainActivity.kt | 0 .../main/res/drawable/launch_background.xml | 0 .../src/main/res/mipmap-hdpi/ic_launcher.png | Bin .../src/main/res/mipmap-mdpi/ic_launcher.png | Bin .../src/main/res/mipmap-xhdpi/ic_launcher.png | Bin .../main/res/mipmap-xxhdpi/ic_launcher.png | Bin .../main/res/mipmap-xxxhdpi/ic_launcher.png | Bin .../app/src/main/res/values/styles.xml | 0 .../app/src/profile/AndroidManifest.xml | 0 .../example/android/build.gradle | 0 .../example/android/gradle.properties | 0 .../gradle/wrapper/gradle-wrapper.properties | 0 .../example/android/settings.gradle | 0 .../example/android/settings_aar.gradle | 0 .../example/assets/android_icon.png | Bin .../example/assets/icon_arrow_right.svg | 0 .../example/assets/ios_icon.png | Bin .../example/assets/logo.svg | 0 .../example/ios/.gitignore | 0 .../ios/Flutter/AppFrameworkInfo.plist | 0 .../example/ios/Flutter/Debug.xcconfig | 0 .../example/ios/Flutter/Release.xcconfig | 0 .../example/ios/Gemfile | 0 .../example/ios/Gemfile.lock | 0 .../example/ios/Notifications/Info.plist | 0 .../Notifications/NotificationService.swift | 0 .../Notifications/Notifications.entitlements | 0 .../ios/Runner.xcodeproj/project.pbxproj | 0 .../contents.xcworkspacedata | 0 .../xcshareddata/IDEWorkspaceChecks.plist | 0 .../xcshareddata/WorkspaceSettings.xcsettings | 0 .../xcschemes/Notifications.xcscheme | 0 .../xcshareddata/xcschemes/Runner.xcscheme | 0 .../contents.xcworkspacedata | 0 .../xcshareddata/IDEWorkspaceChecks.plist | 0 .../xcshareddata/WorkspaceSettings.xcsettings | 0 .../example/ios/Runner/AppDelegate.swift | 0 .../AppIcon.appiconset/Contents.json | 0 .../Icon-App-1024x1024@1x.png | Bin .../AppIcon.appiconset/Icon-App-20x20@1x.png | Bin .../AppIcon.appiconset/Icon-App-20x20@2x.png | Bin .../AppIcon.appiconset/Icon-App-20x20@3x.png | Bin .../AppIcon.appiconset/Icon-App-29x29@1x.png | Bin .../AppIcon.appiconset/Icon-App-29x29@2x.png | Bin .../AppIcon.appiconset/Icon-App-29x29@3x.png | Bin .../AppIcon.appiconset/Icon-App-40x40@1x.png | Bin .../AppIcon.appiconset/Icon-App-40x40@2x.png | Bin .../AppIcon.appiconset/Icon-App-40x40@3x.png | Bin .../AppIcon.appiconset/Icon-App-60x60@2x.png | Bin .../AppIcon.appiconset/Icon-App-60x60@3x.png | Bin .../AppIcon.appiconset/Icon-App-76x76@1x.png | Bin .../AppIcon.appiconset/Icon-App-76x76@2x.png | Bin .../Icon-App-83.5x83.5@2x.png | Bin .../LaunchImage.imageset/Contents.json | 0 .../LaunchImage.imageset/LaunchImage.png | Bin .../LaunchImage.imageset/LaunchImage@2x.png | Bin .../LaunchImage.imageset/LaunchImage@3x.png | Bin .../LaunchImage.imageset/README.md | 0 .../Runner/Base.lproj/LaunchScreen.storyboard | 0 .../ios/Runner/Base.lproj/Main.storyboard | 0 .../example/ios/Runner/Info.plist | 0 .../ios/Runner/Runner-Bridging-Header.h | 0 .../example/ios/Runner/Runner.entitlements | 0 .../example/ios/fastlane/Appfile | 0 .../example/ios/fastlane/Fastfile | 0 .../example/ios/fastlane/Matchfile | 0 .../example/ios/fastlane/Pluginfile | 0 .../example/ios/fastlane/README.md | 0 .../fastlane/beta_gym_export_options.plist | 0 .../example/ios/fastlane/report.xml | 0 .../example/lib/advanced_options_page.dart | 0 .../example/lib/chat_info_screen.dart | 0 .../example/lib/chips_input_text_field.dart | 0 .../example/lib/choose_user_page.dart | 0 .../example/lib/custom_message.dart | 0 .../example/lib/custom_theme.dart | 0 .../lib/customize_channel_preview.dart | 0 .../example/lib/customize_message_widget.dart | 0 .../lib/group_chat_details_screen.dart | 0 .../example/lib/group_info_screen.dart | 0 .../example/lib/main.dart | 0 .../example/lib/multiple_conversation.dart | 0 .../example/lib/new_chat_screen.dart | 0 .../example/lib/new_group_chat_screen.dart | 0 .../example/lib/notifications_service.dart | 0 .../example/lib/routes/app_routes.dart | 0 .../example/lib/routes/routes.dart | 0 .../example/lib/search_text_field.dart | 0 .../example/lib/single_conversation.dart | 0 .../example/lib/split_view.dart | 0 .../example/lib/stream_version.dart | 0 .../example/lib/threads.dart | 0 .../example/pubspec.yaml | 0 .../test_driver/single_conversation.dart | 0 .../test_driver/single_conversation_test.dart | 0 .../example/web/favicon.png | Bin .../example/web/icons/Icon-192.png | Bin .../example/web/icons/Icon-512.png | Bin .../example/web/index.html | 0 .../example/web/manifest.json | 0 .../example/web/sql-wasm.js | 0 .../example/web/sql-wasm.wasm | Bin .../images/giphy_icon.png | Bin .../images/placeholder.png | Bin .../lib/src/attachment_error.dart | 0 .../lib/src/attachment_title.dart | 0 .../lib/src/back_button.dart | 0 .../lib/src/channel_bottom_sheet.dart | 0 .../lib/src/channel_file_display_screen.dart | 0 .../lib/src/channel_header.dart | 0 .../lib/src/channel_image.dart | 0 .../lib/src/channel_info.dart | 0 .../lib/src/channel_list_header.dart | 0 .../lib/src/channel_list_view.dart | 0 .../lib/src/channel_media_display_screen.dart | 0 .../lib/src/channel_name.dart | 0 .../lib/src/channel_preview.dart | 0 .../lib/src/channel_unread_indicator.dart | 0 .../lib/src/compress_video_service.dart | 0 .../lib/src/connection_status_builder.dart | 0 .../lib/src/date_divider.dart | 0 .../lib/src/deleted_message.dart | 0 .../lib/src/extension.dart | 0 .../lib/src/file_attachment.dart | 0 .../lib/src/full_screen_media.dart | 0 .../lib/src/giphy_attachment.dart | 0 .../lib/src/group_image.dart | 0 .../lib/src/image_actions_modal.dart | 0 .../lib/src/image_attachment.dart | 0 .../lib/src/image_footer.dart | 0 .../lib/src/image_group.dart | 0 .../lib/src/image_header.dart | 0 .../lib/src/info_tile.dart | 0 .../lib/src/media_list_view.dart | 0 .../lib/src/media_utils.dart | 0 .../lib/src/message_actions_modal.dart | 0 .../lib/src/message_input.dart | 0 .../lib/src/message_list_view.dart | 0 .../lib/src/message_reactions_modal.dart | 0 .../lib/src/message_search_item.dart | 0 .../lib/src/message_search_list_view.dart | 0 .../lib/src/message_text.dart | 0 .../lib/src/message_widget.dart | 0 .../lib/src/option_list_tile.dart | 0 .../lib/src/quoted_message_widget.dart | 0 .../lib/src/reaction_bubble.dart | 0 .../lib/src/reaction_icon.dart | 0 .../lib/src/reaction_picker.dart | 0 .../lib/src/sending_indicator.dart | 0 .../lib/src/stream_chat.dart | 0 .../lib/src/stream_chat_theme.dart | 0 .../lib/src/stream_neumorphic_button.dart | 0 .../lib/src/stream_svg_icon.dart | 0 .../lib/src/swipeable.dart | 0 .../lib/src/system_message.dart | 0 .../lib/src/thread_header.dart | 0 .../lib/src/typing_indicator.dart | 0 .../lib/src/unread_indicator.dart | 0 .../lib/src/url_attachment.dart | 0 .../lib/src/user_avatar.dart | 0 .../lib/src/user_item.dart | 0 .../lib/src/user_list_view.dart | 0 .../lib/src/user_reaction_display.dart | 0 .../lib/src/utils.dart | 0 .../lib/src/video_attachment.dart | 0 .../lib/stream_chat_flutter.dart | 0 .../lib/svgs/Empty State_Camera.svg | 0 .../lib/svgs/Empty State_Files.svg | 0 .../lib/svgs/Empty State_No channel.svg | 0 .../lib/svgs/Empty State_Search.svg | 0 .../lib/svgs/Empty State_picture.svg | 0 .../lib/svgs/Giphy icon.svg | 0 .../lib/svgs/Icon_LOL_reaction.svg | 0 .../lib/svgs/Icon_Thread_Reply.svg | 0 .../lib/svgs/Icon_User_add.svg | 0 .../lib/svgs/Icon_User_deselect.svg | 0 .../lib/svgs/Icon_arrow_right.svg | 0 .../lib/svgs/Icon_attach.svg | 0 .../lib/svgs/Icon_camera.svg | 0 .../lib/svgs/Icon_check.svg | 0 .../lib/svgs/Icon_check_all.svg | 0 .../lib/svgs/Icon_check_big.svg | 0 .../lib/svgs/Icon_check_send.svg | 0 .../lib/svgs/Icon_circle_right.svg | 0 .../lib/svgs/Icon_circle_up.svg | 0 .../lib/svgs/Icon_close.svg | 0 .../lib/svgs/Icon_close_black.svg | 0 .../lib/svgs/Icon_close_sml.svg | 0 .../lib/svgs/Icon_cloud_download.svg | 0 .../lib/svgs/Icon_contacts.svg | 0 .../lib/svgs/Icon_copy.svg | 0 .../lib/svgs/Icon_curve_line_left_up.svg | 0 .../lib/svgs/Icon_curve_line_left_up_big.svg | 0 .../lib/svgs/Icon_delete.svg | 0 .../lib/svgs/Icon_down.svg | 0 .../lib/svgs/Icon_download.svg | 0 .../lib/svgs/Icon_edit.svg | 0 .../lib/svgs/Icon_empty_circle_left.svg | 0 .../lib/svgs/Icon_error.svg | 0 .../lib/svgs/Icon_eye-off.svg | 0 .../lib/svgs/Icon_grid.svg | 0 .../lib/svgs/Icon_group.svg | 0 .../lib/svgs/Icon_left.svg | 0 .../svgs/Icon_lightning-command runner.svg | 0 .../lib/svgs/Icon_love_reaction.svg | 0 .../lib/svgs/Icon_menu_point_v.svg | 0 .../lib/svgs/Icon_message.svg | 0 .../lib/svgs/Icon_mute.svg | 0 .../lib/svgs/Icon_notification.svg | 0 .../lib/svgs/Icon_pen-write.svg | 0 .../lib/svgs/Icon_record.svg | 0 .../lib/svgs/Icon_right.svg | 0 .../lib/svgs/Icon_save.svg | 0 .../lib/svgs/Icon_search.svg | 0 .../lib/svgs/Icon_send_message.svg | 0 .../lib/svgs/Icon_smile.svg | 0 .../lib/svgs/Icon_thumbs_down_reaction.svg | 0 .../lib/svgs/Icon_thumbs_up_reaction.svg | 0 .../lib/svgs/Icon_time.svg | 0 .../lib/svgs/Icon_user.svg | 0 .../lib/svgs/Icon_user_delete.svg | 0 .../lib/svgs/Icon_user_settings.svg | 0 .../lib/svgs/Icon_wut_reaction.svg | 0 .../lib/svgs/STREAM MARK 1.svg | 0 .../svgs/UI_Reverse Pagination Loading.svg | 0 .../lib/svgs/eye-line_big.svg | 0 .../lib/svgs/files.svg | 0 .../lib/svgs/filetype_7z.svg | 0 .../lib/svgs/filetype_CSV.svg | 0 .../lib/svgs/filetype_DOC.svg | 0 .../lib/svgs/filetype_DOCX.svg | 0 .../lib/svgs/filetype_Generic.svg | 0 .../lib/svgs/filetype_MD.svg | 0 .../lib/svgs/filetype_ODT.svg | 0 .../lib/svgs/filetype_PDF.svg | 0 .../lib/svgs/filetype_PPT.svg | 0 .../lib/svgs/filetype_PPTX-1.svg | 0 .../lib/svgs/filetype_PPTX.svg | 0 .../lib/svgs/filetype_RAR.svg | 0 .../lib/svgs/filetype_RTF.svg | 0 .../lib/svgs/filetype_TAR.svg | 0 .../lib/svgs/filetype_TXT.svg | 0 .../lib/svgs/filetype_XLS.svg | 0 .../lib/svgs/filetype_XLSX.svg | 0 .../lib/svgs/filetype_ZIP.svg | 0 .../lib/svgs/filetype_html.svg | 0 .../lib/svgs/flag.svg | 0 .../lib/svgs/giphy icon blue.svg | 0 .../lib/svgs/giphy_icon.svg | 0 .../lib/svgs/icon_SHARE.svg | 0 .../lib/svgs/icon_delete_grey.svg | 0 .../lib/svgs/icon_flag.svg | 0 .../lib/svgs/icon_mentions.svg | 0 .../lib/svgs/icon_moon.svg | 0 .../lib/svgs/imgur.svg | 0 .../lib/svgs/mentions.svg | 0 .../lib/svgs/pictures.svg | 0 .../lib/svgs/settings.svg | 0 .../lib/svgs/share_arrow.svg | 0 .../lib/svgs/volume-up.svg | 0 .../pubspec.yaml | 0 .../screenshots/channel_header.png | Bin .../screenshots/channel_header_paint.png | Bin .../screenshots/channel_image.png | Bin .../screenshots/channel_image_paint.png | Bin .../screenshots/channel_list_view.png | Bin .../screenshots/channel_list_view_paint.png | Bin .../screenshots/channel_preview.png | Bin .../screenshots/channel_preview_paint.png | Bin .../screenshots/message_input.png | Bin .../screenshots/message_input2.png | Bin .../screenshots/message_input2_paint.png | Bin .../screenshots/message_input_paint.png | Bin .../screenshots/message_listview.png | Bin .../screenshots/message_listview_paint.png | Bin .../screenshots/message_widget.png | Bin .../screenshots/message_widget_paint.png | Bin .../screenshots/reaction_picker.png | Bin .../screenshots/reaction_picker_paint.png | Bin .../screenshots/thread_header.png | Bin .../screenshots/thread_header_paint.png | Bin .../svgs/giphy_icon.svg | 0 .../svgs/icon_camera.svg | 0 .../svgs/icon_pen_write.svg | 0 .../svgs/icon_picture_empty_state.svg | 0 .../svgs/video_call_icon.svg | 0 .../test/src/channel_preview_test.dart | 0 .../test/src/message_action_modal_test.dart | 0 .../test/src/message_reaction_modal_test.dart | 0 .../test/src/mocks.dart | 0 .../test/src/reaction_bubble_test.dart | 0 packages/stream_chat_persistence/pubspec.yaml | 2 +- 445 files changed, 1 insertion(+), 343 deletions(-) delete mode 100644 packages/flutter_widgets/example/ios/Podfile delete mode 100644 packages/flutter_widgets/example/ios/Podfile.lock rename packages/{dart_client => stream_chat}/.gitignore (100%) rename packages/{dart_client => stream_chat}/.metadata (100%) rename packages/{dart_client => stream_chat}/CHANGELOG.md (100%) rename packages/{dart_client => stream_chat}/LICENSE (100%) rename packages/{dart_client => stream_chat}/README.md (100%) rename packages/{dart_client => stream_chat}/analysis_options.yaml (100%) rename packages/{dart_client => stream_chat}/build.yaml (100%) rename packages/{dart_client => stream_chat}/example/.gitignore (100%) rename packages/{dart_client => stream_chat}/example/.metadata (100%) rename packages/{dart_client => stream_chat}/example/README.md (100%) rename packages/{dart_client => stream_chat}/example/android/.gitignore (100%) rename packages/{dart_client => stream_chat}/example/android/app/build.gradle (100%) rename packages/{dart_client => stream_chat}/example/android/app/src/debug/AndroidManifest.xml (100%) rename packages/{dart_client => stream_chat}/example/android/app/src/main/AndroidManifest.xml (100%) rename packages/{dart_client => stream_chat}/example/android/app/src/main/kotlin/com/example/example/MainActivity.kt (100%) rename packages/{dart_client => stream_chat}/example/android/app/src/main/res/drawable/launch_background.xml (100%) rename packages/{dart_client => stream_chat}/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png (100%) rename packages/{dart_client => stream_chat}/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png (100%) rename packages/{dart_client => stream_chat}/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png (100%) rename packages/{dart_client => stream_chat}/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png (100%) rename packages/{dart_client => stream_chat}/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png (100%) rename packages/{dart_client => stream_chat}/example/android/app/src/main/res/values/styles.xml (100%) rename packages/{dart_client => stream_chat}/example/android/app/src/profile/AndroidManifest.xml (100%) rename packages/{dart_client => stream_chat}/example/android/build.gradle (100%) rename packages/{dart_client => stream_chat}/example/android/gradle.properties (100%) rename packages/{dart_client => stream_chat}/example/android/gradle/wrapper/gradle-wrapper.properties (100%) rename packages/{dart_client => stream_chat}/example/android/settings.gradle (100%) rename packages/{dart_client => stream_chat}/example/ios/.gitignore (100%) rename packages/{dart_client => stream_chat}/example/ios/Flutter/AppFrameworkInfo.plist (100%) rename packages/{dart_client => stream_chat}/example/ios/Flutter/Debug.xcconfig (100%) rename packages/{dart_client => stream_chat}/example/ios/Flutter/Release.xcconfig (100%) rename packages/{dart_client => stream_chat}/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata (100%) rename packages/{dart_client => stream_chat}/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist (100%) rename packages/{dart_client => stream_chat}/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings (100%) rename packages/{dart_client => stream_chat}/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme (100%) rename packages/{dart_client => stream_chat}/example/ios/Runner.xcworkspace/contents.xcworkspacedata (100%) rename packages/{dart_client => stream_chat}/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist (100%) rename packages/{dart_client => stream_chat}/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings (100%) rename packages/{dart_client => stream_chat}/example/ios/Runner/AppDelegate.swift (100%) rename packages/{dart_client => stream_chat}/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json (100%) rename packages/{dart_client => stream_chat}/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png (100%) rename packages/{dart_client => stream_chat}/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png (100%) rename packages/{dart_client => stream_chat}/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png (100%) rename packages/{dart_client => stream_chat}/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png (100%) rename packages/{dart_client => stream_chat}/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png (100%) rename packages/{dart_client => stream_chat}/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png (100%) rename packages/{dart_client => stream_chat}/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png (100%) rename packages/{dart_client => stream_chat}/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png (100%) rename packages/{dart_client => stream_chat}/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png (100%) rename packages/{dart_client => stream_chat}/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png (100%) rename packages/{dart_client => stream_chat}/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png (100%) rename packages/{dart_client => stream_chat}/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png (100%) rename packages/{dart_client => stream_chat}/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png (100%) rename packages/{dart_client => stream_chat}/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png (100%) rename packages/{dart_client => stream_chat}/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png (100%) rename packages/{dart_client => stream_chat}/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json (100%) rename packages/{dart_client => stream_chat}/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png (100%) rename packages/{dart_client => stream_chat}/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png (100%) rename packages/{dart_client => stream_chat}/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png (100%) rename packages/{dart_client => stream_chat}/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md (100%) rename packages/{dart_client => stream_chat}/example/ios/Runner/Base.lproj/LaunchScreen.storyboard (100%) rename packages/{dart_client => stream_chat}/example/ios/Runner/Base.lproj/Main.storyboard (100%) rename packages/{dart_client => stream_chat}/example/ios/Runner/Info.plist (100%) rename packages/{dart_client => stream_chat}/example/ios/Runner/Runner-Bridging-Header.h (100%) rename packages/{dart_client => stream_chat}/example/lib/main.dart (100%) rename packages/{dart_client => stream_chat}/example/pubspec.yaml (100%) rename packages/{dart_client => stream_chat}/lib/src/api/channel.dart (100%) rename packages/{dart_client => stream_chat}/lib/src/api/connection_status.dart (100%) rename packages/{dart_client => stream_chat}/lib/src/api/requests.dart (100%) rename packages/{dart_client => stream_chat}/lib/src/api/requests.g.dart (100%) rename packages/{dart_client => stream_chat}/lib/src/api/responses.dart (100%) rename packages/{dart_client => stream_chat}/lib/src/api/responses.g.dart (100%) rename packages/{dart_client => stream_chat}/lib/src/api/retry_policy.dart (100%) rename packages/{dart_client => stream_chat}/lib/src/api/retry_queue.dart (100%) rename packages/{dart_client => stream_chat}/lib/src/api/web_socket_channel_html.dart (100%) rename packages/{dart_client => stream_chat}/lib/src/api/web_socket_channel_io.dart (100%) rename packages/{dart_client => stream_chat}/lib/src/api/web_socket_channel_stub.dart (100%) rename packages/{dart_client => stream_chat}/lib/src/api/websocket.dart (100%) rename packages/{dart_client => stream_chat}/lib/src/client.dart (100%) rename packages/{dart_client => stream_chat}/lib/src/db/chat_persistence_client.dart (100%) rename packages/{dart_client => stream_chat}/lib/src/event_type.dart (100%) rename packages/{dart_client => stream_chat}/lib/src/exceptions.dart (100%) rename packages/{dart_client => stream_chat}/lib/src/models/action.dart (100%) rename packages/{dart_client => stream_chat}/lib/src/models/action.g.dart (100%) rename packages/{dart_client => stream_chat}/lib/src/models/attachment.dart (100%) rename packages/{dart_client => stream_chat}/lib/src/models/attachment.g.dart (100%) rename packages/{dart_client => stream_chat}/lib/src/models/channel_config.dart (100%) rename packages/{dart_client => stream_chat}/lib/src/models/channel_config.g.dart (100%) rename packages/{dart_client => stream_chat}/lib/src/models/channel_model.dart (100%) rename packages/{dart_client => stream_chat}/lib/src/models/channel_model.g.dart (100%) rename packages/{dart_client => stream_chat}/lib/src/models/channel_state.dart (100%) rename packages/{dart_client => stream_chat}/lib/src/models/channel_state.g.dart (100%) rename packages/{dart_client => stream_chat}/lib/src/models/command.dart (100%) rename packages/{dart_client => stream_chat}/lib/src/models/command.g.dart (100%) rename packages/{dart_client => stream_chat}/lib/src/models/device.dart (100%) rename packages/{dart_client => stream_chat}/lib/src/models/device.g.dart (100%) rename packages/{dart_client => stream_chat}/lib/src/models/event.dart (100%) rename packages/{dart_client => stream_chat}/lib/src/models/event.g.dart (100%) rename packages/{dart_client => stream_chat}/lib/src/models/member.dart (100%) rename packages/{dart_client => stream_chat}/lib/src/models/member.g.dart (100%) rename packages/{dart_client => stream_chat}/lib/src/models/message.dart (100%) rename packages/{dart_client => stream_chat}/lib/src/models/message.g.dart (100%) rename packages/{dart_client => stream_chat}/lib/src/models/mute.dart (100%) rename packages/{dart_client => stream_chat}/lib/src/models/mute.g.dart (100%) rename packages/{dart_client => stream_chat}/lib/src/models/own_user.dart (100%) rename packages/{dart_client => stream_chat}/lib/src/models/own_user.g.dart (100%) rename packages/{dart_client => stream_chat}/lib/src/models/reaction.dart (100%) rename packages/{dart_client => stream_chat}/lib/src/models/reaction.g.dart (100%) rename packages/{dart_client => stream_chat}/lib/src/models/read.dart (100%) rename packages/{dart_client => stream_chat}/lib/src/models/read.g.dart (100%) rename packages/{dart_client => stream_chat}/lib/src/models/serialization.dart (100%) rename packages/{dart_client => stream_chat}/lib/src/models/user.dart (100%) rename packages/{dart_client => stream_chat}/lib/src/models/user.g.dart (100%) rename packages/{dart_client => stream_chat}/lib/stream_chat.dart (100%) rename packages/{dart_client => stream_chat}/lib/version.dart (100%) rename packages/{dart_client => stream_chat}/peanut.yaml (100%) rename packages/{dart_client => stream_chat}/pubspec.yaml (100%) rename packages/{dart_client => stream_chat}/test/src/api/channel_test.dart (100%) rename packages/{dart_client => stream_chat}/test/src/api/requests_test.dart (100%) rename packages/{dart_client => stream_chat}/test/src/api/responses_test.dart (100%) rename packages/{dart_client => stream_chat}/test/src/api/web_socket_stub_test.dart (100%) rename packages/{dart_client => stream_chat}/test/src/api/websocket_test.dart (100%) rename packages/{dart_client => stream_chat}/test/src/client_test.dart (100%) rename packages/{dart_client => stream_chat}/test/src/models/action_test.dart (100%) rename packages/{dart_client => stream_chat}/test/src/models/attachment_test.dart (100%) rename packages/{dart_client => stream_chat}/test/src/models/channel_state_test.dart (100%) rename packages/{dart_client => stream_chat}/test/src/models/channel_test.dart (100%) rename packages/{dart_client => stream_chat}/test/src/models/command_test.dart (100%) rename packages/{dart_client => stream_chat}/test/src/models/device_test.dart (100%) rename packages/{dart_client => stream_chat}/test/src/models/event_test.dart (100%) rename packages/{dart_client => stream_chat}/test/src/models/member_test.dart (100%) rename packages/{dart_client => stream_chat}/test/src/models/message_test.dart (100%) rename packages/{dart_client => stream_chat}/test/src/models/reaction_test.dart (100%) rename packages/{dart_client => stream_chat}/test/src/models/read_test.dart (100%) rename packages/{dart_client => stream_chat}/test/src/models/serialization_test.dart (100%) rename packages/{dart_client => stream_chat}/test/src/models/user_test.dart (100%) rename packages/{dart_client => stream_chat}/test/version_test.dart (100%) rename packages/{flutter_widgets => stream_chat_flutter}/.gitignore (100%) rename packages/{flutter_widgets => stream_chat_flutter}/CHANGELOG.md (100%) rename packages/{flutter_widgets => stream_chat_flutter}/LICENSE (100%) rename packages/{flutter_widgets => stream_chat_flutter}/README.md (100%) rename packages/{flutter_widgets => stream_chat_flutter}/analysis_options.yaml (100%) rename packages/{flutter_widgets => stream_chat_flutter}/animations/typing_dots.json (100%) rename packages/{flutter_widgets => stream_chat_flutter}/example/.gitignore (100%) rename packages/{flutter_widgets => stream_chat_flutter}/example/.metadata (100%) rename packages/{flutter_widgets => stream_chat_flutter}/example/README.md (100%) rename packages/{flutter_widgets => stream_chat_flutter}/example/android/.gitignore (100%) rename packages/{flutter_widgets => stream_chat_flutter}/example/android/app/build.gradle (100%) rename packages/{flutter_widgets => stream_chat_flutter}/example/android/app/src/debug/AndroidManifest.xml (100%) rename packages/{flutter_widgets => stream_chat_flutter}/example/android/app/src/main/AndroidManifest.xml (100%) rename packages/{flutter_widgets => stream_chat_flutter}/example/android/app/src/main/kotlin/com/example/example/Application.kt (100%) rename packages/{flutter_widgets => stream_chat_flutter}/example/android/app/src/main/kotlin/com/example/example/MainActivity.kt (100%) rename packages/{flutter_widgets => stream_chat_flutter}/example/android/app/src/main/res/drawable/launch_background.xml (100%) rename packages/{flutter_widgets => stream_chat_flutter}/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png (100%) rename packages/{flutter_widgets => stream_chat_flutter}/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png (100%) rename packages/{flutter_widgets => stream_chat_flutter}/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png (100%) rename packages/{flutter_widgets => stream_chat_flutter}/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png (100%) rename packages/{flutter_widgets => stream_chat_flutter}/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png (100%) rename packages/{flutter_widgets => stream_chat_flutter}/example/android/app/src/main/res/values/styles.xml (100%) rename packages/{flutter_widgets => stream_chat_flutter}/example/android/app/src/profile/AndroidManifest.xml (100%) rename packages/{flutter_widgets => stream_chat_flutter}/example/android/build.gradle (100%) rename packages/{flutter_widgets => stream_chat_flutter}/example/android/gradle.properties (100%) rename packages/{flutter_widgets => stream_chat_flutter}/example/android/gradle/wrapper/gradle-wrapper.properties (100%) rename packages/{flutter_widgets => stream_chat_flutter}/example/android/settings.gradle (100%) rename packages/{flutter_widgets => stream_chat_flutter}/example/android/settings_aar.gradle (100%) rename packages/{flutter_widgets => stream_chat_flutter}/example/assets/android_icon.png (100%) rename packages/{flutter_widgets => stream_chat_flutter}/example/assets/icon_arrow_right.svg (100%) rename packages/{flutter_widgets => stream_chat_flutter}/example/assets/ios_icon.png (100%) rename packages/{flutter_widgets => stream_chat_flutter}/example/assets/logo.svg (100%) rename packages/{flutter_widgets => stream_chat_flutter}/example/ios/.gitignore (100%) rename packages/{flutter_widgets => stream_chat_flutter}/example/ios/Flutter/AppFrameworkInfo.plist (100%) rename packages/{flutter_widgets => stream_chat_flutter}/example/ios/Flutter/Debug.xcconfig (100%) rename packages/{flutter_widgets => stream_chat_flutter}/example/ios/Flutter/Release.xcconfig (100%) rename packages/{flutter_widgets => stream_chat_flutter}/example/ios/Gemfile (100%) rename packages/{flutter_widgets => stream_chat_flutter}/example/ios/Gemfile.lock (100%) rename packages/{flutter_widgets => stream_chat_flutter}/example/ios/Notifications/Info.plist (100%) rename packages/{flutter_widgets => stream_chat_flutter}/example/ios/Notifications/NotificationService.swift (100%) rename packages/{flutter_widgets => stream_chat_flutter}/example/ios/Notifications/Notifications.entitlements (100%) rename packages/{flutter_widgets => stream_chat_flutter}/example/ios/Runner.xcodeproj/project.pbxproj (100%) rename packages/{flutter_widgets => stream_chat_flutter}/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata (100%) rename packages/{flutter_widgets => stream_chat_flutter}/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist (100%) rename packages/{flutter_widgets => stream_chat_flutter}/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings (100%) rename packages/{flutter_widgets => stream_chat_flutter}/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Notifications.xcscheme (100%) rename packages/{flutter_widgets => stream_chat_flutter}/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme (100%) rename packages/{flutter_widgets => stream_chat_flutter}/example/ios/Runner.xcworkspace/contents.xcworkspacedata (100%) rename packages/{flutter_widgets => stream_chat_flutter}/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist (100%) rename packages/{flutter_widgets => stream_chat_flutter}/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings (100%) rename packages/{flutter_widgets => stream_chat_flutter}/example/ios/Runner/AppDelegate.swift (100%) rename packages/{flutter_widgets => stream_chat_flutter}/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json (100%) rename packages/{flutter_widgets => stream_chat_flutter}/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png (100%) rename packages/{flutter_widgets => stream_chat_flutter}/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png (100%) rename packages/{flutter_widgets => stream_chat_flutter}/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png (100%) rename packages/{flutter_widgets => stream_chat_flutter}/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png (100%) rename packages/{flutter_widgets => stream_chat_flutter}/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png (100%) rename packages/{flutter_widgets => stream_chat_flutter}/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png (100%) rename packages/{flutter_widgets => stream_chat_flutter}/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png (100%) rename packages/{flutter_widgets => stream_chat_flutter}/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png (100%) rename packages/{flutter_widgets => stream_chat_flutter}/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png (100%) rename packages/{flutter_widgets => stream_chat_flutter}/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png (100%) rename packages/{flutter_widgets => stream_chat_flutter}/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png (100%) rename packages/{flutter_widgets => stream_chat_flutter}/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png (100%) rename packages/{flutter_widgets => stream_chat_flutter}/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png (100%) rename packages/{flutter_widgets => stream_chat_flutter}/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png (100%) rename packages/{flutter_widgets => stream_chat_flutter}/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png (100%) rename packages/{flutter_widgets => stream_chat_flutter}/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json (100%) rename packages/{flutter_widgets => stream_chat_flutter}/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png (100%) rename packages/{flutter_widgets => stream_chat_flutter}/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png (100%) rename packages/{flutter_widgets => stream_chat_flutter}/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png (100%) rename packages/{flutter_widgets => stream_chat_flutter}/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md (100%) rename packages/{flutter_widgets => stream_chat_flutter}/example/ios/Runner/Base.lproj/LaunchScreen.storyboard (100%) rename packages/{flutter_widgets => stream_chat_flutter}/example/ios/Runner/Base.lproj/Main.storyboard (100%) rename packages/{flutter_widgets => stream_chat_flutter}/example/ios/Runner/Info.plist (100%) rename packages/{flutter_widgets => stream_chat_flutter}/example/ios/Runner/Runner-Bridging-Header.h (100%) rename packages/{flutter_widgets => stream_chat_flutter}/example/ios/Runner/Runner.entitlements (100%) rename packages/{flutter_widgets => stream_chat_flutter}/example/ios/fastlane/Appfile (100%) rename packages/{flutter_widgets => stream_chat_flutter}/example/ios/fastlane/Fastfile (100%) rename packages/{flutter_widgets => stream_chat_flutter}/example/ios/fastlane/Matchfile (100%) rename packages/{flutter_widgets => stream_chat_flutter}/example/ios/fastlane/Pluginfile (100%) rename packages/{flutter_widgets => stream_chat_flutter}/example/ios/fastlane/README.md (100%) rename packages/{flutter_widgets => stream_chat_flutter}/example/ios/fastlane/beta_gym_export_options.plist (100%) rename packages/{flutter_widgets => stream_chat_flutter}/example/ios/fastlane/report.xml (100%) rename packages/{flutter_widgets => stream_chat_flutter}/example/lib/advanced_options_page.dart (100%) rename packages/{flutter_widgets => stream_chat_flutter}/example/lib/chat_info_screen.dart (100%) rename packages/{flutter_widgets => stream_chat_flutter}/example/lib/chips_input_text_field.dart (100%) rename packages/{flutter_widgets => stream_chat_flutter}/example/lib/choose_user_page.dart (100%) rename packages/{flutter_widgets => stream_chat_flutter}/example/lib/custom_message.dart (100%) rename packages/{flutter_widgets => stream_chat_flutter}/example/lib/custom_theme.dart (100%) rename packages/{flutter_widgets => stream_chat_flutter}/example/lib/customize_channel_preview.dart (100%) rename packages/{flutter_widgets => stream_chat_flutter}/example/lib/customize_message_widget.dart (100%) rename packages/{flutter_widgets => stream_chat_flutter}/example/lib/group_chat_details_screen.dart (100%) rename packages/{flutter_widgets => stream_chat_flutter}/example/lib/group_info_screen.dart (100%) rename packages/{flutter_widgets => stream_chat_flutter}/example/lib/main.dart (100%) rename packages/{flutter_widgets => stream_chat_flutter}/example/lib/multiple_conversation.dart (100%) rename packages/{flutter_widgets => stream_chat_flutter}/example/lib/new_chat_screen.dart (100%) rename packages/{flutter_widgets => stream_chat_flutter}/example/lib/new_group_chat_screen.dart (100%) rename packages/{flutter_widgets => stream_chat_flutter}/example/lib/notifications_service.dart (100%) rename packages/{flutter_widgets => stream_chat_flutter}/example/lib/routes/app_routes.dart (100%) rename packages/{flutter_widgets => stream_chat_flutter}/example/lib/routes/routes.dart (100%) rename packages/{flutter_widgets => stream_chat_flutter}/example/lib/search_text_field.dart (100%) rename packages/{flutter_widgets => stream_chat_flutter}/example/lib/single_conversation.dart (100%) rename packages/{flutter_widgets => stream_chat_flutter}/example/lib/split_view.dart (100%) rename packages/{flutter_widgets => stream_chat_flutter}/example/lib/stream_version.dart (100%) rename packages/{flutter_widgets => stream_chat_flutter}/example/lib/threads.dart (100%) rename packages/{flutter_widgets => stream_chat_flutter}/example/pubspec.yaml (100%) rename packages/{flutter_widgets => stream_chat_flutter}/example/test_driver/single_conversation.dart (100%) rename packages/{flutter_widgets => stream_chat_flutter}/example/test_driver/single_conversation_test.dart (100%) rename packages/{flutter_widgets => stream_chat_flutter}/example/web/favicon.png (100%) rename packages/{flutter_widgets => stream_chat_flutter}/example/web/icons/Icon-192.png (100%) rename packages/{flutter_widgets => stream_chat_flutter}/example/web/icons/Icon-512.png (100%) rename packages/{flutter_widgets => stream_chat_flutter}/example/web/index.html (100%) rename packages/{flutter_widgets => stream_chat_flutter}/example/web/manifest.json (100%) rename packages/{flutter_widgets => stream_chat_flutter}/example/web/sql-wasm.js (100%) rename packages/{flutter_widgets => stream_chat_flutter}/example/web/sql-wasm.wasm (100%) rename packages/{flutter_widgets => stream_chat_flutter}/images/giphy_icon.png (100%) rename packages/{flutter_widgets => stream_chat_flutter}/images/placeholder.png (100%) rename packages/{flutter_widgets => stream_chat_flutter}/lib/src/attachment_error.dart (100%) rename packages/{flutter_widgets => stream_chat_flutter}/lib/src/attachment_title.dart (100%) rename packages/{flutter_widgets => stream_chat_flutter}/lib/src/back_button.dart (100%) rename packages/{flutter_widgets => stream_chat_flutter}/lib/src/channel_bottom_sheet.dart (100%) rename packages/{flutter_widgets => stream_chat_flutter}/lib/src/channel_file_display_screen.dart (100%) rename packages/{flutter_widgets => stream_chat_flutter}/lib/src/channel_header.dart (100%) rename packages/{flutter_widgets => stream_chat_flutter}/lib/src/channel_image.dart (100%) rename packages/{flutter_widgets => stream_chat_flutter}/lib/src/channel_info.dart (100%) rename packages/{flutter_widgets => stream_chat_flutter}/lib/src/channel_list_header.dart (100%) rename packages/{flutter_widgets => stream_chat_flutter}/lib/src/channel_list_view.dart (100%) rename packages/{flutter_widgets => stream_chat_flutter}/lib/src/channel_media_display_screen.dart (100%) rename packages/{flutter_widgets => stream_chat_flutter}/lib/src/channel_name.dart (100%) rename packages/{flutter_widgets => stream_chat_flutter}/lib/src/channel_preview.dart (100%) rename packages/{flutter_widgets => stream_chat_flutter}/lib/src/channel_unread_indicator.dart (100%) rename packages/{flutter_widgets => stream_chat_flutter}/lib/src/compress_video_service.dart (100%) rename packages/{flutter_widgets => stream_chat_flutter}/lib/src/connection_status_builder.dart (100%) rename packages/{flutter_widgets => stream_chat_flutter}/lib/src/date_divider.dart (100%) rename packages/{flutter_widgets => stream_chat_flutter}/lib/src/deleted_message.dart (100%) rename packages/{flutter_widgets => stream_chat_flutter}/lib/src/extension.dart (100%) rename packages/{flutter_widgets => stream_chat_flutter}/lib/src/file_attachment.dart (100%) rename packages/{flutter_widgets => stream_chat_flutter}/lib/src/full_screen_media.dart (100%) rename packages/{flutter_widgets => stream_chat_flutter}/lib/src/giphy_attachment.dart (100%) rename packages/{flutter_widgets => stream_chat_flutter}/lib/src/group_image.dart (100%) rename packages/{flutter_widgets => stream_chat_flutter}/lib/src/image_actions_modal.dart (100%) rename packages/{flutter_widgets => stream_chat_flutter}/lib/src/image_attachment.dart (100%) rename packages/{flutter_widgets => stream_chat_flutter}/lib/src/image_footer.dart (100%) rename packages/{flutter_widgets => stream_chat_flutter}/lib/src/image_group.dart (100%) rename packages/{flutter_widgets => stream_chat_flutter}/lib/src/image_header.dart (100%) rename packages/{flutter_widgets => stream_chat_flutter}/lib/src/info_tile.dart (100%) rename packages/{flutter_widgets => stream_chat_flutter}/lib/src/media_list_view.dart (100%) rename packages/{flutter_widgets => stream_chat_flutter}/lib/src/media_utils.dart (100%) rename packages/{flutter_widgets => stream_chat_flutter}/lib/src/message_actions_modal.dart (100%) rename packages/{flutter_widgets => stream_chat_flutter}/lib/src/message_input.dart (100%) rename packages/{flutter_widgets => stream_chat_flutter}/lib/src/message_list_view.dart (100%) rename packages/{flutter_widgets => stream_chat_flutter}/lib/src/message_reactions_modal.dart (100%) rename packages/{flutter_widgets => stream_chat_flutter}/lib/src/message_search_item.dart (100%) rename packages/{flutter_widgets => stream_chat_flutter}/lib/src/message_search_list_view.dart (100%) rename packages/{flutter_widgets => stream_chat_flutter}/lib/src/message_text.dart (100%) rename packages/{flutter_widgets => stream_chat_flutter}/lib/src/message_widget.dart (100%) rename packages/{flutter_widgets => stream_chat_flutter}/lib/src/option_list_tile.dart (100%) rename packages/{flutter_widgets => stream_chat_flutter}/lib/src/quoted_message_widget.dart (100%) rename packages/{flutter_widgets => stream_chat_flutter}/lib/src/reaction_bubble.dart (100%) rename packages/{flutter_widgets => stream_chat_flutter}/lib/src/reaction_icon.dart (100%) rename packages/{flutter_widgets => stream_chat_flutter}/lib/src/reaction_picker.dart (100%) rename packages/{flutter_widgets => stream_chat_flutter}/lib/src/sending_indicator.dart (100%) rename packages/{flutter_widgets => stream_chat_flutter}/lib/src/stream_chat.dart (100%) rename packages/{flutter_widgets => stream_chat_flutter}/lib/src/stream_chat_theme.dart (100%) rename packages/{flutter_widgets => stream_chat_flutter}/lib/src/stream_neumorphic_button.dart (100%) rename packages/{flutter_widgets => stream_chat_flutter}/lib/src/stream_svg_icon.dart (100%) rename packages/{flutter_widgets => stream_chat_flutter}/lib/src/swipeable.dart (100%) rename packages/{flutter_widgets => stream_chat_flutter}/lib/src/system_message.dart (100%) rename packages/{flutter_widgets => stream_chat_flutter}/lib/src/thread_header.dart (100%) rename packages/{flutter_widgets => stream_chat_flutter}/lib/src/typing_indicator.dart (100%) rename packages/{flutter_widgets => stream_chat_flutter}/lib/src/unread_indicator.dart (100%) rename packages/{flutter_widgets => stream_chat_flutter}/lib/src/url_attachment.dart (100%) rename packages/{flutter_widgets => stream_chat_flutter}/lib/src/user_avatar.dart (100%) rename packages/{flutter_widgets => stream_chat_flutter}/lib/src/user_item.dart (100%) rename packages/{flutter_widgets => stream_chat_flutter}/lib/src/user_list_view.dart (100%) rename packages/{flutter_widgets => stream_chat_flutter}/lib/src/user_reaction_display.dart (100%) rename packages/{flutter_widgets => stream_chat_flutter}/lib/src/utils.dart (100%) rename packages/{flutter_widgets => stream_chat_flutter}/lib/src/video_attachment.dart (100%) rename packages/{flutter_widgets => stream_chat_flutter}/lib/stream_chat_flutter.dart (100%) rename packages/{flutter_widgets => stream_chat_flutter}/lib/svgs/Empty State_Camera.svg (100%) rename packages/{flutter_widgets => stream_chat_flutter}/lib/svgs/Empty State_Files.svg (100%) rename packages/{flutter_widgets => stream_chat_flutter}/lib/svgs/Empty State_No channel.svg (100%) rename packages/{flutter_widgets => stream_chat_flutter}/lib/svgs/Empty State_Search.svg (100%) rename packages/{flutter_widgets => stream_chat_flutter}/lib/svgs/Empty State_picture.svg (100%) rename packages/{flutter_widgets => stream_chat_flutter}/lib/svgs/Giphy icon.svg (100%) rename packages/{flutter_widgets => stream_chat_flutter}/lib/svgs/Icon_LOL_reaction.svg (100%) rename packages/{flutter_widgets => stream_chat_flutter}/lib/svgs/Icon_Thread_Reply.svg (100%) rename packages/{flutter_widgets => stream_chat_flutter}/lib/svgs/Icon_User_add.svg (100%) rename packages/{flutter_widgets => stream_chat_flutter}/lib/svgs/Icon_User_deselect.svg (100%) rename packages/{flutter_widgets => stream_chat_flutter}/lib/svgs/Icon_arrow_right.svg (100%) rename packages/{flutter_widgets => stream_chat_flutter}/lib/svgs/Icon_attach.svg (100%) rename packages/{flutter_widgets => stream_chat_flutter}/lib/svgs/Icon_camera.svg (100%) rename packages/{flutter_widgets => stream_chat_flutter}/lib/svgs/Icon_check.svg (100%) rename packages/{flutter_widgets => stream_chat_flutter}/lib/svgs/Icon_check_all.svg (100%) rename packages/{flutter_widgets => stream_chat_flutter}/lib/svgs/Icon_check_big.svg (100%) rename packages/{flutter_widgets => stream_chat_flutter}/lib/svgs/Icon_check_send.svg (100%) rename packages/{flutter_widgets => stream_chat_flutter}/lib/svgs/Icon_circle_right.svg (100%) rename packages/{flutter_widgets => stream_chat_flutter}/lib/svgs/Icon_circle_up.svg (100%) rename packages/{flutter_widgets => stream_chat_flutter}/lib/svgs/Icon_close.svg (100%) rename packages/{flutter_widgets => stream_chat_flutter}/lib/svgs/Icon_close_black.svg (100%) rename packages/{flutter_widgets => stream_chat_flutter}/lib/svgs/Icon_close_sml.svg (100%) rename packages/{flutter_widgets => stream_chat_flutter}/lib/svgs/Icon_cloud_download.svg (100%) rename packages/{flutter_widgets => stream_chat_flutter}/lib/svgs/Icon_contacts.svg (100%) rename packages/{flutter_widgets => stream_chat_flutter}/lib/svgs/Icon_copy.svg (100%) rename packages/{flutter_widgets => stream_chat_flutter}/lib/svgs/Icon_curve_line_left_up.svg (100%) rename packages/{flutter_widgets => stream_chat_flutter}/lib/svgs/Icon_curve_line_left_up_big.svg (100%) rename packages/{flutter_widgets => stream_chat_flutter}/lib/svgs/Icon_delete.svg (100%) rename packages/{flutter_widgets => stream_chat_flutter}/lib/svgs/Icon_down.svg (100%) rename packages/{flutter_widgets => stream_chat_flutter}/lib/svgs/Icon_download.svg (100%) rename packages/{flutter_widgets => stream_chat_flutter}/lib/svgs/Icon_edit.svg (100%) rename packages/{flutter_widgets => stream_chat_flutter}/lib/svgs/Icon_empty_circle_left.svg (100%) rename packages/{flutter_widgets => stream_chat_flutter}/lib/svgs/Icon_error.svg (100%) rename packages/{flutter_widgets => stream_chat_flutter}/lib/svgs/Icon_eye-off.svg (100%) rename packages/{flutter_widgets => stream_chat_flutter}/lib/svgs/Icon_grid.svg (100%) rename packages/{flutter_widgets => stream_chat_flutter}/lib/svgs/Icon_group.svg (100%) rename packages/{flutter_widgets => stream_chat_flutter}/lib/svgs/Icon_left.svg (100%) rename packages/{flutter_widgets => stream_chat_flutter}/lib/svgs/Icon_lightning-command runner.svg (100%) rename packages/{flutter_widgets => stream_chat_flutter}/lib/svgs/Icon_love_reaction.svg (100%) rename packages/{flutter_widgets => stream_chat_flutter}/lib/svgs/Icon_menu_point_v.svg (100%) rename packages/{flutter_widgets => stream_chat_flutter}/lib/svgs/Icon_message.svg (100%) rename packages/{flutter_widgets => stream_chat_flutter}/lib/svgs/Icon_mute.svg (100%) rename packages/{flutter_widgets => stream_chat_flutter}/lib/svgs/Icon_notification.svg (100%) rename packages/{flutter_widgets => stream_chat_flutter}/lib/svgs/Icon_pen-write.svg (100%) rename packages/{flutter_widgets => stream_chat_flutter}/lib/svgs/Icon_record.svg (100%) rename packages/{flutter_widgets => stream_chat_flutter}/lib/svgs/Icon_right.svg (100%) rename packages/{flutter_widgets => stream_chat_flutter}/lib/svgs/Icon_save.svg (100%) rename packages/{flutter_widgets => stream_chat_flutter}/lib/svgs/Icon_search.svg (100%) rename packages/{flutter_widgets => stream_chat_flutter}/lib/svgs/Icon_send_message.svg (100%) rename packages/{flutter_widgets => stream_chat_flutter}/lib/svgs/Icon_smile.svg (100%) rename packages/{flutter_widgets => stream_chat_flutter}/lib/svgs/Icon_thumbs_down_reaction.svg (100%) rename packages/{flutter_widgets => stream_chat_flutter}/lib/svgs/Icon_thumbs_up_reaction.svg (100%) rename packages/{flutter_widgets => stream_chat_flutter}/lib/svgs/Icon_time.svg (100%) rename packages/{flutter_widgets => stream_chat_flutter}/lib/svgs/Icon_user.svg (100%) rename packages/{flutter_widgets => stream_chat_flutter}/lib/svgs/Icon_user_delete.svg (100%) rename packages/{flutter_widgets => stream_chat_flutter}/lib/svgs/Icon_user_settings.svg (100%) rename packages/{flutter_widgets => stream_chat_flutter}/lib/svgs/Icon_wut_reaction.svg (100%) rename packages/{flutter_widgets => stream_chat_flutter}/lib/svgs/STREAM MARK 1.svg (100%) rename packages/{flutter_widgets => stream_chat_flutter}/lib/svgs/UI_Reverse Pagination Loading.svg (100%) rename packages/{flutter_widgets => stream_chat_flutter}/lib/svgs/eye-line_big.svg (100%) rename packages/{flutter_widgets => stream_chat_flutter}/lib/svgs/files.svg (100%) rename packages/{flutter_widgets => stream_chat_flutter}/lib/svgs/filetype_7z.svg (100%) rename packages/{flutter_widgets => stream_chat_flutter}/lib/svgs/filetype_CSV.svg (100%) rename packages/{flutter_widgets => stream_chat_flutter}/lib/svgs/filetype_DOC.svg (100%) rename packages/{flutter_widgets => stream_chat_flutter}/lib/svgs/filetype_DOCX.svg (100%) rename packages/{flutter_widgets => stream_chat_flutter}/lib/svgs/filetype_Generic.svg (100%) rename packages/{flutter_widgets => stream_chat_flutter}/lib/svgs/filetype_MD.svg (100%) rename packages/{flutter_widgets => stream_chat_flutter}/lib/svgs/filetype_ODT.svg (100%) rename packages/{flutter_widgets => stream_chat_flutter}/lib/svgs/filetype_PDF.svg (100%) rename packages/{flutter_widgets => stream_chat_flutter}/lib/svgs/filetype_PPT.svg (100%) rename packages/{flutter_widgets => stream_chat_flutter}/lib/svgs/filetype_PPTX-1.svg (100%) rename packages/{flutter_widgets => stream_chat_flutter}/lib/svgs/filetype_PPTX.svg (100%) rename packages/{flutter_widgets => stream_chat_flutter}/lib/svgs/filetype_RAR.svg (100%) rename packages/{flutter_widgets => stream_chat_flutter}/lib/svgs/filetype_RTF.svg (100%) rename packages/{flutter_widgets => stream_chat_flutter}/lib/svgs/filetype_TAR.svg (100%) rename packages/{flutter_widgets => stream_chat_flutter}/lib/svgs/filetype_TXT.svg (100%) rename packages/{flutter_widgets => stream_chat_flutter}/lib/svgs/filetype_XLS.svg (100%) rename packages/{flutter_widgets => stream_chat_flutter}/lib/svgs/filetype_XLSX.svg (100%) rename packages/{flutter_widgets => stream_chat_flutter}/lib/svgs/filetype_ZIP.svg (100%) rename packages/{flutter_widgets => stream_chat_flutter}/lib/svgs/filetype_html.svg (100%) rename packages/{flutter_widgets => stream_chat_flutter}/lib/svgs/flag.svg (100%) rename packages/{flutter_widgets => stream_chat_flutter}/lib/svgs/giphy icon blue.svg (100%) rename packages/{flutter_widgets => stream_chat_flutter}/lib/svgs/giphy_icon.svg (100%) rename packages/{flutter_widgets => stream_chat_flutter}/lib/svgs/icon_SHARE.svg (100%) rename packages/{flutter_widgets => stream_chat_flutter}/lib/svgs/icon_delete_grey.svg (100%) rename packages/{flutter_widgets => stream_chat_flutter}/lib/svgs/icon_flag.svg (100%) rename packages/{flutter_widgets => stream_chat_flutter}/lib/svgs/icon_mentions.svg (100%) rename packages/{flutter_widgets => stream_chat_flutter}/lib/svgs/icon_moon.svg (100%) rename packages/{flutter_widgets => stream_chat_flutter}/lib/svgs/imgur.svg (100%) rename packages/{flutter_widgets => stream_chat_flutter}/lib/svgs/mentions.svg (100%) rename packages/{flutter_widgets => stream_chat_flutter}/lib/svgs/pictures.svg (100%) rename packages/{flutter_widgets => stream_chat_flutter}/lib/svgs/settings.svg (100%) rename packages/{flutter_widgets => stream_chat_flutter}/lib/svgs/share_arrow.svg (100%) rename packages/{flutter_widgets => stream_chat_flutter}/lib/svgs/volume-up.svg (100%) rename packages/{flutter_widgets => stream_chat_flutter}/pubspec.yaml (100%) rename packages/{flutter_widgets => stream_chat_flutter}/screenshots/channel_header.png (100%) rename packages/{flutter_widgets => stream_chat_flutter}/screenshots/channel_header_paint.png (100%) rename packages/{flutter_widgets => stream_chat_flutter}/screenshots/channel_image.png (100%) rename packages/{flutter_widgets => stream_chat_flutter}/screenshots/channel_image_paint.png (100%) rename packages/{flutter_widgets => stream_chat_flutter}/screenshots/channel_list_view.png (100%) rename packages/{flutter_widgets => stream_chat_flutter}/screenshots/channel_list_view_paint.png (100%) rename packages/{flutter_widgets => stream_chat_flutter}/screenshots/channel_preview.png (100%) rename packages/{flutter_widgets => stream_chat_flutter}/screenshots/channel_preview_paint.png (100%) rename packages/{flutter_widgets => stream_chat_flutter}/screenshots/message_input.png (100%) rename packages/{flutter_widgets => stream_chat_flutter}/screenshots/message_input2.png (100%) rename packages/{flutter_widgets => stream_chat_flutter}/screenshots/message_input2_paint.png (100%) rename packages/{flutter_widgets => stream_chat_flutter}/screenshots/message_input_paint.png (100%) rename packages/{flutter_widgets => stream_chat_flutter}/screenshots/message_listview.png (100%) rename packages/{flutter_widgets => stream_chat_flutter}/screenshots/message_listview_paint.png (100%) rename packages/{flutter_widgets => stream_chat_flutter}/screenshots/message_widget.png (100%) rename packages/{flutter_widgets => stream_chat_flutter}/screenshots/message_widget_paint.png (100%) rename packages/{flutter_widgets => stream_chat_flutter}/screenshots/reaction_picker.png (100%) rename packages/{flutter_widgets => stream_chat_flutter}/screenshots/reaction_picker_paint.png (100%) rename packages/{flutter_widgets => stream_chat_flutter}/screenshots/thread_header.png (100%) rename packages/{flutter_widgets => stream_chat_flutter}/screenshots/thread_header_paint.png (100%) rename packages/{flutter_widgets => stream_chat_flutter}/svgs/giphy_icon.svg (100%) rename packages/{flutter_widgets => stream_chat_flutter}/svgs/icon_camera.svg (100%) rename packages/{flutter_widgets => stream_chat_flutter}/svgs/icon_pen_write.svg (100%) rename packages/{flutter_widgets => stream_chat_flutter}/svgs/icon_picture_empty_state.svg (100%) rename packages/{flutter_widgets => stream_chat_flutter}/svgs/video_call_icon.svg (100%) rename packages/{flutter_widgets => stream_chat_flutter}/test/src/channel_preview_test.dart (100%) rename packages/{flutter_widgets => stream_chat_flutter}/test/src/message_action_modal_test.dart (100%) rename packages/{flutter_widgets => stream_chat_flutter}/test/src/message_reaction_modal_test.dart (100%) rename packages/{flutter_widgets => stream_chat_flutter}/test/src/mocks.dart (100%) rename packages/{flutter_widgets => stream_chat_flutter}/test/src/reaction_bubble_test.dart (100%) diff --git a/packages/flutter_widgets/example/ios/Podfile b/packages/flutter_widgets/example/ios/Podfile deleted file mode 100644 index 63861e27..00000000 --- a/packages/flutter_widgets/example/ios/Podfile +++ /dev/null @@ -1,43 +0,0 @@ -# Uncomment this line to define a global platform for your project -platform :ios, '11.0' - -# CocoaPods analytics sends network stats synchronously affecting flutter build latency. -ENV['COCOAPODS_DISABLE_STATS'] = 'true' - -project 'Runner', { - 'Debug' => :debug, - 'Profile' => :release, - 'Release' => :release, -} - -def flutter_root - generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__) - unless File.exist?(generated_xcode_build_settings_path) - raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first" - end - - File.foreach(generated_xcode_build_settings_path) do |line| - matches = line.match(/FLUTTER_ROOT\=(.*)/) - return matches[1].strip if matches - end - raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get" -end - -require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) - -flutter_ios_podfile_setup - -target 'Runner' do - use_frameworks! - use_modular_headers! - - flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) -end - -pod 'StreamChatClient' - -post_install do |installer| - installer.pods_project.targets.each do |target| - flutter_additional_ios_build_settings(target) - end -end diff --git a/packages/flutter_widgets/example/ios/Podfile.lock b/packages/flutter_widgets/example/ios/Podfile.lock deleted file mode 100644 index f266b656..00000000 --- a/packages/flutter_widgets/example/ios/Podfile.lock +++ /dev/null @@ -1,299 +0,0 @@ -PODS: - - DKImagePickerController/Core (4.3.2): - - DKImagePickerController/ImageDataManager - - DKImagePickerController/Resource - - DKImagePickerController/ImageDataManager (4.3.2) - - DKImagePickerController/PhotoGallery (4.3.2): - - DKImagePickerController/Core - - DKPhotoGallery - - DKImagePickerController/Resource (4.3.2) - - DKPhotoGallery (0.0.17): - - DKPhotoGallery/Core (= 0.0.17) - - DKPhotoGallery/Model (= 0.0.17) - - DKPhotoGallery/Preview (= 0.0.17) - - DKPhotoGallery/Resource (= 0.0.17) - - SDWebImage - - SwiftyGif - - DKPhotoGallery/Core (0.0.17): - - DKPhotoGallery/Model - - DKPhotoGallery/Preview - - SDWebImage - - SwiftyGif - - DKPhotoGallery/Model (0.0.17): - - SDWebImage - - SwiftyGif - - DKPhotoGallery/Preview (0.0.17): - - DKPhotoGallery/Model - - DKPhotoGallery/Resource - - SDWebImage - - SwiftyGif - - DKPhotoGallery/Resource (0.0.17): - - SDWebImage - - SwiftyGif - - esys_flutter_share (0.0.1): - - Flutter - - file_picker (0.0.1): - - DKImagePickerController/PhotoGallery - - Flutter - - Firebase/CoreOnly (6.33.0): - - FirebaseCore (= 6.10.3) - - Firebase/Messaging (6.33.0): - - Firebase/CoreOnly - - FirebaseMessaging (~> 4.7.0) - - firebase_core (0.5.3): - - Firebase/CoreOnly (~> 6.33.0) - - Flutter - - firebase_messaging (7.0.3): - - Firebase/CoreOnly (~> 6.33.0) - - Firebase/Messaging (~> 6.33.0) - - firebase_core - - Flutter - - FirebaseCore (6.10.3): - - FirebaseCoreDiagnostics (~> 1.6) - - GoogleUtilities/Environment (~> 6.7) - - GoogleUtilities/Logger (~> 6.7) - - FirebaseCoreDiagnostics (1.7.0): - - GoogleDataTransport (~> 7.4) - - GoogleUtilities/Environment (~> 6.7) - - GoogleUtilities/Logger (~> 6.7) - - nanopb (~> 1.30906.0) - - FirebaseInstallations (1.7.0): - - FirebaseCore (~> 6.10) - - GoogleUtilities/Environment (~> 6.7) - - GoogleUtilities/UserDefaults (~> 6.7) - - PromisesObjC (~> 1.2) - - FirebaseInstanceID (4.8.0): - - FirebaseCore (~> 6.10) - - FirebaseInstallations (~> 1.6) - - GoogleUtilities/Environment (~> 6.7) - - GoogleUtilities/UserDefaults (~> 6.7) - - FirebaseMessaging (4.7.1): - - FirebaseCore (~> 6.10) - - FirebaseInstanceID (~> 4.7) - - GoogleUtilities/AppDelegateSwizzler (~> 6.7) - - GoogleUtilities/Environment (~> 6.7) - - GoogleUtilities/Reachability (~> 6.7) - - GoogleUtilities/UserDefaults (~> 6.7) - - Protobuf (>= 3.9.2, ~> 3.9) - - 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): - - Flutter - - flutter_secure_storage (3.3.1): - - Flutter - - FMDB (2.7.5): - - FMDB/standard (= 2.7.5) - - FMDB/standard (2.7.5) - - GoogleDataTransport (7.5.1): - - nanopb (~> 1.30906.0) - - GoogleUtilities/AppDelegateSwizzler (6.7.2): - - GoogleUtilities/Environment - - GoogleUtilities/Logger - - GoogleUtilities/Network - - GoogleUtilities/Environment (6.7.2): - - PromisesObjC (~> 1.2) - - GoogleUtilities/Logger (6.7.2): - - GoogleUtilities/Environment - - GoogleUtilities/Network (6.7.2): - - GoogleUtilities/Logger - - "GoogleUtilities/NSData+zlib" - - GoogleUtilities/Reachability - - "GoogleUtilities/NSData+zlib (6.7.2)" - - GoogleUtilities/Reachability (6.7.2): - - GoogleUtilities/Logger - - GoogleUtilities/UserDefaults (6.7.2): - - GoogleUtilities/Logger - - image_gallery_saver (1.5.0): - - Flutter - - image_picker (0.0.1): - - Flutter - - nanopb (1.30906.0): - - nanopb/decode (= 1.30906.0) - - nanopb/encode (= 1.30906.0) - - nanopb/decode (1.30906.0) - - nanopb/encode (1.30906.0) - - path_provider (0.0.1): - - Flutter - - photo_manager (0.0.1): - - Flutter - - PromisesObjC (1.2.11) - - Protobuf (3.13.0) - - SDWebImage (5.10.0): - - SDWebImage/Core (= 5.10.0) - - SDWebImage/Core (5.10.0) - - shared_preferences (0.0.1): - - Flutter - - sqflite (0.0.2): - - Flutter - - FMDB (>= 2.7.5) - - sqlite3 (3.32.3): - - sqlite3/common (= 3.32.3) - - sqlite3/common (3.32.3) - - sqlite3/fts5 (3.32.3): - - sqlite3/common - - sqlite3/json1 (3.32.3): - - sqlite3/common - - sqlite3/perf-threadsafe (3.32.3): - - sqlite3/common - - sqlite3/rtree (3.32.3): - - sqlite3/common - - sqlite3_flutter_libs (0.0.1): - - Flutter - - sqlite3 (~> 3.32.3) - - sqlite3/fts5 - - sqlite3/json1 - - sqlite3/perf-threadsafe - - sqlite3/rtree - - Starscream (4.0.4) - - StreamChatClient (2.4.2): - - Starscream (~> 4.0) - - SwiftyGif (5.3.0) - - url_launcher (0.0.1): - - Flutter - - video_compress (0.3.0): - - Flutter - - video_player (0.0.1): - - Flutter - - wakelock (0.0.1): - - Flutter - -DEPENDENCIES: - - esys_flutter_share (from `.symlinks/plugins/esys_flutter_share/ios`) - - file_picker (from `.symlinks/plugins/file_picker/ios`) - - firebase_core (from `.symlinks/plugins/firebase_core/ios`) - - 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`) - - flutter_secure_storage (from `.symlinks/plugins/flutter_secure_storage/ios`) - - image_gallery_saver (from `.symlinks/plugins/image_gallery_saver/ios`) - - image_picker (from `.symlinks/plugins/image_picker/ios`) - - path_provider (from `.symlinks/plugins/path_provider/ios`) - - photo_manager (from `.symlinks/plugins/photo_manager/ios`) - - shared_preferences (from `.symlinks/plugins/shared_preferences/ios`) - - sqflite (from `.symlinks/plugins/sqflite/ios`) - - sqlite3_flutter_libs (from `.symlinks/plugins/sqlite3_flutter_libs/ios`) - - StreamChatClient - - url_launcher (from `.symlinks/plugins/url_launcher/ios`) - - video_compress (from `.symlinks/plugins/video_compress/ios`) - - video_player (from `.symlinks/plugins/video_player/ios`) - - wakelock (from `.symlinks/plugins/wakelock/ios`) - -SPEC REPOS: - trunk: - - DKImagePickerController - - DKPhotoGallery - - Firebase - - FirebaseCore - - FirebaseCoreDiagnostics - - FirebaseInstallations - - FirebaseInstanceID - - FirebaseMessaging - - FMDB - - GoogleDataTransport - - GoogleUtilities - - nanopb - - PromisesObjC - - Protobuf - - SDWebImage - - sqlite3 - - Starscream - - StreamChatClient - - SwiftyGif - -EXTERNAL SOURCES: - esys_flutter_share: - :path: ".symlinks/plugins/esys_flutter_share/ios" - file_picker: - :path: ".symlinks/plugins/file_picker/ios" - firebase_core: - :path: ".symlinks/plugins/firebase_core/ios" - firebase_messaging: - :path: ".symlinks/plugins/firebase_messaging/ios" - Flutter: - :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: - :path: ".symlinks/plugins/flutter_local_notifications/ios" - flutter_secure_storage: - :path: ".symlinks/plugins/flutter_secure_storage/ios" - image_gallery_saver: - :path: ".symlinks/plugins/image_gallery_saver/ios" - image_picker: - :path: ".symlinks/plugins/image_picker/ios" - path_provider: - :path: ".symlinks/plugins/path_provider/ios" - photo_manager: - :path: ".symlinks/plugins/photo_manager/ios" - shared_preferences: - :path: ".symlinks/plugins/shared_preferences/ios" - sqflite: - :path: ".symlinks/plugins/sqflite/ios" - sqlite3_flutter_libs: - :path: ".symlinks/plugins/sqlite3_flutter_libs/ios" - url_launcher: - :path: ".symlinks/plugins/url_launcher/ios" - video_compress: - :path: ".symlinks/plugins/video_compress/ios" - video_player: - :path: ".symlinks/plugins/video_player/ios" - wakelock: - :path: ".symlinks/plugins/wakelock/ios" - -SPEC CHECKSUMS: - DKImagePickerController: b5eb7f7a388e4643264105d648d01f727110fc3d - DKPhotoGallery: fdfad5125a9fdda9cc57df834d49df790dbb4179 - esys_flutter_share: 403498dab005b36ce1f8d7aff377e81f0621b0b4 - file_picker: 3e6c3790de664ccf9b882732d9db5eaf6b8d4eb1 - Firebase: 8db6f2d1b2c5e2984efba4949a145875a8f65fe5 - firebase_core: 5d6a02f3d85acd5f8321c2d6d62877626a670659 - firebase_messaging: 0aea2cd5885b65e19ede58ee3507f485c992cc75 - FirebaseCore: d889d9e12535b7f36ac8bfbf1713a0836a3012cd - FirebaseCoreDiagnostics: 770ac5958e1372ce67959ae4b4f31d8e127c3ac1 - FirebaseInstallations: 466c7b4d1f58fe16707693091da253726a731ed2 - FirebaseInstanceID: bd3ffc24367f901a43c063b36c640b345a4a5dd1 - FirebaseMessaging: 5eca4ef173de76253352511aafef774caa1cba2a - Flutter: 0e3d915762c693b495b44d77113d4970485de6ec - flutter_apns: ddc629f26016140bf52165040b0a8e8869f9ce32 - flutter_app_badger: 65de4d6f0c34a891df49e6cfb8a1c0496426fa68 - flutter_keyboard_visibility: 0339d06371254c3eb25eeb90ba8d17dca8f9c069 - flutter_local_notifications: 0c0b1ae97e741e1521e4c1629a459d04b9aec743 - flutter_secure_storage: 7953c38a04c3fdbb00571bcd87d8e3b5ceb9daec - FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a - GoogleDataTransport: f56af7caa4ed338dc8e138a5d7c5973e66440833 - GoogleUtilities: 7f2f5a07f888cdb145101d6042bc4422f57e70b3 - image_gallery_saver: 259eab68fb271cfd57d599904f7acdc7832e7ef2 - image_picker: 9c3312491f862b28d21ecd8fdf0ee14e601b3f09 - nanopb: 59317e09cf1f1a0af72f12af412d54edf52603fc - path_provider: abfe2b5c733d04e238b0d8691db0cfd63a27a93c - photo_manager: f7c619c2cc8c2adb8d85c63363babac477de9c67 - PromisesObjC: 8c196f5a328c2cba3e74624585467a557dcb482f - Protobuf: 3dac39b34a08151c6d949560efe3f86134a3f748 - SDWebImage: 9169792e9eec3e45bba2a0c02f74bf8bd922d1ee - shared_preferences: af6bfa751691cdc24be3045c43ec037377ada40d - sqflite: 6d358c025f5b867b29ed92fc697fd34924e11904 - sqlite3: 8f7d2078ae27778699a622a94b853285793422a2 - sqlite3_flutter_libs: 5651f8ff48e3b44d910863c4ea5916085b1b245f - Starscream: 5178aed56b316f13fa3bc55694e583d35dd414d9 - StreamChatClient: fc6419fa7ceda9c048188bb7c8e9f07755ced05f - SwiftyGif: e466e86c660d343357ab944a819a101c4127cb40 - url_launcher: 6fef411d543ceb26efce54b05a0a40bfd74cbbef - video_compress: fce97e4fb1dfd88175aa07d2ffc8a2f297f87fbe - video_player: 9cc823b1d9da7e8427ee591e8438bfbcde500e6e - wakelock: bfc7955c418d0db797614075aabbc58a39ab5107 - -PODFILE CHECKSUM: eb001256612a59f8f9e4d083ad8b9671e69dd184 - -COCOAPODS: 1.10.0 diff --git a/packages/dart_client/.gitignore b/packages/stream_chat/.gitignore similarity index 100% rename from packages/dart_client/.gitignore rename to packages/stream_chat/.gitignore diff --git a/packages/dart_client/.metadata b/packages/stream_chat/.metadata similarity index 100% rename from packages/dart_client/.metadata rename to packages/stream_chat/.metadata diff --git a/packages/dart_client/CHANGELOG.md b/packages/stream_chat/CHANGELOG.md similarity index 100% rename from packages/dart_client/CHANGELOG.md rename to packages/stream_chat/CHANGELOG.md diff --git a/packages/dart_client/LICENSE b/packages/stream_chat/LICENSE similarity index 100% rename from packages/dart_client/LICENSE rename to packages/stream_chat/LICENSE diff --git a/packages/dart_client/README.md b/packages/stream_chat/README.md similarity index 100% rename from packages/dart_client/README.md rename to packages/stream_chat/README.md diff --git a/packages/dart_client/analysis_options.yaml b/packages/stream_chat/analysis_options.yaml similarity index 100% rename from packages/dart_client/analysis_options.yaml rename to packages/stream_chat/analysis_options.yaml diff --git a/packages/dart_client/build.yaml b/packages/stream_chat/build.yaml similarity index 100% rename from packages/dart_client/build.yaml rename to packages/stream_chat/build.yaml diff --git a/packages/dart_client/example/.gitignore b/packages/stream_chat/example/.gitignore similarity index 100% rename from packages/dart_client/example/.gitignore rename to packages/stream_chat/example/.gitignore diff --git a/packages/dart_client/example/.metadata b/packages/stream_chat/example/.metadata similarity index 100% rename from packages/dart_client/example/.metadata rename to packages/stream_chat/example/.metadata diff --git a/packages/dart_client/example/README.md b/packages/stream_chat/example/README.md similarity index 100% rename from packages/dart_client/example/README.md rename to packages/stream_chat/example/README.md diff --git a/packages/dart_client/example/android/.gitignore b/packages/stream_chat/example/android/.gitignore similarity index 100% rename from packages/dart_client/example/android/.gitignore rename to packages/stream_chat/example/android/.gitignore diff --git a/packages/dart_client/example/android/app/build.gradle b/packages/stream_chat/example/android/app/build.gradle similarity index 100% rename from packages/dart_client/example/android/app/build.gradle rename to packages/stream_chat/example/android/app/build.gradle diff --git a/packages/dart_client/example/android/app/src/debug/AndroidManifest.xml b/packages/stream_chat/example/android/app/src/debug/AndroidManifest.xml similarity index 100% rename from packages/dart_client/example/android/app/src/debug/AndroidManifest.xml rename to packages/stream_chat/example/android/app/src/debug/AndroidManifest.xml diff --git a/packages/dart_client/example/android/app/src/main/AndroidManifest.xml b/packages/stream_chat/example/android/app/src/main/AndroidManifest.xml similarity index 100% rename from packages/dart_client/example/android/app/src/main/AndroidManifest.xml rename to packages/stream_chat/example/android/app/src/main/AndroidManifest.xml diff --git a/packages/dart_client/example/android/app/src/main/kotlin/com/example/example/MainActivity.kt b/packages/stream_chat/example/android/app/src/main/kotlin/com/example/example/MainActivity.kt similarity index 100% rename from packages/dart_client/example/android/app/src/main/kotlin/com/example/example/MainActivity.kt rename to packages/stream_chat/example/android/app/src/main/kotlin/com/example/example/MainActivity.kt diff --git a/packages/dart_client/example/android/app/src/main/res/drawable/launch_background.xml b/packages/stream_chat/example/android/app/src/main/res/drawable/launch_background.xml similarity index 100% rename from packages/dart_client/example/android/app/src/main/res/drawable/launch_background.xml rename to packages/stream_chat/example/android/app/src/main/res/drawable/launch_background.xml diff --git a/packages/dart_client/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/packages/stream_chat/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png similarity index 100% rename from packages/dart_client/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png rename to packages/stream_chat/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png diff --git a/packages/dart_client/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/packages/stream_chat/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png similarity index 100% rename from packages/dart_client/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png rename to packages/stream_chat/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png diff --git a/packages/dart_client/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/packages/stream_chat/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png similarity index 100% rename from packages/dart_client/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png rename to packages/stream_chat/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png diff --git a/packages/dart_client/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/packages/stream_chat/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png similarity index 100% rename from packages/dart_client/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png rename to packages/stream_chat/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png diff --git a/packages/dart_client/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/packages/stream_chat/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png similarity index 100% rename from packages/dart_client/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png rename to packages/stream_chat/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png diff --git a/packages/dart_client/example/android/app/src/main/res/values/styles.xml b/packages/stream_chat/example/android/app/src/main/res/values/styles.xml similarity index 100% rename from packages/dart_client/example/android/app/src/main/res/values/styles.xml rename to packages/stream_chat/example/android/app/src/main/res/values/styles.xml diff --git a/packages/dart_client/example/android/app/src/profile/AndroidManifest.xml b/packages/stream_chat/example/android/app/src/profile/AndroidManifest.xml similarity index 100% rename from packages/dart_client/example/android/app/src/profile/AndroidManifest.xml rename to packages/stream_chat/example/android/app/src/profile/AndroidManifest.xml diff --git a/packages/dart_client/example/android/build.gradle b/packages/stream_chat/example/android/build.gradle similarity index 100% rename from packages/dart_client/example/android/build.gradle rename to packages/stream_chat/example/android/build.gradle diff --git a/packages/dart_client/example/android/gradle.properties b/packages/stream_chat/example/android/gradle.properties similarity index 100% rename from packages/dart_client/example/android/gradle.properties rename to packages/stream_chat/example/android/gradle.properties diff --git a/packages/dart_client/example/android/gradle/wrapper/gradle-wrapper.properties b/packages/stream_chat/example/android/gradle/wrapper/gradle-wrapper.properties similarity index 100% rename from packages/dart_client/example/android/gradle/wrapper/gradle-wrapper.properties rename to packages/stream_chat/example/android/gradle/wrapper/gradle-wrapper.properties diff --git a/packages/dart_client/example/android/settings.gradle b/packages/stream_chat/example/android/settings.gradle similarity index 100% rename from packages/dart_client/example/android/settings.gradle rename to packages/stream_chat/example/android/settings.gradle diff --git a/packages/dart_client/example/ios/.gitignore b/packages/stream_chat/example/ios/.gitignore similarity index 100% rename from packages/dart_client/example/ios/.gitignore rename to packages/stream_chat/example/ios/.gitignore diff --git a/packages/dart_client/example/ios/Flutter/AppFrameworkInfo.plist b/packages/stream_chat/example/ios/Flutter/AppFrameworkInfo.plist similarity index 100% rename from packages/dart_client/example/ios/Flutter/AppFrameworkInfo.plist rename to packages/stream_chat/example/ios/Flutter/AppFrameworkInfo.plist diff --git a/packages/dart_client/example/ios/Flutter/Debug.xcconfig b/packages/stream_chat/example/ios/Flutter/Debug.xcconfig similarity index 100% rename from packages/dart_client/example/ios/Flutter/Debug.xcconfig rename to packages/stream_chat/example/ios/Flutter/Debug.xcconfig diff --git a/packages/dart_client/example/ios/Flutter/Release.xcconfig b/packages/stream_chat/example/ios/Flutter/Release.xcconfig similarity index 100% rename from packages/dart_client/example/ios/Flutter/Release.xcconfig rename to packages/stream_chat/example/ios/Flutter/Release.xcconfig diff --git a/packages/dart_client/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/packages/stream_chat/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata similarity index 100% rename from packages/dart_client/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata rename to packages/stream_chat/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata diff --git a/packages/dart_client/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/packages/stream_chat/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist similarity index 100% rename from packages/dart_client/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist rename to packages/stream_chat/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/packages/dart_client/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/packages/stream_chat/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings similarity index 100% rename from packages/dart_client/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings rename to packages/stream_chat/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings diff --git a/packages/dart_client/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/packages/stream_chat/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme similarity index 100% rename from packages/dart_client/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme rename to packages/stream_chat/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme diff --git a/packages/dart_client/example/ios/Runner.xcworkspace/contents.xcworkspacedata b/packages/stream_chat/example/ios/Runner.xcworkspace/contents.xcworkspacedata similarity index 100% rename from packages/dart_client/example/ios/Runner.xcworkspace/contents.xcworkspacedata rename to packages/stream_chat/example/ios/Runner.xcworkspace/contents.xcworkspacedata diff --git a/packages/dart_client/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/packages/stream_chat/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist similarity index 100% rename from packages/dart_client/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist rename to packages/stream_chat/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/packages/dart_client/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/packages/stream_chat/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings similarity index 100% rename from packages/dart_client/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings rename to packages/stream_chat/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings diff --git a/packages/dart_client/example/ios/Runner/AppDelegate.swift b/packages/stream_chat/example/ios/Runner/AppDelegate.swift similarity index 100% rename from packages/dart_client/example/ios/Runner/AppDelegate.swift rename to packages/stream_chat/example/ios/Runner/AppDelegate.swift diff --git a/packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/packages/stream_chat/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json similarity index 100% rename from packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json rename to packages/stream_chat/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json diff --git a/packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png b/packages/stream_chat/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png similarity index 100% rename from packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png rename to packages/stream_chat/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png diff --git a/packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png b/packages/stream_chat/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png similarity index 100% rename from packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png rename to packages/stream_chat/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png diff --git a/packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png b/packages/stream_chat/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png similarity index 100% rename from packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png rename to packages/stream_chat/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png diff --git a/packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/packages/stream_chat/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png similarity index 100% rename from packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png rename to packages/stream_chat/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png diff --git a/packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png b/packages/stream_chat/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png similarity index 100% rename from packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png rename to packages/stream_chat/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png diff --git a/packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/packages/stream_chat/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png similarity index 100% rename from packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png rename to packages/stream_chat/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png diff --git a/packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png b/packages/stream_chat/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png similarity index 100% rename from packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png rename to packages/stream_chat/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png diff --git a/packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png b/packages/stream_chat/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png similarity index 100% rename from packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png rename to packages/stream_chat/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png diff --git a/packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/packages/stream_chat/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png similarity index 100% rename from packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png rename to packages/stream_chat/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png diff --git a/packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/packages/stream_chat/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png similarity index 100% rename from packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png rename to packages/stream_chat/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png diff --git a/packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/packages/stream_chat/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png similarity index 100% rename from packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png rename to packages/stream_chat/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png diff --git a/packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/packages/stream_chat/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png similarity index 100% rename from packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png rename to packages/stream_chat/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png diff --git a/packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/packages/stream_chat/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png similarity index 100% rename from packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png rename to packages/stream_chat/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png diff --git a/packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png b/packages/stream_chat/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png similarity index 100% rename from packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png rename to packages/stream_chat/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png diff --git a/packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png b/packages/stream_chat/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png similarity index 100% rename from packages/dart_client/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png rename to packages/stream_chat/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png diff --git a/packages/dart_client/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json b/packages/stream_chat/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json similarity index 100% rename from packages/dart_client/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json rename to packages/stream_chat/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json diff --git a/packages/dart_client/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png b/packages/stream_chat/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png similarity index 100% rename from packages/dart_client/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png rename to packages/stream_chat/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png diff --git a/packages/dart_client/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png b/packages/stream_chat/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png similarity index 100% rename from packages/dart_client/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png rename to packages/stream_chat/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png diff --git a/packages/dart_client/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png b/packages/stream_chat/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png similarity index 100% rename from packages/dart_client/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png rename to packages/stream_chat/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png diff --git a/packages/dart_client/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md b/packages/stream_chat/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md similarity index 100% rename from packages/dart_client/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md rename to packages/stream_chat/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md diff --git a/packages/dart_client/example/ios/Runner/Base.lproj/LaunchScreen.storyboard b/packages/stream_chat/example/ios/Runner/Base.lproj/LaunchScreen.storyboard similarity index 100% rename from packages/dart_client/example/ios/Runner/Base.lproj/LaunchScreen.storyboard rename to packages/stream_chat/example/ios/Runner/Base.lproj/LaunchScreen.storyboard diff --git a/packages/dart_client/example/ios/Runner/Base.lproj/Main.storyboard b/packages/stream_chat/example/ios/Runner/Base.lproj/Main.storyboard similarity index 100% rename from packages/dart_client/example/ios/Runner/Base.lproj/Main.storyboard rename to packages/stream_chat/example/ios/Runner/Base.lproj/Main.storyboard diff --git a/packages/dart_client/example/ios/Runner/Info.plist b/packages/stream_chat/example/ios/Runner/Info.plist similarity index 100% rename from packages/dart_client/example/ios/Runner/Info.plist rename to packages/stream_chat/example/ios/Runner/Info.plist diff --git a/packages/dart_client/example/ios/Runner/Runner-Bridging-Header.h b/packages/stream_chat/example/ios/Runner/Runner-Bridging-Header.h similarity index 100% rename from packages/dart_client/example/ios/Runner/Runner-Bridging-Header.h rename to packages/stream_chat/example/ios/Runner/Runner-Bridging-Header.h diff --git a/packages/dart_client/example/lib/main.dart b/packages/stream_chat/example/lib/main.dart similarity index 100% rename from packages/dart_client/example/lib/main.dart rename to packages/stream_chat/example/lib/main.dart diff --git a/packages/dart_client/example/pubspec.yaml b/packages/stream_chat/example/pubspec.yaml similarity index 100% rename from packages/dart_client/example/pubspec.yaml rename to packages/stream_chat/example/pubspec.yaml diff --git a/packages/dart_client/lib/src/api/channel.dart b/packages/stream_chat/lib/src/api/channel.dart similarity index 100% rename from packages/dart_client/lib/src/api/channel.dart rename to packages/stream_chat/lib/src/api/channel.dart diff --git a/packages/dart_client/lib/src/api/connection_status.dart b/packages/stream_chat/lib/src/api/connection_status.dart similarity index 100% rename from packages/dart_client/lib/src/api/connection_status.dart rename to packages/stream_chat/lib/src/api/connection_status.dart diff --git a/packages/dart_client/lib/src/api/requests.dart b/packages/stream_chat/lib/src/api/requests.dart similarity index 100% rename from packages/dart_client/lib/src/api/requests.dart rename to packages/stream_chat/lib/src/api/requests.dart diff --git a/packages/dart_client/lib/src/api/requests.g.dart b/packages/stream_chat/lib/src/api/requests.g.dart similarity index 100% rename from packages/dart_client/lib/src/api/requests.g.dart rename to packages/stream_chat/lib/src/api/requests.g.dart diff --git a/packages/dart_client/lib/src/api/responses.dart b/packages/stream_chat/lib/src/api/responses.dart similarity index 100% rename from packages/dart_client/lib/src/api/responses.dart rename to packages/stream_chat/lib/src/api/responses.dart diff --git a/packages/dart_client/lib/src/api/responses.g.dart b/packages/stream_chat/lib/src/api/responses.g.dart similarity index 100% rename from packages/dart_client/lib/src/api/responses.g.dart rename to packages/stream_chat/lib/src/api/responses.g.dart diff --git a/packages/dart_client/lib/src/api/retry_policy.dart b/packages/stream_chat/lib/src/api/retry_policy.dart similarity index 100% rename from packages/dart_client/lib/src/api/retry_policy.dart rename to packages/stream_chat/lib/src/api/retry_policy.dart diff --git a/packages/dart_client/lib/src/api/retry_queue.dart b/packages/stream_chat/lib/src/api/retry_queue.dart similarity index 100% rename from packages/dart_client/lib/src/api/retry_queue.dart rename to packages/stream_chat/lib/src/api/retry_queue.dart diff --git a/packages/dart_client/lib/src/api/web_socket_channel_html.dart b/packages/stream_chat/lib/src/api/web_socket_channel_html.dart similarity index 100% rename from packages/dart_client/lib/src/api/web_socket_channel_html.dart rename to packages/stream_chat/lib/src/api/web_socket_channel_html.dart diff --git a/packages/dart_client/lib/src/api/web_socket_channel_io.dart b/packages/stream_chat/lib/src/api/web_socket_channel_io.dart similarity index 100% rename from packages/dart_client/lib/src/api/web_socket_channel_io.dart rename to packages/stream_chat/lib/src/api/web_socket_channel_io.dart diff --git a/packages/dart_client/lib/src/api/web_socket_channel_stub.dart b/packages/stream_chat/lib/src/api/web_socket_channel_stub.dart similarity index 100% rename from packages/dart_client/lib/src/api/web_socket_channel_stub.dart rename to packages/stream_chat/lib/src/api/web_socket_channel_stub.dart diff --git a/packages/dart_client/lib/src/api/websocket.dart b/packages/stream_chat/lib/src/api/websocket.dart similarity index 100% rename from packages/dart_client/lib/src/api/websocket.dart rename to packages/stream_chat/lib/src/api/websocket.dart diff --git a/packages/dart_client/lib/src/client.dart b/packages/stream_chat/lib/src/client.dart similarity index 100% rename from packages/dart_client/lib/src/client.dart rename to packages/stream_chat/lib/src/client.dart diff --git a/packages/dart_client/lib/src/db/chat_persistence_client.dart b/packages/stream_chat/lib/src/db/chat_persistence_client.dart similarity index 100% rename from packages/dart_client/lib/src/db/chat_persistence_client.dart rename to packages/stream_chat/lib/src/db/chat_persistence_client.dart diff --git a/packages/dart_client/lib/src/event_type.dart b/packages/stream_chat/lib/src/event_type.dart similarity index 100% rename from packages/dart_client/lib/src/event_type.dart rename to packages/stream_chat/lib/src/event_type.dart diff --git a/packages/dart_client/lib/src/exceptions.dart b/packages/stream_chat/lib/src/exceptions.dart similarity index 100% rename from packages/dart_client/lib/src/exceptions.dart rename to packages/stream_chat/lib/src/exceptions.dart diff --git a/packages/dart_client/lib/src/models/action.dart b/packages/stream_chat/lib/src/models/action.dart similarity index 100% rename from packages/dart_client/lib/src/models/action.dart rename to packages/stream_chat/lib/src/models/action.dart diff --git a/packages/dart_client/lib/src/models/action.g.dart b/packages/stream_chat/lib/src/models/action.g.dart similarity index 100% rename from packages/dart_client/lib/src/models/action.g.dart rename to packages/stream_chat/lib/src/models/action.g.dart diff --git a/packages/dart_client/lib/src/models/attachment.dart b/packages/stream_chat/lib/src/models/attachment.dart similarity index 100% rename from packages/dart_client/lib/src/models/attachment.dart rename to packages/stream_chat/lib/src/models/attachment.dart diff --git a/packages/dart_client/lib/src/models/attachment.g.dart b/packages/stream_chat/lib/src/models/attachment.g.dart similarity index 100% rename from packages/dart_client/lib/src/models/attachment.g.dart rename to packages/stream_chat/lib/src/models/attachment.g.dart diff --git a/packages/dart_client/lib/src/models/channel_config.dart b/packages/stream_chat/lib/src/models/channel_config.dart similarity index 100% rename from packages/dart_client/lib/src/models/channel_config.dart rename to packages/stream_chat/lib/src/models/channel_config.dart diff --git a/packages/dart_client/lib/src/models/channel_config.g.dart b/packages/stream_chat/lib/src/models/channel_config.g.dart similarity index 100% rename from packages/dart_client/lib/src/models/channel_config.g.dart rename to packages/stream_chat/lib/src/models/channel_config.g.dart diff --git a/packages/dart_client/lib/src/models/channel_model.dart b/packages/stream_chat/lib/src/models/channel_model.dart similarity index 100% rename from packages/dart_client/lib/src/models/channel_model.dart rename to packages/stream_chat/lib/src/models/channel_model.dart diff --git a/packages/dart_client/lib/src/models/channel_model.g.dart b/packages/stream_chat/lib/src/models/channel_model.g.dart similarity index 100% rename from packages/dart_client/lib/src/models/channel_model.g.dart rename to packages/stream_chat/lib/src/models/channel_model.g.dart diff --git a/packages/dart_client/lib/src/models/channel_state.dart b/packages/stream_chat/lib/src/models/channel_state.dart similarity index 100% rename from packages/dart_client/lib/src/models/channel_state.dart rename to packages/stream_chat/lib/src/models/channel_state.dart diff --git a/packages/dart_client/lib/src/models/channel_state.g.dart b/packages/stream_chat/lib/src/models/channel_state.g.dart similarity index 100% rename from packages/dart_client/lib/src/models/channel_state.g.dart rename to packages/stream_chat/lib/src/models/channel_state.g.dart diff --git a/packages/dart_client/lib/src/models/command.dart b/packages/stream_chat/lib/src/models/command.dart similarity index 100% rename from packages/dart_client/lib/src/models/command.dart rename to packages/stream_chat/lib/src/models/command.dart diff --git a/packages/dart_client/lib/src/models/command.g.dart b/packages/stream_chat/lib/src/models/command.g.dart similarity index 100% rename from packages/dart_client/lib/src/models/command.g.dart rename to packages/stream_chat/lib/src/models/command.g.dart diff --git a/packages/dart_client/lib/src/models/device.dart b/packages/stream_chat/lib/src/models/device.dart similarity index 100% rename from packages/dart_client/lib/src/models/device.dart rename to packages/stream_chat/lib/src/models/device.dart diff --git a/packages/dart_client/lib/src/models/device.g.dart b/packages/stream_chat/lib/src/models/device.g.dart similarity index 100% rename from packages/dart_client/lib/src/models/device.g.dart rename to packages/stream_chat/lib/src/models/device.g.dart diff --git a/packages/dart_client/lib/src/models/event.dart b/packages/stream_chat/lib/src/models/event.dart similarity index 100% rename from packages/dart_client/lib/src/models/event.dart rename to packages/stream_chat/lib/src/models/event.dart diff --git a/packages/dart_client/lib/src/models/event.g.dart b/packages/stream_chat/lib/src/models/event.g.dart similarity index 100% rename from packages/dart_client/lib/src/models/event.g.dart rename to packages/stream_chat/lib/src/models/event.g.dart diff --git a/packages/dart_client/lib/src/models/member.dart b/packages/stream_chat/lib/src/models/member.dart similarity index 100% rename from packages/dart_client/lib/src/models/member.dart rename to packages/stream_chat/lib/src/models/member.dart diff --git a/packages/dart_client/lib/src/models/member.g.dart b/packages/stream_chat/lib/src/models/member.g.dart similarity index 100% rename from packages/dart_client/lib/src/models/member.g.dart rename to packages/stream_chat/lib/src/models/member.g.dart diff --git a/packages/dart_client/lib/src/models/message.dart b/packages/stream_chat/lib/src/models/message.dart similarity index 100% rename from packages/dart_client/lib/src/models/message.dart rename to packages/stream_chat/lib/src/models/message.dart diff --git a/packages/dart_client/lib/src/models/message.g.dart b/packages/stream_chat/lib/src/models/message.g.dart similarity index 100% rename from packages/dart_client/lib/src/models/message.g.dart rename to packages/stream_chat/lib/src/models/message.g.dart diff --git a/packages/dart_client/lib/src/models/mute.dart b/packages/stream_chat/lib/src/models/mute.dart similarity index 100% rename from packages/dart_client/lib/src/models/mute.dart rename to packages/stream_chat/lib/src/models/mute.dart diff --git a/packages/dart_client/lib/src/models/mute.g.dart b/packages/stream_chat/lib/src/models/mute.g.dart similarity index 100% rename from packages/dart_client/lib/src/models/mute.g.dart rename to packages/stream_chat/lib/src/models/mute.g.dart diff --git a/packages/dart_client/lib/src/models/own_user.dart b/packages/stream_chat/lib/src/models/own_user.dart similarity index 100% rename from packages/dart_client/lib/src/models/own_user.dart rename to packages/stream_chat/lib/src/models/own_user.dart diff --git a/packages/dart_client/lib/src/models/own_user.g.dart b/packages/stream_chat/lib/src/models/own_user.g.dart similarity index 100% rename from packages/dart_client/lib/src/models/own_user.g.dart rename to packages/stream_chat/lib/src/models/own_user.g.dart diff --git a/packages/dart_client/lib/src/models/reaction.dart b/packages/stream_chat/lib/src/models/reaction.dart similarity index 100% rename from packages/dart_client/lib/src/models/reaction.dart rename to packages/stream_chat/lib/src/models/reaction.dart diff --git a/packages/dart_client/lib/src/models/reaction.g.dart b/packages/stream_chat/lib/src/models/reaction.g.dart similarity index 100% rename from packages/dart_client/lib/src/models/reaction.g.dart rename to packages/stream_chat/lib/src/models/reaction.g.dart diff --git a/packages/dart_client/lib/src/models/read.dart b/packages/stream_chat/lib/src/models/read.dart similarity index 100% rename from packages/dart_client/lib/src/models/read.dart rename to packages/stream_chat/lib/src/models/read.dart diff --git a/packages/dart_client/lib/src/models/read.g.dart b/packages/stream_chat/lib/src/models/read.g.dart similarity index 100% rename from packages/dart_client/lib/src/models/read.g.dart rename to packages/stream_chat/lib/src/models/read.g.dart diff --git a/packages/dart_client/lib/src/models/serialization.dart b/packages/stream_chat/lib/src/models/serialization.dart similarity index 100% rename from packages/dart_client/lib/src/models/serialization.dart rename to packages/stream_chat/lib/src/models/serialization.dart diff --git a/packages/dart_client/lib/src/models/user.dart b/packages/stream_chat/lib/src/models/user.dart similarity index 100% rename from packages/dart_client/lib/src/models/user.dart rename to packages/stream_chat/lib/src/models/user.dart diff --git a/packages/dart_client/lib/src/models/user.g.dart b/packages/stream_chat/lib/src/models/user.g.dart similarity index 100% rename from packages/dart_client/lib/src/models/user.g.dart rename to packages/stream_chat/lib/src/models/user.g.dart diff --git a/packages/dart_client/lib/stream_chat.dart b/packages/stream_chat/lib/stream_chat.dart similarity index 100% rename from packages/dart_client/lib/stream_chat.dart rename to packages/stream_chat/lib/stream_chat.dart diff --git a/packages/dart_client/lib/version.dart b/packages/stream_chat/lib/version.dart similarity index 100% rename from packages/dart_client/lib/version.dart rename to packages/stream_chat/lib/version.dart diff --git a/packages/dart_client/peanut.yaml b/packages/stream_chat/peanut.yaml similarity index 100% rename from packages/dart_client/peanut.yaml rename to packages/stream_chat/peanut.yaml diff --git a/packages/dart_client/pubspec.yaml b/packages/stream_chat/pubspec.yaml similarity index 100% rename from packages/dart_client/pubspec.yaml rename to packages/stream_chat/pubspec.yaml diff --git a/packages/dart_client/test/src/api/channel_test.dart b/packages/stream_chat/test/src/api/channel_test.dart similarity index 100% rename from packages/dart_client/test/src/api/channel_test.dart rename to packages/stream_chat/test/src/api/channel_test.dart diff --git a/packages/dart_client/test/src/api/requests_test.dart b/packages/stream_chat/test/src/api/requests_test.dart similarity index 100% rename from packages/dart_client/test/src/api/requests_test.dart rename to packages/stream_chat/test/src/api/requests_test.dart diff --git a/packages/dart_client/test/src/api/responses_test.dart b/packages/stream_chat/test/src/api/responses_test.dart similarity index 100% rename from packages/dart_client/test/src/api/responses_test.dart rename to packages/stream_chat/test/src/api/responses_test.dart diff --git a/packages/dart_client/test/src/api/web_socket_stub_test.dart b/packages/stream_chat/test/src/api/web_socket_stub_test.dart similarity index 100% rename from packages/dart_client/test/src/api/web_socket_stub_test.dart rename to packages/stream_chat/test/src/api/web_socket_stub_test.dart diff --git a/packages/dart_client/test/src/api/websocket_test.dart b/packages/stream_chat/test/src/api/websocket_test.dart similarity index 100% rename from packages/dart_client/test/src/api/websocket_test.dart rename to packages/stream_chat/test/src/api/websocket_test.dart diff --git a/packages/dart_client/test/src/client_test.dart b/packages/stream_chat/test/src/client_test.dart similarity index 100% rename from packages/dart_client/test/src/client_test.dart rename to packages/stream_chat/test/src/client_test.dart diff --git a/packages/dart_client/test/src/models/action_test.dart b/packages/stream_chat/test/src/models/action_test.dart similarity index 100% rename from packages/dart_client/test/src/models/action_test.dart rename to packages/stream_chat/test/src/models/action_test.dart diff --git a/packages/dart_client/test/src/models/attachment_test.dart b/packages/stream_chat/test/src/models/attachment_test.dart similarity index 100% rename from packages/dart_client/test/src/models/attachment_test.dart rename to packages/stream_chat/test/src/models/attachment_test.dart diff --git a/packages/dart_client/test/src/models/channel_state_test.dart b/packages/stream_chat/test/src/models/channel_state_test.dart similarity index 100% rename from packages/dart_client/test/src/models/channel_state_test.dart rename to packages/stream_chat/test/src/models/channel_state_test.dart diff --git a/packages/dart_client/test/src/models/channel_test.dart b/packages/stream_chat/test/src/models/channel_test.dart similarity index 100% rename from packages/dart_client/test/src/models/channel_test.dart rename to packages/stream_chat/test/src/models/channel_test.dart diff --git a/packages/dart_client/test/src/models/command_test.dart b/packages/stream_chat/test/src/models/command_test.dart similarity index 100% rename from packages/dart_client/test/src/models/command_test.dart rename to packages/stream_chat/test/src/models/command_test.dart diff --git a/packages/dart_client/test/src/models/device_test.dart b/packages/stream_chat/test/src/models/device_test.dart similarity index 100% rename from packages/dart_client/test/src/models/device_test.dart rename to packages/stream_chat/test/src/models/device_test.dart diff --git a/packages/dart_client/test/src/models/event_test.dart b/packages/stream_chat/test/src/models/event_test.dart similarity index 100% rename from packages/dart_client/test/src/models/event_test.dart rename to packages/stream_chat/test/src/models/event_test.dart diff --git a/packages/dart_client/test/src/models/member_test.dart b/packages/stream_chat/test/src/models/member_test.dart similarity index 100% rename from packages/dart_client/test/src/models/member_test.dart rename to packages/stream_chat/test/src/models/member_test.dart diff --git a/packages/dart_client/test/src/models/message_test.dart b/packages/stream_chat/test/src/models/message_test.dart similarity index 100% rename from packages/dart_client/test/src/models/message_test.dart rename to packages/stream_chat/test/src/models/message_test.dart diff --git a/packages/dart_client/test/src/models/reaction_test.dart b/packages/stream_chat/test/src/models/reaction_test.dart similarity index 100% rename from packages/dart_client/test/src/models/reaction_test.dart rename to packages/stream_chat/test/src/models/reaction_test.dart diff --git a/packages/dart_client/test/src/models/read_test.dart b/packages/stream_chat/test/src/models/read_test.dart similarity index 100% rename from packages/dart_client/test/src/models/read_test.dart rename to packages/stream_chat/test/src/models/read_test.dart diff --git a/packages/dart_client/test/src/models/serialization_test.dart b/packages/stream_chat/test/src/models/serialization_test.dart similarity index 100% rename from packages/dart_client/test/src/models/serialization_test.dart rename to packages/stream_chat/test/src/models/serialization_test.dart diff --git a/packages/dart_client/test/src/models/user_test.dart b/packages/stream_chat/test/src/models/user_test.dart similarity index 100% rename from packages/dart_client/test/src/models/user_test.dart rename to packages/stream_chat/test/src/models/user_test.dart diff --git a/packages/dart_client/test/version_test.dart b/packages/stream_chat/test/version_test.dart similarity index 100% rename from packages/dart_client/test/version_test.dart rename to packages/stream_chat/test/version_test.dart diff --git a/packages/flutter_widgets/.gitignore b/packages/stream_chat_flutter/.gitignore similarity index 100% rename from packages/flutter_widgets/.gitignore rename to packages/stream_chat_flutter/.gitignore diff --git a/packages/flutter_widgets/CHANGELOG.md b/packages/stream_chat_flutter/CHANGELOG.md similarity index 100% rename from packages/flutter_widgets/CHANGELOG.md rename to packages/stream_chat_flutter/CHANGELOG.md diff --git a/packages/flutter_widgets/LICENSE b/packages/stream_chat_flutter/LICENSE similarity index 100% rename from packages/flutter_widgets/LICENSE rename to packages/stream_chat_flutter/LICENSE diff --git a/packages/flutter_widgets/README.md b/packages/stream_chat_flutter/README.md similarity index 100% rename from packages/flutter_widgets/README.md rename to packages/stream_chat_flutter/README.md diff --git a/packages/flutter_widgets/analysis_options.yaml b/packages/stream_chat_flutter/analysis_options.yaml similarity index 100% rename from packages/flutter_widgets/analysis_options.yaml rename to packages/stream_chat_flutter/analysis_options.yaml diff --git a/packages/flutter_widgets/animations/typing_dots.json b/packages/stream_chat_flutter/animations/typing_dots.json similarity index 100% rename from packages/flutter_widgets/animations/typing_dots.json rename to packages/stream_chat_flutter/animations/typing_dots.json diff --git a/packages/flutter_widgets/example/.gitignore b/packages/stream_chat_flutter/example/.gitignore similarity index 100% rename from packages/flutter_widgets/example/.gitignore rename to packages/stream_chat_flutter/example/.gitignore diff --git a/packages/flutter_widgets/example/.metadata b/packages/stream_chat_flutter/example/.metadata similarity index 100% rename from packages/flutter_widgets/example/.metadata rename to packages/stream_chat_flutter/example/.metadata diff --git a/packages/flutter_widgets/example/README.md b/packages/stream_chat_flutter/example/README.md similarity index 100% rename from packages/flutter_widgets/example/README.md rename to packages/stream_chat_flutter/example/README.md diff --git a/packages/flutter_widgets/example/android/.gitignore b/packages/stream_chat_flutter/example/android/.gitignore similarity index 100% rename from packages/flutter_widgets/example/android/.gitignore rename to packages/stream_chat_flutter/example/android/.gitignore diff --git a/packages/flutter_widgets/example/android/app/build.gradle b/packages/stream_chat_flutter/example/android/app/build.gradle similarity index 100% rename from packages/flutter_widgets/example/android/app/build.gradle rename to packages/stream_chat_flutter/example/android/app/build.gradle diff --git a/packages/flutter_widgets/example/android/app/src/debug/AndroidManifest.xml b/packages/stream_chat_flutter/example/android/app/src/debug/AndroidManifest.xml similarity index 100% rename from packages/flutter_widgets/example/android/app/src/debug/AndroidManifest.xml rename to packages/stream_chat_flutter/example/android/app/src/debug/AndroidManifest.xml diff --git a/packages/flutter_widgets/example/android/app/src/main/AndroidManifest.xml b/packages/stream_chat_flutter/example/android/app/src/main/AndroidManifest.xml similarity index 100% rename from packages/flutter_widgets/example/android/app/src/main/AndroidManifest.xml rename to packages/stream_chat_flutter/example/android/app/src/main/AndroidManifest.xml diff --git a/packages/flutter_widgets/example/android/app/src/main/kotlin/com/example/example/Application.kt b/packages/stream_chat_flutter/example/android/app/src/main/kotlin/com/example/example/Application.kt similarity index 100% rename from packages/flutter_widgets/example/android/app/src/main/kotlin/com/example/example/Application.kt rename to packages/stream_chat_flutter/example/android/app/src/main/kotlin/com/example/example/Application.kt diff --git a/packages/flutter_widgets/example/android/app/src/main/kotlin/com/example/example/MainActivity.kt b/packages/stream_chat_flutter/example/android/app/src/main/kotlin/com/example/example/MainActivity.kt similarity index 100% rename from packages/flutter_widgets/example/android/app/src/main/kotlin/com/example/example/MainActivity.kt rename to packages/stream_chat_flutter/example/android/app/src/main/kotlin/com/example/example/MainActivity.kt diff --git a/packages/flutter_widgets/example/android/app/src/main/res/drawable/launch_background.xml b/packages/stream_chat_flutter/example/android/app/src/main/res/drawable/launch_background.xml similarity index 100% rename from packages/flutter_widgets/example/android/app/src/main/res/drawable/launch_background.xml rename to packages/stream_chat_flutter/example/android/app/src/main/res/drawable/launch_background.xml diff --git a/packages/flutter_widgets/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/packages/stream_chat_flutter/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png similarity index 100% rename from packages/flutter_widgets/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png rename to packages/stream_chat_flutter/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png diff --git a/packages/flutter_widgets/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/packages/stream_chat_flutter/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png similarity index 100% rename from packages/flutter_widgets/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png rename to packages/stream_chat_flutter/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png diff --git a/packages/flutter_widgets/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/packages/stream_chat_flutter/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png similarity index 100% rename from packages/flutter_widgets/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png rename to packages/stream_chat_flutter/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png diff --git a/packages/flutter_widgets/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/packages/stream_chat_flutter/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png similarity index 100% rename from packages/flutter_widgets/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png rename to packages/stream_chat_flutter/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png diff --git a/packages/flutter_widgets/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/packages/stream_chat_flutter/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png similarity index 100% rename from packages/flutter_widgets/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png rename to packages/stream_chat_flutter/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png diff --git a/packages/flutter_widgets/example/android/app/src/main/res/values/styles.xml b/packages/stream_chat_flutter/example/android/app/src/main/res/values/styles.xml similarity index 100% rename from packages/flutter_widgets/example/android/app/src/main/res/values/styles.xml rename to packages/stream_chat_flutter/example/android/app/src/main/res/values/styles.xml diff --git a/packages/flutter_widgets/example/android/app/src/profile/AndroidManifest.xml b/packages/stream_chat_flutter/example/android/app/src/profile/AndroidManifest.xml similarity index 100% rename from packages/flutter_widgets/example/android/app/src/profile/AndroidManifest.xml rename to packages/stream_chat_flutter/example/android/app/src/profile/AndroidManifest.xml diff --git a/packages/flutter_widgets/example/android/build.gradle b/packages/stream_chat_flutter/example/android/build.gradle similarity index 100% rename from packages/flutter_widgets/example/android/build.gradle rename to packages/stream_chat_flutter/example/android/build.gradle diff --git a/packages/flutter_widgets/example/android/gradle.properties b/packages/stream_chat_flutter/example/android/gradle.properties similarity index 100% rename from packages/flutter_widgets/example/android/gradle.properties rename to packages/stream_chat_flutter/example/android/gradle.properties diff --git a/packages/flutter_widgets/example/android/gradle/wrapper/gradle-wrapper.properties b/packages/stream_chat_flutter/example/android/gradle/wrapper/gradle-wrapper.properties similarity index 100% rename from packages/flutter_widgets/example/android/gradle/wrapper/gradle-wrapper.properties rename to packages/stream_chat_flutter/example/android/gradle/wrapper/gradle-wrapper.properties diff --git a/packages/flutter_widgets/example/android/settings.gradle b/packages/stream_chat_flutter/example/android/settings.gradle similarity index 100% rename from packages/flutter_widgets/example/android/settings.gradle rename to packages/stream_chat_flutter/example/android/settings.gradle diff --git a/packages/flutter_widgets/example/android/settings_aar.gradle b/packages/stream_chat_flutter/example/android/settings_aar.gradle similarity index 100% rename from packages/flutter_widgets/example/android/settings_aar.gradle rename to packages/stream_chat_flutter/example/android/settings_aar.gradle diff --git a/packages/flutter_widgets/example/assets/android_icon.png b/packages/stream_chat_flutter/example/assets/android_icon.png similarity index 100% rename from packages/flutter_widgets/example/assets/android_icon.png rename to packages/stream_chat_flutter/example/assets/android_icon.png diff --git a/packages/flutter_widgets/example/assets/icon_arrow_right.svg b/packages/stream_chat_flutter/example/assets/icon_arrow_right.svg similarity index 100% rename from packages/flutter_widgets/example/assets/icon_arrow_right.svg rename to packages/stream_chat_flutter/example/assets/icon_arrow_right.svg diff --git a/packages/flutter_widgets/example/assets/ios_icon.png b/packages/stream_chat_flutter/example/assets/ios_icon.png similarity index 100% rename from packages/flutter_widgets/example/assets/ios_icon.png rename to packages/stream_chat_flutter/example/assets/ios_icon.png diff --git a/packages/flutter_widgets/example/assets/logo.svg b/packages/stream_chat_flutter/example/assets/logo.svg similarity index 100% rename from packages/flutter_widgets/example/assets/logo.svg rename to packages/stream_chat_flutter/example/assets/logo.svg diff --git a/packages/flutter_widgets/example/ios/.gitignore b/packages/stream_chat_flutter/example/ios/.gitignore similarity index 100% rename from packages/flutter_widgets/example/ios/.gitignore rename to packages/stream_chat_flutter/example/ios/.gitignore diff --git a/packages/flutter_widgets/example/ios/Flutter/AppFrameworkInfo.plist b/packages/stream_chat_flutter/example/ios/Flutter/AppFrameworkInfo.plist similarity index 100% rename from packages/flutter_widgets/example/ios/Flutter/AppFrameworkInfo.plist rename to packages/stream_chat_flutter/example/ios/Flutter/AppFrameworkInfo.plist diff --git a/packages/flutter_widgets/example/ios/Flutter/Debug.xcconfig b/packages/stream_chat_flutter/example/ios/Flutter/Debug.xcconfig similarity index 100% rename from packages/flutter_widgets/example/ios/Flutter/Debug.xcconfig rename to packages/stream_chat_flutter/example/ios/Flutter/Debug.xcconfig diff --git a/packages/flutter_widgets/example/ios/Flutter/Release.xcconfig b/packages/stream_chat_flutter/example/ios/Flutter/Release.xcconfig similarity index 100% rename from packages/flutter_widgets/example/ios/Flutter/Release.xcconfig rename to packages/stream_chat_flutter/example/ios/Flutter/Release.xcconfig diff --git a/packages/flutter_widgets/example/ios/Gemfile b/packages/stream_chat_flutter/example/ios/Gemfile similarity index 100% rename from packages/flutter_widgets/example/ios/Gemfile rename to packages/stream_chat_flutter/example/ios/Gemfile diff --git a/packages/flutter_widgets/example/ios/Gemfile.lock b/packages/stream_chat_flutter/example/ios/Gemfile.lock similarity index 100% rename from packages/flutter_widgets/example/ios/Gemfile.lock rename to packages/stream_chat_flutter/example/ios/Gemfile.lock diff --git a/packages/flutter_widgets/example/ios/Notifications/Info.plist b/packages/stream_chat_flutter/example/ios/Notifications/Info.plist similarity index 100% rename from packages/flutter_widgets/example/ios/Notifications/Info.plist rename to packages/stream_chat_flutter/example/ios/Notifications/Info.plist diff --git a/packages/flutter_widgets/example/ios/Notifications/NotificationService.swift b/packages/stream_chat_flutter/example/ios/Notifications/NotificationService.swift similarity index 100% rename from packages/flutter_widgets/example/ios/Notifications/NotificationService.swift rename to packages/stream_chat_flutter/example/ios/Notifications/NotificationService.swift diff --git a/packages/flutter_widgets/example/ios/Notifications/Notifications.entitlements b/packages/stream_chat_flutter/example/ios/Notifications/Notifications.entitlements similarity index 100% rename from packages/flutter_widgets/example/ios/Notifications/Notifications.entitlements rename to packages/stream_chat_flutter/example/ios/Notifications/Notifications.entitlements diff --git a/packages/flutter_widgets/example/ios/Runner.xcodeproj/project.pbxproj b/packages/stream_chat_flutter/example/ios/Runner.xcodeproj/project.pbxproj similarity index 100% rename from packages/flutter_widgets/example/ios/Runner.xcodeproj/project.pbxproj rename to packages/stream_chat_flutter/example/ios/Runner.xcodeproj/project.pbxproj diff --git a/packages/flutter_widgets/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/packages/stream_chat_flutter/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata similarity index 100% rename from packages/flutter_widgets/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata rename to packages/stream_chat_flutter/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata diff --git a/packages/flutter_widgets/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/packages/stream_chat_flutter/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist similarity index 100% rename from packages/flutter_widgets/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist rename to packages/stream_chat_flutter/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/packages/flutter_widgets/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/packages/stream_chat_flutter/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings similarity index 100% rename from packages/flutter_widgets/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings rename to packages/stream_chat_flutter/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings diff --git a/packages/flutter_widgets/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Notifications.xcscheme b/packages/stream_chat_flutter/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Notifications.xcscheme similarity index 100% rename from packages/flutter_widgets/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Notifications.xcscheme rename to packages/stream_chat_flutter/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Notifications.xcscheme diff --git a/packages/flutter_widgets/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/packages/stream_chat_flutter/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme similarity index 100% rename from packages/flutter_widgets/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme rename to packages/stream_chat_flutter/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme diff --git a/packages/flutter_widgets/example/ios/Runner.xcworkspace/contents.xcworkspacedata b/packages/stream_chat_flutter/example/ios/Runner.xcworkspace/contents.xcworkspacedata similarity index 100% rename from packages/flutter_widgets/example/ios/Runner.xcworkspace/contents.xcworkspacedata rename to packages/stream_chat_flutter/example/ios/Runner.xcworkspace/contents.xcworkspacedata diff --git a/packages/flutter_widgets/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/packages/stream_chat_flutter/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist similarity index 100% rename from packages/flutter_widgets/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist rename to packages/stream_chat_flutter/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/packages/flutter_widgets/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/packages/stream_chat_flutter/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings similarity index 100% rename from packages/flutter_widgets/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings rename to packages/stream_chat_flutter/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings diff --git a/packages/flutter_widgets/example/ios/Runner/AppDelegate.swift b/packages/stream_chat_flutter/example/ios/Runner/AppDelegate.swift similarity index 100% rename from packages/flutter_widgets/example/ios/Runner/AppDelegate.swift rename to packages/stream_chat_flutter/example/ios/Runner/AppDelegate.swift diff --git a/packages/flutter_widgets/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/packages/stream_chat_flutter/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json similarity index 100% rename from packages/flutter_widgets/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json rename to packages/stream_chat_flutter/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json diff --git a/packages/flutter_widgets/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png b/packages/stream_chat_flutter/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png similarity index 100% rename from packages/flutter_widgets/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png rename to packages/stream_chat_flutter/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png diff --git a/packages/flutter_widgets/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png b/packages/stream_chat_flutter/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png similarity index 100% rename from packages/flutter_widgets/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png rename to packages/stream_chat_flutter/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png diff --git a/packages/flutter_widgets/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png b/packages/stream_chat_flutter/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png similarity index 100% rename from packages/flutter_widgets/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png rename to packages/stream_chat_flutter/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png diff --git a/packages/flutter_widgets/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/packages/stream_chat_flutter/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png similarity index 100% rename from packages/flutter_widgets/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png rename to packages/stream_chat_flutter/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png diff --git a/packages/flutter_widgets/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png b/packages/stream_chat_flutter/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png similarity index 100% rename from packages/flutter_widgets/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png rename to packages/stream_chat_flutter/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png diff --git a/packages/flutter_widgets/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/packages/stream_chat_flutter/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png similarity index 100% rename from packages/flutter_widgets/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png rename to packages/stream_chat_flutter/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png diff --git a/packages/flutter_widgets/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png b/packages/stream_chat_flutter/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png similarity index 100% rename from packages/flutter_widgets/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png rename to packages/stream_chat_flutter/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png diff --git a/packages/flutter_widgets/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png b/packages/stream_chat_flutter/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png similarity index 100% rename from packages/flutter_widgets/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png rename to packages/stream_chat_flutter/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png diff --git a/packages/flutter_widgets/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/packages/stream_chat_flutter/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png similarity index 100% rename from packages/flutter_widgets/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png rename to packages/stream_chat_flutter/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png diff --git a/packages/flutter_widgets/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/packages/stream_chat_flutter/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png similarity index 100% rename from packages/flutter_widgets/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png rename to packages/stream_chat_flutter/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png diff --git a/packages/flutter_widgets/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/packages/stream_chat_flutter/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png similarity index 100% rename from packages/flutter_widgets/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png rename to packages/stream_chat_flutter/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png diff --git a/packages/flutter_widgets/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/packages/stream_chat_flutter/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png similarity index 100% rename from packages/flutter_widgets/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png rename to packages/stream_chat_flutter/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png diff --git a/packages/flutter_widgets/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/packages/stream_chat_flutter/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png similarity index 100% rename from packages/flutter_widgets/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png rename to packages/stream_chat_flutter/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png diff --git a/packages/flutter_widgets/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png b/packages/stream_chat_flutter/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png similarity index 100% rename from packages/flutter_widgets/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png rename to packages/stream_chat_flutter/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png diff --git a/packages/flutter_widgets/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png b/packages/stream_chat_flutter/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png similarity index 100% rename from packages/flutter_widgets/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png rename to packages/stream_chat_flutter/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png diff --git a/packages/flutter_widgets/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json b/packages/stream_chat_flutter/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json similarity index 100% rename from packages/flutter_widgets/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json rename to packages/stream_chat_flutter/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json diff --git a/packages/flutter_widgets/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png b/packages/stream_chat_flutter/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png similarity index 100% rename from packages/flutter_widgets/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png rename to packages/stream_chat_flutter/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png diff --git a/packages/flutter_widgets/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png b/packages/stream_chat_flutter/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png similarity index 100% rename from packages/flutter_widgets/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png rename to packages/stream_chat_flutter/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png diff --git a/packages/flutter_widgets/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png b/packages/stream_chat_flutter/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png similarity index 100% rename from packages/flutter_widgets/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png rename to packages/stream_chat_flutter/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png diff --git a/packages/flutter_widgets/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md b/packages/stream_chat_flutter/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md similarity index 100% rename from packages/flutter_widgets/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md rename to packages/stream_chat_flutter/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md diff --git a/packages/flutter_widgets/example/ios/Runner/Base.lproj/LaunchScreen.storyboard b/packages/stream_chat_flutter/example/ios/Runner/Base.lproj/LaunchScreen.storyboard similarity index 100% rename from packages/flutter_widgets/example/ios/Runner/Base.lproj/LaunchScreen.storyboard rename to packages/stream_chat_flutter/example/ios/Runner/Base.lproj/LaunchScreen.storyboard diff --git a/packages/flutter_widgets/example/ios/Runner/Base.lproj/Main.storyboard b/packages/stream_chat_flutter/example/ios/Runner/Base.lproj/Main.storyboard similarity index 100% rename from packages/flutter_widgets/example/ios/Runner/Base.lproj/Main.storyboard rename to packages/stream_chat_flutter/example/ios/Runner/Base.lproj/Main.storyboard diff --git a/packages/flutter_widgets/example/ios/Runner/Info.plist b/packages/stream_chat_flutter/example/ios/Runner/Info.plist similarity index 100% rename from packages/flutter_widgets/example/ios/Runner/Info.plist rename to packages/stream_chat_flutter/example/ios/Runner/Info.plist diff --git a/packages/flutter_widgets/example/ios/Runner/Runner-Bridging-Header.h b/packages/stream_chat_flutter/example/ios/Runner/Runner-Bridging-Header.h similarity index 100% rename from packages/flutter_widgets/example/ios/Runner/Runner-Bridging-Header.h rename to packages/stream_chat_flutter/example/ios/Runner/Runner-Bridging-Header.h diff --git a/packages/flutter_widgets/example/ios/Runner/Runner.entitlements b/packages/stream_chat_flutter/example/ios/Runner/Runner.entitlements similarity index 100% rename from packages/flutter_widgets/example/ios/Runner/Runner.entitlements rename to packages/stream_chat_flutter/example/ios/Runner/Runner.entitlements diff --git a/packages/flutter_widgets/example/ios/fastlane/Appfile b/packages/stream_chat_flutter/example/ios/fastlane/Appfile similarity index 100% rename from packages/flutter_widgets/example/ios/fastlane/Appfile rename to packages/stream_chat_flutter/example/ios/fastlane/Appfile diff --git a/packages/flutter_widgets/example/ios/fastlane/Fastfile b/packages/stream_chat_flutter/example/ios/fastlane/Fastfile similarity index 100% rename from packages/flutter_widgets/example/ios/fastlane/Fastfile rename to packages/stream_chat_flutter/example/ios/fastlane/Fastfile diff --git a/packages/flutter_widgets/example/ios/fastlane/Matchfile b/packages/stream_chat_flutter/example/ios/fastlane/Matchfile similarity index 100% rename from packages/flutter_widgets/example/ios/fastlane/Matchfile rename to packages/stream_chat_flutter/example/ios/fastlane/Matchfile diff --git a/packages/flutter_widgets/example/ios/fastlane/Pluginfile b/packages/stream_chat_flutter/example/ios/fastlane/Pluginfile similarity index 100% rename from packages/flutter_widgets/example/ios/fastlane/Pluginfile rename to packages/stream_chat_flutter/example/ios/fastlane/Pluginfile diff --git a/packages/flutter_widgets/example/ios/fastlane/README.md b/packages/stream_chat_flutter/example/ios/fastlane/README.md similarity index 100% rename from packages/flutter_widgets/example/ios/fastlane/README.md rename to packages/stream_chat_flutter/example/ios/fastlane/README.md diff --git a/packages/flutter_widgets/example/ios/fastlane/beta_gym_export_options.plist b/packages/stream_chat_flutter/example/ios/fastlane/beta_gym_export_options.plist similarity index 100% rename from packages/flutter_widgets/example/ios/fastlane/beta_gym_export_options.plist rename to packages/stream_chat_flutter/example/ios/fastlane/beta_gym_export_options.plist diff --git a/packages/flutter_widgets/example/ios/fastlane/report.xml b/packages/stream_chat_flutter/example/ios/fastlane/report.xml similarity index 100% rename from packages/flutter_widgets/example/ios/fastlane/report.xml rename to packages/stream_chat_flutter/example/ios/fastlane/report.xml diff --git a/packages/flutter_widgets/example/lib/advanced_options_page.dart b/packages/stream_chat_flutter/example/lib/advanced_options_page.dart similarity index 100% rename from packages/flutter_widgets/example/lib/advanced_options_page.dart rename to packages/stream_chat_flutter/example/lib/advanced_options_page.dart diff --git a/packages/flutter_widgets/example/lib/chat_info_screen.dart b/packages/stream_chat_flutter/example/lib/chat_info_screen.dart similarity index 100% rename from packages/flutter_widgets/example/lib/chat_info_screen.dart rename to packages/stream_chat_flutter/example/lib/chat_info_screen.dart diff --git a/packages/flutter_widgets/example/lib/chips_input_text_field.dart b/packages/stream_chat_flutter/example/lib/chips_input_text_field.dart similarity index 100% rename from packages/flutter_widgets/example/lib/chips_input_text_field.dart rename to packages/stream_chat_flutter/example/lib/chips_input_text_field.dart diff --git a/packages/flutter_widgets/example/lib/choose_user_page.dart b/packages/stream_chat_flutter/example/lib/choose_user_page.dart similarity index 100% rename from packages/flutter_widgets/example/lib/choose_user_page.dart rename to packages/stream_chat_flutter/example/lib/choose_user_page.dart diff --git a/packages/flutter_widgets/example/lib/custom_message.dart b/packages/stream_chat_flutter/example/lib/custom_message.dart similarity index 100% rename from packages/flutter_widgets/example/lib/custom_message.dart rename to packages/stream_chat_flutter/example/lib/custom_message.dart diff --git a/packages/flutter_widgets/example/lib/custom_theme.dart b/packages/stream_chat_flutter/example/lib/custom_theme.dart similarity index 100% rename from packages/flutter_widgets/example/lib/custom_theme.dart rename to packages/stream_chat_flutter/example/lib/custom_theme.dart diff --git a/packages/flutter_widgets/example/lib/customize_channel_preview.dart b/packages/stream_chat_flutter/example/lib/customize_channel_preview.dart similarity index 100% rename from packages/flutter_widgets/example/lib/customize_channel_preview.dart rename to packages/stream_chat_flutter/example/lib/customize_channel_preview.dart diff --git a/packages/flutter_widgets/example/lib/customize_message_widget.dart b/packages/stream_chat_flutter/example/lib/customize_message_widget.dart similarity index 100% rename from packages/flutter_widgets/example/lib/customize_message_widget.dart rename to packages/stream_chat_flutter/example/lib/customize_message_widget.dart diff --git a/packages/flutter_widgets/example/lib/group_chat_details_screen.dart b/packages/stream_chat_flutter/example/lib/group_chat_details_screen.dart similarity index 100% rename from packages/flutter_widgets/example/lib/group_chat_details_screen.dart rename to packages/stream_chat_flutter/example/lib/group_chat_details_screen.dart diff --git a/packages/flutter_widgets/example/lib/group_info_screen.dart b/packages/stream_chat_flutter/example/lib/group_info_screen.dart similarity index 100% rename from packages/flutter_widgets/example/lib/group_info_screen.dart rename to packages/stream_chat_flutter/example/lib/group_info_screen.dart diff --git a/packages/flutter_widgets/example/lib/main.dart b/packages/stream_chat_flutter/example/lib/main.dart similarity index 100% rename from packages/flutter_widgets/example/lib/main.dart rename to packages/stream_chat_flutter/example/lib/main.dart diff --git a/packages/flutter_widgets/example/lib/multiple_conversation.dart b/packages/stream_chat_flutter/example/lib/multiple_conversation.dart similarity index 100% rename from packages/flutter_widgets/example/lib/multiple_conversation.dart rename to packages/stream_chat_flutter/example/lib/multiple_conversation.dart diff --git a/packages/flutter_widgets/example/lib/new_chat_screen.dart b/packages/stream_chat_flutter/example/lib/new_chat_screen.dart similarity index 100% rename from packages/flutter_widgets/example/lib/new_chat_screen.dart rename to packages/stream_chat_flutter/example/lib/new_chat_screen.dart diff --git a/packages/flutter_widgets/example/lib/new_group_chat_screen.dart b/packages/stream_chat_flutter/example/lib/new_group_chat_screen.dart similarity index 100% rename from packages/flutter_widgets/example/lib/new_group_chat_screen.dart rename to packages/stream_chat_flutter/example/lib/new_group_chat_screen.dart diff --git a/packages/flutter_widgets/example/lib/notifications_service.dart b/packages/stream_chat_flutter/example/lib/notifications_service.dart similarity index 100% rename from packages/flutter_widgets/example/lib/notifications_service.dart rename to packages/stream_chat_flutter/example/lib/notifications_service.dart diff --git a/packages/flutter_widgets/example/lib/routes/app_routes.dart b/packages/stream_chat_flutter/example/lib/routes/app_routes.dart similarity index 100% rename from packages/flutter_widgets/example/lib/routes/app_routes.dart rename to packages/stream_chat_flutter/example/lib/routes/app_routes.dart diff --git a/packages/flutter_widgets/example/lib/routes/routes.dart b/packages/stream_chat_flutter/example/lib/routes/routes.dart similarity index 100% rename from packages/flutter_widgets/example/lib/routes/routes.dart rename to packages/stream_chat_flutter/example/lib/routes/routes.dart diff --git a/packages/flutter_widgets/example/lib/search_text_field.dart b/packages/stream_chat_flutter/example/lib/search_text_field.dart similarity index 100% rename from packages/flutter_widgets/example/lib/search_text_field.dart rename to packages/stream_chat_flutter/example/lib/search_text_field.dart diff --git a/packages/flutter_widgets/example/lib/single_conversation.dart b/packages/stream_chat_flutter/example/lib/single_conversation.dart similarity index 100% rename from packages/flutter_widgets/example/lib/single_conversation.dart rename to packages/stream_chat_flutter/example/lib/single_conversation.dart diff --git a/packages/flutter_widgets/example/lib/split_view.dart b/packages/stream_chat_flutter/example/lib/split_view.dart similarity index 100% rename from packages/flutter_widgets/example/lib/split_view.dart rename to packages/stream_chat_flutter/example/lib/split_view.dart diff --git a/packages/flutter_widgets/example/lib/stream_version.dart b/packages/stream_chat_flutter/example/lib/stream_version.dart similarity index 100% rename from packages/flutter_widgets/example/lib/stream_version.dart rename to packages/stream_chat_flutter/example/lib/stream_version.dart diff --git a/packages/flutter_widgets/example/lib/threads.dart b/packages/stream_chat_flutter/example/lib/threads.dart similarity index 100% rename from packages/flutter_widgets/example/lib/threads.dart rename to packages/stream_chat_flutter/example/lib/threads.dart diff --git a/packages/flutter_widgets/example/pubspec.yaml b/packages/stream_chat_flutter/example/pubspec.yaml similarity index 100% rename from packages/flutter_widgets/example/pubspec.yaml rename to packages/stream_chat_flutter/example/pubspec.yaml diff --git a/packages/flutter_widgets/example/test_driver/single_conversation.dart b/packages/stream_chat_flutter/example/test_driver/single_conversation.dart similarity index 100% rename from packages/flutter_widgets/example/test_driver/single_conversation.dart rename to packages/stream_chat_flutter/example/test_driver/single_conversation.dart diff --git a/packages/flutter_widgets/example/test_driver/single_conversation_test.dart b/packages/stream_chat_flutter/example/test_driver/single_conversation_test.dart similarity index 100% rename from packages/flutter_widgets/example/test_driver/single_conversation_test.dart rename to packages/stream_chat_flutter/example/test_driver/single_conversation_test.dart diff --git a/packages/flutter_widgets/example/web/favicon.png b/packages/stream_chat_flutter/example/web/favicon.png similarity index 100% rename from packages/flutter_widgets/example/web/favicon.png rename to packages/stream_chat_flutter/example/web/favicon.png diff --git a/packages/flutter_widgets/example/web/icons/Icon-192.png b/packages/stream_chat_flutter/example/web/icons/Icon-192.png similarity index 100% rename from packages/flutter_widgets/example/web/icons/Icon-192.png rename to packages/stream_chat_flutter/example/web/icons/Icon-192.png diff --git a/packages/flutter_widgets/example/web/icons/Icon-512.png b/packages/stream_chat_flutter/example/web/icons/Icon-512.png similarity index 100% rename from packages/flutter_widgets/example/web/icons/Icon-512.png rename to packages/stream_chat_flutter/example/web/icons/Icon-512.png diff --git a/packages/flutter_widgets/example/web/index.html b/packages/stream_chat_flutter/example/web/index.html similarity index 100% rename from packages/flutter_widgets/example/web/index.html rename to packages/stream_chat_flutter/example/web/index.html diff --git a/packages/flutter_widgets/example/web/manifest.json b/packages/stream_chat_flutter/example/web/manifest.json similarity index 100% rename from packages/flutter_widgets/example/web/manifest.json rename to packages/stream_chat_flutter/example/web/manifest.json diff --git a/packages/flutter_widgets/example/web/sql-wasm.js b/packages/stream_chat_flutter/example/web/sql-wasm.js similarity index 100% rename from packages/flutter_widgets/example/web/sql-wasm.js rename to packages/stream_chat_flutter/example/web/sql-wasm.js diff --git a/packages/flutter_widgets/example/web/sql-wasm.wasm b/packages/stream_chat_flutter/example/web/sql-wasm.wasm similarity index 100% rename from packages/flutter_widgets/example/web/sql-wasm.wasm rename to packages/stream_chat_flutter/example/web/sql-wasm.wasm diff --git a/packages/flutter_widgets/images/giphy_icon.png b/packages/stream_chat_flutter/images/giphy_icon.png similarity index 100% rename from packages/flutter_widgets/images/giphy_icon.png rename to packages/stream_chat_flutter/images/giphy_icon.png diff --git a/packages/flutter_widgets/images/placeholder.png b/packages/stream_chat_flutter/images/placeholder.png similarity index 100% rename from packages/flutter_widgets/images/placeholder.png rename to packages/stream_chat_flutter/images/placeholder.png diff --git a/packages/flutter_widgets/lib/src/attachment_error.dart b/packages/stream_chat_flutter/lib/src/attachment_error.dart similarity index 100% rename from packages/flutter_widgets/lib/src/attachment_error.dart rename to packages/stream_chat_flutter/lib/src/attachment_error.dart diff --git a/packages/flutter_widgets/lib/src/attachment_title.dart b/packages/stream_chat_flutter/lib/src/attachment_title.dart similarity index 100% rename from packages/flutter_widgets/lib/src/attachment_title.dart rename to packages/stream_chat_flutter/lib/src/attachment_title.dart diff --git a/packages/flutter_widgets/lib/src/back_button.dart b/packages/stream_chat_flutter/lib/src/back_button.dart similarity index 100% rename from packages/flutter_widgets/lib/src/back_button.dart rename to packages/stream_chat_flutter/lib/src/back_button.dart diff --git a/packages/flutter_widgets/lib/src/channel_bottom_sheet.dart b/packages/stream_chat_flutter/lib/src/channel_bottom_sheet.dart similarity index 100% rename from packages/flutter_widgets/lib/src/channel_bottom_sheet.dart rename to packages/stream_chat_flutter/lib/src/channel_bottom_sheet.dart diff --git a/packages/flutter_widgets/lib/src/channel_file_display_screen.dart b/packages/stream_chat_flutter/lib/src/channel_file_display_screen.dart similarity index 100% rename from packages/flutter_widgets/lib/src/channel_file_display_screen.dart rename to packages/stream_chat_flutter/lib/src/channel_file_display_screen.dart diff --git a/packages/flutter_widgets/lib/src/channel_header.dart b/packages/stream_chat_flutter/lib/src/channel_header.dart similarity index 100% rename from packages/flutter_widgets/lib/src/channel_header.dart rename to packages/stream_chat_flutter/lib/src/channel_header.dart diff --git a/packages/flutter_widgets/lib/src/channel_image.dart b/packages/stream_chat_flutter/lib/src/channel_image.dart similarity index 100% rename from packages/flutter_widgets/lib/src/channel_image.dart rename to packages/stream_chat_flutter/lib/src/channel_image.dart diff --git a/packages/flutter_widgets/lib/src/channel_info.dart b/packages/stream_chat_flutter/lib/src/channel_info.dart similarity index 100% rename from packages/flutter_widgets/lib/src/channel_info.dart rename to packages/stream_chat_flutter/lib/src/channel_info.dart diff --git a/packages/flutter_widgets/lib/src/channel_list_header.dart b/packages/stream_chat_flutter/lib/src/channel_list_header.dart similarity index 100% rename from packages/flutter_widgets/lib/src/channel_list_header.dart rename to packages/stream_chat_flutter/lib/src/channel_list_header.dart diff --git a/packages/flutter_widgets/lib/src/channel_list_view.dart b/packages/stream_chat_flutter/lib/src/channel_list_view.dart similarity index 100% rename from packages/flutter_widgets/lib/src/channel_list_view.dart rename to packages/stream_chat_flutter/lib/src/channel_list_view.dart diff --git a/packages/flutter_widgets/lib/src/channel_media_display_screen.dart b/packages/stream_chat_flutter/lib/src/channel_media_display_screen.dart similarity index 100% rename from packages/flutter_widgets/lib/src/channel_media_display_screen.dart rename to packages/stream_chat_flutter/lib/src/channel_media_display_screen.dart diff --git a/packages/flutter_widgets/lib/src/channel_name.dart b/packages/stream_chat_flutter/lib/src/channel_name.dart similarity index 100% rename from packages/flutter_widgets/lib/src/channel_name.dart rename to packages/stream_chat_flutter/lib/src/channel_name.dart diff --git a/packages/flutter_widgets/lib/src/channel_preview.dart b/packages/stream_chat_flutter/lib/src/channel_preview.dart similarity index 100% rename from packages/flutter_widgets/lib/src/channel_preview.dart rename to packages/stream_chat_flutter/lib/src/channel_preview.dart diff --git a/packages/flutter_widgets/lib/src/channel_unread_indicator.dart b/packages/stream_chat_flutter/lib/src/channel_unread_indicator.dart similarity index 100% rename from packages/flutter_widgets/lib/src/channel_unread_indicator.dart rename to packages/stream_chat_flutter/lib/src/channel_unread_indicator.dart diff --git a/packages/flutter_widgets/lib/src/compress_video_service.dart b/packages/stream_chat_flutter/lib/src/compress_video_service.dart similarity index 100% rename from packages/flutter_widgets/lib/src/compress_video_service.dart rename to packages/stream_chat_flutter/lib/src/compress_video_service.dart diff --git a/packages/flutter_widgets/lib/src/connection_status_builder.dart b/packages/stream_chat_flutter/lib/src/connection_status_builder.dart similarity index 100% rename from packages/flutter_widgets/lib/src/connection_status_builder.dart rename to packages/stream_chat_flutter/lib/src/connection_status_builder.dart diff --git a/packages/flutter_widgets/lib/src/date_divider.dart b/packages/stream_chat_flutter/lib/src/date_divider.dart similarity index 100% rename from packages/flutter_widgets/lib/src/date_divider.dart rename to packages/stream_chat_flutter/lib/src/date_divider.dart diff --git a/packages/flutter_widgets/lib/src/deleted_message.dart b/packages/stream_chat_flutter/lib/src/deleted_message.dart similarity index 100% rename from packages/flutter_widgets/lib/src/deleted_message.dart rename to packages/stream_chat_flutter/lib/src/deleted_message.dart diff --git a/packages/flutter_widgets/lib/src/extension.dart b/packages/stream_chat_flutter/lib/src/extension.dart similarity index 100% rename from packages/flutter_widgets/lib/src/extension.dart rename to packages/stream_chat_flutter/lib/src/extension.dart diff --git a/packages/flutter_widgets/lib/src/file_attachment.dart b/packages/stream_chat_flutter/lib/src/file_attachment.dart similarity index 100% rename from packages/flutter_widgets/lib/src/file_attachment.dart rename to packages/stream_chat_flutter/lib/src/file_attachment.dart diff --git a/packages/flutter_widgets/lib/src/full_screen_media.dart b/packages/stream_chat_flutter/lib/src/full_screen_media.dart similarity index 100% rename from packages/flutter_widgets/lib/src/full_screen_media.dart rename to packages/stream_chat_flutter/lib/src/full_screen_media.dart diff --git a/packages/flutter_widgets/lib/src/giphy_attachment.dart b/packages/stream_chat_flutter/lib/src/giphy_attachment.dart similarity index 100% rename from packages/flutter_widgets/lib/src/giphy_attachment.dart rename to packages/stream_chat_flutter/lib/src/giphy_attachment.dart diff --git a/packages/flutter_widgets/lib/src/group_image.dart b/packages/stream_chat_flutter/lib/src/group_image.dart similarity index 100% rename from packages/flutter_widgets/lib/src/group_image.dart rename to packages/stream_chat_flutter/lib/src/group_image.dart diff --git a/packages/flutter_widgets/lib/src/image_actions_modal.dart b/packages/stream_chat_flutter/lib/src/image_actions_modal.dart similarity index 100% rename from packages/flutter_widgets/lib/src/image_actions_modal.dart rename to packages/stream_chat_flutter/lib/src/image_actions_modal.dart diff --git a/packages/flutter_widgets/lib/src/image_attachment.dart b/packages/stream_chat_flutter/lib/src/image_attachment.dart similarity index 100% rename from packages/flutter_widgets/lib/src/image_attachment.dart rename to packages/stream_chat_flutter/lib/src/image_attachment.dart diff --git a/packages/flutter_widgets/lib/src/image_footer.dart b/packages/stream_chat_flutter/lib/src/image_footer.dart similarity index 100% rename from packages/flutter_widgets/lib/src/image_footer.dart rename to packages/stream_chat_flutter/lib/src/image_footer.dart diff --git a/packages/flutter_widgets/lib/src/image_group.dart b/packages/stream_chat_flutter/lib/src/image_group.dart similarity index 100% rename from packages/flutter_widgets/lib/src/image_group.dart rename to packages/stream_chat_flutter/lib/src/image_group.dart diff --git a/packages/flutter_widgets/lib/src/image_header.dart b/packages/stream_chat_flutter/lib/src/image_header.dart similarity index 100% rename from packages/flutter_widgets/lib/src/image_header.dart rename to packages/stream_chat_flutter/lib/src/image_header.dart diff --git a/packages/flutter_widgets/lib/src/info_tile.dart b/packages/stream_chat_flutter/lib/src/info_tile.dart similarity index 100% rename from packages/flutter_widgets/lib/src/info_tile.dart rename to packages/stream_chat_flutter/lib/src/info_tile.dart diff --git a/packages/flutter_widgets/lib/src/media_list_view.dart b/packages/stream_chat_flutter/lib/src/media_list_view.dart similarity index 100% rename from packages/flutter_widgets/lib/src/media_list_view.dart rename to packages/stream_chat_flutter/lib/src/media_list_view.dart diff --git a/packages/flutter_widgets/lib/src/media_utils.dart b/packages/stream_chat_flutter/lib/src/media_utils.dart similarity index 100% rename from packages/flutter_widgets/lib/src/media_utils.dart rename to packages/stream_chat_flutter/lib/src/media_utils.dart diff --git a/packages/flutter_widgets/lib/src/message_actions_modal.dart b/packages/stream_chat_flutter/lib/src/message_actions_modal.dart similarity index 100% rename from packages/flutter_widgets/lib/src/message_actions_modal.dart rename to packages/stream_chat_flutter/lib/src/message_actions_modal.dart diff --git a/packages/flutter_widgets/lib/src/message_input.dart b/packages/stream_chat_flutter/lib/src/message_input.dart similarity index 100% rename from packages/flutter_widgets/lib/src/message_input.dart rename to packages/stream_chat_flutter/lib/src/message_input.dart diff --git a/packages/flutter_widgets/lib/src/message_list_view.dart b/packages/stream_chat_flutter/lib/src/message_list_view.dart similarity index 100% rename from packages/flutter_widgets/lib/src/message_list_view.dart rename to packages/stream_chat_flutter/lib/src/message_list_view.dart diff --git a/packages/flutter_widgets/lib/src/message_reactions_modal.dart b/packages/stream_chat_flutter/lib/src/message_reactions_modal.dart similarity index 100% rename from packages/flutter_widgets/lib/src/message_reactions_modal.dart rename to packages/stream_chat_flutter/lib/src/message_reactions_modal.dart diff --git a/packages/flutter_widgets/lib/src/message_search_item.dart b/packages/stream_chat_flutter/lib/src/message_search_item.dart similarity index 100% rename from packages/flutter_widgets/lib/src/message_search_item.dart rename to packages/stream_chat_flutter/lib/src/message_search_item.dart diff --git a/packages/flutter_widgets/lib/src/message_search_list_view.dart b/packages/stream_chat_flutter/lib/src/message_search_list_view.dart similarity index 100% rename from packages/flutter_widgets/lib/src/message_search_list_view.dart rename to packages/stream_chat_flutter/lib/src/message_search_list_view.dart diff --git a/packages/flutter_widgets/lib/src/message_text.dart b/packages/stream_chat_flutter/lib/src/message_text.dart similarity index 100% rename from packages/flutter_widgets/lib/src/message_text.dart rename to packages/stream_chat_flutter/lib/src/message_text.dart diff --git a/packages/flutter_widgets/lib/src/message_widget.dart b/packages/stream_chat_flutter/lib/src/message_widget.dart similarity index 100% rename from packages/flutter_widgets/lib/src/message_widget.dart rename to packages/stream_chat_flutter/lib/src/message_widget.dart diff --git a/packages/flutter_widgets/lib/src/option_list_tile.dart b/packages/stream_chat_flutter/lib/src/option_list_tile.dart similarity index 100% rename from packages/flutter_widgets/lib/src/option_list_tile.dart rename to packages/stream_chat_flutter/lib/src/option_list_tile.dart diff --git a/packages/flutter_widgets/lib/src/quoted_message_widget.dart b/packages/stream_chat_flutter/lib/src/quoted_message_widget.dart similarity index 100% rename from packages/flutter_widgets/lib/src/quoted_message_widget.dart rename to packages/stream_chat_flutter/lib/src/quoted_message_widget.dart diff --git a/packages/flutter_widgets/lib/src/reaction_bubble.dart b/packages/stream_chat_flutter/lib/src/reaction_bubble.dart similarity index 100% rename from packages/flutter_widgets/lib/src/reaction_bubble.dart rename to packages/stream_chat_flutter/lib/src/reaction_bubble.dart diff --git a/packages/flutter_widgets/lib/src/reaction_icon.dart b/packages/stream_chat_flutter/lib/src/reaction_icon.dart similarity index 100% rename from packages/flutter_widgets/lib/src/reaction_icon.dart rename to packages/stream_chat_flutter/lib/src/reaction_icon.dart diff --git a/packages/flutter_widgets/lib/src/reaction_picker.dart b/packages/stream_chat_flutter/lib/src/reaction_picker.dart similarity index 100% rename from packages/flutter_widgets/lib/src/reaction_picker.dart rename to packages/stream_chat_flutter/lib/src/reaction_picker.dart diff --git a/packages/flutter_widgets/lib/src/sending_indicator.dart b/packages/stream_chat_flutter/lib/src/sending_indicator.dart similarity index 100% rename from packages/flutter_widgets/lib/src/sending_indicator.dart rename to packages/stream_chat_flutter/lib/src/sending_indicator.dart diff --git a/packages/flutter_widgets/lib/src/stream_chat.dart b/packages/stream_chat_flutter/lib/src/stream_chat.dart similarity index 100% rename from packages/flutter_widgets/lib/src/stream_chat.dart rename to packages/stream_chat_flutter/lib/src/stream_chat.dart diff --git a/packages/flutter_widgets/lib/src/stream_chat_theme.dart b/packages/stream_chat_flutter/lib/src/stream_chat_theme.dart similarity index 100% rename from packages/flutter_widgets/lib/src/stream_chat_theme.dart rename to packages/stream_chat_flutter/lib/src/stream_chat_theme.dart diff --git a/packages/flutter_widgets/lib/src/stream_neumorphic_button.dart b/packages/stream_chat_flutter/lib/src/stream_neumorphic_button.dart similarity index 100% rename from packages/flutter_widgets/lib/src/stream_neumorphic_button.dart rename to packages/stream_chat_flutter/lib/src/stream_neumorphic_button.dart diff --git a/packages/flutter_widgets/lib/src/stream_svg_icon.dart b/packages/stream_chat_flutter/lib/src/stream_svg_icon.dart similarity index 100% rename from packages/flutter_widgets/lib/src/stream_svg_icon.dart rename to packages/stream_chat_flutter/lib/src/stream_svg_icon.dart diff --git a/packages/flutter_widgets/lib/src/swipeable.dart b/packages/stream_chat_flutter/lib/src/swipeable.dart similarity index 100% rename from packages/flutter_widgets/lib/src/swipeable.dart rename to packages/stream_chat_flutter/lib/src/swipeable.dart diff --git a/packages/flutter_widgets/lib/src/system_message.dart b/packages/stream_chat_flutter/lib/src/system_message.dart similarity index 100% rename from packages/flutter_widgets/lib/src/system_message.dart rename to packages/stream_chat_flutter/lib/src/system_message.dart diff --git a/packages/flutter_widgets/lib/src/thread_header.dart b/packages/stream_chat_flutter/lib/src/thread_header.dart similarity index 100% rename from packages/flutter_widgets/lib/src/thread_header.dart rename to packages/stream_chat_flutter/lib/src/thread_header.dart diff --git a/packages/flutter_widgets/lib/src/typing_indicator.dart b/packages/stream_chat_flutter/lib/src/typing_indicator.dart similarity index 100% rename from packages/flutter_widgets/lib/src/typing_indicator.dart rename to packages/stream_chat_flutter/lib/src/typing_indicator.dart diff --git a/packages/flutter_widgets/lib/src/unread_indicator.dart b/packages/stream_chat_flutter/lib/src/unread_indicator.dart similarity index 100% rename from packages/flutter_widgets/lib/src/unread_indicator.dart rename to packages/stream_chat_flutter/lib/src/unread_indicator.dart diff --git a/packages/flutter_widgets/lib/src/url_attachment.dart b/packages/stream_chat_flutter/lib/src/url_attachment.dart similarity index 100% rename from packages/flutter_widgets/lib/src/url_attachment.dart rename to packages/stream_chat_flutter/lib/src/url_attachment.dart diff --git a/packages/flutter_widgets/lib/src/user_avatar.dart b/packages/stream_chat_flutter/lib/src/user_avatar.dart similarity index 100% rename from packages/flutter_widgets/lib/src/user_avatar.dart rename to packages/stream_chat_flutter/lib/src/user_avatar.dart diff --git a/packages/flutter_widgets/lib/src/user_item.dart b/packages/stream_chat_flutter/lib/src/user_item.dart similarity index 100% rename from packages/flutter_widgets/lib/src/user_item.dart rename to packages/stream_chat_flutter/lib/src/user_item.dart diff --git a/packages/flutter_widgets/lib/src/user_list_view.dart b/packages/stream_chat_flutter/lib/src/user_list_view.dart similarity index 100% rename from packages/flutter_widgets/lib/src/user_list_view.dart rename to packages/stream_chat_flutter/lib/src/user_list_view.dart diff --git a/packages/flutter_widgets/lib/src/user_reaction_display.dart b/packages/stream_chat_flutter/lib/src/user_reaction_display.dart similarity index 100% rename from packages/flutter_widgets/lib/src/user_reaction_display.dart rename to packages/stream_chat_flutter/lib/src/user_reaction_display.dart diff --git a/packages/flutter_widgets/lib/src/utils.dart b/packages/stream_chat_flutter/lib/src/utils.dart similarity index 100% rename from packages/flutter_widgets/lib/src/utils.dart rename to packages/stream_chat_flutter/lib/src/utils.dart diff --git a/packages/flutter_widgets/lib/src/video_attachment.dart b/packages/stream_chat_flutter/lib/src/video_attachment.dart similarity index 100% rename from packages/flutter_widgets/lib/src/video_attachment.dart rename to packages/stream_chat_flutter/lib/src/video_attachment.dart diff --git a/packages/flutter_widgets/lib/stream_chat_flutter.dart b/packages/stream_chat_flutter/lib/stream_chat_flutter.dart similarity index 100% rename from packages/flutter_widgets/lib/stream_chat_flutter.dart rename to packages/stream_chat_flutter/lib/stream_chat_flutter.dart diff --git a/packages/flutter_widgets/lib/svgs/Empty State_Camera.svg b/packages/stream_chat_flutter/lib/svgs/Empty State_Camera.svg similarity index 100% rename from packages/flutter_widgets/lib/svgs/Empty State_Camera.svg rename to packages/stream_chat_flutter/lib/svgs/Empty State_Camera.svg diff --git a/packages/flutter_widgets/lib/svgs/Empty State_Files.svg b/packages/stream_chat_flutter/lib/svgs/Empty State_Files.svg similarity index 100% rename from packages/flutter_widgets/lib/svgs/Empty State_Files.svg rename to packages/stream_chat_flutter/lib/svgs/Empty State_Files.svg diff --git a/packages/flutter_widgets/lib/svgs/Empty State_No channel.svg b/packages/stream_chat_flutter/lib/svgs/Empty State_No channel.svg similarity index 100% rename from packages/flutter_widgets/lib/svgs/Empty State_No channel.svg rename to packages/stream_chat_flutter/lib/svgs/Empty State_No channel.svg diff --git a/packages/flutter_widgets/lib/svgs/Empty State_Search.svg b/packages/stream_chat_flutter/lib/svgs/Empty State_Search.svg similarity index 100% rename from packages/flutter_widgets/lib/svgs/Empty State_Search.svg rename to packages/stream_chat_flutter/lib/svgs/Empty State_Search.svg diff --git a/packages/flutter_widgets/lib/svgs/Empty State_picture.svg b/packages/stream_chat_flutter/lib/svgs/Empty State_picture.svg similarity index 100% rename from packages/flutter_widgets/lib/svgs/Empty State_picture.svg rename to packages/stream_chat_flutter/lib/svgs/Empty State_picture.svg diff --git a/packages/flutter_widgets/lib/svgs/Giphy icon.svg b/packages/stream_chat_flutter/lib/svgs/Giphy icon.svg similarity index 100% rename from packages/flutter_widgets/lib/svgs/Giphy icon.svg rename to packages/stream_chat_flutter/lib/svgs/Giphy icon.svg diff --git a/packages/flutter_widgets/lib/svgs/Icon_LOL_reaction.svg b/packages/stream_chat_flutter/lib/svgs/Icon_LOL_reaction.svg similarity index 100% rename from packages/flutter_widgets/lib/svgs/Icon_LOL_reaction.svg rename to packages/stream_chat_flutter/lib/svgs/Icon_LOL_reaction.svg diff --git a/packages/flutter_widgets/lib/svgs/Icon_Thread_Reply.svg b/packages/stream_chat_flutter/lib/svgs/Icon_Thread_Reply.svg similarity index 100% rename from packages/flutter_widgets/lib/svgs/Icon_Thread_Reply.svg rename to packages/stream_chat_flutter/lib/svgs/Icon_Thread_Reply.svg diff --git a/packages/flutter_widgets/lib/svgs/Icon_User_add.svg b/packages/stream_chat_flutter/lib/svgs/Icon_User_add.svg similarity index 100% rename from packages/flutter_widgets/lib/svgs/Icon_User_add.svg rename to packages/stream_chat_flutter/lib/svgs/Icon_User_add.svg diff --git a/packages/flutter_widgets/lib/svgs/Icon_User_deselect.svg b/packages/stream_chat_flutter/lib/svgs/Icon_User_deselect.svg similarity index 100% rename from packages/flutter_widgets/lib/svgs/Icon_User_deselect.svg rename to packages/stream_chat_flutter/lib/svgs/Icon_User_deselect.svg diff --git a/packages/flutter_widgets/lib/svgs/Icon_arrow_right.svg b/packages/stream_chat_flutter/lib/svgs/Icon_arrow_right.svg similarity index 100% rename from packages/flutter_widgets/lib/svgs/Icon_arrow_right.svg rename to packages/stream_chat_flutter/lib/svgs/Icon_arrow_right.svg diff --git a/packages/flutter_widgets/lib/svgs/Icon_attach.svg b/packages/stream_chat_flutter/lib/svgs/Icon_attach.svg similarity index 100% rename from packages/flutter_widgets/lib/svgs/Icon_attach.svg rename to packages/stream_chat_flutter/lib/svgs/Icon_attach.svg diff --git a/packages/flutter_widgets/lib/svgs/Icon_camera.svg b/packages/stream_chat_flutter/lib/svgs/Icon_camera.svg similarity index 100% rename from packages/flutter_widgets/lib/svgs/Icon_camera.svg rename to packages/stream_chat_flutter/lib/svgs/Icon_camera.svg diff --git a/packages/flutter_widgets/lib/svgs/Icon_check.svg b/packages/stream_chat_flutter/lib/svgs/Icon_check.svg similarity index 100% rename from packages/flutter_widgets/lib/svgs/Icon_check.svg rename to packages/stream_chat_flutter/lib/svgs/Icon_check.svg diff --git a/packages/flutter_widgets/lib/svgs/Icon_check_all.svg b/packages/stream_chat_flutter/lib/svgs/Icon_check_all.svg similarity index 100% rename from packages/flutter_widgets/lib/svgs/Icon_check_all.svg rename to packages/stream_chat_flutter/lib/svgs/Icon_check_all.svg diff --git a/packages/flutter_widgets/lib/svgs/Icon_check_big.svg b/packages/stream_chat_flutter/lib/svgs/Icon_check_big.svg similarity index 100% rename from packages/flutter_widgets/lib/svgs/Icon_check_big.svg rename to packages/stream_chat_flutter/lib/svgs/Icon_check_big.svg diff --git a/packages/flutter_widgets/lib/svgs/Icon_check_send.svg b/packages/stream_chat_flutter/lib/svgs/Icon_check_send.svg similarity index 100% rename from packages/flutter_widgets/lib/svgs/Icon_check_send.svg rename to packages/stream_chat_flutter/lib/svgs/Icon_check_send.svg diff --git a/packages/flutter_widgets/lib/svgs/Icon_circle_right.svg b/packages/stream_chat_flutter/lib/svgs/Icon_circle_right.svg similarity index 100% rename from packages/flutter_widgets/lib/svgs/Icon_circle_right.svg rename to packages/stream_chat_flutter/lib/svgs/Icon_circle_right.svg diff --git a/packages/flutter_widgets/lib/svgs/Icon_circle_up.svg b/packages/stream_chat_flutter/lib/svgs/Icon_circle_up.svg similarity index 100% rename from packages/flutter_widgets/lib/svgs/Icon_circle_up.svg rename to packages/stream_chat_flutter/lib/svgs/Icon_circle_up.svg diff --git a/packages/flutter_widgets/lib/svgs/Icon_close.svg b/packages/stream_chat_flutter/lib/svgs/Icon_close.svg similarity index 100% rename from packages/flutter_widgets/lib/svgs/Icon_close.svg rename to packages/stream_chat_flutter/lib/svgs/Icon_close.svg diff --git a/packages/flutter_widgets/lib/svgs/Icon_close_black.svg b/packages/stream_chat_flutter/lib/svgs/Icon_close_black.svg similarity index 100% rename from packages/flutter_widgets/lib/svgs/Icon_close_black.svg rename to packages/stream_chat_flutter/lib/svgs/Icon_close_black.svg diff --git a/packages/flutter_widgets/lib/svgs/Icon_close_sml.svg b/packages/stream_chat_flutter/lib/svgs/Icon_close_sml.svg similarity index 100% rename from packages/flutter_widgets/lib/svgs/Icon_close_sml.svg rename to packages/stream_chat_flutter/lib/svgs/Icon_close_sml.svg diff --git a/packages/flutter_widgets/lib/svgs/Icon_cloud_download.svg b/packages/stream_chat_flutter/lib/svgs/Icon_cloud_download.svg similarity index 100% rename from packages/flutter_widgets/lib/svgs/Icon_cloud_download.svg rename to packages/stream_chat_flutter/lib/svgs/Icon_cloud_download.svg diff --git a/packages/flutter_widgets/lib/svgs/Icon_contacts.svg b/packages/stream_chat_flutter/lib/svgs/Icon_contacts.svg similarity index 100% rename from packages/flutter_widgets/lib/svgs/Icon_contacts.svg rename to packages/stream_chat_flutter/lib/svgs/Icon_contacts.svg diff --git a/packages/flutter_widgets/lib/svgs/Icon_copy.svg b/packages/stream_chat_flutter/lib/svgs/Icon_copy.svg similarity index 100% rename from packages/flutter_widgets/lib/svgs/Icon_copy.svg rename to packages/stream_chat_flutter/lib/svgs/Icon_copy.svg diff --git a/packages/flutter_widgets/lib/svgs/Icon_curve_line_left_up.svg b/packages/stream_chat_flutter/lib/svgs/Icon_curve_line_left_up.svg similarity index 100% rename from packages/flutter_widgets/lib/svgs/Icon_curve_line_left_up.svg rename to packages/stream_chat_flutter/lib/svgs/Icon_curve_line_left_up.svg diff --git a/packages/flutter_widgets/lib/svgs/Icon_curve_line_left_up_big.svg b/packages/stream_chat_flutter/lib/svgs/Icon_curve_line_left_up_big.svg similarity index 100% rename from packages/flutter_widgets/lib/svgs/Icon_curve_line_left_up_big.svg rename to packages/stream_chat_flutter/lib/svgs/Icon_curve_line_left_up_big.svg diff --git a/packages/flutter_widgets/lib/svgs/Icon_delete.svg b/packages/stream_chat_flutter/lib/svgs/Icon_delete.svg similarity index 100% rename from packages/flutter_widgets/lib/svgs/Icon_delete.svg rename to packages/stream_chat_flutter/lib/svgs/Icon_delete.svg diff --git a/packages/flutter_widgets/lib/svgs/Icon_down.svg b/packages/stream_chat_flutter/lib/svgs/Icon_down.svg similarity index 100% rename from packages/flutter_widgets/lib/svgs/Icon_down.svg rename to packages/stream_chat_flutter/lib/svgs/Icon_down.svg diff --git a/packages/flutter_widgets/lib/svgs/Icon_download.svg b/packages/stream_chat_flutter/lib/svgs/Icon_download.svg similarity index 100% rename from packages/flutter_widgets/lib/svgs/Icon_download.svg rename to packages/stream_chat_flutter/lib/svgs/Icon_download.svg diff --git a/packages/flutter_widgets/lib/svgs/Icon_edit.svg b/packages/stream_chat_flutter/lib/svgs/Icon_edit.svg similarity index 100% rename from packages/flutter_widgets/lib/svgs/Icon_edit.svg rename to packages/stream_chat_flutter/lib/svgs/Icon_edit.svg diff --git a/packages/flutter_widgets/lib/svgs/Icon_empty_circle_left.svg b/packages/stream_chat_flutter/lib/svgs/Icon_empty_circle_left.svg similarity index 100% rename from packages/flutter_widgets/lib/svgs/Icon_empty_circle_left.svg rename to packages/stream_chat_flutter/lib/svgs/Icon_empty_circle_left.svg diff --git a/packages/flutter_widgets/lib/svgs/Icon_error.svg b/packages/stream_chat_flutter/lib/svgs/Icon_error.svg similarity index 100% rename from packages/flutter_widgets/lib/svgs/Icon_error.svg rename to packages/stream_chat_flutter/lib/svgs/Icon_error.svg diff --git a/packages/flutter_widgets/lib/svgs/Icon_eye-off.svg b/packages/stream_chat_flutter/lib/svgs/Icon_eye-off.svg similarity index 100% rename from packages/flutter_widgets/lib/svgs/Icon_eye-off.svg rename to packages/stream_chat_flutter/lib/svgs/Icon_eye-off.svg diff --git a/packages/flutter_widgets/lib/svgs/Icon_grid.svg b/packages/stream_chat_flutter/lib/svgs/Icon_grid.svg similarity index 100% rename from packages/flutter_widgets/lib/svgs/Icon_grid.svg rename to packages/stream_chat_flutter/lib/svgs/Icon_grid.svg diff --git a/packages/flutter_widgets/lib/svgs/Icon_group.svg b/packages/stream_chat_flutter/lib/svgs/Icon_group.svg similarity index 100% rename from packages/flutter_widgets/lib/svgs/Icon_group.svg rename to packages/stream_chat_flutter/lib/svgs/Icon_group.svg diff --git a/packages/flutter_widgets/lib/svgs/Icon_left.svg b/packages/stream_chat_flutter/lib/svgs/Icon_left.svg similarity index 100% rename from packages/flutter_widgets/lib/svgs/Icon_left.svg rename to packages/stream_chat_flutter/lib/svgs/Icon_left.svg diff --git a/packages/flutter_widgets/lib/svgs/Icon_lightning-command runner.svg b/packages/stream_chat_flutter/lib/svgs/Icon_lightning-command runner.svg similarity index 100% rename from packages/flutter_widgets/lib/svgs/Icon_lightning-command runner.svg rename to packages/stream_chat_flutter/lib/svgs/Icon_lightning-command runner.svg diff --git a/packages/flutter_widgets/lib/svgs/Icon_love_reaction.svg b/packages/stream_chat_flutter/lib/svgs/Icon_love_reaction.svg similarity index 100% rename from packages/flutter_widgets/lib/svgs/Icon_love_reaction.svg rename to packages/stream_chat_flutter/lib/svgs/Icon_love_reaction.svg diff --git a/packages/flutter_widgets/lib/svgs/Icon_menu_point_v.svg b/packages/stream_chat_flutter/lib/svgs/Icon_menu_point_v.svg similarity index 100% rename from packages/flutter_widgets/lib/svgs/Icon_menu_point_v.svg rename to packages/stream_chat_flutter/lib/svgs/Icon_menu_point_v.svg diff --git a/packages/flutter_widgets/lib/svgs/Icon_message.svg b/packages/stream_chat_flutter/lib/svgs/Icon_message.svg similarity index 100% rename from packages/flutter_widgets/lib/svgs/Icon_message.svg rename to packages/stream_chat_flutter/lib/svgs/Icon_message.svg diff --git a/packages/flutter_widgets/lib/svgs/Icon_mute.svg b/packages/stream_chat_flutter/lib/svgs/Icon_mute.svg similarity index 100% rename from packages/flutter_widgets/lib/svgs/Icon_mute.svg rename to packages/stream_chat_flutter/lib/svgs/Icon_mute.svg diff --git a/packages/flutter_widgets/lib/svgs/Icon_notification.svg b/packages/stream_chat_flutter/lib/svgs/Icon_notification.svg similarity index 100% rename from packages/flutter_widgets/lib/svgs/Icon_notification.svg rename to packages/stream_chat_flutter/lib/svgs/Icon_notification.svg diff --git a/packages/flutter_widgets/lib/svgs/Icon_pen-write.svg b/packages/stream_chat_flutter/lib/svgs/Icon_pen-write.svg similarity index 100% rename from packages/flutter_widgets/lib/svgs/Icon_pen-write.svg rename to packages/stream_chat_flutter/lib/svgs/Icon_pen-write.svg diff --git a/packages/flutter_widgets/lib/svgs/Icon_record.svg b/packages/stream_chat_flutter/lib/svgs/Icon_record.svg similarity index 100% rename from packages/flutter_widgets/lib/svgs/Icon_record.svg rename to packages/stream_chat_flutter/lib/svgs/Icon_record.svg diff --git a/packages/flutter_widgets/lib/svgs/Icon_right.svg b/packages/stream_chat_flutter/lib/svgs/Icon_right.svg similarity index 100% rename from packages/flutter_widgets/lib/svgs/Icon_right.svg rename to packages/stream_chat_flutter/lib/svgs/Icon_right.svg diff --git a/packages/flutter_widgets/lib/svgs/Icon_save.svg b/packages/stream_chat_flutter/lib/svgs/Icon_save.svg similarity index 100% rename from packages/flutter_widgets/lib/svgs/Icon_save.svg rename to packages/stream_chat_flutter/lib/svgs/Icon_save.svg diff --git a/packages/flutter_widgets/lib/svgs/Icon_search.svg b/packages/stream_chat_flutter/lib/svgs/Icon_search.svg similarity index 100% rename from packages/flutter_widgets/lib/svgs/Icon_search.svg rename to packages/stream_chat_flutter/lib/svgs/Icon_search.svg diff --git a/packages/flutter_widgets/lib/svgs/Icon_send_message.svg b/packages/stream_chat_flutter/lib/svgs/Icon_send_message.svg similarity index 100% rename from packages/flutter_widgets/lib/svgs/Icon_send_message.svg rename to packages/stream_chat_flutter/lib/svgs/Icon_send_message.svg diff --git a/packages/flutter_widgets/lib/svgs/Icon_smile.svg b/packages/stream_chat_flutter/lib/svgs/Icon_smile.svg similarity index 100% rename from packages/flutter_widgets/lib/svgs/Icon_smile.svg rename to packages/stream_chat_flutter/lib/svgs/Icon_smile.svg diff --git a/packages/flutter_widgets/lib/svgs/Icon_thumbs_down_reaction.svg b/packages/stream_chat_flutter/lib/svgs/Icon_thumbs_down_reaction.svg similarity index 100% rename from packages/flutter_widgets/lib/svgs/Icon_thumbs_down_reaction.svg rename to packages/stream_chat_flutter/lib/svgs/Icon_thumbs_down_reaction.svg diff --git a/packages/flutter_widgets/lib/svgs/Icon_thumbs_up_reaction.svg b/packages/stream_chat_flutter/lib/svgs/Icon_thumbs_up_reaction.svg similarity index 100% rename from packages/flutter_widgets/lib/svgs/Icon_thumbs_up_reaction.svg rename to packages/stream_chat_flutter/lib/svgs/Icon_thumbs_up_reaction.svg diff --git a/packages/flutter_widgets/lib/svgs/Icon_time.svg b/packages/stream_chat_flutter/lib/svgs/Icon_time.svg similarity index 100% rename from packages/flutter_widgets/lib/svgs/Icon_time.svg rename to packages/stream_chat_flutter/lib/svgs/Icon_time.svg diff --git a/packages/flutter_widgets/lib/svgs/Icon_user.svg b/packages/stream_chat_flutter/lib/svgs/Icon_user.svg similarity index 100% rename from packages/flutter_widgets/lib/svgs/Icon_user.svg rename to packages/stream_chat_flutter/lib/svgs/Icon_user.svg diff --git a/packages/flutter_widgets/lib/svgs/Icon_user_delete.svg b/packages/stream_chat_flutter/lib/svgs/Icon_user_delete.svg similarity index 100% rename from packages/flutter_widgets/lib/svgs/Icon_user_delete.svg rename to packages/stream_chat_flutter/lib/svgs/Icon_user_delete.svg diff --git a/packages/flutter_widgets/lib/svgs/Icon_user_settings.svg b/packages/stream_chat_flutter/lib/svgs/Icon_user_settings.svg similarity index 100% rename from packages/flutter_widgets/lib/svgs/Icon_user_settings.svg rename to packages/stream_chat_flutter/lib/svgs/Icon_user_settings.svg diff --git a/packages/flutter_widgets/lib/svgs/Icon_wut_reaction.svg b/packages/stream_chat_flutter/lib/svgs/Icon_wut_reaction.svg similarity index 100% rename from packages/flutter_widgets/lib/svgs/Icon_wut_reaction.svg rename to packages/stream_chat_flutter/lib/svgs/Icon_wut_reaction.svg diff --git a/packages/flutter_widgets/lib/svgs/STREAM MARK 1.svg b/packages/stream_chat_flutter/lib/svgs/STREAM MARK 1.svg similarity index 100% rename from packages/flutter_widgets/lib/svgs/STREAM MARK 1.svg rename to packages/stream_chat_flutter/lib/svgs/STREAM MARK 1.svg diff --git a/packages/flutter_widgets/lib/svgs/UI_Reverse Pagination Loading.svg b/packages/stream_chat_flutter/lib/svgs/UI_Reverse Pagination Loading.svg similarity index 100% rename from packages/flutter_widgets/lib/svgs/UI_Reverse Pagination Loading.svg rename to packages/stream_chat_flutter/lib/svgs/UI_Reverse Pagination Loading.svg diff --git a/packages/flutter_widgets/lib/svgs/eye-line_big.svg b/packages/stream_chat_flutter/lib/svgs/eye-line_big.svg similarity index 100% rename from packages/flutter_widgets/lib/svgs/eye-line_big.svg rename to packages/stream_chat_flutter/lib/svgs/eye-line_big.svg diff --git a/packages/flutter_widgets/lib/svgs/files.svg b/packages/stream_chat_flutter/lib/svgs/files.svg similarity index 100% rename from packages/flutter_widgets/lib/svgs/files.svg rename to packages/stream_chat_flutter/lib/svgs/files.svg diff --git a/packages/flutter_widgets/lib/svgs/filetype_7z.svg b/packages/stream_chat_flutter/lib/svgs/filetype_7z.svg similarity index 100% rename from packages/flutter_widgets/lib/svgs/filetype_7z.svg rename to packages/stream_chat_flutter/lib/svgs/filetype_7z.svg diff --git a/packages/flutter_widgets/lib/svgs/filetype_CSV.svg b/packages/stream_chat_flutter/lib/svgs/filetype_CSV.svg similarity index 100% rename from packages/flutter_widgets/lib/svgs/filetype_CSV.svg rename to packages/stream_chat_flutter/lib/svgs/filetype_CSV.svg diff --git a/packages/flutter_widgets/lib/svgs/filetype_DOC.svg b/packages/stream_chat_flutter/lib/svgs/filetype_DOC.svg similarity index 100% rename from packages/flutter_widgets/lib/svgs/filetype_DOC.svg rename to packages/stream_chat_flutter/lib/svgs/filetype_DOC.svg diff --git a/packages/flutter_widgets/lib/svgs/filetype_DOCX.svg b/packages/stream_chat_flutter/lib/svgs/filetype_DOCX.svg similarity index 100% rename from packages/flutter_widgets/lib/svgs/filetype_DOCX.svg rename to packages/stream_chat_flutter/lib/svgs/filetype_DOCX.svg diff --git a/packages/flutter_widgets/lib/svgs/filetype_Generic.svg b/packages/stream_chat_flutter/lib/svgs/filetype_Generic.svg similarity index 100% rename from packages/flutter_widgets/lib/svgs/filetype_Generic.svg rename to packages/stream_chat_flutter/lib/svgs/filetype_Generic.svg diff --git a/packages/flutter_widgets/lib/svgs/filetype_MD.svg b/packages/stream_chat_flutter/lib/svgs/filetype_MD.svg similarity index 100% rename from packages/flutter_widgets/lib/svgs/filetype_MD.svg rename to packages/stream_chat_flutter/lib/svgs/filetype_MD.svg diff --git a/packages/flutter_widgets/lib/svgs/filetype_ODT.svg b/packages/stream_chat_flutter/lib/svgs/filetype_ODT.svg similarity index 100% rename from packages/flutter_widgets/lib/svgs/filetype_ODT.svg rename to packages/stream_chat_flutter/lib/svgs/filetype_ODT.svg diff --git a/packages/flutter_widgets/lib/svgs/filetype_PDF.svg b/packages/stream_chat_flutter/lib/svgs/filetype_PDF.svg similarity index 100% rename from packages/flutter_widgets/lib/svgs/filetype_PDF.svg rename to packages/stream_chat_flutter/lib/svgs/filetype_PDF.svg diff --git a/packages/flutter_widgets/lib/svgs/filetype_PPT.svg b/packages/stream_chat_flutter/lib/svgs/filetype_PPT.svg similarity index 100% rename from packages/flutter_widgets/lib/svgs/filetype_PPT.svg rename to packages/stream_chat_flutter/lib/svgs/filetype_PPT.svg diff --git a/packages/flutter_widgets/lib/svgs/filetype_PPTX-1.svg b/packages/stream_chat_flutter/lib/svgs/filetype_PPTX-1.svg similarity index 100% rename from packages/flutter_widgets/lib/svgs/filetype_PPTX-1.svg rename to packages/stream_chat_flutter/lib/svgs/filetype_PPTX-1.svg diff --git a/packages/flutter_widgets/lib/svgs/filetype_PPTX.svg b/packages/stream_chat_flutter/lib/svgs/filetype_PPTX.svg similarity index 100% rename from packages/flutter_widgets/lib/svgs/filetype_PPTX.svg rename to packages/stream_chat_flutter/lib/svgs/filetype_PPTX.svg diff --git a/packages/flutter_widgets/lib/svgs/filetype_RAR.svg b/packages/stream_chat_flutter/lib/svgs/filetype_RAR.svg similarity index 100% rename from packages/flutter_widgets/lib/svgs/filetype_RAR.svg rename to packages/stream_chat_flutter/lib/svgs/filetype_RAR.svg diff --git a/packages/flutter_widgets/lib/svgs/filetype_RTF.svg b/packages/stream_chat_flutter/lib/svgs/filetype_RTF.svg similarity index 100% rename from packages/flutter_widgets/lib/svgs/filetype_RTF.svg rename to packages/stream_chat_flutter/lib/svgs/filetype_RTF.svg diff --git a/packages/flutter_widgets/lib/svgs/filetype_TAR.svg b/packages/stream_chat_flutter/lib/svgs/filetype_TAR.svg similarity index 100% rename from packages/flutter_widgets/lib/svgs/filetype_TAR.svg rename to packages/stream_chat_flutter/lib/svgs/filetype_TAR.svg diff --git a/packages/flutter_widgets/lib/svgs/filetype_TXT.svg b/packages/stream_chat_flutter/lib/svgs/filetype_TXT.svg similarity index 100% rename from packages/flutter_widgets/lib/svgs/filetype_TXT.svg rename to packages/stream_chat_flutter/lib/svgs/filetype_TXT.svg diff --git a/packages/flutter_widgets/lib/svgs/filetype_XLS.svg b/packages/stream_chat_flutter/lib/svgs/filetype_XLS.svg similarity index 100% rename from packages/flutter_widgets/lib/svgs/filetype_XLS.svg rename to packages/stream_chat_flutter/lib/svgs/filetype_XLS.svg diff --git a/packages/flutter_widgets/lib/svgs/filetype_XLSX.svg b/packages/stream_chat_flutter/lib/svgs/filetype_XLSX.svg similarity index 100% rename from packages/flutter_widgets/lib/svgs/filetype_XLSX.svg rename to packages/stream_chat_flutter/lib/svgs/filetype_XLSX.svg diff --git a/packages/flutter_widgets/lib/svgs/filetype_ZIP.svg b/packages/stream_chat_flutter/lib/svgs/filetype_ZIP.svg similarity index 100% rename from packages/flutter_widgets/lib/svgs/filetype_ZIP.svg rename to packages/stream_chat_flutter/lib/svgs/filetype_ZIP.svg diff --git a/packages/flutter_widgets/lib/svgs/filetype_html.svg b/packages/stream_chat_flutter/lib/svgs/filetype_html.svg similarity index 100% rename from packages/flutter_widgets/lib/svgs/filetype_html.svg rename to packages/stream_chat_flutter/lib/svgs/filetype_html.svg diff --git a/packages/flutter_widgets/lib/svgs/flag.svg b/packages/stream_chat_flutter/lib/svgs/flag.svg similarity index 100% rename from packages/flutter_widgets/lib/svgs/flag.svg rename to packages/stream_chat_flutter/lib/svgs/flag.svg diff --git a/packages/flutter_widgets/lib/svgs/giphy icon blue.svg b/packages/stream_chat_flutter/lib/svgs/giphy icon blue.svg similarity index 100% rename from packages/flutter_widgets/lib/svgs/giphy icon blue.svg rename to packages/stream_chat_flutter/lib/svgs/giphy icon blue.svg diff --git a/packages/flutter_widgets/lib/svgs/giphy_icon.svg b/packages/stream_chat_flutter/lib/svgs/giphy_icon.svg similarity index 100% rename from packages/flutter_widgets/lib/svgs/giphy_icon.svg rename to packages/stream_chat_flutter/lib/svgs/giphy_icon.svg diff --git a/packages/flutter_widgets/lib/svgs/icon_SHARE.svg b/packages/stream_chat_flutter/lib/svgs/icon_SHARE.svg similarity index 100% rename from packages/flutter_widgets/lib/svgs/icon_SHARE.svg rename to packages/stream_chat_flutter/lib/svgs/icon_SHARE.svg diff --git a/packages/flutter_widgets/lib/svgs/icon_delete_grey.svg b/packages/stream_chat_flutter/lib/svgs/icon_delete_grey.svg similarity index 100% rename from packages/flutter_widgets/lib/svgs/icon_delete_grey.svg rename to packages/stream_chat_flutter/lib/svgs/icon_delete_grey.svg diff --git a/packages/flutter_widgets/lib/svgs/icon_flag.svg b/packages/stream_chat_flutter/lib/svgs/icon_flag.svg similarity index 100% rename from packages/flutter_widgets/lib/svgs/icon_flag.svg rename to packages/stream_chat_flutter/lib/svgs/icon_flag.svg diff --git a/packages/flutter_widgets/lib/svgs/icon_mentions.svg b/packages/stream_chat_flutter/lib/svgs/icon_mentions.svg similarity index 100% rename from packages/flutter_widgets/lib/svgs/icon_mentions.svg rename to packages/stream_chat_flutter/lib/svgs/icon_mentions.svg diff --git a/packages/flutter_widgets/lib/svgs/icon_moon.svg b/packages/stream_chat_flutter/lib/svgs/icon_moon.svg similarity index 100% rename from packages/flutter_widgets/lib/svgs/icon_moon.svg rename to packages/stream_chat_flutter/lib/svgs/icon_moon.svg diff --git a/packages/flutter_widgets/lib/svgs/imgur.svg b/packages/stream_chat_flutter/lib/svgs/imgur.svg similarity index 100% rename from packages/flutter_widgets/lib/svgs/imgur.svg rename to packages/stream_chat_flutter/lib/svgs/imgur.svg diff --git a/packages/flutter_widgets/lib/svgs/mentions.svg b/packages/stream_chat_flutter/lib/svgs/mentions.svg similarity index 100% rename from packages/flutter_widgets/lib/svgs/mentions.svg rename to packages/stream_chat_flutter/lib/svgs/mentions.svg diff --git a/packages/flutter_widgets/lib/svgs/pictures.svg b/packages/stream_chat_flutter/lib/svgs/pictures.svg similarity index 100% rename from packages/flutter_widgets/lib/svgs/pictures.svg rename to packages/stream_chat_flutter/lib/svgs/pictures.svg diff --git a/packages/flutter_widgets/lib/svgs/settings.svg b/packages/stream_chat_flutter/lib/svgs/settings.svg similarity index 100% rename from packages/flutter_widgets/lib/svgs/settings.svg rename to packages/stream_chat_flutter/lib/svgs/settings.svg diff --git a/packages/flutter_widgets/lib/svgs/share_arrow.svg b/packages/stream_chat_flutter/lib/svgs/share_arrow.svg similarity index 100% rename from packages/flutter_widgets/lib/svgs/share_arrow.svg rename to packages/stream_chat_flutter/lib/svgs/share_arrow.svg diff --git a/packages/flutter_widgets/lib/svgs/volume-up.svg b/packages/stream_chat_flutter/lib/svgs/volume-up.svg similarity index 100% rename from packages/flutter_widgets/lib/svgs/volume-up.svg rename to packages/stream_chat_flutter/lib/svgs/volume-up.svg diff --git a/packages/flutter_widgets/pubspec.yaml b/packages/stream_chat_flutter/pubspec.yaml similarity index 100% rename from packages/flutter_widgets/pubspec.yaml rename to packages/stream_chat_flutter/pubspec.yaml diff --git a/packages/flutter_widgets/screenshots/channel_header.png b/packages/stream_chat_flutter/screenshots/channel_header.png similarity index 100% rename from packages/flutter_widgets/screenshots/channel_header.png rename to packages/stream_chat_flutter/screenshots/channel_header.png diff --git a/packages/flutter_widgets/screenshots/channel_header_paint.png b/packages/stream_chat_flutter/screenshots/channel_header_paint.png similarity index 100% rename from packages/flutter_widgets/screenshots/channel_header_paint.png rename to packages/stream_chat_flutter/screenshots/channel_header_paint.png diff --git a/packages/flutter_widgets/screenshots/channel_image.png b/packages/stream_chat_flutter/screenshots/channel_image.png similarity index 100% rename from packages/flutter_widgets/screenshots/channel_image.png rename to packages/stream_chat_flutter/screenshots/channel_image.png diff --git a/packages/flutter_widgets/screenshots/channel_image_paint.png b/packages/stream_chat_flutter/screenshots/channel_image_paint.png similarity index 100% rename from packages/flutter_widgets/screenshots/channel_image_paint.png rename to packages/stream_chat_flutter/screenshots/channel_image_paint.png diff --git a/packages/flutter_widgets/screenshots/channel_list_view.png b/packages/stream_chat_flutter/screenshots/channel_list_view.png similarity index 100% rename from packages/flutter_widgets/screenshots/channel_list_view.png rename to packages/stream_chat_flutter/screenshots/channel_list_view.png diff --git a/packages/flutter_widgets/screenshots/channel_list_view_paint.png b/packages/stream_chat_flutter/screenshots/channel_list_view_paint.png similarity index 100% rename from packages/flutter_widgets/screenshots/channel_list_view_paint.png rename to packages/stream_chat_flutter/screenshots/channel_list_view_paint.png diff --git a/packages/flutter_widgets/screenshots/channel_preview.png b/packages/stream_chat_flutter/screenshots/channel_preview.png similarity index 100% rename from packages/flutter_widgets/screenshots/channel_preview.png rename to packages/stream_chat_flutter/screenshots/channel_preview.png diff --git a/packages/flutter_widgets/screenshots/channel_preview_paint.png b/packages/stream_chat_flutter/screenshots/channel_preview_paint.png similarity index 100% rename from packages/flutter_widgets/screenshots/channel_preview_paint.png rename to packages/stream_chat_flutter/screenshots/channel_preview_paint.png diff --git a/packages/flutter_widgets/screenshots/message_input.png b/packages/stream_chat_flutter/screenshots/message_input.png similarity index 100% rename from packages/flutter_widgets/screenshots/message_input.png rename to packages/stream_chat_flutter/screenshots/message_input.png diff --git a/packages/flutter_widgets/screenshots/message_input2.png b/packages/stream_chat_flutter/screenshots/message_input2.png similarity index 100% rename from packages/flutter_widgets/screenshots/message_input2.png rename to packages/stream_chat_flutter/screenshots/message_input2.png diff --git a/packages/flutter_widgets/screenshots/message_input2_paint.png b/packages/stream_chat_flutter/screenshots/message_input2_paint.png similarity index 100% rename from packages/flutter_widgets/screenshots/message_input2_paint.png rename to packages/stream_chat_flutter/screenshots/message_input2_paint.png diff --git a/packages/flutter_widgets/screenshots/message_input_paint.png b/packages/stream_chat_flutter/screenshots/message_input_paint.png similarity index 100% rename from packages/flutter_widgets/screenshots/message_input_paint.png rename to packages/stream_chat_flutter/screenshots/message_input_paint.png diff --git a/packages/flutter_widgets/screenshots/message_listview.png b/packages/stream_chat_flutter/screenshots/message_listview.png similarity index 100% rename from packages/flutter_widgets/screenshots/message_listview.png rename to packages/stream_chat_flutter/screenshots/message_listview.png diff --git a/packages/flutter_widgets/screenshots/message_listview_paint.png b/packages/stream_chat_flutter/screenshots/message_listview_paint.png similarity index 100% rename from packages/flutter_widgets/screenshots/message_listview_paint.png rename to packages/stream_chat_flutter/screenshots/message_listview_paint.png diff --git a/packages/flutter_widgets/screenshots/message_widget.png b/packages/stream_chat_flutter/screenshots/message_widget.png similarity index 100% rename from packages/flutter_widgets/screenshots/message_widget.png rename to packages/stream_chat_flutter/screenshots/message_widget.png diff --git a/packages/flutter_widgets/screenshots/message_widget_paint.png b/packages/stream_chat_flutter/screenshots/message_widget_paint.png similarity index 100% rename from packages/flutter_widgets/screenshots/message_widget_paint.png rename to packages/stream_chat_flutter/screenshots/message_widget_paint.png diff --git a/packages/flutter_widgets/screenshots/reaction_picker.png b/packages/stream_chat_flutter/screenshots/reaction_picker.png similarity index 100% rename from packages/flutter_widgets/screenshots/reaction_picker.png rename to packages/stream_chat_flutter/screenshots/reaction_picker.png diff --git a/packages/flutter_widgets/screenshots/reaction_picker_paint.png b/packages/stream_chat_flutter/screenshots/reaction_picker_paint.png similarity index 100% rename from packages/flutter_widgets/screenshots/reaction_picker_paint.png rename to packages/stream_chat_flutter/screenshots/reaction_picker_paint.png diff --git a/packages/flutter_widgets/screenshots/thread_header.png b/packages/stream_chat_flutter/screenshots/thread_header.png similarity index 100% rename from packages/flutter_widgets/screenshots/thread_header.png rename to packages/stream_chat_flutter/screenshots/thread_header.png diff --git a/packages/flutter_widgets/screenshots/thread_header_paint.png b/packages/stream_chat_flutter/screenshots/thread_header_paint.png similarity index 100% rename from packages/flutter_widgets/screenshots/thread_header_paint.png rename to packages/stream_chat_flutter/screenshots/thread_header_paint.png diff --git a/packages/flutter_widgets/svgs/giphy_icon.svg b/packages/stream_chat_flutter/svgs/giphy_icon.svg similarity index 100% rename from packages/flutter_widgets/svgs/giphy_icon.svg rename to packages/stream_chat_flutter/svgs/giphy_icon.svg diff --git a/packages/flutter_widgets/svgs/icon_camera.svg b/packages/stream_chat_flutter/svgs/icon_camera.svg similarity index 100% rename from packages/flutter_widgets/svgs/icon_camera.svg rename to packages/stream_chat_flutter/svgs/icon_camera.svg diff --git a/packages/flutter_widgets/svgs/icon_pen_write.svg b/packages/stream_chat_flutter/svgs/icon_pen_write.svg similarity index 100% rename from packages/flutter_widgets/svgs/icon_pen_write.svg rename to packages/stream_chat_flutter/svgs/icon_pen_write.svg diff --git a/packages/flutter_widgets/svgs/icon_picture_empty_state.svg b/packages/stream_chat_flutter/svgs/icon_picture_empty_state.svg similarity index 100% rename from packages/flutter_widgets/svgs/icon_picture_empty_state.svg rename to packages/stream_chat_flutter/svgs/icon_picture_empty_state.svg diff --git a/packages/flutter_widgets/svgs/video_call_icon.svg b/packages/stream_chat_flutter/svgs/video_call_icon.svg similarity index 100% rename from packages/flutter_widgets/svgs/video_call_icon.svg rename to packages/stream_chat_flutter/svgs/video_call_icon.svg diff --git a/packages/flutter_widgets/test/src/channel_preview_test.dart b/packages/stream_chat_flutter/test/src/channel_preview_test.dart similarity index 100% rename from packages/flutter_widgets/test/src/channel_preview_test.dart rename to packages/stream_chat_flutter/test/src/channel_preview_test.dart diff --git a/packages/flutter_widgets/test/src/message_action_modal_test.dart b/packages/stream_chat_flutter/test/src/message_action_modal_test.dart similarity index 100% rename from packages/flutter_widgets/test/src/message_action_modal_test.dart rename to packages/stream_chat_flutter/test/src/message_action_modal_test.dart diff --git a/packages/flutter_widgets/test/src/message_reaction_modal_test.dart b/packages/stream_chat_flutter/test/src/message_reaction_modal_test.dart similarity index 100% rename from packages/flutter_widgets/test/src/message_reaction_modal_test.dart rename to packages/stream_chat_flutter/test/src/message_reaction_modal_test.dart diff --git a/packages/flutter_widgets/test/src/mocks.dart b/packages/stream_chat_flutter/test/src/mocks.dart similarity index 100% rename from packages/flutter_widgets/test/src/mocks.dart rename to packages/stream_chat_flutter/test/src/mocks.dart diff --git a/packages/flutter_widgets/test/src/reaction_bubble_test.dart b/packages/stream_chat_flutter/test/src/reaction_bubble_test.dart similarity index 100% rename from packages/flutter_widgets/test/src/reaction_bubble_test.dart rename to packages/stream_chat_flutter/test/src/reaction_bubble_test.dart diff --git a/packages/stream_chat_persistence/pubspec.yaml b/packages/stream_chat_persistence/pubspec.yaml index 06015495..bf666445 100644 --- a/packages/stream_chat_persistence/pubspec.yaml +++ b/packages/stream_chat_persistence/pubspec.yaml @@ -14,7 +14,7 @@ dependencies: path_provider: ^1.6.27 sqlite3_flutter_libs: ^0.3.0 stream_chat: - path: ../dart_client + path: ../stream_chat dev_dependencies: test: ^1.15.7 From 38a1b880e54a668dc9420576ccf14c91d1541d66 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Mon, 1 Feb 2021 16:11:29 +0100 Subject: [PATCH 1119/1140] update deps --- .github/workflows/stream_flutter_workflow.yml | 2 +- packages/stream_chat/lib/version.dart | 2 +- packages/stream_chat/pubspec.yaml | 10 +++++----- packages/stream_chat_flutter/pubspec.yaml | 2 +- packages/stream_chat_flutter_core/pubspec.yaml | 2 +- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/.github/workflows/stream_flutter_workflow.yml b/.github/workflows/stream_flutter_workflow.yml index 240c0310..fa2a5e69 100644 --- a/.github/workflows/stream_flutter_workflow.yml +++ b/.github/workflows/stream_flutter_workflow.yml @@ -83,7 +83,7 @@ jobs: - name: 'Bootstrap Workspace' run: melos bootstrap - name: 'Flutter Test' - run: cd packages/dart_client && flutter pub run test + run: cd packages/stream_chat && flutter pub run test test_flutter: runs-on: ubuntu-latest diff --git a/packages/stream_chat/lib/version.dart b/packages/stream_chat/lib/version.dart index 3f084128..3a2dc170 100644 --- a/packages/stream_chat/lib/version.dart +++ b/packages/stream_chat/lib/version.dart @@ -2,4 +2,4 @@ import 'package:stream_chat/src/client.dart'; /// Current package version /// Used in [StreamChatClient] to build the `x-stream-client` header -const PACKAGE_VERSION = '0.2.24+2'; +const PACKAGE_VERSION = '1.0.0-beta'; diff --git a/packages/stream_chat/pubspec.yaml b/packages/stream_chat/pubspec.yaml index e9036a09..e13625bb 100644 --- a/packages/stream_chat/pubspec.yaml +++ b/packages/stream_chat/pubspec.yaml @@ -1,7 +1,7 @@ name: stream_chat homepage: https://getstream.io/ description: The official Dart client for Stream Chat, a service for building chat applications. -version: 0.2.24+2 +version: 1.0.0-beta repository: https://github.com/GetStream/stream-chat-dart issue_tracker: https://github.com/GetStream/stream-chat-dart/issues @@ -14,13 +14,13 @@ dependencies: dio: ^3.0.10 web_socket_channel: ^1.1.0 uuid: ^2.2.2 - async: ^2.4.1 - rxdart: ^0.24.1 - collection: ^1.14.12 + async: ^2.4.2 + rxdart: ^0.25.0 + collection: ^1.14.13 + pedantic: ^1.9.2 dev_dependencies: build_runner: ^1.10.0 json_serializable: ^3.3.0 test: ^1.15.7 mockito: ^4.1.1 - pedantic: ^1.9.2 diff --git a/packages/stream_chat_flutter/pubspec.yaml b/packages/stream_chat_flutter/pubspec.yaml index af2e39f4..6b994ebf 100644 --- a/packages/stream_chat_flutter/pubspec.yaml +++ b/packages/stream_chat_flutter/pubspec.yaml @@ -16,7 +16,7 @@ dependencies: path: ../stream_chat_flutter_core flutter_app_badger: ^1.1.2 photo_view: ^0.10.3 - rxdart: ^0.24.1 + rxdart: ^0.25.0 scrollable_positioned_list: ^0.1.8 jiffy: ^3.0.1 flutter_svg: ^0.19.1 diff --git a/packages/stream_chat_flutter_core/pubspec.yaml b/packages/stream_chat_flutter_core/pubspec.yaml index cf7fb31d..6c9647e8 100644 --- a/packages/stream_chat_flutter_core/pubspec.yaml +++ b/packages/stream_chat_flutter_core/pubspec.yaml @@ -11,7 +11,7 @@ environment: dependencies: stream_chat: - path: ../dart_client + path: ../stream_chat flutter: sdk: flutter From 3a6dd5e2cc52cb515d7d63e95a5bb538f32e85a1 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Mon, 1 Feb 2021 16:16:06 +0100 Subject: [PATCH 1120/1140] fix dependencies --- packages/stream_chat/pubspec.yaml | 1 + packages/stream_chat_flutter_core/pubspec.yaml | 1 + 2 files changed, 2 insertions(+) diff --git a/packages/stream_chat/pubspec.yaml b/packages/stream_chat/pubspec.yaml index e13625bb..a626812b 100644 --- a/packages/stream_chat/pubspec.yaml +++ b/packages/stream_chat/pubspec.yaml @@ -18,6 +18,7 @@ dependencies: rxdart: ^0.25.0 collection: ^1.14.13 pedantic: ^1.9.2 + meta: ^1.2.4 dev_dependencies: build_runner: ^1.10.0 diff --git a/packages/stream_chat_flutter_core/pubspec.yaml b/packages/stream_chat_flutter_core/pubspec.yaml index 6c9647e8..b1896fcb 100644 --- a/packages/stream_chat_flutter_core/pubspec.yaml +++ b/packages/stream_chat_flutter_core/pubspec.yaml @@ -14,6 +14,7 @@ dependencies: path: ../stream_chat flutter: sdk: flutter + rxdart: ^0.25.0 dev_dependencies: mockito: ^4.1.4 From 0e5dcfb35460da45392abc5c83d5f96105ea9489 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Mon, 1 Feb 2021 20:54:24 +0530 Subject: [PATCH 1121/1140] [StreamChatPersistence] Add example Signed-off-by: Sahil Kumar --- .../example/.gitignore | 41 +++ .../stream_chat_persistence/example/.metadata | 10 + .../stream_chat_persistence/example/README.md | 2 + .../example/android/.gitignore | 11 + .../example/android/app/build.gradle | 63 +++++ .../android/app/src/debug/AndroidManifest.xml | 7 + .../android/app/src/main/AndroidManifest.xml | 47 ++++ .../com/example/example/MainActivity.kt | 6 + .../main/res/drawable/launch_background.xml | 12 + .../src/main/res/mipmap-hdpi/ic_launcher.png | Bin 0 -> 544 bytes .../src/main/res/mipmap-mdpi/ic_launcher.png | Bin 0 -> 442 bytes .../src/main/res/mipmap-xhdpi/ic_launcher.png | Bin 0 -> 721 bytes .../main/res/mipmap-xxhdpi/ic_launcher.png | Bin 0 -> 1031 bytes .../main/res/mipmap-xxxhdpi/ic_launcher.png | Bin 0 -> 1443 bytes .../app/src/main/res/values/styles.xml | 18 ++ .../app/src/profile/AndroidManifest.xml | 7 + .../example/android/build.gradle | 31 +++ .../example/android/gradle.properties | 4 + .../gradle/wrapper/gradle-wrapper.properties | 6 + .../example/android/settings.gradle | 11 + .../example/ios/.gitignore | 32 +++ .../ios/Flutter/AppFrameworkInfo.plist | 26 ++ .../example/ios/Flutter/Debug.xcconfig | 2 + .../example/ios/Flutter/Release.xcconfig | 2 + .../contents.xcworkspacedata | 7 + .../xcshareddata/IDEWorkspaceChecks.plist | 8 + .../xcshareddata/WorkspaceSettings.xcsettings | 8 + .../xcshareddata/xcschemes/Runner.xcscheme | 91 +++++++ .../contents.xcworkspacedata | 7 + .../xcshareddata/IDEWorkspaceChecks.plist | 8 + .../xcshareddata/WorkspaceSettings.xcsettings | 8 + .../example/ios/Runner/AppDelegate.swift | 13 + .../AppIcon.appiconset/Contents.json | 122 +++++++++ .../Icon-App-1024x1024@1x.png | Bin 0 -> 10932 bytes .../AppIcon.appiconset/Icon-App-20x20@1x.png | Bin 0 -> 564 bytes .../AppIcon.appiconset/Icon-App-20x20@2x.png | Bin 0 -> 1283 bytes .../AppIcon.appiconset/Icon-App-20x20@3x.png | Bin 0 -> 1588 bytes .../AppIcon.appiconset/Icon-App-29x29@1x.png | Bin 0 -> 1025 bytes .../AppIcon.appiconset/Icon-App-29x29@2x.png | Bin 0 -> 1716 bytes .../AppIcon.appiconset/Icon-App-29x29@3x.png | Bin 0 -> 1920 bytes .../AppIcon.appiconset/Icon-App-40x40@1x.png | Bin 0 -> 1283 bytes .../AppIcon.appiconset/Icon-App-40x40@2x.png | Bin 0 -> 1895 bytes .../AppIcon.appiconset/Icon-App-40x40@3x.png | Bin 0 -> 2665 bytes .../AppIcon.appiconset/Icon-App-60x60@2x.png | Bin 0 -> 2665 bytes .../AppIcon.appiconset/Icon-App-60x60@3x.png | Bin 0 -> 3831 bytes .../AppIcon.appiconset/Icon-App-76x76@1x.png | Bin 0 -> 1888 bytes .../AppIcon.appiconset/Icon-App-76x76@2x.png | Bin 0 -> 3294 bytes .../Icon-App-83.5x83.5@2x.png | Bin 0 -> 3612 bytes .../LaunchImage.imageset/Contents.json | 23 ++ .../LaunchImage.imageset/LaunchImage.png | Bin 0 -> 68 bytes .../LaunchImage.imageset/LaunchImage@2x.png | Bin 0 -> 68 bytes .../LaunchImage.imageset/LaunchImage@3x.png | Bin 0 -> 68 bytes .../LaunchImage.imageset/README.md | 5 + .../Runner/Base.lproj/LaunchScreen.storyboard | 37 +++ .../ios/Runner/Base.lproj/Main.storyboard | 26 ++ .../example/ios/Runner/Info.plist | 45 ++++ .../ios/Runner/Runner-Bridging-Header.h | 1 + .../example/lib/main.dart | 255 ++++++++++++++++++ .../example/pubspec.yaml | 23 ++ 59 files changed, 1025 insertions(+) create mode 100644 packages/stream_chat_persistence/example/.gitignore create mode 100644 packages/stream_chat_persistence/example/.metadata create mode 100644 packages/stream_chat_persistence/example/README.md create mode 100644 packages/stream_chat_persistence/example/android/.gitignore create mode 100644 packages/stream_chat_persistence/example/android/app/build.gradle create mode 100644 packages/stream_chat_persistence/example/android/app/src/debug/AndroidManifest.xml create mode 100644 packages/stream_chat_persistence/example/android/app/src/main/AndroidManifest.xml create mode 100644 packages/stream_chat_persistence/example/android/app/src/main/kotlin/com/example/example/MainActivity.kt create mode 100644 packages/stream_chat_persistence/example/android/app/src/main/res/drawable/launch_background.xml create mode 100644 packages/stream_chat_persistence/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png create mode 100644 packages/stream_chat_persistence/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png create mode 100644 packages/stream_chat_persistence/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png create mode 100644 packages/stream_chat_persistence/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png create mode 100644 packages/stream_chat_persistence/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png create mode 100644 packages/stream_chat_persistence/example/android/app/src/main/res/values/styles.xml create mode 100644 packages/stream_chat_persistence/example/android/app/src/profile/AndroidManifest.xml create mode 100644 packages/stream_chat_persistence/example/android/build.gradle create mode 100644 packages/stream_chat_persistence/example/android/gradle.properties create mode 100644 packages/stream_chat_persistence/example/android/gradle/wrapper/gradle-wrapper.properties create mode 100644 packages/stream_chat_persistence/example/android/settings.gradle create mode 100644 packages/stream_chat_persistence/example/ios/.gitignore create mode 100644 packages/stream_chat_persistence/example/ios/Flutter/AppFrameworkInfo.plist create mode 100644 packages/stream_chat_persistence/example/ios/Flutter/Debug.xcconfig create mode 100644 packages/stream_chat_persistence/example/ios/Flutter/Release.xcconfig create mode 100644 packages/stream_chat_persistence/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata create mode 100644 packages/stream_chat_persistence/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 packages/stream_chat_persistence/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings create mode 100644 packages/stream_chat_persistence/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme create mode 100644 packages/stream_chat_persistence/example/ios/Runner.xcworkspace/contents.xcworkspacedata create mode 100644 packages/stream_chat_persistence/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 packages/stream_chat_persistence/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings create mode 100644 packages/stream_chat_persistence/example/ios/Runner/AppDelegate.swift create mode 100644 packages/stream_chat_persistence/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json create mode 100644 packages/stream_chat_persistence/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png create mode 100644 packages/stream_chat_persistence/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png create mode 100644 packages/stream_chat_persistence/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png create mode 100644 packages/stream_chat_persistence/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png create mode 100644 packages/stream_chat_persistence/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png create mode 100644 packages/stream_chat_persistence/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png create mode 100644 packages/stream_chat_persistence/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png create mode 100644 packages/stream_chat_persistence/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png create mode 100644 packages/stream_chat_persistence/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png create mode 100644 packages/stream_chat_persistence/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png create mode 100644 packages/stream_chat_persistence/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png create mode 100644 packages/stream_chat_persistence/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png create mode 100644 packages/stream_chat_persistence/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png create mode 100644 packages/stream_chat_persistence/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png create mode 100644 packages/stream_chat_persistence/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png create mode 100644 packages/stream_chat_persistence/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json create mode 100644 packages/stream_chat_persistence/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png create mode 100644 packages/stream_chat_persistence/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png create mode 100644 packages/stream_chat_persistence/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png create mode 100644 packages/stream_chat_persistence/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md create mode 100644 packages/stream_chat_persistence/example/ios/Runner/Base.lproj/LaunchScreen.storyboard create mode 100644 packages/stream_chat_persistence/example/ios/Runner/Base.lproj/Main.storyboard create mode 100644 packages/stream_chat_persistence/example/ios/Runner/Info.plist create mode 100644 packages/stream_chat_persistence/example/ios/Runner/Runner-Bridging-Header.h create mode 100644 packages/stream_chat_persistence/example/lib/main.dart create mode 100644 packages/stream_chat_persistence/example/pubspec.yaml diff --git a/packages/stream_chat_persistence/example/.gitignore b/packages/stream_chat_persistence/example/.gitignore new file mode 100644 index 00000000..9d532b18 --- /dev/null +++ b/packages/stream_chat_persistence/example/.gitignore @@ -0,0 +1,41 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# IntelliJ related +*.iml +*.ipr +*.iws +.idea/ + +# The .vscode folder contains launch configuration and tasks you configure in +# VS Code which you may wish to be included in version control, so this line +# is commented out by default. +#.vscode/ + +# Flutter/Dart/Pub related +**/doc/api/ +**/ios/Flutter/.last_build_id +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json diff --git a/packages/stream_chat_persistence/example/.metadata b/packages/stream_chat_persistence/example/.metadata new file mode 100644 index 00000000..182cccaf --- /dev/null +++ b/packages/stream_chat_persistence/example/.metadata @@ -0,0 +1,10 @@ +# This file tracks properties of this Flutter project. +# Used by Flutter tool to assess capabilities and perform upgrades etc. +# +# This file should be version controlled and should not be manually edited. + +version: + revision: 78910062997c3a836feee883712c241a5fd22983 + channel: stable + +project_type: app diff --git a/packages/stream_chat_persistence/example/README.md b/packages/stream_chat_persistence/example/README.md new file mode 100644 index 00000000..11089159 --- /dev/null +++ b/packages/stream_chat_persistence/example/README.md @@ -0,0 +1,2 @@ +# Stream Chat Dart Example +Please see `lib/` for example code. \ No newline at end of file diff --git a/packages/stream_chat_persistence/example/android/.gitignore b/packages/stream_chat_persistence/example/android/.gitignore new file mode 100644 index 00000000..0a741cb4 --- /dev/null +++ b/packages/stream_chat_persistence/example/android/.gitignore @@ -0,0 +1,11 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java + +# Remember to never publicly share your keystore. +# See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app +key.properties diff --git a/packages/stream_chat_persistence/example/android/app/build.gradle b/packages/stream_chat_persistence/example/android/app/build.gradle new file mode 100644 index 00000000..3932aa91 --- /dev/null +++ b/packages/stream_chat_persistence/example/android/app/build.gradle @@ -0,0 +1,63 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 29 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.example" + minSdkVersion 16 + targetSdkVersion 29 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + + buildTypes { + release { + // TODO: Add your own signing config for the release build. + // Signing with the debug keys for now, so `flutter run --release` works. + signingConfig signingConfigs.debug + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/packages/stream_chat_persistence/example/android/app/src/debug/AndroidManifest.xml b/packages/stream_chat_persistence/example/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 00000000..c208884f --- /dev/null +++ b/packages/stream_chat_persistence/example/android/app/src/debug/AndroidManifest.xml @@ -0,0 +1,7 @@ + + + + diff --git a/packages/stream_chat_persistence/example/android/app/src/main/AndroidManifest.xml b/packages/stream_chat_persistence/example/android/app/src/main/AndroidManifest.xml new file mode 100644 index 00000000..55ca830c --- /dev/null +++ b/packages/stream_chat_persistence/example/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/packages/stream_chat_persistence/example/android/app/src/main/kotlin/com/example/example/MainActivity.kt b/packages/stream_chat_persistence/example/android/app/src/main/kotlin/com/example/example/MainActivity.kt new file mode 100644 index 00000000..e793a000 --- /dev/null +++ b/packages/stream_chat_persistence/example/android/app/src/main/kotlin/com/example/example/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.example + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} diff --git a/packages/stream_chat_persistence/example/android/app/src/main/res/drawable/launch_background.xml b/packages/stream_chat_persistence/example/android/app/src/main/res/drawable/launch_background.xml new file mode 100644 index 00000000..304732f8 --- /dev/null +++ b/packages/stream_chat_persistence/example/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/packages/stream_chat_persistence/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/packages/stream_chat_persistence/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..db77bb4b7b0906d62b1847e87f15cdcacf6a4f29 GIT binary patch literal 544 zcmeAS@N?(olHy`uVBq!ia0vp^9w5xY3?!3`olAj~WQl7;NpOBzNqJ&XDuZK6ep0G} zXKrG8YEWuoN@d~6R2!h8bpbvhu0Wd6uZuB!w&u2PAxD2eNXD>P5D~Wn-+_Wa#27Xc zC?Zj|6r#X(-D3u$NCt}(Ms06KgJ4FxJVv{GM)!I~&n8Bnc94O7-Hd)cjDZswgC;Qs zO=b+9!WcT8F?0rF7!Uys2bs@gozCP?z~o%U|N3vA*22NaGQG zlg@K`O_XuxvZ&Ks^m&R!`&1=spLvfx7oGDKDwpwW`#iqdw@AL`7MR}m`rwr|mZgU`8P7SBkL78fFf!WnuYWm$5Z0 zNXhDbCv&49sM544K|?c)WrFfiZvCi9h0O)B3Pgg&ebxsLQ05GG~ AQ2+n{ literal 0 HcmV?d00001 diff --git a/packages/stream_chat_persistence/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/packages/stream_chat_persistence/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..17987b79bb8a35cc66c3c1fd44f5a5526c1b78be GIT binary patch literal 442 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA3?vioaBc-sk|nMYCBgY=CFO}lsSJ)O`AMk? zp1FzXsX?iUDV2pMQ*D5Xx&nMcT!A!W`0S9QKQy;}1Cl^CgaH=;G9cpY;r$Q>i*pfB zP2drbID<_#qf;rPZx^FqH)F_D#*k@@q03KywUtLX8Ua?`H+NMzkczFPK3lFz@i_kW%1NOn0|D2I9n9wzH8m|-tHjsw|9>@K=iMBhxvkv6m8Y-l zytQ?X=U+MF$@3 zt`~i=@j|6y)RWMK--}M|=T`o&^Ni>IoWKHEbBXz7?A@mgWoL>!*SXo`SZH-*HSdS+ yn*9;$7;m`l>wYBC5bq;=U}IMqLzqbYCidGC!)_gkIk_C@Uy!y&wkt5C($~2D>~)O*cj@FGjOCM)M>_ixfudOh)?xMu#Fs z#}Y=@YDTwOM)x{K_j*Q;dPdJ?Mz0n|pLRx{4n|)f>SXlmV)XB04CrSJn#dS5nK2lM zrZ9#~WelCp7&e13Y$jvaEXHskn$2V!!DN-nWS__6T*l;H&Fopn?A6HZ-6WRLFP=R` zqG+CE#d4|IbyAI+rJJ`&x9*T`+a=p|0O(+s{UBcyZdkhj=yS1>AirP+0R;mf2uMgM zC}@~JfByORAh4SyRgi&!(cja>F(l*O+nd+@4m$|6K6KDn_&uvCpV23&>G9HJp{xgg zoq1^2_p9@|WEo z*X_Uko@K)qYYv~>43eQGMdbiGbo>E~Q& zrYBH{QP^@Sti!`2)uG{irBBq@y*$B zi#&(U-*=fp74j)RyIw49+0MRPMRU)+a2r*PJ$L5roHt2$UjExCTZSbq%V!HeS7J$N zdG@vOZB4v_lF7Plrx+hxo7(fCV&}fHq)$ literal 0 HcmV?d00001 diff --git a/packages/stream_chat_persistence/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/packages/stream_chat_persistence/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..d5f1c8d34e7a88e3f88bea192c3a370d44689c3c GIT binary patch literal 1031 zcmeAS@N?(olHy`uVBq!ia0vp^6F``Q8Ax83A=Cw=BuiW)N`mv#O3D+9QW+dm@{>{( zJaZG%Q-e|yQz{EjrrIztFa`(sgt!6~Yi|1%a`XoT0ojZ}lNrNjb9xjc(B0U1_% zz5^97Xt*%oq$rQy4?0GKNfJ44uvxI)gC`h-NZ|&0-7(qS@?b!5r36oQ}zyZrNO3 zMO=Or+<~>+A&uN&E!^Sl+>xE!QC-|oJv`ApDhqC^EWD|@=#J`=d#Xzxs4ah}w&Jnc z$|q_opQ^2TrnVZ0o~wh<3t%W&flvYGe#$xqda2bR_R zvPYgMcHgjZ5nSA^lJr%;<&0do;O^tDDh~=pIxA#coaCY>&N%M2^tq^U%3DB@ynvKo}b?yu-bFc-u0JHzced$sg7S3zqI(2 z#Km{dPr7I=pQ5>FuK#)QwK?Y`E`B?nP+}U)I#c1+FM*1kNvWG|a(TpksZQ3B@sD~b zpQ2)*V*TdwjFOtHvV|;OsiDqHi=6%)o4b!)x$)%9pGTsE z-JL={-Ffv+T87W(Xpooq<`r*VzWQcgBN$$`u}f>-ZQI1BB8ykN*=e4rIsJx9>z}*o zo~|9I;xof literal 0 HcmV?d00001 diff --git a/packages/stream_chat_persistence/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/packages/stream_chat_persistence/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..4d6372eebdb28e45604e46eeda8dd24651419bc0 GIT binary patch literal 1443 zcmb`G{WsKk6vsdJTdFg%tJav9_E4vzrOaqkWF|A724Nly!y+?N9`YV6wZ}5(X(D_N(?!*n3`|_r0Hc?=PQw&*vnU?QTFY zB_MsH|!j$PP;I}?dppoE_gA(4uc!jV&0!l7_;&p2^pxNo>PEcNJv za5_RT$o2Mf!<+r?&EbHH6nMoTsDOa;mN(wv8RNsHpG)`^ymG-S5By8=l9iVXzN_eG%Xg2@Xeq76tTZ*dGh~Lo9vl;Zfs+W#BydUw zCkZ$o1LqWQO$FC9aKlLl*7x9^0q%0}$OMlp@Kk_jHXOjofdePND+j!A{q!8~Jn+s3 z?~~w@4?egS02}8NuulUA=L~QQfm;MzCGd)XhiftT;+zFO&JVyp2mBww?;QByS_1w! zrQlx%{^cMj0|Bo1FjwY@Q8?Hx0cIPF*@-ZRFpPc#bBw{5@tD(5%sClzIfl8WU~V#u zm5Q;_F!wa$BSpqhN>W@2De?TKWR*!ujY;Yylk_X5#~V!L*Gw~;$%4Q8~Mad z@`-kG?yb$a9cHIApZDVZ^U6Xkp<*4rU82O7%}0jjHlK{id@?-wpN*fCHXyXh(bLt* zPc}H-x0e4E&nQ>y%B-(EL=9}RyC%MyX=upHuFhAk&MLbsF0LP-q`XnH78@fT+pKPW zu72MW`|?8ht^tz$iC}ZwLp4tB;Q49K!QCF3@!iB1qOI=?w z7In!}F~ij(18UYUjnbmC!qKhPo%24?8U1x{7o(+?^Zu0Hx81|FuS?bJ0jgBhEMzf< zCgUq7r2OCB(`XkKcN-TL>u5y#dD6D!)5W?`O5)V^>jb)P)GBdy%t$uUMpf$SNV31$ zb||OojAbvMP?T@$h_ZiFLFVHDmbyMhJF|-_)HX3%m=CDI+ID$0^C>kzxprBW)hw(v zr!Gmda);ICoQyhV_oP5+C%?jcG8v+D@9f?Dk*!BxY}dazmrT@64UrP3hlslANK)bq z$67n83eh}OeW&SV@HG95P|bjfqJ7gw$e+`Hxo!4cx`jdK1bJ>YDSpGKLPZ^1cv$ek zIB?0S<#tX?SJCLWdMd{-ME?$hc7A$zBOdIJ)4!KcAwb=VMov)nK;9z>x~rfT1>dS+ zZ6#`2v@`jgbqq)P22H)Tx2CpmM^o1$B+xT6`(v%5xJ(?j#>Q$+rx_R|7TzDZe{J6q zG1*EcU%tE?!kO%^M;3aM6JN*LAKUVb^xz8-Pxo#jR5(-KBeLJvA@-gxNHx0M-ZJLl z;#JwQoh~9V?`UVo#}{6ka@II>++D@%KqGpMdlQ}?9E*wFcf5(#XQnP$Dk5~%iX^>f z%$y;?M0BLp{O3a(-4A?ewryHrrD%cx#Q^%KY1H zNre$ve+vceSLZcNY4U(RBX&)oZn*Py()h)XkE?PL$!bNb{N5FVI2Y%LKEm%yvpyTP z(1P?z~7YxD~Rf<(a@_y` literal 0 HcmV?d00001 diff --git a/packages/stream_chat_persistence/example/android/app/src/main/res/values/styles.xml b/packages/stream_chat_persistence/example/android/app/src/main/res/values/styles.xml new file mode 100644 index 00000000..1f83a33f --- /dev/null +++ b/packages/stream_chat_persistence/example/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/packages/stream_chat_persistence/example/android/app/src/profile/AndroidManifest.xml b/packages/stream_chat_persistence/example/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 00000000..c208884f --- /dev/null +++ b/packages/stream_chat_persistence/example/android/app/src/profile/AndroidManifest.xml @@ -0,0 +1,7 @@ + + + + diff --git a/packages/stream_chat_persistence/example/android/build.gradle b/packages/stream_chat_persistence/example/android/build.gradle new file mode 100644 index 00000000..3100ad2d --- /dev/null +++ b/packages/stream_chat_persistence/example/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/packages/stream_chat_persistence/example/android/gradle.properties b/packages/stream_chat_persistence/example/android/gradle.properties new file mode 100644 index 00000000..a6738207 --- /dev/null +++ b/packages/stream_chat_persistence/example/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.useAndroidX=true +android.enableJetifier=true +android.enableR8=true diff --git a/packages/stream_chat_persistence/example/android/gradle/wrapper/gradle-wrapper.properties b/packages/stream_chat_persistence/example/android/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 00000000..de2ccd60 --- /dev/null +++ b/packages/stream_chat_persistence/example/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-bin.zip diff --git a/packages/stream_chat_persistence/example/android/settings.gradle b/packages/stream_chat_persistence/example/android/settings.gradle new file mode 100644 index 00000000..44e62bcf --- /dev/null +++ b/packages/stream_chat_persistence/example/android/settings.gradle @@ -0,0 +1,11 @@ +include ':app' + +def localPropertiesFile = new File(rootProject.projectDir, "local.properties") +def properties = new Properties() + +assert localPropertiesFile.exists() +localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) } + +def flutterSdkPath = properties.getProperty("flutter.sdk") +assert flutterSdkPath != null, "flutter.sdk not set in local.properties" +apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle" diff --git a/packages/stream_chat_persistence/example/ios/.gitignore b/packages/stream_chat_persistence/example/ios/.gitignore new file mode 100644 index 00000000..e96ef602 --- /dev/null +++ b/packages/stream_chat_persistence/example/ios/.gitignore @@ -0,0 +1,32 @@ +*.mode1v3 +*.mode2v3 +*.moved-aside +*.pbxuser +*.perspectivev3 +**/*sync/ +.sconsign.dblite +.tags* +**/.vagrant/ +**/DerivedData/ +Icon? +**/Pods/ +**/.symlinks/ +profile +xcuserdata +**/.generated/ +Flutter/App.framework +Flutter/Flutter.framework +Flutter/Flutter.podspec +Flutter/Generated.xcconfig +Flutter/app.flx +Flutter/app.zip +Flutter/flutter_assets/ +Flutter/flutter_export_environment.sh +ServiceDefinitions.json +Runner/GeneratedPluginRegistrant.* + +# Exceptions to above rules. +!default.mode1v3 +!default.mode2v3 +!default.pbxuser +!default.perspectivev3 diff --git a/packages/stream_chat_persistence/example/ios/Flutter/AppFrameworkInfo.plist b/packages/stream_chat_persistence/example/ios/Flutter/AppFrameworkInfo.plist new file mode 100644 index 00000000..6b4c0f78 --- /dev/null +++ b/packages/stream_chat_persistence/example/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 8.0 + + diff --git a/packages/stream_chat_persistence/example/ios/Flutter/Debug.xcconfig b/packages/stream_chat_persistence/example/ios/Flutter/Debug.xcconfig new file mode 100644 index 00000000..e8efba11 --- /dev/null +++ b/packages/stream_chat_persistence/example/ios/Flutter/Debug.xcconfig @@ -0,0 +1,2 @@ +#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" +#include "Generated.xcconfig" diff --git a/packages/stream_chat_persistence/example/ios/Flutter/Release.xcconfig b/packages/stream_chat_persistence/example/ios/Flutter/Release.xcconfig new file mode 100644 index 00000000..399e9340 --- /dev/null +++ b/packages/stream_chat_persistence/example/ios/Flutter/Release.xcconfig @@ -0,0 +1,2 @@ +#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" +#include "Generated.xcconfig" diff --git a/packages/stream_chat_persistence/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/packages/stream_chat_persistence/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 00000000..1d526a16 --- /dev/null +++ b/packages/stream_chat_persistence/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/packages/stream_chat_persistence/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/packages/stream_chat_persistence/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 00000000..18d98100 --- /dev/null +++ b/packages/stream_chat_persistence/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/packages/stream_chat_persistence/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/packages/stream_chat_persistence/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 00000000..f9b0d7c5 --- /dev/null +++ b/packages/stream_chat_persistence/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + PreviewsEnabled + + + diff --git a/packages/stream_chat_persistence/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/packages/stream_chat_persistence/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme new file mode 100644 index 00000000..a28140cf --- /dev/null +++ b/packages/stream_chat_persistence/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/stream_chat_persistence/example/ios/Runner.xcworkspace/contents.xcworkspacedata b/packages/stream_chat_persistence/example/ios/Runner.xcworkspace/contents.xcworkspacedata new file mode 100644 index 00000000..1d526a16 --- /dev/null +++ b/packages/stream_chat_persistence/example/ios/Runner.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/packages/stream_chat_persistence/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/packages/stream_chat_persistence/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 00000000..18d98100 --- /dev/null +++ b/packages/stream_chat_persistence/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/packages/stream_chat_persistence/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/packages/stream_chat_persistence/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 00000000..f9b0d7c5 --- /dev/null +++ b/packages/stream_chat_persistence/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + PreviewsEnabled + + + diff --git a/packages/stream_chat_persistence/example/ios/Runner/AppDelegate.swift b/packages/stream_chat_persistence/example/ios/Runner/AppDelegate.swift new file mode 100644 index 00000000..70693e4a --- /dev/null +++ b/packages/stream_chat_persistence/example/ios/Runner/AppDelegate.swift @@ -0,0 +1,13 @@ +import UIKit +import Flutter + +@UIApplicationMain +@objc class AppDelegate: FlutterAppDelegate { + override func application( + _ application: UIApplication, + didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? + ) -> Bool { + GeneratedPluginRegistrant.register(with: self) + return super.application(application, didFinishLaunchingWithOptions: launchOptions) + } +} diff --git a/packages/stream_chat_persistence/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/packages/stream_chat_persistence/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 00000000..d36b1fab --- /dev/null +++ b/packages/stream_chat_persistence/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,122 @@ +{ + "images" : [ + { + "size" : "20x20", + "idiom" : "iphone", + "filename" : "Icon-App-20x20@2x.png", + "scale" : "2x" + }, + { + "size" : "20x20", + "idiom" : "iphone", + "filename" : "Icon-App-20x20@3x.png", + "scale" : "3x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@1x.png", + "scale" : "1x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@2x.png", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@3x.png", + "scale" : "3x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "Icon-App-40x40@2x.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "Icon-App-40x40@3x.png", + "scale" : "3x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "Icon-App-60x60@2x.png", + "scale" : "2x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "Icon-App-60x60@3x.png", + "scale" : "3x" + }, + { + "size" : "20x20", + "idiom" : "ipad", + "filename" : "Icon-App-20x20@1x.png", + "scale" : "1x" + }, + { + "size" : "20x20", + "idiom" : "ipad", + "filename" : "Icon-App-20x20@2x.png", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "Icon-App-29x29@1x.png", + "scale" : "1x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "Icon-App-29x29@2x.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "Icon-App-40x40@1x.png", + "scale" : "1x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "Icon-App-40x40@2x.png", + "scale" : "2x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "Icon-App-76x76@1x.png", + "scale" : "1x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "Icon-App-76x76@2x.png", + "scale" : "2x" + }, + { + "size" : "83.5x83.5", + "idiom" : "ipad", + "filename" : "Icon-App-83.5x83.5@2x.png", + "scale" : "2x" + }, + { + "size" : "1024x1024", + "idiom" : "ios-marketing", + "filename" : "Icon-App-1024x1024@1x.png", + "scale" : "1x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/packages/stream_chat_persistence/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png b/packages/stream_chat_persistence/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png new file mode 100644 index 0000000000000000000000000000000000000000..dc9ada4725e9b0ddb1deab583e5b5102493aa332 GIT binary patch literal 10932 zcmeHN2~<R zh`|8`A_PQ1nSu(UMFx?8j8PC!!VDphaL#`F42fd#7Vlc`zIE4n%Y~eiz4y1j|NDpi z?<@|pSJ-HM`qifhf@m%MamgwK83`XpBA<+azdF#2QsT{X@z0A9Bq>~TVErigKH1~P zRX-!h-f0NJ4Mh++{D}J+K>~~rq}d%o%+4dogzXp7RxX4C>Km5XEI|PAFDmo;DFm6G zzjVoB`@qW98Yl0Kvc-9w09^PrsobmG*Eju^=3f?0o-t$U)TL1B3;sZ^!++3&bGZ!o-*6w?;oOhf z=A+Qb$scV5!RbG+&2S}BQ6YH!FKb0``VVX~T$dzzeSZ$&9=X$3)_7Z{SspSYJ!lGE z7yig_41zpQ)%5dr4ff0rh$@ky3-JLRk&DK)NEIHecf9c*?Z1bUB4%pZjQ7hD!A0r-@NF(^WKdr(LXj|=UE7?gBYGgGQV zidf2`ZT@pzXf7}!NH4q(0IMcxsUGDih(0{kRSez&z?CFA0RVXsVFw3^u=^KMtt95q z43q$b*6#uQDLoiCAF_{RFc{!H^moH_cmll#Fc^KXi{9GDl{>%+3qyfOE5;Zq|6#Hb zp^#1G+z^AXfRKaa9HK;%b3Ux~U@q?xg<2DXP%6k!3E)PA<#4$ui8eDy5|9hA5&{?v z(-;*1%(1~-NTQ`Is1_MGdQ{+i*ccd96ab$R$T3=% zw_KuNF@vI!A>>Y_2pl9L{9h1-C6H8<)J4gKI6{WzGBi<@u3P6hNsXG=bRq5c+z;Gc3VUCe;LIIFDmQAGy+=mRyF++u=drBWV8-^>0yE9N&*05XHZpPlE zxu@?8(ZNy7rm?|<+UNe0Vs6&o?l`Pt>P&WaL~M&#Eh%`rg@Mbb)J&@DA-wheQ>hRV z<(XhigZAT z>=M;URcdCaiO3d^?H<^EiEMDV+7HsTiOhoaMX%P65E<(5xMPJKxf!0u>U~uVqnPN7T!X!o@_gs3Ct1 zlZ_$5QXP4{Aj645wG_SNT&6m|O6~Tsl$q?nK*)(`{J4b=(yb^nOATtF1_aS978$x3 zx>Q@s4i3~IT*+l{@dx~Hst21fR*+5}S1@cf>&8*uLw-0^zK(+OpW?cS-YG1QBZ5q! zgTAgivzoF#`cSz&HL>Ti!!v#?36I1*l^mkrx7Y|K6L#n!-~5=d3;K<;Zqi|gpNUn_ z_^GaQDEQ*jfzh;`j&KXb66fWEk1K7vxQIMQ_#Wu_%3 z4Oeb7FJ`8I>Px;^S?)}2+4D_83gHEq>8qSQY0PVP?o)zAv3K~;R$fnwTmI-=ZLK`= zTm+0h*e+Yfr(IlH3i7gUclNH^!MU>id$Jw>O?2i0Cila#v|twub21@e{S2v}8Z13( zNDrTXZVgris|qYm<0NU(tAPouG!QF4ZNpZPkX~{tVf8xY690JqY1NVdiTtW+NqyRP zZ&;T0ikb8V{wxmFhlLTQ&?OP7 z;(z*<+?J2~z*6asSe7h`$8~Se(@t(#%?BGLVs$p``;CyvcT?7Y!{tIPva$LxCQ&4W z6v#F*);|RXvI%qnoOY&i4S*EL&h%hP3O zLsrFZhv&Hu5tF$Lx!8(hs&?!Kx5&L(fdu}UI5d*wn~A`nPUhG&Rv z2#ixiJdhSF-K2tpVL=)5UkXRuPAFrEW}7mW=uAmtVQ&pGE-&az6@#-(Te^n*lrH^m@X-ftVcwO_#7{WI)5v(?>uC9GG{lcGXYJ~Q8q zbMFl7;t+kV;|;KkBW2!P_o%Czhw&Q(nXlxK9ak&6r5t_KH8#1Mr-*0}2h8R9XNkr zto5-b7P_auqTJb(TJlmJ9xreA=6d=d)CVbYP-r4$hDn5|TIhB>SReMfh&OVLkMk-T zYf%$taLF0OqYF?V{+6Xkn>iX@TuqQ?&cN6UjC9YF&%q{Ut3zv{U2)~$>-3;Dp)*(? zg*$mu8^i=-e#acaj*T$pNowo{xiGEk$%DusaQiS!KjJH96XZ-hXv+jk%ard#fu=@Q z$AM)YWvE^{%tDfK%nD49=PI|wYu}lYVbB#a7wtN^Nml@CE@{Gv7+jo{_V?I*jkdLD zJE|jfdrmVbkfS>rN*+`#l%ZUi5_bMS<>=MBDNlpiSb_tAF|Zy`K7kcp@|d?yaTmB^ zo?(vg;B$vxS|SszusORgDg-*Uitzdi{dUV+glA~R8V(?`3GZIl^egW{a919!j#>f` znL1o_^-b`}xnU0+~KIFLQ)$Q6#ym%)(GYC`^XM*{g zv3AM5$+TtDRs%`2TyR^$(hqE7Y1b&`Jd6dS6B#hDVbJlUXcG3y*439D8MrK!2D~6gn>UD4Imctb z+IvAt0iaW73Iq$K?4}H`7wq6YkTMm`tcktXgK0lKPmh=>h+l}Y+pDtvHnG>uqBA)l zAH6BV4F}v$(o$8Gfo*PB>IuaY1*^*`OTx4|hM8jZ?B6HY;F6p4{`OcZZ(us-RVwDx zUzJrCQlp@mz1ZFiSZ*$yX3c_#h9J;yBE$2g%xjmGF4ca z&yL`nGVs!Zxsh^j6i%$a*I3ZD2SoNT`{D%mU=LKaEwbN(_J5%i-6Va?@*>=3(dQy` zOv%$_9lcy9+(t>qohkuU4r_P=R^6ME+wFu&LA9tw9RA?azGhjrVJKy&8=*qZT5Dr8g--d+S8zAyJ$1HlW3Olryt`yE zFIph~Z6oF&o64rw{>lgZISC6p^CBer9C5G6yq%?8tC+)7*d+ib^?fU!JRFxynRLEZ zj;?PwtS}Ao#9whV@KEmwQgM0TVP{hs>dg(1*DiMUOKHdQGIqa0`yZnHk9mtbPfoLx zo;^V6pKUJ!5#n`w2D&381#5#_t}AlTGEgDz$^;u;-vxDN?^#5!zN9ngytY@oTv!nc zp1Xn8uR$1Z;7vY`-<*?DfPHB;x|GUi_fI9@I9SVRv1)qETbNU_8{5U|(>Du84qP#7 z*l9Y$SgA&wGbj>R1YeT9vYjZuC@|{rajTL0f%N@>3$DFU=`lSPl=Iv;EjuGjBa$Gw zHD-;%YOE@<-!7-Mn`0WuO3oWuL6tB2cpPw~Nvuj|KM@))ixuDK`9;jGMe2d)7gHin zS<>k@!x;!TJEc#HdL#RF(`|4W+H88d4V%zlh(7#{q2d0OQX9*FW^`^_<3r$kabWAB z$9BONo5}*(%kx zOXi-yM_cmB3>inPpI~)duvZykJ@^^aWzQ=eQ&STUa}2uT@lV&WoRzkUoE`rR0)`=l zFT%f|LA9fCw>`enm$p7W^E@U7RNBtsh{_-7vVz3DtB*y#*~(L9+x9*wn8VjWw|Q~q zKFsj1Yl>;}%MG3=PY`$g$_mnyhuV&~O~u~)968$0b2!Jkd;2MtAP#ZDYw9hmK_+M$ zb3pxyYC&|CuAbtiG8HZjj?MZJBFbt`ryf+c1dXFuC z0*ZQhBzNBd*}s6K_G}(|Z_9NDV162#y%WSNe|FTDDhx)K!c(mMJh@h87@8(^YdK$&d*^WQe8Z53 z(|@MRJ$Lk-&ii74MPIs80WsOFZ(NX23oR-?As+*aq6b?~62@fSVmM-_*cb1RzZ)`5$agEiL`-E9s7{GM2?(KNPgK1(+c*|-FKoy}X(D_b#etO|YR z(BGZ)0Ntfv-7R4GHoXp?l5g#*={S1{u-QzxCGng*oWr~@X-5f~RA14b8~B+pLKvr4 zfgL|7I>jlak9>D4=(i(cqYf7#318!OSR=^`xxvI!bBlS??`xxWeg?+|>MxaIdH1U~#1tHu zB{QMR?EGRmQ_l4p6YXJ{o(hh-7Tdm>TAX380TZZZyVkqHNzjUn*_|cb?T? zt;d2s-?B#Mc>T-gvBmQZx(y_cfkXZO~{N zT6rP7SD6g~n9QJ)8F*8uHxTLCAZ{l1Y&?6v)BOJZ)=R-pY=Y=&1}jE7fQ>USS}xP#exo57uND0i*rEk@$;nLvRB@u~s^dwRf?G?_enN@$t* zbL%JO=rV(3Ju8#GqUpeE3l_Wu1lN9Y{D4uaUe`g>zlj$1ER$6S6@{m1!~V|bYkhZA z%CvrDRTkHuajMU8;&RZ&itnC~iYLW4DVkP<$}>#&(`UO>!n)Po;Mt(SY8Yb`AS9lt znbX^i?Oe9r_o=?})IHKHoQGKXsps_SE{hwrg?6dMI|^+$CeC&z@*LuF+P`7LfZ*yr+KN8B4{Nzv<`A(wyR@!|gw{zB6Ha ziwPAYh)oJ(nlqSknu(8g9N&1hu0$vFK$W#mp%>X~AU1ay+EKWcFdif{% z#4!4aoVVJ;ULmkQf!ke2}3hqxLK>eq|-d7Ly7-J9zMpT`?dxo6HdfJA|t)?qPEVBDv z{y_b?4^|YA4%WW0VZd8C(ZgQzRI5(I^)=Ub`Y#MHc@nv0w-DaJAqsbEHDWG8Ia6ju zo-iyr*sq((gEwCC&^TYBWt4_@|81?=B-?#P6NMff(*^re zYqvDuO`K@`mjm_Jd;mW_tP`3$cS?R$jR1ZN09$YO%_iBqh5ftzSpMQQtxKFU=FYmP zeY^jph+g<4>YO;U^O>-NFLn~-RqlHvnZl2yd2A{Yc1G@Ga$d+Q&(f^tnPf+Z7serIU};17+2DU_f4Z z@GaPFut27d?!YiD+QP@)T=77cR9~MK@bd~pY%X(h%L={{OIb8IQmf-!xmZkm8A0Ga zQSWONI17_ru5wpHg3jI@i9D+_Y|pCqVuHJNdHUauTD=R$JcD2K_liQisqG$(sm=k9;L* z!L?*4B~ql7uioSX$zWJ?;q-SWXRFhz2Jt4%fOHA=Bwf|RzhwqdXGr78y$J)LR7&3T zE1WWz*>GPWKZ0%|@%6=fyx)5rzUpI;bCj>3RKzNG_1w$fIFCZ&UR0(7S?g}`&Pg$M zf`SLsz8wK82Vyj7;RyKmY{a8G{2BHG%w!^T|Njr!h9TO2LaP^_f22Q1=l$QiU84ao zHe_#{S6;qrC6w~7{y(hs-?-j?lbOfgH^E=XcSgnwW*eEz{_Z<_Px$?ny*JR5%f>l)FnDQ543{x%ZCiu33$Wg!pQFfT_}?5Q|_VSlIbLC`dpoMXL}9 zHfd9&47Mo(7D231gb+kjFxZHS4-m~7WurTH&doVX2KI5sU4v(sJ1@T9eCIKPjsqSr z)C01LsCxk=72-vXmX}CQD#BD;Cthymh&~=f$Q8nn0J<}ZrusBy4PvRNE}+1ceuj8u z0mW5k8fmgeLnTbWHGwfKA3@PdZxhn|PypR&^p?weGftrtCbjF#+zk_5BJh7;0`#Wr zgDpM_;Ax{jO##IrT`Oz;MvfwGfV$zD#c2xckpcXC6oou4ML~ezCc2EtnsQTB4tWNg z?4bkf;hG7IMfhgNI(FV5Gs4|*GyMTIY0$B=_*mso9Ityq$m^S>15>-?0(zQ<8Qy<_TjHE33(?_M8oaM zyc;NxzRVK@DL6RJnX%U^xW0Gpg(lXp(!uK1v0YgHjs^ZXSQ|m#lV7ip7{`C_J2TxPmfw%h$|%acrYHt)Re^PB%O&&=~a zhS(%I#+V>J-vjIib^<+s%ludY7y^C(P8nmqn9fp!i+?vr`bziDE=bx`%2W#Xyrj|i z!XQ4v1%L`m{7KT7q+LZNB^h8Ha2e=`Wp65^0;J00)_^G=au=8Yo;1b`CV&@#=jIBo zjN^JNVfYSs)+kDdGe7`1&8!?MQYKS?DuHZf3iogk_%#9E|5S zWeHrmAo>P;ejX7mwq#*}W25m^ZI+{(Z8fI?4jM_fffY0nok=+88^|*_DwcW>mR#e+ zX$F_KMdb6sRz!~7KkyN0G(3XQ+;z3X%PZ4gh;n-%62U<*VUKNv(D&Q->Na@Xb&u5Q3`3DGf+a8O5x7c#7+R+EAYl@R5us)CIw z7sT@_y~Ao@uL#&^LIh&QceqiT^+lb0YbFZt_SHOtWA%mgPEKVNvVgCsXy{5+zl*X8 zCJe)Q@y>wH^>l4;h1l^Y*9%-23TSmE>q5nI@?mt%n;Sj4Qq`Z+ib)a*a^cJc%E9^J zB;4s+K@rARbcBLT5P=@r;IVnBMKvT*)ew*R;&8vu%?Z&S>s?8?)3*YawM0P4!q$Kv zMmKh3lgE~&w&v%wVzH3Oe=jeNT=n@Y6J6TdHWTjXfX~-=1A1Bw`EW8rn}MqeI34nh zexFeA?&C3B2(E?0{drE@DA2pu(A#ElY&6el60Rn|Qpn-FkfQ8M93AfWIr)drgDFEU zghdWK)^71EWCP(@(=c4kfH1Y(4iugD4fve6;nSUpLT%!)MUHs1!zJYy4y||C+SwQ! z)KM&$7_tyM`sljP2fz6&Z;jxRn{Wup8IOUx8D4uh&(=O zx-7$a;U><*5L^!%xRlw)vAbh;sdlR||& ze}8_8%)c2Fwy=F&H|LM+p{pZB5DKTx>Y?F1N%BlZkXf!}JeGuMZk~LPi7{cidvUGB zAJ4LVeNV%XO>LTrklB#^-;8nb;}6l;1oW&WS=Mz*Az!4cqqQzbOSFq`$Q%PfD7srM zpKgP-D_0XPTRX*hAqeq0TDkJ;5HB1%$3Np)99#16c{ zJImlNL(npL!W|Gr_kxl1GVmF5&^$^YherS7+~q$p zt}{a=*RiD2Ikv6o=IM1kgc7zqpaZ;OB)P!1zz*i3{U()Dq#jG)egvK}@uFLa`oyWZ zf~=MV)|yJn`M^$N%ul5);JuQvaU1r2wt(}J_Qgyy`qWQI`hEeRX0uC@c1(dQ2}=U$ tNIIaX+dr)NRWXcxoR{>fqI{SF_dm1Ylv~=3YHI)h002ovPDHLkV1g(pWS;;4 literal 0 HcmV?d00001 diff --git a/packages/stream_chat_persistence/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/packages/stream_chat_persistence/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..f091b6b0bca859a3f474b03065bef75ba58a9e4c GIT binary patch literal 1588 zcmV-42Fv-0P)C1SqPt}wig>|5Crh^=oyX$BK<}M8eLU3e2hGT;=G|!_SP)7zNI6fqUMB=)y zRAZ>eDe#*r`yDAVgB_R*LB*MAc)8(b{g{9McCXW!lq7r(btRoB9!8B-#AI6JMb~YFBEvdsV)`mEQO^&#eRKx@b&x- z5lZm*!WfD8oCLzfHGz#u7sT0^VLMI1MqGxF^v+`4YYnVYgk*=kU?HsSz{v({E3lb9 z>+xILjBN)t6`=g~IBOelGQ(O990@BfXf(DRI5I$qN$0Gkz-FSc$3a+2fX$AedL4u{ z4V+5Ong(9LiGcIKW?_352sR;LtDPmPJXI{YtT=O8=76o9;*n%_m|xo!i>7$IrZ-{l z-x3`7M}qzHsPV@$v#>H-TpjDh2UE$9g6sysUREDy_R(a)>=eHw-WAyfIN z*qb!_hW>G)Tu8nSw9yn#3wFMiLcfc4pY0ek1}8(NqkBR@t4{~oC>ryc-h_ByH(Cg5 z>ao-}771+xE3um9lWAY1FeQFxowa1(!J(;Jg*wrg!=6FdRX+t_<%z&d&?|Bn){>zm zZQj(aA_HeBY&OC^jj*)N`8fa^ePOU72VpInJoI1?`ty#lvlNzs(&MZX+R%2xS~5Kh zX*|AU4QE#~SgPzOXe9>tRj>hjU@c1k5Y_mW*Jp3fI;)1&g3j|zDgC+}2Q_v%YfDax z!?umcN^n}KYQ|a$Lr+51Nf9dkkYFSjZZjkma$0KOj+;aQ&721~t7QUKx61J3(P4P1 zstI~7-wOACnWP4=8oGOwz%vNDqD8w&Q`qcNGGrbbf&0s9L0De{4{mRS?o0MU+nR_! zrvshUau0G^DeMhM_v{5BuLjb#Hh@r23lDAk8oF(C+P0rsBpv85EP>4CVMx#04MOfG z;P%vktHcXwTj~+IE(~px)3*MY77e}p#|c>TD?sMatC0Tu4iKKJ0(X8jxQY*gYtxsC z(zYC$g|@+I+kY;dg_dE>scBf&bP1Nc@Hz<3R)V`=AGkc;8CXqdi=B4l2k|g;2%#m& z*jfX^%b!A8#bI!j9-0Fi0bOXl(-c^AB9|nQaE`*)Hw+o&jS9@7&Gov#HbD~#d{twV zXd^Tr^mWLfFh$@Dr$e;PBEz4(-2q1FF0}c;~B5sA}+Q>TOoP+t>wf)V9Iy=5ruQa;z)y zI9C9*oUga6=hxw6QasLPnee@3^Rr*M{CdaL5=R41nLs(AHk_=Y+A9$2&H(B7!_pURs&8aNw7?`&Z&xY_Ye z)~D5Bog^td-^QbUtkTirdyK^mTHAOuptDflut!#^lnKqU md>ggs(5nOWAqO?umG&QVYK#ibz}*4>0000U6E9hRK9^#O7(mu>ETqrXGsduA8$)?`v2seloOCza43C{NQ$$gAOH**MCn0Q?+L7dl7qnbRdqZ8LSVp1ItDxhxD?t@5_yHg6A8yI zC*%Wgg22K|8E#!~cTNYR~@Y9KepMPrrB8cABapAFa=`H+UGhkXUZV1GnwR1*lPyZ;*K(i~2gp|@bzp8}og7e*#% zEnr|^CWdVV!-4*Y_7rFvlww2Ze+>j*!Z!pQ?2l->4q#nqRu9`ELo6RMS5=br47g_X zRw}P9a7RRYQ%2Vsd0Me{_(EggTnuN6j=-?uFS6j^u69elMypu?t>op*wBx<=Wx8?( ztpe^(fwM6jJX7M-l*k3kEpWOl_Vk3@(_w4oc}4YF4|Rt=2V^XU?#Yz`8(e?aZ@#li0n*=g^qOcVpd-Wbok=@b#Yw zqn8u9a)z>l(1kEaPYZ6hwubN6i<8QHgsu0oE) ziJ(p;Wxm>sf!K+cw>R-(^Y2_bahB+&KI9y^);#0qt}t-$C|Bo71lHi{_+lg#f%RFy z0um=e3$K3i6K{U_4K!EX?F&rExl^W|G8Z8;`5z-k}OGNZ0#WVb$WCpQu-_YsiqKP?BB# vzVHS-CTUF4Ozn5G+mq_~Qqto~ahA+K`|lyv3(-e}00000NkvXXu0mjfd`9t{ literal 0 HcmV?d00001 diff --git a/packages/stream_chat_persistence/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/packages/stream_chat_persistence/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..d0ef06e7edb86cdfe0d15b4b0d98334a86163658 GIT binary patch literal 1716 zcmds$`#;kQ7{|XelZftyR5~xW7?MLxS4^|Hw3&P7^y)@A9Fj{Xm1~_CIV^XZ%SLBn zA;!r`GqGHg=7>xrB{?psZQs88ZaedDoagm^KF{a*>G|dJWRSe^I$DNW008I^+;Kjt z>9p3GNR^I;v>5_`+91i(*G;u5|L+Bu6M=(afLjtkya#yZ175|z$pU~>2#^Z_pCZ7o z1c6UNcv2B3?; zX%qdxCXQpdKRz=#b*q0P%b&o)5ZrNZt7$fiETSK_VaY=mb4GK`#~0K#~9^ zcY!`#Af+4h?UMR-gMKOmpuYeN5P*RKF!(tb`)oe0j2BH1l?=>y#S5pMqkx6i{*=V9JF%>N8`ewGhRE(|WohnD59R^$_36{4>S zDFlPC5|k?;SPsDo87!B{6*7eqmMdU|QZ84>6)Kd9wNfh90=y=TFQay-0__>=<4pk& zYDjgIhL-jQ9o>z32K)BgAH+HxamL{ZL~ozu)Qqe@a`FpH=oQRA8=L-m-1dam(Ix2V z?du;LdMO+ooBelr^_y4{|44tmgH^2hSzPFd;U^!1p>6d|o)(-01z{i&Kj@)z-yfWQ)V#3Uo!_U}q3u`(fOs`_f^ueFii1xBNUB z6MecwJN$CqV&vhc+)b(p4NzGGEgwWNs z@*lUV6LaduZH)4_g!cE<2G6#+hJrWd5(|p1Z;YJ7ifVHv+n49btR}dq?HHDjl{m$T z!jLZcGkb&XS2OG~u%&R$(X+Z`CWec%QKt>NGYvd5g20)PU(dOn^7%@6kQb}C(%=vr z{?RP(z~C9DPnL{q^@pVw@|Vx~@3v!9dCaBtbh2EdtoNHm4kGxp>i#ct)7p|$QJs+U z-a3qtcPvhihub?wnJqEt>zC@)2suY?%-96cYCm$Q8R%-8$PZYsx3~QOLMDf(piXMm zB=<63yQk1AdOz#-qsEDX>>c)EES%$owHKue;?B3)8aRd}m~_)>SL3h2(9X;|+2#7X z+#2)NpD%qJvCQ0a-uzZLmz*ms+l*N}w)3LRQ*6>|Ub-fyptY(keUxw+)jfwF5K{L9 z|Cl_w=`!l_o><384d&?)$6Nh(GAm=4p_;{qVn#hI8lqewW7~wUlyBM-4Z|)cZr?Rh z=xZ&Ol>4(CU85ea(CZ^aO@2N18K>ftl8>2MqetAR53_JA>Fal`^)1Y--Am~UDa4th zKfCYpcXky$XSFDWBMIl(q=Mxj$iMBX=|j9P)^fDmF(5(5$|?Cx}DKEJa&XZP%OyE`*GvvYQ4PV&!g2|L^Q z?YG}tx;sY@GzMmsY`7r$P+F_YLz)(e}% zyakqFB<6|x9R#TdoP{R$>o7y(-`$$p0NxJ6?2B8tH)4^yF(WhqGZlM3=9Ibs$%U1w zWzcss*_c0=v_+^bfb`kBFsI`d;ElwiU%frgRB%qBjn@!0U2zZehBn|{%uNIKBA7n= zzE`nnwTP85{g;8AkYxA68>#muXa!G>xH22D1I*SiD~7C?7Za+9y7j1SHiuSkKK*^O zsZ==KO(Ua#?YUpXl{ViynyT#Hzk=}5X$e04O@fsMQjb}EMuPWFO0e&8(2N(29$@Vd zn1h8Yd>6z(*p^E{c(L0Lg=wVdupg!z@WG;E0k|4a%s7Up5C0c)55XVK*|x9RQeZ1J@1v9MX;>n34(i>=YE@Iur`0Vah(inE3VUFZNqf~tSz{1fz3Fsn_x4F>o(Yo;kpqvBe-sbwH(*Y zu$JOl0b83zu$JMvy<#oH^Wl>aWL*?aDwnS0iEAwC?DK@aT)GHRLhnz2WCvf3Ba;o=aY7 z2{Asu5MEjGOY4O#Ggz@@J;q*0`kd2n8I3BeNuMmYZf{}pg=jTdTCrIIYuW~luKecn z+E-pHY%ohj@uS0%^ z&(OxwPFPD$+#~`H?fMvi9geVLci(`K?Kj|w{rZ9JgthFHV+=6vMbK~0)Ea<&WY-NC zy-PnZft_k2tfeQ*SuC=nUj4H%SQ&Y$gbH4#2sT0cU0SdFs=*W*4hKGpuR1{)mV;Qf5pw4? zfiQgy0w3fC*w&Bj#{&=7033qFR*<*61B4f9K%CQvxEn&bsWJ{&winp;FP!KBj=(P6 z4Z_n4L7cS;ao2)ax?Tm|I1pH|uLpDSRVghkA_UtFFuZ0b2#>!8;>-_0ELjQSD-DRd z4im;599VHDZYtnWZGAB25W-e(2VrzEh|etsv2YoP#VbIZ{aFkwPrzJ#JvCvA*mXS& z`}Q^v9(W4GiSs}#s7BaN!WA2bniM$0J(#;MR>uIJ^uvgD3GS^%*ikdW6-!VFUU?JV zZc2)4cMsX@j z5HQ^e3BUzOdm}yC-xA%SY``k$rbfk z;CHqifhU*jfGM@DkYCecD9vl*qr58l6x<8URB=&%{!Cu3RO*MrKZ4VO}V6R0a zZw3Eg^0iKWM1dcTYZ0>N899=r6?+adUiBKPciJw}L$=1f4cs^bio&cr9baLF>6#BM z(F}EXe-`F=f_@`A7+Q&|QaZ??Txp_dB#lg!NH=t3$G8&06MFhwR=Iu*Im0s_b2B@| znW>X}sy~m#EW)&6E&!*0%}8UAS)wjt+A(io#wGI@Z2S+Ms1Cxl%YVE800007ip7{`C_J2TxPmfw%h$|%acrYHt)Re^PB%O&&=~a zhS(%I#+V>J-vjIib^<+s%ludY7y^C(P8nmqn9fp!i+?vr`bziDE=bx`%2W#Xyrj|i z!XQ4v1%L`m{7KT7q+LZNB^h8Ha2e=`Wp65^0;J00)_^G=au=8Yo;1b`CV&@#=jIBo zjN^JNVfYSs)+kDdGe7`1&8!?MQYKS?DuHZf3iogk_%#9E|5S zWeHrmAo>P;ejX7mwq#*}W25m^ZI+{(Z8fI?4jM_fffY0nok=+88^|*_DwcW>mR#e+ zX$F_KMdb6sRz!~7KkyN0G(3XQ+;z3X%PZ4gh;n-%62U<*VUKNv(D&Q->Na@Xb&u5Q3`3DGf+a8O5x7c#7+R+EAYl@R5us)CIw z7sT@_y~Ao@uL#&^LIh&QceqiT^+lb0YbFZt_SHOtWA%mgPEKVNvVgCsXy{5+zl*X8 zCJe)Q@y>wH^>l4;h1l^Y*9%-23TSmE>q5nI@?mt%n;Sj4Qq`Z+ib)a*a^cJc%E9^J zB;4s+K@rARbcBLT5P=@r;IVnBMKvT*)ew*R;&8vu%?Z&S>s?8?)3*YawM0P4!q$Kv zMmKh3lgE~&w&v%wVzH3Oe=jeNT=n@Y6J6TdHWTjXfX~-=1A1Bw`EW8rn}MqeI34nh zexFeA?&C3B2(E?0{drE@DA2pu(A#ElY&6el60Rn|Qpn-FkfQ8M93AfWIr)drgDFEU zghdWK)^71EWCP(@(=c4kfH1Y(4iugD4fve6;nSUpLT%!)MUHs1!zJYy4y||C+SwQ! z)KM&$7_tyM`sljP2fz6&Z;jxRn{Wup8IOUx8D4uh&(=O zx-7$a;U><*5L^!%xRlw)vAbh;sdlR||& ze}8_8%)c2Fwy=F&H|LM+p{pZB5DKTx>Y?F1N%BlZkXf!}JeGuMZk~LPi7{cidvUGB zAJ4LVeNV%XO>LTrklB#^-;8nb;}6l;1oW&WS=Mz*Az!4cqqQzbOSFq`$Q%PfD7srM zpKgP-D_0XPTRX*hAqeq0TDkJ;5HB1%$3Np)99#16c{ zJImlNL(npL!W|Gr_kxl1GVmF5&^$^YherS7+~q$p zt}{a=*RiD2Ikv6o=IM1kgc7zqpaZ;OB)P!1zz*i3{U()Dq#jG)egvK}@uFLa`oyWZ zf~=MV)|yJn`M^$N%ul5);JuQvaU1r2wt(}J_Qgyy`qWQI`hEeRX0uC@c1(dQ2}=U$ tNIIaX+dr)NRWXcxoR{>fqI{SF_dm1Ylv~=3YHI)h002ovPDHLkV1g(pWS;;4 literal 0 HcmV?d00001 diff --git a/packages/stream_chat_persistence/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/packages/stream_chat_persistence/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..c8f9ed8f5cee1c98386d13b17e89f719e83555b2 GIT binary patch literal 1895 zcmV-t2blPYP)FQtfgmafE#=YDCq`qUBt#QpG%*H6QHY765~R=q zZ6iudfM}q!Pz#~9JgOi8QJ|DSu?1-*(kSi1K4#~5?#|rh?sS)(-JQqX*}ciXJ56_H zdw=^s_srbAdqxlvGyrgGet#6T7_|j;95sL%MtM;q86vOxKM$f#puR)Bjv9Zvz9-di zXOTSsZkM83)E9PYBXC<$6(|>lNLVBb&&6y{NByFCp%6+^ALR@NCTse_wqvNmSWI-m z!$%KlHFH2omF!>#%1l3LTZg(s7eof$7*xB)ZQ0h?ejh?Ta9fDv59+u#MokW+1t8Zb zgHv%K(u9G^Lv`lh#f3<6!JVTL3(dCpxHbnbA;kKqQyd1~^Xe0VIaYBSWm6nsr;dFj z4;G-RyL?cYgsN1{L4ZFFNa;8)Rv0fM0C(~Tkit94 zz#~A)59?QjD&pAPSEQ)p8gP|DS{ng)j=2ux)_EzzJ773GmQ_Cic%3JJhC0t2cx>|v zJcVusIB!%F90{+}8hG3QU4KNeKmK%T>mN57NnCZ^56=0?&3@!j>a>B43pi{!u z7JyDj7`6d)qVp^R=%j>UIY6f+3`+qzIc!Y_=+uN^3BYV|o+$vGo-j-Wm<10%A=(Yk^beI{t%ld@yhKjq0iNjqN4XMGgQtbKubPM$JWBz}YA65k%dm*awtC^+f;a-x4+ddbH^7iDWGg&N0n#MW{kA|=8iMUiFYvMoDY@sPC#t$55gn6ykUTPAr`a@!(;np824>2xJthS z*ZdmT`g5-`BuJs`0LVhz+D9NNa3<=6m;cQLaF?tCv8)zcRSh66*Z|vXhG@$I%U~2l z?`Q zykI#*+rQ=z6Jm=Bui-SfpDYLA=|vzGE(dYm=OC8XM&MDo7ux4UF1~0J1+i%aCUpRe zt3L_uNyQ*cE(38Uy03H%I*)*Bh=Lb^Xj3?I^Hnbeq72(EOK^Y93CNp*uAA{5Lc=ky zx=~RKa4{iTm{_>_vSCm?$Ej=i6@=m%@VvAITnigVg{&@!7CDgs908761meDK5azA} z4?=NOH|PdvabgJ&fW2{Mo$Q0CcD8Qc84%{JPYt5EiG{MdLIAeX%T=D7NIP4%Hw}p9 zg)==!2Lbp#j{u_}hMiao9=!VSyx0gHbeCS`;q&vzeq|fs`y&^X-lso(Ls@-706qmA z7u*T5PMo_w3{se1t2`zWeO^hOvTsohG_;>J0wVqVe+n)AbQCx)yh9;w+J6?NF5Lmo zecS@ieAKL8%bVd@+-KT{yI|S}O>pYckUFs;ry9Ow$CD@ztz5K-*D$^{i(_1llhSh^ zEkL$}tsQt5>QA^;QgjgIfBDmcOgi5YDyu?t6vSnbp=1+@6D& z5MJ}B8q;bRlVoxasyhcUF1+)o`&3r0colr}QJ3hcSdLu;9;td>kf@Tcn<@9sIx&=m z;AD;SCh95=&p;$r{Xz3iWCO^MX83AGJ(yH&eTXgv|0=34#-&WAmw{)U7OU9!Wz^!7 zZ%jZFi@JR;>Mhi7S>V7wQ176|FdW2m?&`qa(ScO^CFPR80HucLHOTy%5s*HR0^8)i h0WYBP*#0Ks^FNSabJA*5${_#%002ovPDHLkV1oKhTl@e3 literal 0 HcmV?d00001 diff --git a/packages/stream_chat_persistence/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/packages/stream_chat_persistence/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..a6d6b8609df07bf62e5100a53a01510388bd2b22 GIT binary patch literal 2665 zcmV-v3YPVWP)oFh3q0MFesq&64WThn3$;G69TfjsAv=f2G9}p zgSx99+!YV6qME!>9MD13x)k(+XE7W?_O4LoLb5ND8 zaV{9+P@>42xDfRiYBMSgD$0!vssptcb;&?u9u(LLBKmkZ>RMD=kvD3h`sk6!QYtBa ztlZI#nu$8lJ^q2Z79UTgZe>BU73(Aospiq+?SdMt8lDZ;*?@tyWVZVS_Q7S&*tJaiRlJ z+aSMOmbg3@h5}v;A*c8SbqM3icg-`Cnwl;7Ts%A1RkNIp+Txl-Ckkvg4oxrqGA5ewEgYqwtECD<_3Egu)xGllKt&J8g&+=ac@Jq4-?w6M3b*>w5 z69N3O%=I^6&UL5gZ!}trC7bUj*12xLdkNs~Bz4QdJJ*UDZox2UGR}SNg@lmOvhCc~ z*f_UeXv(=#I#*7>VZx2ObEN~UoGUTl=-@)E;YtCRZ>SVp$p9yG5hEFZ!`wI!spd)n zSk+vK0Vin7FL{7f&6OB%f;SH22dtbcF<|9fi2Fp%q4kxL!b1#l^)8dUwJ zwEf{(wJj@8iYDVnKB`eSU+;ml-t2`@%_)0jDM`+a46xhDbBj2+&Ih>1A>6aky#(-SYyE{R3f#y57wfLs z6w1p~$bp;6!9DX$M+J~S@D6vJAaElETnsX4h9a5tvPhC3L@qB~bOzkL@^z0k_hS{T4PF*TDrgdXp+dzsE? z>V|VR035Pl9n5&-RePFdS{7KAr2vPOqR9=M$vXA1Yy5>w;EsF`;OK{2pkn-kpp9Pw z)r;5JfJKKaT$4qCb{TaXHjb$QA{y0EYy*+b1XI;6Ah- zw13P)xT`>~eFoJC!>{2XL(a_#upp3gaR1#5+L(Jmzp4TBnx{~WHedpJ1ch8JFk~Sw z>F+gN+i+VD?gMXwcIhn8rz`>e>J^TI3E-MW>f}6R-pL}>WMOa0k#jN+`RyUVUC;#D zg|~oS^$6%wpF{^Qr+}X>0PKcr3Fc&>Z>uv@C);pwDs@2bZWhYP!rvGx?_|q{d`t<*XEb#=aOb=N+L@CVBGqImZf&+a zCQEa3$~@#kC);pasdG=f6tuIi0PO-y&tvX%>Mv=oY3U$nD zJ#gMegnQ46pq+3r=;zmgcG+zRc9D~c>z+jo9&D+`E6$LmyFqlmCYw;-Zooma{sR@~ z)_^|YL1&&@|GXo*pivH7k!msl+$Sew3%XJnxajt0K%3M6Bd&YFNy9}tWG^aovK2eX z1aL1%7;KRDrA@eG-Wr6w+;*H_VD~qLiVI`{_;>o)k`{8xa3EJT1O_>#iy_?va0eR? zDV=N%;Zjb%Z2s$@O>w@iqt!I}tLjGk!=p`D23I}N4Be@$(|iSA zf3Ih7b<{zqpDB4WF_5X1(peKe+rASze%u8eKLn#KKXt;UZ+Adf$_TO+vTqshLLJ5c z52HucO=lrNVae5XWOLm!V@n-ObU11!b+DN<$RuU+YsrBq*lYT;?AwJpmNKniF0Q1< zJCo>Q$=v$@&y=sj6{r!Y&y&`0$-I}S!H_~pI&2H8Z1C|BX4VgZ^-! zje3-;x0PBD!M`v*J_)rL^+$<1VJhH*2Fi~aA7s&@_rUHYJ9zD=M%4AFQ`}k8OC$9s XsPq=LnkwKG00000NkvXXu0mjfhAk5^ literal 0 HcmV?d00001 diff --git a/packages/stream_chat_persistence/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/packages/stream_chat_persistence/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..a6d6b8609df07bf62e5100a53a01510388bd2b22 GIT binary patch literal 2665 zcmV-v3YPVWP)oFh3q0MFesq&64WThn3$;G69TfjsAv=f2G9}p zgSx99+!YV6qME!>9MD13x)k(+XE7W?_O4LoLb5ND8 zaV{9+P@>42xDfRiYBMSgD$0!vssptcb;&?u9u(LLBKmkZ>RMD=kvD3h`sk6!QYtBa ztlZI#nu$8lJ^q2Z79UTgZe>BU73(Aospiq+?SdMt8lDZ;*?@tyWVZVS_Q7S&*tJaiRlJ z+aSMOmbg3@h5}v;A*c8SbqM3icg-`Cnwl;7Ts%A1RkNIp+Txl-Ckkvg4oxrqGA5ewEgYqwtECD<_3Egu)xGllKt&J8g&+=ac@Jq4-?w6M3b*>w5 z69N3O%=I^6&UL5gZ!}trC7bUj*12xLdkNs~Bz4QdJJ*UDZox2UGR}SNg@lmOvhCc~ z*f_UeXv(=#I#*7>VZx2ObEN~UoGUTl=-@)E;YtCRZ>SVp$p9yG5hEFZ!`wI!spd)n zSk+vK0Vin7FL{7f&6OB%f;SH22dtbcF<|9fi2Fp%q4kxL!b1#l^)8dUwJ zwEf{(wJj@8iYDVnKB`eSU+;ml-t2`@%_)0jDM`+a46xhDbBj2+&Ih>1A>6aky#(-SYyE{R3f#y57wfLs z6w1p~$bp;6!9DX$M+J~S@D6vJAaElETnsX4h9a5tvPhC3L@qB~bOzkL@^z0k_hS{T4PF*TDrgdXp+dzsE? z>V|VR035Pl9n5&-RePFdS{7KAr2vPOqR9=M$vXA1Yy5>w;EsF`;OK{2pkn-kpp9Pw z)r;5JfJKKaT$4qCb{TaXHjb$QA{y0EYy*+b1XI;6Ah- zw13P)xT`>~eFoJC!>{2XL(a_#upp3gaR1#5+L(Jmzp4TBnx{~WHedpJ1ch8JFk~Sw z>F+gN+i+VD?gMXwcIhn8rz`>e>J^TI3E-MW>f}6R-pL}>WMOa0k#jN+`RyUVUC;#D zg|~oS^$6%wpF{^Qr+}X>0PKcr3Fc&>Z>uv@C);pwDs@2bZWhYP!rvGx?_|q{d`t<*XEb#=aOb=N+L@CVBGqImZf&+a zCQEa3$~@#kC);pasdG=f6tuIi0PO-y&tvX%>Mv=oY3U$nD zJ#gMegnQ46pq+3r=;zmgcG+zRc9D~c>z+jo9&D+`E6$LmyFqlmCYw;-Zooma{sR@~ z)_^|YL1&&@|GXo*pivH7k!msl+$Sew3%XJnxajt0K%3M6Bd&YFNy9}tWG^aovK2eX z1aL1%7;KRDrA@eG-Wr6w+;*H_VD~qLiVI`{_;>o)k`{8xa3EJT1O_>#iy_?va0eR? zDV=N%;Zjb%Z2s$@O>w@iqt!I}tLjGk!=p`D23I}N4Be@$(|iSA zf3Ih7b<{zqpDB4WF_5X1(peKe+rASze%u8eKLn#KKXt;UZ+Adf$_TO+vTqshLLJ5c z52HucO=lrNVae5XWOLm!V@n-ObU11!b+DN<$RuU+YsrBq*lYT;?AwJpmNKniF0Q1< zJCo>Q$=v$@&y=sj6{r!Y&y&`0$-I}S!H_~pI&2H8Z1C|BX4VgZ^-! zje3-;x0PBD!M`v*J_)rL^+$<1VJhH*2Fi~aA7s&@_rUHYJ9zD=M%4AFQ`}k8OC$9s XsPq=LnkwKG00000NkvXXu0mjfhAk5^ literal 0 HcmV?d00001 diff --git a/packages/stream_chat_persistence/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/packages/stream_chat_persistence/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..75b2d164a5a98e212cca15ea7bf2ab5de5108680 GIT binary patch literal 3831 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 literal 0 HcmV?d00001 diff --git a/packages/stream_chat_persistence/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/packages/stream_chat_persistence/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png new file mode 100644 index 0000000000000000000000000000000000000000..c4df70d39da7941ef3f6dcb7f06a192d8dcb308d GIT binary patch literal 1888 zcmV-m2cP(fP)x~L`~4d)Rspd&<9kFh{hn*KP1LP0~$;u(LfAu zp%fx&qLBcRHx$G|3q(bv@+b;o0*D|jwD-Q9uQR(l*ST}s+uPgQ-MeFwZ#GS?b332? z&Tk$&_miXn3IGq)AmQ)3sisq{raD4(k*bHvpCe-TdWq^NRTEVM)i9xbgQ&ccnUVx* zEY%vS%gDcSg=!tuIK8$Th2_((_h^+7;R|G{n06&O2#6%LK`a}n?h_fL18btz<@lFG za}xS}u?#DBMB> zw^b($1Z)`9G?eP95EKi&$eOy@K%h;ryrR3la%;>|o*>CgB(s>dDcNOXg}CK9SPmD? zmr-s{0wRmxUnbDrYfRvnZ@d z6johZ2sMX{YkGSKWd}m|@V7`Degt-43=2M?+jR%8{(H$&MLLmS;-|JxnX2pnz;el1jsvqQz}pGSF<`mqEXRQ5sC4#BbwnB_4` zc5bFE-Gb#JV3tox9fp-vVEN{(tOCpRse`S+@)?%pz+zVJXSooTrNCUg`R6`hxwb{) zC@{O6MKY8tfZ5@!yy=p5Y|#+myRL=^{tc(6YgAnkg3I(Cd!r5l;|;l-MQ8B`;*SCE z{u)uP^C$lOPM z5d~UhKhRRmvv{LIa^|oavk1$QiEApSrP@~Jjbg`<*dW4TO?4qG%a%sTPUFz(QtW5( zM)lA+5)0TvH~aBaOAs|}?u2FO;yc-CZ1gNM1dAxJ?%m?YsGR`}-xk2*dxC}r5j$d* zE!#Vtbo69h>V4V`BL%_&$} z+oJAo@jQ^Tk`;%xw-4G>hhb&)B?##U+(6Fi7nno`C<|#PVA%$Y{}N-?(Gc$1%tr4Pc}}hm~yY#fTOe!@v9s-ik$dX~|ygArPhByaXn8 zpI^FUjNWMsTFKTP3X7m?UK)3m zp6rI^_zxRYrx6_QmhoWoDR`fp4R7gu6;gdO)!KexaoO2D88F9x#TM1(9Bn7g;|?|o z)~$n&Lh#hCP6_LOPD>a)NmhW})LADx2kq=X7}7wYRj-0?dXr&bHaRWCfSqvzFa=sn z-8^gSyn-RmH=BZ{AJZ~!8n5621GbUJV7Qvs%JNv&$%Q17s_X%s-41vAPfIR>;x0Wlqr5?09S>x#%Qkt>?(&XjFRY}*L6BeQ3 z<6XEBh^S7>AbwGm@XP{RkeEKj6@_o%oV?hDuUpUJ+r#JZO?!IUc;r0R?>mi)*ZpQ) z#((dn=A#i_&EQn|hd)N$#A*fjBFuiHcYvo?@y1 z5|fV=a^a~d!c-%ZbMNqkMKiSzM{Yq=7_c&1H!mXk60Uv32dV;vMg&-kQ)Q{+PFtwc zj|-uQ;b^gts??J*9VxxOro}W~Q9j4Em|zSRv)(WSO9$F$s=Ydu%Q+5DOid~lwk&we zY%W(Z@ofdwPHncEZzZgmqS|!gTj3wQq9rxQy+^eNYKr1mj&?tm@wkO*9@UtnRMG>c aR{jt9+;fr}hV%pg00001^@s67{VYS000c7NklQEG_j zup^)eW&WUIApqy$=APz8jE@awGp)!bsTjDbrJO`$x^ZR^dr;>)LW>{ zs70vpsD38v)19rI=GNk1b(0?Js9~rjsQsu*K;@SD40RB-3^gKU-MYC7G!Bw{fZsqp zih4iIi;Hr_xZ033Iu{sQxLS=}yBXgLMn40d++>aQ0#%8D1EbGZp7+ z5=mK?t31BkVYbGOxE9`i748x`YgCMwL$qMsChbSGSE1`p{nSmadR zcQ#R)(?!~dmtD0+D2!K zR9%!Xp1oOJzm(vbLvT^$IKp@+W2=-}qTzTgVtQ!#Y7Gxz}stUIm<1;oBQ^Sh2X{F4ibaOOx;5ZGSNK z0maF^@(UtV$=p6DXLgRURwF95C=|U8?osGhgOED*b z7woJ_PWXBD>V-NjQAm{~T%sjyJ{5tn2f{G%?J!KRSrrGvQ1(^`YLA5B!~eycY(e5_ z*%aa{at13SxC(=7JT7$IQF~R3sy`Nn%EMv!$-8ZEAryB*yB1k&stni)=)8-ODo41g zkJu~roIgAih94tb=YsL%iH5@^b~kU9M-=aqgXIrbtxMpFy5mekFm#edF9z7RQ6V}R zBIhbXs~pMzt0VWy1Fi$^fh+1xxLDoK09&5&MJl(q#THjPm(0=z2H2Yfm^a&E)V+a5 zbi>08u;bJsDRUKR9(INSc7XyuWv(JsD+BB*0hS)FO&l&7MdViuur@-<-EHw>kHRGY zqoT}3fDv2-m{NhBG8X}+rgOEZ;amh*DqN?jEfQdqxdj08`Sr=C-KmT)qU1 z+9Cl)a1mgXxhQiHVB}l`m;-RpmKy?0*|yl?FXvJkFxuu!fKlcmz$kN(a}i*saM3nr z0!;a~_%Xqy24IxA2rz<+08=B-Q|2PT)O4;EaxP^6qixOv7-cRh?*T?zZU`{nIM-at zTKYWr9rJ=tppQ9I#Z#mLgINVB!pO-^FOcvFw6NhV0gztuO?g ztoA*C-52Q-Z-P#xB4HAY3KQVd%dz1S4PA3vHp0aa=zAO?FCt zC_GaTyVBg2F!bBr3U@Zy2iJgIAt>1sf$JWA9kh{;L+P*HfUBX1Zy{4MgNbDfBV_ly z!y#+753arsZUt@366jIC0klaC@ckuk!qu=pAyf7&QmiBUT^L1&tOHzsK)4n|pmrVT zs2($4=?s~VejTFHbFdDOwG;_58LkIj1Fh@{glkO#F1>a==ymJS$z;gdedT1zPx4Kj ztjS`y_C}%af-RtpehdQDt3a<=W5C4$)9W@QAse;WUry$WYmr51ml9lkeunUrE`-3e zmq1SgSOPNEE-Mf+AGJ$g0M;3@w!$Ej;hMh=v=I+Lpz^n%Pg^MgwyqOkNyu2c^of)C z1~ALor3}}+RiF*K4+4{(1%1j3pif1>sv0r^mTZ?5Jd-It!tfPfiG_p$AY*Vfak%FG z4z#;wLtw&E&?}w+eKG^=#jF7HQzr8rV0mY<1YAJ_uGz~$E13p?F^fPSzXSn$8UcI$ z8er9{5w5iv0qf8%70zV71T1IBB1N}R5Kp%NO0=5wJalZt8;xYp;b{1K) zHY>2wW-`Sl{=NpR%iu3(u6l&)rc%%cSA#aV7WCowfbFR4wcc{LQZv~o1u_`}EJA3>ki`?9CKYTA!rhO)if*zRdd}Kn zEPfYbhoVE~!FI_2YbC5qAj1kq;xP6%J8+?2PAs?`V3}nyFVD#sV3+uP`pi}{$l9U^ zSz}_M9f7RgnnRhaoIJgT8us!1aB&4!*vYF07Hp&}L zCRlop0oK4DL@ISz{2_BPlezc;xj2|I z23RlDNpi9LgTG_#(w%cMaS)%N`e>~1&a3<{Xy}>?WbF>OOLuO+j&hc^YohQ$4F&ze z+hwnro1puQjnKm;vFG~o>`kCeUIlkA-2tI?WBKCFLMBY=J{hpSsQ=PDtU$=duS_hq zHpymHt^uuV1q@uc4bFb{MdG*|VoW@15Osrqt2@8ll0qO=j*uOXn{M0UJX#SUztui9FN4)K3{9!y8PC-AHHvpVTU;x|-7P+taAtyglk#rjlH2 z5Gq8ik}BPaGiM{#Woyg;*&N9R2{J0V+WGB69cEtH7F?U~Kbi6ksi*`CFXsi931q7Y zGO82?whBhN%w1iDetv%~wM*Y;E^)@Vl?VDj-f*RX>{;o_=$fU!&KAXbuadYZ46Zbg z&6jMF=49$uL^73y;;N5jaHYv)BTyfh&`qVLYn?`o6BCA_z-0niZz=qPG!vonK3MW_ zo$V96zM!+kJRs{P-5-rQVse0VBH*n6A58)4uc&gfHMa{gIhV2fGf{st>E8sKyP-$8zp~wJX^A*@DI&-;8>gANXZj zU)R+Y)PB?=)a|Kj>8NXEu^S_h^7R`~Q&7*Kn!xyvzVv&^>?^iu;S~R2e-2fJx-oUb cX)(b1KSk$MOV07*qoM6N<$f&6$jw%VRuvdN2+38CZWny1cRtlsl+0_KtW)EU14Ei(F!UtWuj4IK+3{sK@>rh zs1Z;=(DD&U6+tlyL?UnHVN^&g6QhFi2#HS+*qz;(>63G(`|jRtW|nz$Pv7qTovP!^ zP_jES{mr@O-02w%!^a?^1ZP!_KmQiz0L~jZ=W@Qt`8wzOoclQsAS<5YdH;a(4bGLE zk8s}1If(PSIgVi!XE!5kA?~z*sobvNyohr;=Q_@h2@$6Flyej3J)D-6YfheRGl`HEcPk|~huT_2-U?PfL=4BPV)f1o!%rQ!NMt_MYw-5bUSwQ9Z&zC>u zOrl~UJglJNa%f50Ok}?WB{on`Ci`p^Y!xBA?m@rcJXLxtrE0FhRF3d*ir>yzO|BD$ z3V}HpFcCh6bTzY}Nt_(W%QYd3NG)jJ4<`F<1Od) zfQblTdC&h2lCz`>y?>|9o2CdvC8qZeIZt%jN;B7Hdn2l*k4M4MFEtq`q_#5?}c$b$pf_3y{Y!cRDafZBEj-*OD|gz#PBDeu3QoueOesLzB+O zxjf2wvf6Wwz>@AiOo2mO4=TkAV+g~%_n&R;)l#!cBxjuoD$aS-`IIJv7cdX%2{WT7 zOm%5rs(wqyPE^k5SIpUZ!&Lq4<~%{*>_Hu$2|~Xa;iX*tz8~G6O3uFOS?+)tWtdi| zV2b#;zRN!m@H&jd=!$7YY6_}|=!IU@=SjvGDFtL;aCtw06U;-v^0%k0FOyESt z1Wv$={b_H&8FiRV?MrzoHWd>%v6KTRU;-v^Miiz+@q`(BoT!+<37CKhoKb)|8!+RG z6BQFU^@fRW;s8!mOf2QViKQGk0TVER6EG1`#;Nm39Do^PoT!+<37AD!%oJe86(=et zZ~|sLzU>V-qYiU6V8$0GmU7_K8|Fd0B?+9Un1BhKAz#V~Fk^`mJtlCX#{^8^M8!me z8Yg;8-~>!e<-iG;h*0B1kBKm}hItVGY6WnjVpgnTTAC$rqQ^v)4KvOtpY|sIj@WYg zyw##ZZ5AC2IKNC;^hwg9BPk0wLStlmBr;E|$5GoAo$&Ui_;S9WY62n3)i49|T%C#i017z3J=$RF|KyZWnci*@lW4 z=AKhNN6+m`Q!V3Ye68|8y@%=am>YD0nG99M)NWc20%)gwO!96j7muR}Fr&54SxKP2 zP30S~lt=a*qDlbu3+Av57=9v&vr<6g0&`!8E2fq>I|EJGKs}t|{h7+KT@)LfIV-3K zK)r_fr2?}FFyn*MYoLC>oV-J~eavL2ho4a4^r{E-8m2hi>~hA?_vIG4a*KT;2eyl1 zh_hUvUJpNCFwBvRq5BI*srSle>c6%n`#VNsyC|MGa{(P&08p=C9+WUw9Hl<1o9T4M zdD=_C0F7#o8A_bRR?sFNmU0R6tW`ElnF8p53IdHo#S9(JoZCz}fHwJ6F<&?qrpVqE zte|m%89JQD+XwaPU#%#lVs-@-OL);|MdfINd6!XwP2h(eyafTUsoRkA%&@fe?9m@jw-v(yTTiV2(*fthQH9}SqmsRPVnwwbV$1E(_lkmo&S zF-truCU914_$jpqjr(>Ha4HkM4YMT>m~NosUu&UZ>zirfHo%N6PPs9^_o$WqPA0#5 z%tG>qFCL+b*0s?sZ;Sht0nE7Kl>OVXy=gjWxxK;OJ3yGd7-pZf7JYNcZo2*1SF`u6 zHJyRRxGw9mDlOiXqVMsNe#WX`fC`vrtjSQ%KmLcl(lC>ZOQzG^%iql2w-f_K@r?OE zwCICifM#L-HJyc7Gm>Ern?+Sk3&|Khmu4(~3qa$(m6Ub^U0E5RHq49za|XklN#?kP zl;EstdW?(_4D>kwjWy2f!LM)y?F94kyU3`W!6+AyId-89v}sXJpuic^NLL7GJItl~ zsiuB98AI-(#Mnm|=A-R6&2fwJ0JVSY#Q>&3$zFh|@;#%0qeF=j5Ajq@4i0tIIW z&}sk$&fGwoJpe&u-JeGLi^r?dO`m=y(QO{@h zQqAC7$rvz&5+mo3IqE?h=a~6m>%r5Quapvzq;{y~p zJpyXOBgD9VrW7@#p6l7O?o3feml(DtSL>D^R) zZUY%T2b0-vBAFN7VB;M88!~HuOXi4KcI6aRQ&h|XQ0A?m%j2=l1f0cGP}h(oVfJ`N zz#PpmFC*ieab)zJK<4?^k=g%OjPnkANzbAbmGZHoVRk*mTfm75s_cWVa`l*f$B@xu z5E*?&@seIo#*Y~1rBm!7sF9~~u6Wrj5oICUOuz}CS)jdNIznfzCA(stJ(7$c^e5wN z?lt>eYgbA!kvAR7zYSD&*r1$b|(@;9dcZ^67R0 zXAXJKa|5Sdmj!g578Nwt6d$sXuc&MWezA0Whd`94$h{{?1IwXP4)Tx4obDK%xoFZ_Z zjjHJ_P@R_e5blG@yEjnaJb`l;s%Lb2&=8$&Ct-fV`E^4CUs)=jTk!I}2d&n!f@)bm z@ z_4Dc86+3l2*p|~;o-Sb~oXb_RuLmoifDU^&Te$*FevycC0*nE3Xws8gsWp|Rj2>SM zns)qcYj?^2sd8?N!_w~4v+f-HCF|a$TNZDoNl$I1Uq87euoNgKb6&r26TNrfkUa@o zfdiFA@p{K&mH3b8i!lcoz)V{n8Q@g(vR4ns4r6w;K z>1~ecQR0-<^J|Ndg5fvVUM9g;lbu-){#ghGw(fg>L zh)T5Ljb%lWE;V9L!;Cqk>AV1(rULYF07ZBJbGb9qbSoLAd;in9{)95YqX$J43-dY7YU*k~vrM25 zxh5_IqO0LYZW%oxQ5HOzmk4x{atE*vipUk}sh88$b2tn?!ujEHn`tQLe&vo}nMb&{ zio`xzZ&GG6&ZyN3jnaQy#iVqXE9VT(3tWY$n-)uWDQ|tc{`?fq2F`oQ{;d3aWPg4Hp-(iE{ry>MIPWL> iW8Zci7-kcv6Uzs@r-FtIZ-&5|)J Q1PU{Fy85}Sb4q9e0B4a5jsO4v literal 0 HcmV?d00001 diff --git a/packages/stream_chat_persistence/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png b/packages/stream_chat_persistence/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..9da19eacad3b03bb08bbddbbf4ac48dd78b3d838 GIT binary patch literal 68 zcmeAS@N?(olHy`uVBq!ia0vp^j3CUx0wlM}@Gt=>Zci7-kcv6Uzs@r-FtIZ-&5|)J Q1PU{Fy85}Sb4q9e0B4a5jsO4v literal 0 HcmV?d00001 diff --git a/packages/stream_chat_persistence/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png b/packages/stream_chat_persistence/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..9da19eacad3b03bb08bbddbbf4ac48dd78b3d838 GIT binary patch literal 68 zcmeAS@N?(olHy`uVBq!ia0vp^j3CUx0wlM}@Gt=>Zci7-kcv6Uzs@r-FtIZ-&5|)J Q1PU{Fy85}Sb4q9e0B4a5jsO4v literal 0 HcmV?d00001 diff --git a/packages/stream_chat_persistence/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md b/packages/stream_chat_persistence/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md new file mode 100644 index 00000000..89c2725b --- /dev/null +++ b/packages/stream_chat_persistence/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md @@ -0,0 +1,5 @@ +# Launch Screen Assets + +You can customize the launch screen with your own desired assets by replacing the image files in this directory. + +You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images. \ No newline at end of file diff --git a/packages/stream_chat_persistence/example/ios/Runner/Base.lproj/LaunchScreen.storyboard b/packages/stream_chat_persistence/example/ios/Runner/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 00000000..f2e259c7 --- /dev/null +++ b/packages/stream_chat_persistence/example/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/stream_chat_persistence/example/ios/Runner/Base.lproj/Main.storyboard b/packages/stream_chat_persistence/example/ios/Runner/Base.lproj/Main.storyboard new file mode 100644 index 00000000..f3c28516 --- /dev/null +++ b/packages/stream_chat_persistence/example/ios/Runner/Base.lproj/Main.storyboard @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/stream_chat_persistence/example/ios/Runner/Info.plist b/packages/stream_chat_persistence/example/ios/Runner/Info.plist new file mode 100644 index 00000000..a060db61 --- /dev/null +++ b/packages/stream_chat_persistence/example/ios/Runner/Info.plist @@ -0,0 +1,45 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + example + CFBundlePackageType + APPL + CFBundleShortVersionString + $(FLUTTER_BUILD_NAME) + CFBundleSignature + ???? + CFBundleVersion + $(FLUTTER_BUILD_NUMBER) + LSRequiresIPhoneOS + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UIViewControllerBasedStatusBarAppearance + + + diff --git a/packages/stream_chat_persistence/example/ios/Runner/Runner-Bridging-Header.h b/packages/stream_chat_persistence/example/ios/Runner/Runner-Bridging-Header.h new file mode 100644 index 00000000..308a2a56 --- /dev/null +++ b/packages/stream_chat_persistence/example/ios/Runner/Runner-Bridging-Header.h @@ -0,0 +1 @@ +#import "GeneratedPluginRegistrant.h" diff --git a/packages/stream_chat_persistence/example/lib/main.dart b/packages/stream_chat_persistence/example/lib/main.dart new file mode 100644 index 00000000..6d47d254 --- /dev/null +++ b/packages/stream_chat_persistence/example/lib/main.dart @@ -0,0 +1,255 @@ +import 'package:flutter/material.dart'; +import 'package:stream_chat/stream_chat.dart'; +import 'package:stream_chat_persistence/stream_chat_persistence.dart'; + +Future main() async { + /// Create a new instance of [StreamChatClient] passing the apikey obtained from your + /// project dashboard. + final client = StreamChatClient('b67pax5b2wdq'); + + /// Set the chatPersistenceClient for offline support + client.chatPersistenceClient = StreamChatPersistenceClient( + logLevel: Level.INFO, + connectionMode: ConnectionMode.background, + ); + + /// Set the current user. In a production scenario, this should be done using + /// a backend to generate a user token using our server SDK. + /// Please see the following for more information: + /// https://getstream.io/chat/docs/ios_user_setup_and_tokens/ + await client.setUser( + User( + id: 'cool-shadow-7', + extraData: { + 'image': + 'https://getstream.io/random_png/?id=cool-shadow-7&name=Cool+shadow', + }, + ), + 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoiY29vbC1zaGFkb3ctNyJ9.gkOlCRb1qgy4joHPaxFwPOdXcGvSPvp6QY0S4mpRkVo', + ); + + /// Creates a channel using the type `messaging` and `godevs`. + /// Channels are containers for holding messages between different members. To + /// learn more about channels and some of our predefined types, checkout our + /// our channel docs: https://getstream.io/chat/docs/initialize_channel/?language=dart + final channel = client.channel('messaging', id: 'godevs'); + + /// `.watch()` is used to create and listen to the channel for updates. If the + /// channel already exists, it will simply listen for new events. + await channel.watch(); + + runApp( + StreamExample( + client: client, + channel: channel, + ), + ); +} + +/// Example using Stream's Low Level Dart client. +class StreamExample extends StatelessWidget { + /// To initialize this example, an instance of [client] and [channel] is required. + const StreamExample({ + Key key, + @required this.client, + @required this.channel, + }) : super(key: key); + + /// Instance of [StreamChatClient] we created earlier. This contains information about + /// our application and connection state. + final StreamChatClient client; + + /// The channel we'd like to observe and participate. + final Channel channel; + + @override + Widget build(BuildContext context) { + return MaterialApp( + title: 'Stream Chat Dart Example', + home: HomeScreen(channel: channel), + ); + } +} + +/// Main screen of our application. The layout is comprised of an [AppBar] +/// containing the channel name and a [MessageView] displaying recent messages. +class HomeScreen extends StatelessWidget { + /// [HomeScreen] is constructed using the [Channel] we defined earlier. + const HomeScreen({Key key, @required this.channel}) : super(key: key); + + /// Channel object containing the [Channel.id] we'd like to observe. + final Channel channel; + + @override + Widget build(BuildContext context) { + final messages = channel.state.channelStateStream; + return Scaffold( + appBar: AppBar( + title: Text('Channel: ${channel.id}'), + ), + body: SafeArea( + child: StreamBuilder( + stream: messages, + builder: ( + BuildContext context, + AsyncSnapshot snapshot, + ) { + if (snapshot.hasData && snapshot.data != null) { + return MessageView( + messages: snapshot.data.messages.reversed.toList(), + channel: channel, + ); + } else if (snapshot.hasError) { + return const Center( + child: Text( + 'There was an error loading messages. Please see logs.', + ), + ); + } + return const Center( + child: SizedBox( + width: 100.0, + height: 100.0, + child: CircularProgressIndicator(), + ), + ); + }, + ), + ), + ); + } +} + +/// UI used to display a list of recent messages and a [TextField] for sending +/// new messages. +class MessageView extends StatefulWidget { + /// Message takes the latest list of messages and the current channel. + const MessageView({ + Key key, + @required this.messages, + @required this.channel, + }) : super(key: key); + + /// List of messages sent in the given channel. + final List messages; + + /// Current channel being observed. + final Channel channel; + + @override + _MessageViewState createState() => _MessageViewState(); +} + +class _MessageViewState extends State { + TextEditingController _controller; + ScrollController _scrollController; + + List get _messages => widget.messages; + + @override + void initState() { + super.initState(); + _controller = TextEditingController(); + _scrollController = ScrollController(); + } + + @override + void dispose() { + _controller.dispose(); + _scrollController.dispose(); + super.dispose(); + } + + /// Convenience method for scrolling the list view when a new message is sent. + void _updateList() { + _scrollController.animateTo( + 0, + duration: const Duration(milliseconds: 200), + curve: Curves.easeOut, + ); + } + + @override + Widget build(BuildContext context) { + return Column( + children: [ + Expanded( + child: ListView.builder( + controller: _scrollController, + itemCount: _messages.length, + reverse: true, + itemBuilder: (BuildContext context, int index) { + final item = _messages[index]; + if (item.user.id == widget.channel.client.uid) { + return Align( + alignment: Alignment.centerRight, + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Text(item.text), + ), + ); + } else { + return Align( + alignment: Alignment.centerLeft, + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Text(item.text), + ), + ); + } + }, + ), + ), + Padding( + padding: const EdgeInsets.all(8.0), + child: Row( + children: [ + Expanded( + child: TextField( + controller: _controller, + decoration: const InputDecoration( + hintText: 'Enter your message', + ), + ), + ), + Material( + type: MaterialType.circle, + color: Colors.blue, + clipBehavior: Clip.hardEdge, + child: InkWell( + onTap: () async { + // We can send a new message by calling `sendMessage` on + // the current channel. After sending a message, the + // TextField is cleared and the list view is scrolled + // to show the new item. + if (_controller.value.text.isNotEmpty) { + await widget.channel.sendMessage( + Message(text: _controller.value.text), + ); + _controller.clear(); + _updateList(); + } + }, + child: const Padding( + padding: EdgeInsets.all(8.0), + child: Center( + child: Icon( + Icons.send, + color: Colors.white, + ), + ), + ), + ), + ) + ], + ), + ) + ], + ); + } +} + +/// Helper extension for quickly retrieving the current user id from a [StreamChatClient]. +extension on StreamChatClient { + String get uid => state.user.id; +} diff --git a/packages/stream_chat_persistence/example/pubspec.yaml b/packages/stream_chat_persistence/example/pubspec.yaml new file mode 100644 index 00000000..5008566b --- /dev/null +++ b/packages/stream_chat_persistence/example/pubspec.yaml @@ -0,0 +1,23 @@ +name: example +description: A new Flutter project. + +publish_to: 'none' +version: 1.0.0+1 + +environment: + sdk: ">=2.7.0 <3.0.0" + +dependencies: + flutter: + sdk: flutter + cupertino_icons: ^1.0.0 + stream_chat: + path: ../../stream_chat + stream_chat_persistence: + path: ../ + +dev_dependencies: + flutter_test: + sdk: flutter +flutter: + uses-material-design: true \ No newline at end of file From f8aae9c94127b21947c354a1f24952a4543b0a2c Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Mon, 1 Feb 2021 20:59:45 +0530 Subject: [PATCH 1122/1140] [StreamChatPersistence] Update example README.md Signed-off-by: Sahil Kumar --- packages/stream_chat_persistence/example/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/stream_chat_persistence/example/README.md b/packages/stream_chat_persistence/example/README.md index 11089159..07e5ac18 100644 --- a/packages/stream_chat_persistence/example/README.md +++ b/packages/stream_chat_persistence/example/README.md @@ -1,2 +1,2 @@ -# Stream Chat Dart Example +# Stream Chat Persistence Example Please see `lib/` for example code. \ No newline at end of file From 711c20b967c389ea3f14e5c42bf577a0e01c671a Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Mon, 1 Feb 2021 16:50:52 +0100 Subject: [PATCH 1123/1140] fix persistence bugs and update example --- packages/stream_chat/lib/src/api/channel.dart | 26 +++++++++++++------ .../lib/src/db/chat_persistence_client.dart | 18 ++++++++----- .../example/lib/main.dart | 2 ++ .../lib/src/dao/message_dao.dart | 7 ++++- .../lib/src/mapper/message_mapper.dart | 2 +- 5 files changed, 38 insertions(+), 17 deletions(-) diff --git a/packages/stream_chat/lib/src/api/channel.dart b/packages/stream_chat/lib/src/api/channel.dart index 449a5267..6117b5d7 100644 --- a/packages/stream_chat/lib/src/api/channel.dart +++ b/packages/stream_chat/lib/src/api/channel.dart @@ -618,16 +618,26 @@ class Channel { } } - final response = await _client.post(path, data: payload); - final updatedState = _client.decode(response.data, ChannelState.fromJson); + try { + final response = await _client.post(path, data: payload); + final updatedState = _client.decode(response.data, ChannelState.fromJson); - if (_id == null) { - _id = updatedState.channel.id; - _cid = updatedState.channel.cid; + if (_id == null) { + _id = updatedState.channel.id; + _cid = updatedState.channel.cid; + } + + state?.updateChannelState(updatedState); + return updatedState; + } catch (e) { + if (!_client.persistenceEnabled) { + rethrow; + } + return _client.chatPersistenceClient?.getChannelStateByCid( + cid, + messagePagination: messagesPagination, + ); } - - state?.updateChannelState(updatedState); - return updatedState; } /// Query channel members diff --git a/packages/stream_chat/lib/src/db/chat_persistence_client.dart b/packages/stream_chat/lib/src/db/chat_persistence_client.dart index a2a4d313..ac65783d 100644 --- a/packages/stream_chat/lib/src/db/chat_persistence_client.dart +++ b/packages/stream_chat/lib/src/db/chat_persistence_client.dart @@ -173,8 +173,10 @@ abstract class ChatPersistenceClient { final reactions = channelStates.expand((it) => it.messages).expand((it) { return [ - ...it.ownReactions.where((r) => r.userId != null), - ...it.latestReactions.where((r) => r.userId != null) + if (it.ownReactions != null) + ...it.ownReactions.where((r) => r.userId != null), + if (it.latestReactions != null) + ...it.latestReactions.where((r) => r.userId != null) ]; }).where((it) => it != null); @@ -184,12 +186,14 @@ abstract class ChatPersistenceClient { ...cs.messages?.map((m) { return [ m.user, - ...m.latestReactions?.map((r) => r.user), - ...m.ownReactions?.map((r) => r.user), + if (m.latestReactions != null) + ...m.latestReactions.map((r) => r.user), + if (m.ownReactions != null) + ...m.ownReactions.map((r) => r.user), ]; })?.expand((v) => v), - ...cs.read?.map((r) => r.user), - ...cs.members?.map((m) => m.user), + if (cs.read != null) ...cs.read.map((r) => r.user), + if (cs.members != null) ...cs.members.map((m) => m.user), ]) .expand((it) => it) .where((it) => it != null); @@ -202,7 +206,7 @@ abstract class ChatPersistenceClient { final updateReadsFuture = channelStates.map((it) { final cid = it.channel.cid; - final reads = it.read.where((it) => it != null); + final reads = it.read?.where((it) => it != null) ?? []; return updateReads(cid, reads.toList(growable: false)); }).toList(growable: false); diff --git a/packages/stream_chat_persistence/example/lib/main.dart b/packages/stream_chat_persistence/example/lib/main.dart index 6d47d254..82dc1dc9 100644 --- a/packages/stream_chat_persistence/example/lib/main.dart +++ b/packages/stream_chat_persistence/example/lib/main.dart @@ -7,6 +7,8 @@ Future main() async { /// project dashboard. final client = StreamChatClient('b67pax5b2wdq'); + WidgetsFlutterBinding.ensureInitialized(); + /// Set the chatPersistenceClient for offline support client.chatPersistenceClient = StreamChatPersistenceClient( logLevel: Level.INFO, diff --git a/packages/stream_chat_persistence/lib/src/dao/message_dao.dart b/packages/stream_chat_persistence/lib/src/dao/message_dao.dart index 97122232..c207ae20 100644 --- a/packages/stream_chat_persistence/lib/src/dao/message_dao.dart +++ b/packages/stream_chat_persistence/lib/src/dao/message_dao.dart @@ -3,6 +3,7 @@ import 'package:stream_chat/stream_chat.dart'; import 'package:stream_chat_persistence/src/db/moor_chat_database.dart'; import 'package:stream_chat_persistence/src/entity/messages.dart'; import 'package:stream_chat_persistence/src/entity/users.dart'; + import '../mapper/mapper.dart'; part 'message_dao.g.dart'; @@ -136,7 +137,11 @@ class MessageDao extends DatabaseAccessor /// Updates the message data of a particular channel with /// the new [messageList] data - Future updateMessages(String cid, List messageList) { + Future updateMessages(String cid, List messageList) async { + if (messageList == null) { + return; + } + return batch((batch) { batch.insertAll( messages, diff --git a/packages/stream_chat_persistence/lib/src/mapper/message_mapper.dart b/packages/stream_chat_persistence/lib/src/mapper/message_mapper.dart index 510675e6..5ad92ddd 100644 --- a/packages/stream_chat_persistence/lib/src/mapper/message_mapper.dart +++ b/packages/stream_chat_persistence/lib/src/mapper/message_mapper.dart @@ -47,7 +47,7 @@ extension MessageX on Message { MessageEntity toEntity({String cid}) { return MessageEntity( id: id, - attachments: attachments.map((it) => jsonEncode(it)).toList(), + attachments: attachments?.map((it) => jsonEncode(it))?.toList() ?? [], channelCid: cid, type: type, parentId: parentId, From b7cd66e40d9baadb984ca5abe96f20e194d4d4ab Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Mon, 1 Feb 2021 17:30:48 +0100 Subject: [PATCH 1124/1140] remove dart:io import --- packages/stream_chat/lib/src/client.dart | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/stream_chat/lib/src/client.dart b/packages/stream_chat/lib/src/client.dart index 7f9f560a..723b38b6 100644 --- a/packages/stream_chat/lib/src/client.dart +++ b/packages/stream_chat/lib/src/client.dart @@ -1,6 +1,5 @@ import 'dart:async'; import 'dart:convert'; -import 'dart:io'; import 'package:dio/dio.dart'; import 'package:logging/logging.dart'; From fcab7800c2f883fbaae5f87aa2f4315a492afc9b Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Mon, 1 Feb 2021 17:46:36 +0100 Subject: [PATCH 1125/1140] update action --- .github/workflows/build.yml | 4 ++-- packages/stream_chat_persistence/pubspec.yaml | 3 +-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 994582df..6a0bbcb9 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -10,7 +10,7 @@ on: - created defaults: run: - working-directory: packages/flutter_widgets + working-directory: packages/stream_chat_flutter jobs: build_and_deploy_ios: @@ -68,4 +68,4 @@ jobs: token: ${{secrets.FIREBASE_TOKEN}} groups: stream-testers debug: true - file: packages/flutter_widgets/example/build/app/outputs/apk/release/app-release.apk \ No newline at end of file + file: packages/stream_chat_flutter/example/build/app/outputs/apk/release/app-release.apk \ No newline at end of file diff --git a/packages/stream_chat_persistence/pubspec.yaml b/packages/stream_chat_persistence/pubspec.yaml index bf666445..d58d618e 100644 --- a/packages/stream_chat_persistence/pubspec.yaml +++ b/packages/stream_chat_persistence/pubspec.yaml @@ -13,8 +13,7 @@ dependencies: path: ^1.7.0 path_provider: ^1.6.27 sqlite3_flutter_libs: ^0.3.0 - stream_chat: - path: ../stream_chat + stream_chat: 1.0.0-beta dev_dependencies: test: ^1.15.7 From 1b4c3f4434627cb5823e78ddbb92fe976a76257c Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Mon, 1 Feb 2021 18:01:18 +0100 Subject: [PATCH 1126/1140] update persistence dep --- packages/stream_chat_persistence/pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/stream_chat_persistence/pubspec.yaml b/packages/stream_chat_persistence/pubspec.yaml index d58d618e..5c7b9b5c 100644 --- a/packages/stream_chat_persistence/pubspec.yaml +++ b/packages/stream_chat_persistence/pubspec.yaml @@ -13,7 +13,7 @@ dependencies: path: ^1.7.0 path_provider: ^1.6.27 sqlite3_flutter_libs: ^0.3.0 - stream_chat: 1.0.0-beta + stream_chat: ^1.0.0-beta dev_dependencies: test: ^1.15.7 From 80196c5a7a83a64811cfa6f19508af2b246dcd11 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Mon, 1 Feb 2021 18:19:46 +0100 Subject: [PATCH 1127/1140] update dependencies --- packages/stream_chat/CHANGELOG.md | 4 ++++ packages/stream_chat/lib/src/models/event.dart | 7 +++++++ packages/stream_chat/lib/src/models/message.dart | 7 +++++++ packages/stream_chat/lib/version.dart | 2 +- packages/stream_chat/pubspec.yaml | 2 +- packages/stream_chat_flutter_core/pubspec.yaml | 3 +-- 6 files changed, 21 insertions(+), 4 deletions(-) diff --git a/packages/stream_chat/CHANGELOG.md b/packages/stream_chat/CHANGELOG.md index 98730359..42ab16b1 100644 --- a/packages/stream_chat/CHANGELOG.md +++ b/packages/stream_chat/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.0.1-beta + +- Fixed pub analysis issues + ## 1.0.0-beta - 🛑 **BREAKING** Renamed `Client` to less generic `StreamChatClient` diff --git a/packages/stream_chat/lib/src/models/event.dart b/packages/stream_chat/lib/src/models/event.dart index 20537185..03995d67 100644 --- a/packages/stream_chat/lib/src/models/event.dart +++ b/packages/stream_chat/lib/src/models/event.dart @@ -180,4 +180,11 @@ class EventChannel extends ChannelModel { topLevelFields, )); } + + /// Serialize to json + @override + Map toJson() => Serialization.moveFromExtraDataToRoot( + _$EventChannelToJson(this), + topLevelFields, + ); } diff --git a/packages/stream_chat/lib/src/models/message.dart b/packages/stream_chat/lib/src/models/message.dart index a2eef86e..ceff9652 100644 --- a/packages/stream_chat/lib/src/models/message.dart +++ b/packages/stream_chat/lib/src/models/message.dart @@ -307,4 +307,11 @@ class TranslatedMessage extends Message { Serialization.moveToExtraDataFromRoot(json, topLevelFields), ); } + + /// Serialize to json + @override + Map toJson() => Serialization.moveFromExtraDataToRoot( + _$TranslatedMessageToJson(this), + topLevelFields, + ); } diff --git a/packages/stream_chat/lib/version.dart b/packages/stream_chat/lib/version.dart index 3a2dc170..1a44ac24 100644 --- a/packages/stream_chat/lib/version.dart +++ b/packages/stream_chat/lib/version.dart @@ -2,4 +2,4 @@ import 'package:stream_chat/src/client.dart'; /// Current package version /// Used in [StreamChatClient] to build the `x-stream-client` header -const PACKAGE_VERSION = '1.0.0-beta'; +const PACKAGE_VERSION = '1.0.1-beta'; diff --git a/packages/stream_chat/pubspec.yaml b/packages/stream_chat/pubspec.yaml index a626812b..faa190a4 100644 --- a/packages/stream_chat/pubspec.yaml +++ b/packages/stream_chat/pubspec.yaml @@ -1,7 +1,7 @@ name: stream_chat homepage: https://getstream.io/ description: The official Dart client for Stream Chat, a service for building chat applications. -version: 1.0.0-beta +version: 1.0.1-beta repository: https://github.com/GetStream/stream-chat-dart issue_tracker: https://github.com/GetStream/stream-chat-dart/issues diff --git a/packages/stream_chat_flutter_core/pubspec.yaml b/packages/stream_chat_flutter_core/pubspec.yaml index b1896fcb..a657d061 100644 --- a/packages/stream_chat_flutter_core/pubspec.yaml +++ b/packages/stream_chat_flutter_core/pubspec.yaml @@ -10,8 +10,7 @@ environment: flutter: ">=1.17.0" dependencies: - stream_chat: - path: ../stream_chat + stream_chat: ^1.0.0-beta flutter: sdk: flutter rxdart: ^0.25.0 From bed1e23441f6980066002c80690d4f54830546f0 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Mon, 1 Feb 2021 18:24:25 +0100 Subject: [PATCH 1128/1140] update dependencies --- packages/stream_chat_flutter_core/pubspec.yaml | 2 +- packages/stream_chat_persistence/pubspec.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/stream_chat_flutter_core/pubspec.yaml b/packages/stream_chat_flutter_core/pubspec.yaml index a657d061..85e7d8cf 100644 --- a/packages/stream_chat_flutter_core/pubspec.yaml +++ b/packages/stream_chat_flutter_core/pubspec.yaml @@ -10,7 +10,7 @@ environment: flutter: ">=1.17.0" dependencies: - stream_chat: ^1.0.0-beta + stream_chat: ^1.0.1-beta flutter: sdk: flutter rxdart: ^0.25.0 diff --git a/packages/stream_chat_persistence/pubspec.yaml b/packages/stream_chat_persistence/pubspec.yaml index 5c7b9b5c..158e8adf 100644 --- a/packages/stream_chat_persistence/pubspec.yaml +++ b/packages/stream_chat_persistence/pubspec.yaml @@ -13,7 +13,7 @@ dependencies: path: ^1.7.0 path_provider: ^1.6.27 sqlite3_flutter_libs: ^0.3.0 - stream_chat: ^1.0.0-beta + stream_chat: ^1.0.1-beta dev_dependencies: test: ^1.15.7 From ea0bac5df670d085b4019e651e82991925f769d2 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Mon, 1 Feb 2021 18:34:26 +0100 Subject: [PATCH 1129/1140] update dependencies of stream_chat_flutter --- packages/stream_chat_flutter/pubspec.yaml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/stream_chat_flutter/pubspec.yaml b/packages/stream_chat_flutter/pubspec.yaml index 6b994ebf..b92e47ed 100644 --- a/packages/stream_chat_flutter/pubspec.yaml +++ b/packages/stream_chat_flutter/pubspec.yaml @@ -12,8 +12,7 @@ dependencies: flutter: sdk: flutter # TODO: Change over to main dependency when deployed - stream_chat_flutter_core: - path: ../stream_chat_flutter_core + stream_chat_flutter_core: ^1.0.0-beta flutter_app_badger: ^1.1.2 photo_view: ^0.10.3 rxdart: ^0.25.0 From d775aabfd558a7184795ab890bd67e30a1b31e7c Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Mon, 1 Feb 2021 18:36:40 +0100 Subject: [PATCH 1130/1140] fix stream_chat_flutter version --- packages/stream_chat_flutter/CHANGELOG.md | 2 +- packages/stream_chat_flutter/pubspec.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/stream_chat_flutter/CHANGELOG.md b/packages/stream_chat_flutter/CHANGELOG.md index 8a80dbc5..b840a2bb 100644 --- a/packages/stream_chat_flutter/CHANGELOG.md +++ b/packages/stream_chat_flutter/CHANGELOG.md @@ -1,4 +1,4 @@ -## 1.0.0-rc +## 1.0.0-beta - Integrated new-ui, split package functionality, diff --git a/packages/stream_chat_flutter/pubspec.yaml b/packages/stream_chat_flutter/pubspec.yaml index b92e47ed..bf4c3cd8 100644 --- a/packages/stream_chat_flutter/pubspec.yaml +++ b/packages/stream_chat_flutter/pubspec.yaml @@ -1,7 +1,7 @@ name: stream_chat_flutter homepage: https://github.com/GetStream/stream-chat-flutter description: Stream Chat official Flutter SDK. Build your own chat experience using Dart and Flutter. -version: 1.0.0-rc +version: 1.0.0-beta repository: https://github.com/GetStream/stream-chat-flutter issue_tracker: https://github.com/GetStream/stream-chat-flutter/issues From ceb7cc0bdb1ade010b1105f6c29f43f53532dacf Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Mon, 1 Feb 2021 19:08:58 +0100 Subject: [PATCH 1131/1140] solved a couple of analysis issues --- .../lib/src/channel_bottom_sheet.dart | 4 ++-- .../lib/src/compress_video_service.dart | 3 ++- .../lib/src/media_list_view.dart | 2 +- .../lib/src/message_input.dart | 15 +++++++++++---- .../stream_chat_flutter/lib/src/message_text.dart | 2 +- packages/stream_chat_flutter/pubspec.yaml | 3 +-- 6 files changed, 18 insertions(+), 11 deletions(-) diff --git a/packages/stream_chat_flutter/lib/src/channel_bottom_sheet.dart b/packages/stream_chat_flutter/lib/src/channel_bottom_sheet.dart index 3ae7e948..b380eb01 100644 --- a/packages/stream_chat_flutter/lib/src/channel_bottom_sheet.dart +++ b/packages/stream_chat_flutter/lib/src/channel_bottom_sheet.dart @@ -209,7 +209,7 @@ class _ChannelBottomSheetState extends State { ); } - void _showDeleteDialog() async { + Future _showDeleteDialog() async { final res = await showConfirmationDialog( context, title: 'Delete Conversation', @@ -227,7 +227,7 @@ class _ChannelBottomSheetState extends State { } } - void _showLeaveDialog() async { + Future _showLeaveDialog() async { final res = await showConfirmationDialog( context, title: 'Leave conversation', diff --git a/packages/stream_chat_flutter/lib/src/compress_video_service.dart b/packages/stream_chat_flutter/lib/src/compress_video_service.dart index 43d2c79c..4f7bf27d 100644 --- a/packages/stream_chat_flutter/lib/src/compress_video_service.dart +++ b/packages/stream_chat_flutter/lib/src/compress_video_service.dart @@ -1,4 +1,5 @@ import 'dart:async'; + import 'package:synchronized/synchronized.dart'; import 'package:video_compress/video_compress.dart'; @@ -16,5 +17,5 @@ class ICompressVideoService { } } -ICompressVideoService get CompressVideoService => +ICompressVideoService get compressVideoService => ICompressVideoService.instance; diff --git a/packages/stream_chat_flutter/lib/src/media_list_view.dart b/packages/stream_chat_flutter/lib/src/media_list_view.dart index d84a2759..7550e3e4 100644 --- a/packages/stream_chat_flutter/lib/src/media_list_view.dart +++ b/packages/stream_chat_flutter/lib/src/media_list_view.dart @@ -158,7 +158,7 @@ class _MediaListViewState extends State { final media = await assetList.getAssetListPaged(_currentPage, 50); - if (!media.isEmpty) { + if (media.isNotEmpty) { setState(() { _media.addAll(media); }); diff --git a/packages/stream_chat_flutter/lib/src/message_input.dart b/packages/stream_chat_flutter/lib/src/message_input.dart index 0966e75a..b5be1fb1 100644 --- a/packages/stream_chat_flutter/lib/src/message_input.dart +++ b/packages/stream_chat_flutter/lib/src/message_input.dart @@ -13,13 +13,13 @@ import 'package:http_parser/http_parser.dart' as httpParser; import 'package:image_picker/image_picker.dart'; import 'package:mime/mime.dart'; import 'package:photo_manager/photo_manager.dart'; -import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; import 'package:stream_chat_flutter/src/compress_video_service.dart'; import 'package:stream_chat_flutter/src/media_list_view.dart'; import 'package:stream_chat_flutter/src/message_list_view.dart'; import 'package:stream_chat_flutter/src/stream_chat_theme.dart'; import 'package:stream_chat_flutter/src/stream_svg_icon.dart'; import 'package:stream_chat_flutter/src/user_avatar.dart'; +import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; import 'package:substring_highlight/substring_highlight.dart'; import 'package:video_compress/video_compress.dart'; @@ -1040,7 +1040,7 @@ class MessageInputState extends State { if (file.size > _kMaxAttachmentSize) { if (medium?.type == AssetType.video) { - final mediaInfo = await CompressVideoService.compressVideo(file.path); + final mediaInfo = await compressVideoService.compressVideo(file.path); if (mediaInfo.filesize / (1024 * 1024) > _kMaxAttachmentSize) { _showErrorAlert( @@ -1999,7 +1999,7 @@ class MessageInputState extends State { if (file.size / 1024 > _kMaxAttachmentSize) { if (attachmentType == 'video') { - final mediaInfo = await CompressVideoService.compressVideo(file.path); + final mediaInfo = await compressVideoService.compressVideo(file.path); file = PlatformFile( name: mediaInfo.title, size: (mediaInfo.filesize / 1024).ceil(), @@ -2424,5 +2424,12 @@ class Tuple2 { @override bool operator ==(Object other) => - other is Tuple2 && other.item1 == item1 && other.item2 == item2; + identical(this, other) || + other is Tuple2 && + runtimeType == other.runtimeType && + item1 == other.item1 && + item2 == other.item2; + + @override + int get hashCode => item1.hashCode ^ item2.hashCode; } diff --git a/packages/stream_chat_flutter/lib/src/message_text.dart b/packages/stream_chat_flutter/lib/src/message_text.dart index 373acbfc..7557a877 100644 --- a/packages/stream_chat_flutter/lib/src/message_text.dart +++ b/packages/stream_chat_flutter/lib/src/message_text.dart @@ -68,7 +68,7 @@ class MessageText extends StatelessWidget { String _replaceMentions(String text) { message.mentionedUsers?.map((u) => u.name)?.toSet()?.forEach((userName) { text = text.replaceAll( - '@${userName}', '[@${userName}](@${userName.replaceAll(' ', '')})'); + '@$userName', '[@$userName](@${userName.replaceAll(' ', '')})'); }); return text; } diff --git a/packages/stream_chat_flutter/pubspec.yaml b/packages/stream_chat_flutter/pubspec.yaml index bf4c3cd8..1c0a378d 100644 --- a/packages/stream_chat_flutter/pubspec.yaml +++ b/packages/stream_chat_flutter/pubspec.yaml @@ -37,11 +37,10 @@ dependencies: lottie: ^0.7.0+1 substring_highlight: ^0.1.2 flutter_slidable: ^0.5.7 - carousel_slider: ^2.3.1 clipboard: ^0.1.2+8 image_gallery_saver: ^1.6.7 esys_flutter_share: ^1.0.2 - photo_manager: ^0.5.8 + photo_manager: ^0.6.0 transparent_image: ^1.0.0 ezanimation: ^0.4.1 synchronized: ^2.2.0+2 From a728f68a0086c3b9a7c22c9ebde10a01017b97d3 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Tue, 2 Feb 2021 10:02:39 +0100 Subject: [PATCH 1132/1140] fixed markdown links in changelog --- packages/stream_chat/CHANGELOG.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/stream_chat/CHANGELOG.md b/packages/stream_chat/CHANGELOG.md index 42ab16b1..06eb5d23 100644 --- a/packages/stream_chat/CHANGELOG.md +++ b/packages/stream_chat/CHANGELOG.md @@ -5,9 +5,9 @@ ## 1.0.0-beta - 🛑 **BREAKING** Renamed `Client` to less generic `StreamChatClient` -- 🛑 **BREAKING** Segregated the persistence layer into separate package (stream_chat_persistence)[https://pub.dev/packages/stream_chat_persistence] -- 🛑 **BREAKING** Moved `Client.backgroundKeepAlive` to (core package)[https://pub.dev/packages/stream_chat_core] -- 🛑 **BREAKING** Moved `Client.showLocalNotification` to (core package)[https://pub.dev/packages/stream_chat_core] and renamed it to `StreamChatCore.onBackgroundEventReceived` +- 🛑 **BREAKING** Segregated the persistence layer into separate package [stream_chat_persistence](https://pub.dev/packages/stream_chat_persistence) +- 🛑 **BREAKING** Moved `Client.backgroundKeepAlive` to [core package](https://pub.dev/packages/stream_chat_core) +- 🛑 **BREAKING** Moved `Client.showLocalNotification` to [core package](https://pub.dev/packages/stream_chat_core) and renamed it to `StreamChatCore.onBackgroundEventReceived` - Removed `flutter` dependency. This is now a pure Dart package 🥳 - Minor improvements and bugfixes From c89b54a65bc5fa903816e2d26a062f9c01602c18 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Tue, 2 Feb 2021 11:16:46 +0100 Subject: [PATCH 1133/1140] fix repository links --- packages/stream_chat/pubspec.yaml | 4 ++-- packages/stream_chat_flutter/pubspec.yaml | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/stream_chat/pubspec.yaml b/packages/stream_chat/pubspec.yaml index faa190a4..ac466e0f 100644 --- a/packages/stream_chat/pubspec.yaml +++ b/packages/stream_chat/pubspec.yaml @@ -2,8 +2,8 @@ name: stream_chat homepage: https://getstream.io/ description: The official Dart client for Stream Chat, a service for building chat applications. version: 1.0.1-beta -repository: https://github.com/GetStream/stream-chat-dart -issue_tracker: https://github.com/GetStream/stream-chat-dart/issues +repository: https://github.com/GetStream/stream-chat-flutter +issue_tracker: https://github.com/GetStream/stream-chat-flutter/issues environment: sdk: ">=2.7.0 <3.0.0" diff --git a/packages/stream_chat_flutter/pubspec.yaml b/packages/stream_chat_flutter/pubspec.yaml index 1c0a378d..f4fa6f51 100644 --- a/packages/stream_chat_flutter/pubspec.yaml +++ b/packages/stream_chat_flutter/pubspec.yaml @@ -11,7 +11,6 @@ environment: dependencies: flutter: sdk: flutter - # TODO: Change over to main dependency when deployed stream_chat_flutter_core: ^1.0.0-beta flutter_app_badger: ^1.1.2 photo_view: ^0.10.3 From 47ccc0491ae2ba740a2e90b9fe77406cf45085ef Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Tue, 2 Feb 2021 12:15:54 +0100 Subject: [PATCH 1134/1140] fix flutter analyze issues --- .../stream_chat_flutter/analysis_options.yaml | 122 +++++++++--------- .../example/lib/chat_info_screen.dart | 3 +- .../example/lib/choose_user_page.dart | 2 +- .../example/lib/group_info_screen.dart | 8 +- .../stream_chat_flutter/example/lib/main.dart | 2 +- .../example/lib/new_group_chat_screen.dart | 2 +- .../example/lib/search_text_field.dart | 2 +- .../lib/src/channel_bottom_sheet.dart | 2 +- .../lib/src/channel_header.dart | 4 +- .../lib/src/channel_list_header.dart | 4 +- .../lib/src/channel_preview.dart | 4 +- .../lib/src/extension.dart | 8 +- .../lib/src/file_attachment.dart | 4 +- .../lib/src/full_screen_media.dart | 4 +- .../lib/src/image_actions_modal.dart | 8 +- .../lib/src/image_footer.dart | 32 +---- .../lib/src/image_header.dart | 5 +- .../lib/src/media_utils.dart | 10 +- .../lib/src/message_actions_modal.dart | 32 ++--- .../lib/src/message_input.dart | 20 +-- .../lib/src/message_list_view.dart | 12 +- .../lib/src/message_search_item.dart | 4 +- .../lib/src/message_search_list_view.dart | 6 +- .../lib/src/stream_chat_theme.dart | 9 +- .../lib/src/stream_svg_icon.dart | 70 +++++----- .../lib/src/user_list_view.dart | 4 +- .../stream_chat_flutter/lib/src/utils.dart | 38 +++--- 27 files changed, 204 insertions(+), 217 deletions(-) diff --git a/packages/stream_chat_flutter/analysis_options.yaml b/packages/stream_chat_flutter/analysis_options.yaml index 42965ec7..8d6f9064 100644 --- a/packages/stream_chat_flutter/analysis_options.yaml +++ b/packages/stream_chat_flutter/analysis_options.yaml @@ -1,63 +1,63 @@ -#include: package:pedantic/analysis_options.yaml -# -#analyzer: -# enable-experiment: -# - extension-methods -# exclude: -# - lib/**/*.g.dart -# - example/** -# -#linter: -# rules: -# # these rules are documented on and in the same order as -# # the Dart Lint rules page to make maintenance easier -# # https://github.com/dart-lang/linter/blob/master/example/all.yaml -# # - always_declare_return_types -# # - always_specify_types -# # - annotate_overrides -# # - avoid_as -# - avoid_empty_else -# - avoid_init_to_null -# - avoid_return_types_on_setters -# - avoid_web_libraries_in_flutter -# - await_only_futures -# - camel_case_types -# - cancel_subscriptions -# - close_sinks -# # - comment_references # we do not presume as to what people want to reference in their dartdocs -# # - constant_identifier_names # https://github.com/dart-lang/linter/issues/204 -# - control_flow_in_finally -# - empty_constructor_bodies -# - empty_statements -# - hash_and_equals -# - implementation_imports -# # - invariant_booleans -# # - iterable_contains_unrelated_type -# - library_names -# # - library_prefixes -# # - list_remove_unrelated_type -# # - literal_only_boolean_expressions -# - non_constant_identifier_names -# # - one_member_abstracts -# # - only_throw_errors -# # - overridden_fields -## - package_api_docs -# - package_names -# - package_prefixed_library_names -# - prefer_is_not_empty -# # - prefer_mixin # https://github.com/dart-lang/language/issues/32 -# - public_member_api_docs -# - slash_for_doc_comments -# # - sort_constructors_first -# # - sort_unnamed_constructors_first -# # - super_goes_last # no longer needed w/ Dart 2 -# - test_types_in_equals -# - throw_in_finally -# # - type_annotate_public_apis # subset of always_specify_types -# - type_init_formals -# # - unawaited_futures -# - unnecessary_brace_in_string_interps -# - unnecessary_getters_setters -# - unnecessary_statements +include: package:pedantic/analysis_options.yaml + +analyzer: + enable-experiment: + - extension-methods + exclude: + - lib/**/*.g.dart + - example/** + +linter: + rules: + # these rules are documented on and in the same order as + # the Dart Lint rules page to make maintenance easier + # https://github.com/dart-lang/linter/blob/master/example/all.yaml + # - always_declare_return_types + # - always_specify_types + # - annotate_overrides + # - avoid_as + - avoid_empty_else + - avoid_init_to_null + - avoid_return_types_on_setters + - avoid_web_libraries_in_flutter + - await_only_futures + - camel_case_types + - cancel_subscriptions + - close_sinks + # - comment_references # we do not presume as to what people want to reference in their dartdocs + # - constant_identifier_names # https://github.com/dart-lang/linter/issues/204 + - control_flow_in_finally + - empty_constructor_bodies + - empty_statements + - hash_and_equals + - implementation_imports + # - invariant_booleans + # - iterable_contains_unrelated_type + - library_names + # - library_prefixes + # - list_remove_unrelated_type + # - literal_only_boolean_expressions + - non_constant_identifier_names + # - one_member_abstracts + # - only_throw_errors + # - overridden_fields +# - package_api_docs + - package_names + - package_prefixed_library_names + - prefer_is_not_empty + # - prefer_mixin # https://github.com/dart-lang/language/issues/32 + - public_member_api_docs + - slash_for_doc_comments + # - sort_constructors_first + # - sort_unnamed_constructors_first + # - super_goes_last # no longer needed w/ Dart 2 + - test_types_in_equals + - throw_in_finally + # - type_annotate_public_apis # subset of always_specify_types + - type_init_formals + # - unawaited_futures + - unnecessary_brace_in_string_interps + - unnecessary_getters_setters + - unnecessary_statements - unrelated_type_equality_checks - valid_regexps diff --git a/packages/stream_chat_flutter/example/lib/chat_info_screen.dart b/packages/stream_chat_flutter/example/lib/chat_info_screen.dart index a6b14dec..8db438c3 100644 --- a/packages/stream_chat_flutter/example/lib/chat_info_screen.dart +++ b/packages/stream_chat_flutter/example/lib/chat_info_screen.dart @@ -1,7 +1,6 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:jiffy/jiffy.dart'; - import 'package:stream_chat_flutter/stream_chat_flutter.dart'; import 'main.dart'; @@ -285,7 +284,7 @@ class _ChatInfoScreenState extends State { titleTextStyle: StreamChatTheme.of(context).textTheme.body, leading: Padding( padding: const EdgeInsets.symmetric(horizontal: 22.0), - child: StreamSvgIcon.Icon_group( + child: StreamSvgIcon.iconGroup( size: 24.0, color: StreamChatTheme.of(context).colorTheme.black.withOpacity(0.5), diff --git a/packages/stream_chat_flutter/example/lib/choose_user_page.dart b/packages/stream_chat_flutter/example/lib/choose_user_page.dart index 02852c64..a23db661 100644 --- a/packages/stream_chat_flutter/example/lib/choose_user_page.dart +++ b/packages/stream_chat_flutter/example/lib/choose_user_page.dart @@ -213,7 +213,7 @@ class ChooseUserPage extends StatelessWidget { .grey, ), ), - trailing: StreamSvgIcon.arrow_right( + trailing: StreamSvgIcon.arrowRight( color: StreamChatTheme.of(context) .colorTheme .accentBlue, diff --git a/packages/stream_chat_flutter/example/lib/group_info_screen.dart b/packages/stream_chat_flutter/example/lib/group_info_screen.dart index 0f200c82..d22b1ce4 100644 --- a/packages/stream_chat_flutter/example/lib/group_info_screen.dart +++ b/packages/stream_chat_flutter/example/lib/group_info_screen.dart @@ -377,7 +377,7 @@ class _GroupInfoScreenState extends State { mainAxisSize: MainAxisSize.min, children: [ InkWell( - child: StreamSvgIcon.close_small(), + child: StreamSvgIcon.closeSmall(), onTap: () { setState(() { _nameController.text = @@ -739,7 +739,7 @@ class _GroupInfoScreenState extends State { ), SizedBox(width: 16.0), IconButton( - icon: StreamSvgIcon.close_small( + icon: StreamSvgIcon.closeSmall( color: theme.colorTheme.grey, ), constraints: BoxConstraints.tightFor( @@ -869,7 +869,7 @@ class _GroupInfoScreenState extends State { isUserAdmin) _buildModalListTile( context, - StreamSvgIcon.Icon_user_settings( + StreamSvgIcon.iconUserSettings( color: StreamChatTheme.of(context).colorTheme.grey, size: 24.0, ), @@ -891,7 +891,7 @@ class _GroupInfoScreenState extends State { }, color: StreamChatTheme.of(context).colorTheme.accentRed), _buildModalListTile( context, - StreamSvgIcon.close_small( + StreamSvgIcon.closeSmall( color: StreamChatTheme.of(context).colorTheme.grey, size: 24.0, ), diff --git a/packages/stream_chat_flutter/example/lib/main.dart b/packages/stream_chat_flutter/example/lib/main.dart index 775b1d6e..45f86f07 100644 --- a/packages/stream_chat_flutter/example/lib/main.dart +++ b/packages/stream_chat_flutter/example/lib/main.dart @@ -294,7 +294,7 @@ class _HomePageState extends State { ), ), trailing: IconButton( - icon: StreamSvgIcon.Icon_moon( + icon: StreamSvgIcon.iconMoon( size: 24, ), color: StreamChatTheme.of(context).colorTheme.grey, diff --git a/packages/stream_chat_flutter/example/lib/new_group_chat_screen.dart b/packages/stream_chat_flutter/example/lib/new_group_chat_screen.dart index 4e924d86..209d3729 100644 --- a/packages/stream_chat_flutter/example/lib/new_group_chat_screen.dart +++ b/packages/stream_chat_flutter/example/lib/new_group_chat_screen.dart @@ -67,7 +67,7 @@ class _NewGroupChatScreenState extends State { actions: [ if (_selectedUsers.isNotEmpty) IconButton( - icon: StreamSvgIcon.arrow_right( + icon: StreamSvgIcon.arrowRight( color: StreamChatTheme.of(context).colorTheme.accentBlue, ), onPressed: () async { diff --git a/packages/stream_chat_flutter/example/lib/search_text_field.dart b/packages/stream_chat_flutter/example/lib/search_text_field.dart index ff34e8a9..9628ddba 100644 --- a/packages/stream_chat_flutter/example/lib/search_text_field.dart +++ b/packages/stream_chat_flutter/example/lib/search_text_field.dart @@ -71,7 +71,7 @@ class SearchTextField extends StatelessWidget { color: Colors.transparent, child: IconButton( padding: const EdgeInsets.all(0), - icon: StreamSvgIcon.close_small( + icon: StreamSvgIcon.closeSmall( color: Colors.grey, ), splashRadius: 24, diff --git a/packages/stream_chat_flutter/lib/src/channel_bottom_sheet.dart b/packages/stream_chat_flutter/lib/src/channel_bottom_sheet.dart index b380eb01..57b27a2f 100644 --- a/packages/stream_chat_flutter/lib/src/channel_bottom_sheet.dart +++ b/packages/stream_chat_flutter/lib/src/channel_bottom_sheet.dart @@ -195,7 +195,7 @@ class _ChannelBottomSheetState extends State { OptionListTile( leading: Padding( padding: const EdgeInsets.symmetric(horizontal: 16.0), - child: StreamSvgIcon.close_small( + child: StreamSvgIcon.closeSmall( color: StreamChatTheme.of(context).colorTheme.grey, ), ), diff --git a/packages/stream_chat_flutter/lib/src/channel_header.dart b/packages/stream_chat_flutter/lib/src/channel_header.dart index 27194627..6845a632 100644 --- a/packages/stream_chat_flutter/lib/src/channel_header.dart +++ b/packages/stream_chat_flutter/lib/src/channel_header.dart @@ -89,8 +89,8 @@ class ChannelHeader extends StatelessWidget implements PreferredSizeWidget { return ConnectionStatusBuilder( statusBuilder: (context, status) { - String statusString = ''; - bool showStatus = true; + var statusString = ''; + var showStatus = true; switch (status) { case ConnectionStatus.connected: diff --git a/packages/stream_chat_flutter/lib/src/channel_list_header.dart b/packages/stream_chat_flutter/lib/src/channel_list_header.dart index 045d24d5..cca4170e 100644 --- a/packages/stream_chat_flutter/lib/src/channel_list_header.dart +++ b/packages/stream_chat_flutter/lib/src/channel_list_header.dart @@ -82,8 +82,8 @@ class ChannelListHeader extends StatelessWidget implements PreferredSizeWidget { final user = _client.state.user; return ConnectionStatusBuilder( statusBuilder: (context, status) { - String statusString = ''; - bool showStatus = true; + var statusString = ''; + var showStatus = true; switch (status) { case ConnectionStatus.connected: diff --git a/packages/stream_chat_flutter/lib/src/channel_preview.dart b/packages/stream_chat_flutter/lib/src/channel_preview.dart index eddd0ea6..2d29f12b 100644 --- a/packages/stream_chat_flutter/lib/src/channel_preview.dart +++ b/packages/stream_chat_flutter/lib/src/channel_preview.dart @@ -1,8 +1,8 @@ import 'package:flutter/material.dart'; import 'package:flutter/widgets.dart'; import 'package:jiffy/jiffy.dart'; -import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; import 'package:stream_chat_flutter/src/stream_svg_icon.dart'; +import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; import '../stream_chat_flutter.dart'; import 'channel_name.dart'; @@ -269,7 +269,7 @@ class ChannelPreview extends StatelessWidget { TextStyle normalTextStyle, TextStyle mentionsTextStyle) { var textList = text.split(' '); - List resList = []; + var resList = []; for (var e in textList) { if (mentions != null && mentions.isNotEmpty && diff --git a/packages/stream_chat_flutter/lib/src/extension.dart b/packages/stream_chat_flutter/lib/src/extension.dart index ad26735a..75a03925 100644 --- a/packages/stream_chat_flutter/lib/src/extension.dart +++ b/packages/stream_chat_flutter/lib/src/extension.dart @@ -1,18 +1,20 @@ -import 'package:emojis/emoji.dart'; import 'package:characters/characters.dart'; +import 'package:emojis/emoji.dart'; final _emojis = Emoji.all(); +/// String extension extension StringExtension on String { + /// Returns the capitalized string String capitalize() { - return "${this[0].toUpperCase()}${this.substring(1)}"; + return '${this[0].toUpperCase()}${substring(1)}'; } // Emojis guidelines // 1 to 3 emojis: big size with no text bubble. // 4+ emojis or emojis+text: standard size with text bubble. bool get isOnlyEmoji { - final characters = this.trim().characters; + final characters = trim().characters; if (characters.isEmpty) return false; if (characters.length > 3) return false; return characters.every((c) => _emojis.map((e) => e.char).contains(c)); diff --git a/packages/stream_chat_flutter/lib/src/file_attachment.dart b/packages/stream_chat_flutter/lib/src/file_attachment.dart index 0fff2445..209cdb99 100644 --- a/packages/stream_chat_flutter/lib/src/file_attachment.dart +++ b/packages/stream_chat_flutter/lib/src/file_attachment.dart @@ -3,10 +3,10 @@ import 'dart:io'; import 'package:cached_network_image/cached_network_image.dart'; import 'package:file_picker/file_picker.dart'; import 'package:flutter/material.dart'; -import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; import 'package:stream_chat_flutter/src/stream_chat_theme.dart'; import 'package:stream_chat_flutter/src/stream_svg_icon.dart'; import 'package:stream_chat_flutter/src/utils.dart'; +import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; import 'package:video_compress/video_compress.dart'; import 'package:video_player/video_player.dart'; @@ -110,7 +110,7 @@ class _FileAttachmentState extends State { type: MaterialType.transparency, child: widget.trailing ?? IconButton( - icon: StreamSvgIcon.cloud_download( + icon: StreamSvgIcon.cloudDownload( color: StreamChatTheme.of(context).colorTheme.black, ), padding: const EdgeInsets.all(8), diff --git a/packages/stream_chat_flutter/lib/src/full_screen_media.dart b/packages/stream_chat_flutter/lib/src/full_screen_media.dart index 98ed3384..16ab0da5 100644 --- a/packages/stream_chat_flutter/lib/src/full_screen_media.dart +++ b/packages/stream_chat_flutter/lib/src/full_screen_media.dart @@ -258,9 +258,9 @@ class VideoPackage { _videoPlayerController.addListener(errorListener); } - get videoPlayer => _videoPlayerController; + VideoPlayerController get videoPlayer => _videoPlayerController; - get chewieController => _chewieController; + ChewieController get chewieController => _chewieController; void dispose() { _videoPlayerController.dispose(); diff --git a/packages/stream_chat_flutter/lib/src/image_actions_modal.dart b/packages/stream_chat_flutter/lib/src/image_actions_modal.dart index 2a251c61..4be1dc1d 100644 --- a/packages/stream_chat_flutter/lib/src/image_actions_modal.dart +++ b/packages/stream_chat_flutter/lib/src/image_actions_modal.dart @@ -56,7 +56,7 @@ class ImageActionsModal extends StatelessWidget { _buildButton( context, 'Reply', - StreamSvgIcon.Icon_curve_line_left_up( + StreamSvgIcon.iconCurveLineLeftUp( size: 24.0, color: StreamChatTheme.of(context).colorTheme.grey, ), @@ -76,7 +76,7 @@ class ImageActionsModal extends StatelessWidget { _buildButton( context, 'Save ${urls[currentIndex].type == 'video' ? 'Video' : 'Image'}', - StreamSvgIcon.Icon_save( + StreamSvgIcon.iconSave( size: 24.0, color: StreamChatTheme.of(context).colorTheme.grey, ), @@ -167,14 +167,14 @@ class ImageActionsModal extends StatelessWidget { final result = await ImageGallerySaver.saveImage( Uint8List.fromList(response.data), quality: 60, - name: "${DateTime.now().millisecondsSinceEpoch}"); + name: '${DateTime.now().millisecondsSinceEpoch}'); return result; } Future _saveVideo(String url) async { var appDocDir = await getTemporaryDirectory(); var savePath = - appDocDir.path + "/${DateTime.now().millisecondsSinceEpoch}.mp4"; + appDocDir.path + '/${DateTime.now().millisecondsSinceEpoch}.mp4'; await Dio().download(url, savePath); final result = await ImageGallerySaver.saveFile(savePath); print(result); diff --git a/packages/stream_chat_flutter/lib/src/image_footer.dart b/packages/stream_chat_flutter/lib/src/image_footer.dart index 4e87423e..7b0ed621 100644 --- a/packages/stream_chat_flutter/lib/src/image_footer.dart +++ b/packages/stream_chat_flutter/lib/src/image_footer.dart @@ -7,9 +7,9 @@ import 'package:dio/dio.dart'; import 'package:esys_flutter_share/esys_flutter_share.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; -import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; import 'package:stream_chat_flutter/src/stream_chat_theme.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; +import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; class ImageFooter extends StatefulWidget implements PreferredSizeWidget { /// Callback to call when pressing the back button. @@ -54,36 +54,17 @@ class ImageFooter extends StatefulWidget implements PreferredSizeWidget { } class _ImageFooterState extends State { - //ignore:unused_field - bool _userSearchMode = false; TextEditingController _searchController; final TextEditingController _messageController = TextEditingController(); final FocusNode _messageFocusNode = FocusNode(); - //ignore:unused_field - String _channelNameQuery; - final List _selectedChannels = []; - Timer _debounce; - Function modalSetStateCallback; - void _userNameListener() { - if (_debounce?.isActive ?? false) _debounce.cancel(); - _debounce = Timer(const Duration(milliseconds: 350), () { - if (mounted && modalSetStateCallback != null) { - modalSetStateCallback(() { - _channelNameQuery = _searchController.text; - }); - } - }); - } - @override void initState() { super.initState(); - _searchController = TextEditingController()..addListener(_userNameListener); _messageFocusNode.addListener(() { setState(() {}); }); @@ -92,7 +73,6 @@ class _ImageFooterState extends State { @override void dispose() { _searchController?.clear(); - _searchController?.removeListener(_userNameListener); _searchController?.dispose(); super.dispose(); } @@ -113,7 +93,7 @@ class _ImageFooterState extends State { mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ IconButton( - icon: StreamSvgIcon.Icon_SHARE( + icon: StreamSvgIcon.iconShare( size: 24.0, color: StreamChatTheme.of(context).colorTheme.black, ), @@ -151,7 +131,7 @@ class _ImageFooterState extends State { ), ), IconButton( - icon: StreamSvgIcon.Icon_grid( + icon: StreamSvgIcon.iconGrid( color: StreamChatTheme.of(context).colorTheme.black, ), onPressed: () => _showPhotosModal(context), @@ -174,9 +154,9 @@ class _ImageFooterState extends State { backgroundColor: StreamChatTheme.of(context).colorTheme.white, isScrollControlled: true, shape: const RoundedRectangleBorder( - borderRadius: const BorderRadius.only( - topLeft: const Radius.circular(16.0), - topRight: const Radius.circular(16.0), + borderRadius: BorderRadius.only( + topLeft: Radius.circular(16.0), + topRight: Radius.circular(16.0), ), ), builder: (context) { diff --git a/packages/stream_chat_flutter/lib/src/image_header.dart b/packages/stream_chat_flutter/lib/src/image_header.dart index a818ee13..25eab839 100644 --- a/packages/stream_chat_flutter/lib/src/image_header.dart +++ b/packages/stream_chat_flutter/lib/src/image_header.dart @@ -1,7 +1,8 @@ import 'package:flutter/material.dart'; -import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; import 'package:stream_chat_flutter/src/stream_chat_theme.dart'; import 'package:stream_chat_flutter/src/stream_svg_icon.dart'; +import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; + import 'image_actions_modal.dart'; class ImageHeader extends StatelessWidget implements PreferredSizeWidget { @@ -63,7 +64,7 @@ class ImageHeader extends StatelessWidget implements PreferredSizeWidget { StreamChatTheme.of(context).channelTheme.channelHeaderTheme.color, actions: [ IconButton( - icon: StreamSvgIcon.Icon_menu_point_v( + icon: StreamSvgIcon.iconMenuPoint( color: StreamChatTheme.of(context).colorTheme.black, ), onPressed: () { diff --git a/packages/stream_chat_flutter/lib/src/media_utils.dart b/packages/stream_chat_flutter/lib/src/media_utils.dart index e91a47d6..e55e02df 100644 --- a/packages/stream_chat_flutter/lib/src/media_utils.dart +++ b/packages/stream_chat_flutter/lib/src/media_utils.dart @@ -1,14 +1,14 @@ -import 'package:http_parser/http_parser.dart' as httpParser; +import 'package:http_parser/http_parser.dart' as http_parser; import 'package:mime/mime.dart'; class MediaUtils { - static httpParser.MediaType getMimeType(String filename) { - httpParser.MediaType mimeType; + static http_parser.MediaType getMimeType(String filename) { + http_parser.MediaType mimeType; if (filename != null) { if (filename.toLowerCase().endsWith('heic')) { - mimeType = httpParser.MediaType.parse('image/heic'); + mimeType = http_parser.MediaType.parse('image/heic'); } else { - mimeType = httpParser.MediaType.parse(lookupMimeType(filename)); + mimeType = http_parser.MediaType.parse(lookupMimeType(filename)); } } diff --git a/packages/stream_chat_flutter/lib/src/message_actions_modal.dart b/packages/stream_chat_flutter/lib/src/message_actions_modal.dart index 6ca7c688..9551ff71 100644 --- a/packages/stream_chat_flutter/lib/src/message_actions_modal.dart +++ b/packages/stream_chat_flutter/lib/src/message_actions_modal.dart @@ -4,16 +4,16 @@ import 'dart:ui'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; -import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; import 'package:stream_chat_flutter/src/reaction_picker.dart'; import 'package:stream_chat_flutter/src/stream_svg_icon.dart'; import 'package:stream_chat_flutter/src/utils.dart'; +import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; +import 'extension.dart'; import 'message_input.dart'; import 'message_widget.dart'; import 'stream_chat.dart'; import 'stream_chat_theme.dart'; -import 'extension.dart'; class MessageActionsModal extends StatefulWidget { final Widget Function(BuildContext, Message) editMessageInputBuilder; @@ -280,20 +280,22 @@ class _MessageActionsModalState extends State { setState(() { _showActions = false; }); - var answer = await showConfirmationDialog(context, - title: 'Delete message', - icon: StreamSvgIcon.flag( - color: StreamChatTheme.of(context).colorTheme.accentRed, - size: 24.0, - ), - question: 'Are you sure you want to permanently delete this\nmessage?', - okText: 'DELETE', - cancelText: 'CANCEL'); + var answer = await showConfirmationDialog( + context, + title: 'Delete message', + icon: StreamSvgIcon.flag( + color: StreamChatTheme.of(context).colorTheme.accentRed, + size: 24.0, + ), + question: 'Are you sure you want to permanently delete this\nmessage?', + okText: 'DELETE', + cancelText: 'CANCEL', + ); if (answer) { try { Navigator.pop(context); - StreamChat.of(context).client.deleteMessage( + await StreamChat.of(context).client.deleteMessage( widget.message, StreamChannel.of(context).channel.cid, ); @@ -470,7 +472,7 @@ class _MessageActionsModalState extends State { padding: const EdgeInsets.symmetric(vertical: 11.0, horizontal: 16.0), child: Row( children: [ - StreamSvgIcon.icon_flag( + StreamSvgIcon.iconFlag( color: StreamChatTheme.of(context).primaryIconTheme.color, ), const SizedBox(width: 16), @@ -577,7 +579,7 @@ class _MessageActionsModalState extends State { padding: const EdgeInsets.symmetric(vertical: 11.0, horizontal: 16.0), child: Row( children: [ - StreamSvgIcon.circle_up( + StreamSvgIcon.circleUp( color: StreamChatTheme.of(context).colorTheme.accentBlue, ), const SizedBox(width: 16), @@ -632,7 +634,7 @@ class _MessageActionsModalState extends State { ), IconButton( visualDensity: VisualDensity.compact, - icon: StreamSvgIcon.close_small(), + icon: StreamSvgIcon.closeSmall(), onPressed: Navigator.of(context).pop, ), ], diff --git a/packages/stream_chat_flutter/lib/src/message_input.dart b/packages/stream_chat_flutter/lib/src/message_input.dart index b5be1fb1..425bf5ea 100644 --- a/packages/stream_chat_flutter/lib/src/message_input.dart +++ b/packages/stream_chat_flutter/lib/src/message_input.dart @@ -9,7 +9,7 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_keyboard_visibility/flutter_keyboard_visibility.dart'; import 'package:flutter_svg/flutter_svg.dart'; -import 'package:http_parser/http_parser.dart' as httpParser; +import 'package:http_parser/http_parser.dart' as http_parser; import 'package:image_picker/image_picker.dart'; import 'package:mime/mime.dart'; import 'package:photo_manager/photo_manager.dart'; @@ -202,7 +202,7 @@ class MessageInputState extends State { bool _openFilePickerSection = false; int _filePickerIndex = 0; double _filePickerSize = _kMinMediaPickerSize; - KeyboardVisibilityController _keyboardVisibilityController = + final KeyboardVisibilityController _keyboardVisibilityController = KeyboardVisibilityController(); /// The editing controller passed to the input TextField @@ -247,7 +247,7 @@ class MessageInputState extends State { ), IconButton( visualDensity: VisualDensity.compact, - icon: StreamSvgIcon.close_small(), + icon: StreamSvgIcon.closeSmall(), onPressed: widget.onQuotedMessageCleared, ), ], @@ -493,7 +493,7 @@ class MessageInputState extends State { : null, suffixIcon: _commandEnabled ? IconButton( - icon: StreamSvgIcon.close_small(), + icon: StreamSvgIcon.closeSmall(), splashRadius: 24, padding: const EdgeInsets.all(0), constraints: BoxConstraints.tightFor( @@ -1128,7 +1128,7 @@ class MessageInputState extends State { case 'ban': return CircleAvatar( backgroundColor: StreamChatTheme.of(context).colorTheme.accentBlue, - child: StreamSvgIcon.Icon_user_delete( + child: StreamSvgIcon.iconUserDelete( size: 16.0, color: Colors.white, ), @@ -1964,7 +1964,7 @@ class MessageInputState extends State { final mimeType = _getMimeType(file.path.split('/').last); - Map extraDataMap = {}; + var extraDataMap = {}; if (camera) { if (mimeType.type == 'video' || mimeType.type == 'image') { @@ -2074,13 +2074,13 @@ class MessageInputState extends State { return res.file; } - httpParser.MediaType _getMimeType(String filename) { - httpParser.MediaType mimeType; + http_parser.MediaType _getMimeType(String filename) { + http_parser.MediaType mimeType; if (filename != null) { if (filename.toLowerCase().endsWith('heic')) { - mimeType = httpParser.MediaType.parse('image/heic'); + mimeType = http_parser.MediaType.parse('image/heic'); } else { - mimeType = httpParser.MediaType.parse(lookupMimeType(filename)); + mimeType = http_parser.MediaType.parse(lookupMimeType(filename)); } } diff --git a/packages/stream_chat_flutter/lib/src/message_list_view.dart b/packages/stream_chat_flutter/lib/src/message_list_view.dart index 86c1445c..3bb6b716 100644 --- a/packages/stream_chat_flutter/lib/src/message_list_view.dart +++ b/packages/stream_chat_flutter/lib/src/message_list_view.dart @@ -6,18 +6,18 @@ import 'package:flutter/material.dart'; import 'package:jiffy/jiffy.dart'; import 'package:rxdart/rxdart.dart'; import 'package:scrollable_positioned_list/scrollable_positioned_list.dart'; -import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; import 'package:stream_chat_flutter/src/info_tile.dart'; import 'package:stream_chat_flutter/src/message_widget.dart'; import 'package:stream_chat_flutter/src/stream_svg_icon.dart'; import 'package:stream_chat_flutter/src/system_message.dart'; +import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; import 'package:visibility_detector/visibility_detector.dart'; import '../stream_chat_flutter.dart'; import 'connection_status_builder.dart'; import 'date_divider.dart'; -import 'swipeable.dart'; import 'extension.dart'; +import 'swipeable.dart'; typedef MessageBuilder = Widget Function( BuildContext, @@ -237,7 +237,7 @@ class _MessageListViewState extends State { bool _inBetweenList = false; - MessageListController _messageListController = MessageListController(); + final MessageListController _messageListController = MessageListController(); @override Widget build(BuildContext context) { @@ -308,8 +308,8 @@ class _MessageListViewState extends State { children: [ ConnectionStatusBuilder( statusBuilder: (context, status) { - String statusString = ''; - bool showStatus = true; + var statusString = ''; + var showStatus = true; switch (status) { case ConnectionStatus.connected: statusString = 'Connected'; @@ -878,7 +878,7 @@ class _MessageListViewState extends State { if (messages.map((e) => e.id).contains(quotedMessageId)) { scrollToIndex(); } else { - streamChannel.loadChannelAtMessage(quotedMessageId).then((_) { + await streamChannel.loadChannelAtMessage(quotedMessageId).then((_) { WidgetsBinding.instance.addPostFrameCallback((_) { if (messages.map((e) => e.id).contains(quotedMessageId)) { scrollToIndex(); diff --git a/packages/stream_chat_flutter/lib/src/message_search_item.dart b/packages/stream_chat_flutter/lib/src/message_search_item.dart index 4d8d9148..335f7ff4 100644 --- a/packages/stream_chat_flutter/lib/src/message_search_item.dart +++ b/packages/stream_chat_flutter/lib/src/message_search_item.dart @@ -1,7 +1,7 @@ import 'package:flutter/material.dart'; import 'package:jiffy/jiffy.dart'; -import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; +import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; /// It shows the current [Message] preview. /// @@ -152,7 +152,7 @@ class MessageSearchItem extends StatelessWidget { TextStyle normalTextStyle, TextStyle mentionsTextStyle) { var textList = text.split(' '); - List resList = []; + var resList = []; for (var e in textList) { if (mentions != null && mentions.isNotEmpty && diff --git a/packages/stream_chat_flutter/lib/src/message_search_list_view.dart b/packages/stream_chat_flutter/lib/src/message_search_list_view.dart index 8a22bf00..490b3581 100644 --- a/packages/stream_chat_flutter/lib/src/message_search_list_view.dart +++ b/packages/stream_chat_flutter/lib/src/message_search_list_view.dart @@ -1,7 +1,7 @@ import 'package:flutter/material.dart'; -import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; import 'package:stream_chat_flutter/src/info_tile.dart'; import 'package:stream_chat_flutter/src/message_search_item.dart'; +import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; import '../stream_chat_flutter.dart'; @@ -116,7 +116,7 @@ class MessageSearchListView extends StatefulWidget { } class _MessageSearchListViewState extends State { - MessageSearchListController _messageSearchListController = + final MessageSearchListController _messageSearchListController = MessageSearchListController(); @override @@ -245,7 +245,7 @@ class _MessageSearchListViewState extends State { } Widget _buildQueryProgressIndicator(context) { - MessageSearchBlocState messageSearchBloc = MessageSearchBloc.of(context); + final messageSearchBloc = MessageSearchBloc.of(context); return StreamBuilder( stream: messageSearchBloc.queryMessagesLoading, diff --git a/packages/stream_chat_flutter/lib/src/stream_chat_theme.dart b/packages/stream_chat_flutter/lib/src/stream_chat_theme.dart index c65f36cc..be69e366 100644 --- a/packages/stream_chat_flutter/lib/src/stream_chat_theme.dart +++ b/packages/stream_chat_flutter/lib/src/stream_chat_theme.dart @@ -1,11 +1,11 @@ import 'package:cached_network_image/cached_network_image.dart'; import 'package:flutter/material.dart'; -import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; import 'package:stream_chat_flutter/src/channel_header.dart'; import 'package:stream_chat_flutter/src/channel_preview.dart'; import 'package:stream_chat_flutter/src/message_input.dart'; import 'package:stream_chat_flutter/src/reaction_icon.dart'; import 'package:stream_chat_flutter/src/utils.dart'; +import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; /// Inherited widget providing the [StreamChatThemeData] to the widget tree class StreamChatTheme extends InheritedWidget { @@ -476,7 +476,7 @@ class ColorTheme { this.bgGradient = const LinearGradient( begin: Alignment.topCenter, end: Alignment.bottomCenter, - colors: [const Color(0xfff7f7f7), const Color(0xfffcfcfc)], + colors: [Color(0xfff7f7f7), Color(0xfffcfcfc)], stops: [0, 1], ), this.borderTop = const Effect( @@ -519,7 +519,10 @@ class ColorTheme { this.bgGradient = const LinearGradient( begin: Alignment.topCenter, end: Alignment.bottomCenter, - colors: [const Color(0xff101214), const Color(0xff070a0d)], + colors: [ + Color(0xff101214), + Color(0xff070a0d), + ], stops: [0, 1], ), }); diff --git a/packages/stream_chat_flutter/lib/src/stream_svg_icon.dart b/packages/stream_chat_flutter/lib/src/stream_svg_icon.dart index 0d705d31..b0b3d0bb 100644 --- a/packages/stream_chat_flutter/lib/src/stream_svg_icon.dart +++ b/packages/stream_chat_flutter/lib/src/stream_svg_icon.dart @@ -386,7 +386,7 @@ class StreamSvgIcon extends StatelessWidget { ); } - factory StreamSvgIcon.cloud_download({ + factory StreamSvgIcon.cloudDownload({ double size, Color color, }) { @@ -434,7 +434,7 @@ class StreamSvgIcon extends StatelessWidget { ); } - factory StreamSvgIcon.arrow_right({ + factory StreamSvgIcon.arrowRight({ double size, Color color, }) { @@ -446,7 +446,7 @@ class StreamSvgIcon extends StatelessWidget { ); } - factory StreamSvgIcon.close_small({ + factory StreamSvgIcon.closeSmall({ double size, Color color, }) { @@ -458,7 +458,7 @@ class StreamSvgIcon extends StatelessWidget { ); } - factory StreamSvgIcon.Icon_curve_line_left_up({ + factory StreamSvgIcon.iconCurveLineLeftUp({ double size, Color color, }) { @@ -470,7 +470,7 @@ class StreamSvgIcon extends StatelessWidget { ); } - factory StreamSvgIcon.Icon_moon({ + factory StreamSvgIcon.iconMoon({ double size, Color color, }) { @@ -482,7 +482,7 @@ class StreamSvgIcon extends StatelessWidget { ); } - factory StreamSvgIcon.Icon_SHARE({ + factory StreamSvgIcon.iconShare({ double size, Color color, }) { @@ -494,7 +494,7 @@ class StreamSvgIcon extends StatelessWidget { ); } - factory StreamSvgIcon.Icon_grid({ + factory StreamSvgIcon.iconGrid({ double size, Color color, }) { @@ -506,7 +506,7 @@ class StreamSvgIcon extends StatelessWidget { ); } - factory StreamSvgIcon.Icon_send_message({ + factory StreamSvgIcon.iconSendMessage({ double size, Color color, }) { @@ -518,7 +518,7 @@ class StreamSvgIcon extends StatelessWidget { ); } - factory StreamSvgIcon.Icon_menu_point_v({ + factory StreamSvgIcon.iconMenuPoint({ double size, Color color, }) { @@ -530,7 +530,7 @@ class StreamSvgIcon extends StatelessWidget { ); } - factory StreamSvgIcon.Icon_save({ + factory StreamSvgIcon.iconSave({ double size, Color color, }) { @@ -542,7 +542,7 @@ class StreamSvgIcon extends StatelessWidget { ); } - factory StreamSvgIcon.share_arrow({ + factory StreamSvgIcon.shareArrow({ double size, Color color, }) { @@ -554,7 +554,7 @@ class StreamSvgIcon extends StatelessWidget { ); } - factory StreamSvgIcon.filetype_7z({ + factory StreamSvgIcon.filetype7z({ double size, Color color, }) { @@ -566,7 +566,7 @@ class StreamSvgIcon extends StatelessWidget { ); } - factory StreamSvgIcon.filetype_csv({ + factory StreamSvgIcon.filetypeCsv({ double size, Color color, }) { @@ -578,7 +578,7 @@ class StreamSvgIcon extends StatelessWidget { ); } - factory StreamSvgIcon.filetype_doc({ + factory StreamSvgIcon.filetypeDoc({ double size, Color color, }) { @@ -590,7 +590,7 @@ class StreamSvgIcon extends StatelessWidget { ); } - factory StreamSvgIcon.filetype_docx({ + factory StreamSvgIcon.filetypeDocx({ double size, Color color, }) { @@ -602,7 +602,7 @@ class StreamSvgIcon extends StatelessWidget { ); } - factory StreamSvgIcon.filetype_Generic({ + factory StreamSvgIcon.filetypeGeneric({ double size, Color color, }) { @@ -614,7 +614,7 @@ class StreamSvgIcon extends StatelessWidget { ); } - factory StreamSvgIcon.filetype_html({ + factory StreamSvgIcon.filetypeHtml({ double size, Color color, }) { @@ -626,7 +626,7 @@ class StreamSvgIcon extends StatelessWidget { ); } - factory StreamSvgIcon.filetype_md({ + factory StreamSvgIcon.filetypeMd({ double size, Color color, }) { @@ -638,7 +638,7 @@ class StreamSvgIcon extends StatelessWidget { ); } - factory StreamSvgIcon.filetype_odt({ + factory StreamSvgIcon.filetypeOdt({ double size, Color color, }) { @@ -650,7 +650,7 @@ class StreamSvgIcon extends StatelessWidget { ); } - factory StreamSvgIcon.filetype_pdf({ + factory StreamSvgIcon.filetypePdf({ double size, Color color, }) { @@ -662,7 +662,7 @@ class StreamSvgIcon extends StatelessWidget { ); } - factory StreamSvgIcon.filetype_ppt({ + factory StreamSvgIcon.filetypePpt({ double size, Color color, }) { @@ -674,7 +674,7 @@ class StreamSvgIcon extends StatelessWidget { ); } - factory StreamSvgIcon.filetype_pptx({ + factory StreamSvgIcon.filetypePptx({ double size, Color color, }) { @@ -686,7 +686,7 @@ class StreamSvgIcon extends StatelessWidget { ); } - factory StreamSvgIcon.filetype_rar({ + factory StreamSvgIcon.filetypeRar({ double size, Color color, }) { @@ -698,7 +698,7 @@ class StreamSvgIcon extends StatelessWidget { ); } - factory StreamSvgIcon.filetype_rtf({ + factory StreamSvgIcon.filetypeRtf({ double size, Color color, }) { @@ -710,7 +710,7 @@ class StreamSvgIcon extends StatelessWidget { ); } - factory StreamSvgIcon.filetype_tar({ + factory StreamSvgIcon.filetypeTar({ double size, Color color, }) { @@ -722,7 +722,7 @@ class StreamSvgIcon extends StatelessWidget { ); } - factory StreamSvgIcon.filetype_txt({ + factory StreamSvgIcon.filetypeTxt({ double size, Color color, }) { @@ -734,7 +734,7 @@ class StreamSvgIcon extends StatelessWidget { ); } - factory StreamSvgIcon.filetype_xls({ + factory StreamSvgIcon.filetypeXls({ double size, Color color, }) { @@ -746,7 +746,7 @@ class StreamSvgIcon extends StatelessWidget { ); } - factory StreamSvgIcon.filetype_xlsx({ + factory StreamSvgIcon.filetypeXlsx({ double size, Color color, }) { @@ -758,7 +758,7 @@ class StreamSvgIcon extends StatelessWidget { ); } - factory StreamSvgIcon.filetype_zip({ + factory StreamSvgIcon.filetypeZip({ double size, Color color, }) { @@ -770,7 +770,7 @@ class StreamSvgIcon extends StatelessWidget { ); } - factory StreamSvgIcon.Icon_group({ + factory StreamSvgIcon.iconGroup({ double size, Color color, }) { @@ -782,7 +782,7 @@ class StreamSvgIcon extends StatelessWidget { ); } - factory StreamSvgIcon.Icon_notification({ + factory StreamSvgIcon.iconNotification({ double size, Color color, }) { @@ -794,7 +794,7 @@ class StreamSvgIcon extends StatelessWidget { ); } - factory StreamSvgIcon.Icon_user_delete({ + factory StreamSvgIcon.iconUserDelete({ double size, Color color, }) { @@ -818,7 +818,7 @@ class StreamSvgIcon extends StatelessWidget { ); } - factory StreamSvgIcon.circle_up({ + factory StreamSvgIcon.circleUp({ double size, Color color, }) { @@ -830,7 +830,7 @@ class StreamSvgIcon extends StatelessWidget { ); } - factory StreamSvgIcon.Icon_user_settings({ + factory StreamSvgIcon.iconUserSettings({ double size, Color color, }) { @@ -890,7 +890,7 @@ class StreamSvgIcon extends StatelessWidget { ); } - factory StreamSvgIcon.icon_flag({ + factory StreamSvgIcon.iconFlag({ double size, Color color, }) { diff --git a/packages/stream_chat_flutter/lib/src/user_list_view.dart b/packages/stream_chat_flutter/lib/src/user_list_view.dart index a53ba97a..a1819592 100644 --- a/packages/stream_chat_flutter/lib/src/user_list_view.dart +++ b/packages/stream_chat_flutter/lib/src/user_list_view.dart @@ -1,6 +1,6 @@ import 'package:flutter/material.dart'; -import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; +import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; import 'user_item.dart'; @@ -138,7 +138,7 @@ class _UserListViewState extends State with WidgetsBindingObserver { bool get _isListView => widget.crossAxisCount == 1; - UserListController _userListController = UserListController(); + final UserListController _userListController = UserListController(); @override Widget build(BuildContext context) { diff --git a/packages/stream_chat_flutter/lib/src/utils.dart b/packages/stream_chat_flutter/lib/src/utils.dart index 93d87ab2..f7eaf385 100644 --- a/packages/stream_chat_flutter/lib/src/utils.dart +++ b/packages/stream_chat_flutter/lib/src/utils.dart @@ -221,7 +221,7 @@ String getSizeText(int bytes) { } if (bytes <= 1000) { - return '${bytes} bytes'; + return '$bytes bytes'; } else if (bytes <= 100000) { return '${(bytes / 1000).toStringAsFixed(2)} KB'; } else { @@ -233,58 +233,58 @@ String getSizeText(int bytes) { StreamSvgIcon getFileTypeImage(String type) { switch (type) { case '7z': - return StreamSvgIcon.filetype_7z(); + return StreamSvgIcon.filetype7z(); break; case 'csv': - return StreamSvgIcon.filetype_csv(); + return StreamSvgIcon.filetypeCsv(); break; case 'doc': - return StreamSvgIcon.filetype_doc(); + return StreamSvgIcon.filetypeDoc(); break; case 'docx': - return StreamSvgIcon.filetype_docx(); + return StreamSvgIcon.filetypeDocx(); break; case 'html': - return StreamSvgIcon.filetype_html(); + return StreamSvgIcon.filetypeHtml(); break; case 'md': - return StreamSvgIcon.filetype_md(); + return StreamSvgIcon.filetypeMd(); break; case 'odt': - return StreamSvgIcon.filetype_odt(); + return StreamSvgIcon.filetypeOdt(); break; case 'pdf': - return StreamSvgIcon.filetype_pdf(); + return StreamSvgIcon.filetypePdf(); break; case 'ppt': - return StreamSvgIcon.filetype_ppt(); + return StreamSvgIcon.filetypePpt(); break; case 'pptx': - return StreamSvgIcon.filetype_pptx(); + return StreamSvgIcon.filetypePptx(); break; case 'rar': - return StreamSvgIcon.filetype_rar(); + return StreamSvgIcon.filetypeRar(); break; case 'rtf': - return StreamSvgIcon.filetype_rtf(); + return StreamSvgIcon.filetypeRtf(); break; case 'tar': - return StreamSvgIcon.filetype_tar(); + return StreamSvgIcon.filetypeTar(); break; case 'txt': - return StreamSvgIcon.filetype_txt(); + return StreamSvgIcon.filetypeTxt(); break; case 'xls': - return StreamSvgIcon.filetype_xls(); + return StreamSvgIcon.filetypeXls(); break; case 'xlsx': - return StreamSvgIcon.filetype_xlsx(); + return StreamSvgIcon.filetypeXlsx(); break; case 'zip': - return StreamSvgIcon.filetype_zip(); + return StreamSvgIcon.filetypeZip(); break; default: - return StreamSvgIcon.filetype_Generic(); + return StreamSvgIcon.filetypeGeneric(); break; } } From f8b24038da1333a26a032ece37297cf76a059517 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Tue, 2 Feb 2021 13:03:44 +0100 Subject: [PATCH 1135/1140] move sample app to separate repo --- .../stream_chat_flutter/example/.gitignore | 8 +- .../stream_chat_flutter/example/.metadata | 2 +- .../example/android/.gitignore | 4 + .../example/android/app/build.gradle | 10 +- .../android/app/src/main/AndroidManifest.xml | 31 +- .../kotlin/com/example/example/Application.kt | 27 - .../com/example/example/MainActivity.kt | 6 - .../src/main/res/mipmap-hdpi/ic_launcher.png | Bin 5905 -> 544 bytes .../src/main/res/mipmap-mdpi/ic_launcher.png | Bin 3283 -> 442 bytes .../src/main/res/mipmap-xhdpi/ic_launcher.png | Bin 8478 -> 721 bytes .../main/res/mipmap-xxhdpi/ic_launcher.png | Bin 15150 -> 1031 bytes .../main/res/mipmap-xxxhdpi/ic_launcher.png | Bin 21173 -> 1443 bytes .../app/src/main/res/values/styles.xml | 10 + .../example/android/build.gradle | 3 +- .../example/android/gradle.properties | 2 +- .../gradle/wrapper/gradle-wrapper.properties | 4 +- .../example/android/settings.gradle | 18 +- .../example/assets/android_icon.png | Bin 15354 -> 0 bytes .../example/assets/icon_arrow_right.svg | 5 - .../example/assets/ios_icon.png | Bin 40617 -> 0 bytes .../example/assets/logo.svg | 3 - .../stream_chat_flutter/example/ios/Gemfile | 6 - .../example/ios/Gemfile.lock | 180 --- .../example/ios/Notifications/Info.plist | 31 - .../Notifications/NotificationService.swift | 182 --- .../Notifications/Notifications.entitlements | 10 - .../ios/Runner.xcodeproj/project.pbxproj | 368 +----- .../xcschemes/Notifications.xcscheme | 96 -- .../xcshareddata/xcschemes/Runner.xcscheme | 8 +- .../contents.xcworkspacedata | 3 - .../example/ios/Runner/AppDelegate.swift | 46 +- .../Icon-App-1024x1024@1x.png | Bin 52126 -> 10932 bytes .../AppIcon.appiconset/Icon-App-20x20@1x.png | Bin 572 -> 564 bytes .../AppIcon.appiconset/Icon-App-20x20@2x.png | Bin 1472 -> 1283 bytes .../AppIcon.appiconset/Icon-App-20x20@3x.png | Bin 2358 -> 1588 bytes .../AppIcon.appiconset/Icon-App-29x29@1x.png | Bin 990 -> 1025 bytes .../AppIcon.appiconset/Icon-App-29x29@2x.png | Bin 2338 -> 1716 bytes .../AppIcon.appiconset/Icon-App-29x29@3x.png | Bin 3744 -> 1920 bytes .../AppIcon.appiconset/Icon-App-40x40@1x.png | Bin 1472 -> 1283 bytes .../AppIcon.appiconset/Icon-App-40x40@2x.png | Bin 3342 -> 1895 bytes .../AppIcon.appiconset/Icon-App-40x40@3x.png | Bin 5281 -> 2665 bytes .../AppIcon.appiconset/Icon-App-60x60@2x.png | Bin 5281 -> 2665 bytes .../AppIcon.appiconset/Icon-App-60x60@3x.png | Bin 8289 -> 3831 bytes .../AppIcon.appiconset/Icon-App-76x76@1x.png | Bin 3132 -> 1888 bytes .../AppIcon.appiconset/Icon-App-76x76@2x.png | Bin 6964 -> 3294 bytes .../Icon-App-83.5x83.5@2x.png | Bin 7597 -> 3612 bytes .../example/ios/Runner/Info.plist | 33 +- .../ios/Runner/Runner-Bridging-Header.h | 2 +- .../example/ios/Runner/Runner.entitlements | 12 - .../example/ios/fastlane/Appfile | 6 - .../example/ios/fastlane/Fastfile | 46 - .../example/ios/fastlane/Matchfile | 16 - .../example/ios/fastlane/Pluginfile | 5 - .../example/ios/fastlane/README.md | 37 - .../fastlane/beta_gym_export_options.plist | 15 - .../example/ios/fastlane/report.xml | 33 - .../example/lib/advanced_options_page.dart | 328 ------ .../example/lib/chat_info_screen.dart | 599 ---------- .../example/lib/chips_input_text_field.dart | 169 --- .../example/lib/choose_user_page.dart | 267 ----- .../lib/group_chat_details_screen.dart | 331 ------ .../example/lib/group_info_screen.dart | 1023 ----------------- .../stream_chat_flutter/example/lib/main.dart | 821 +------------ .../example/lib/new_chat_screen.dart | 417 ------- .../example/lib/new_group_chat_screen.dart | 339 ------ .../example/lib/notifications_service.dart | 31 - .../example/lib/routes/app_routes.dart | 93 -- .../example/lib/routes/routes.dart | 13 - .../example/lib/search_text_field.dart | 94 -- .../example/lib/stream_version.dart | 39 - .../stream_chat_flutter/example/pubspec.yaml | 81 +- .../example/test/widget_test.dart | 30 + .../test_driver/single_conversation.dart | 9 - .../test_driver/single_conversation_test.dart | 46 - .../example/web/favicon.png | Bin 917 -> 0 bytes .../example/web/icons/Icon-192.png | Bin 5292 -> 0 bytes .../example/web/icons/Icon-512.png | Bin 8252 -> 0 bytes .../example/web/index.html | 34 - .../example/web/manifest.json | 23 - .../example/web/sql-wasm.js | 207 ---- .../example/web/sql-wasm.wasm | Bin 1450157 -> 0 bytes 81 files changed, 206 insertions(+), 6056 deletions(-) delete mode 100644 packages/stream_chat_flutter/example/android/app/src/main/kotlin/com/example/example/Application.kt delete mode 100644 packages/stream_chat_flutter/example/assets/android_icon.png delete mode 100644 packages/stream_chat_flutter/example/assets/icon_arrow_right.svg delete mode 100644 packages/stream_chat_flutter/example/assets/ios_icon.png delete mode 100644 packages/stream_chat_flutter/example/assets/logo.svg delete mode 100644 packages/stream_chat_flutter/example/ios/Gemfile delete mode 100644 packages/stream_chat_flutter/example/ios/Gemfile.lock delete mode 100644 packages/stream_chat_flutter/example/ios/Notifications/Info.plist delete mode 100644 packages/stream_chat_flutter/example/ios/Notifications/NotificationService.swift delete mode 100644 packages/stream_chat_flutter/example/ios/Notifications/Notifications.entitlements delete mode 100644 packages/stream_chat_flutter/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Notifications.xcscheme delete mode 100644 packages/stream_chat_flutter/example/ios/Runner/Runner.entitlements delete mode 100644 packages/stream_chat_flutter/example/ios/fastlane/Appfile delete mode 100644 packages/stream_chat_flutter/example/ios/fastlane/Fastfile delete mode 100644 packages/stream_chat_flutter/example/ios/fastlane/Matchfile delete mode 100644 packages/stream_chat_flutter/example/ios/fastlane/Pluginfile delete mode 100644 packages/stream_chat_flutter/example/ios/fastlane/README.md delete mode 100644 packages/stream_chat_flutter/example/ios/fastlane/beta_gym_export_options.plist delete mode 100644 packages/stream_chat_flutter/example/ios/fastlane/report.xml delete mode 100644 packages/stream_chat_flutter/example/lib/advanced_options_page.dart delete mode 100644 packages/stream_chat_flutter/example/lib/chat_info_screen.dart delete mode 100644 packages/stream_chat_flutter/example/lib/chips_input_text_field.dart delete mode 100644 packages/stream_chat_flutter/example/lib/choose_user_page.dart delete mode 100644 packages/stream_chat_flutter/example/lib/group_chat_details_screen.dart delete mode 100644 packages/stream_chat_flutter/example/lib/group_info_screen.dart delete mode 100644 packages/stream_chat_flutter/example/lib/new_chat_screen.dart delete mode 100644 packages/stream_chat_flutter/example/lib/new_group_chat_screen.dart delete mode 100644 packages/stream_chat_flutter/example/lib/notifications_service.dart delete mode 100644 packages/stream_chat_flutter/example/lib/routes/app_routes.dart delete mode 100644 packages/stream_chat_flutter/example/lib/routes/routes.dart delete mode 100644 packages/stream_chat_flutter/example/lib/search_text_field.dart delete mode 100644 packages/stream_chat_flutter/example/lib/stream_version.dart create mode 100644 packages/stream_chat_flutter/example/test/widget_test.dart delete mode 100644 packages/stream_chat_flutter/example/test_driver/single_conversation.dart delete mode 100644 packages/stream_chat_flutter/example/test_driver/single_conversation_test.dart delete mode 100644 packages/stream_chat_flutter/example/web/favicon.png delete mode 100644 packages/stream_chat_flutter/example/web/icons/Icon-192.png delete mode 100644 packages/stream_chat_flutter/example/web/icons/Icon-512.png delete mode 100644 packages/stream_chat_flutter/example/web/index.html delete mode 100644 packages/stream_chat_flutter/example/web/manifest.json delete mode 100644 packages/stream_chat_flutter/example/web/sql-wasm.js delete mode 100644 packages/stream_chat_flutter/example/web/sql-wasm.wasm diff --git a/packages/stream_chat_flutter/example/.gitignore b/packages/stream_chat_flutter/example/.gitignore index 8011d84b..9d532b18 100644 --- a/packages/stream_chat_flutter/example/.gitignore +++ b/packages/stream_chat_flutter/example/.gitignore @@ -22,6 +22,7 @@ # Flutter/Dart/Pub related **/doc/api/ +**/ios/Flutter/.last_build_id .dart_tool/ .flutter-plugins .flutter-plugins-dependencies @@ -33,7 +34,8 @@ # Web related lib/generated_plugin_registrant.dart -# Exceptions to above rules. -!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages +# Symbolication related +app.*.symbols -fvm \ No newline at end of file +# Obfuscation related +app.*.map.json diff --git a/packages/stream_chat_flutter/example/.metadata b/packages/stream_chat_flutter/example/.metadata index 01d2dcb9..cd984dd0 100644 --- a/packages/stream_chat_flutter/example/.metadata +++ b/packages/stream_chat_flutter/example/.metadata @@ -4,7 +4,7 @@ # This file should be version controlled and should not be manually edited. version: - revision: 0b8abb4724aa590dd0f429683339b1e045a1594d + revision: 9b2d32b605630f28625709ebd9d78ab3016b2bf6 channel: stable project_type: app diff --git a/packages/stream_chat_flutter/example/android/.gitignore b/packages/stream_chat_flutter/example/android/.gitignore index bc2100d8..0a741cb4 100644 --- a/packages/stream_chat_flutter/example/android/.gitignore +++ b/packages/stream_chat_flutter/example/android/.gitignore @@ -5,3 +5,7 @@ gradle-wrapper.jar /gradlew.bat /local.properties GeneratedPluginRegistrant.java + +# Remember to never publicly share your keystore. +# See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app +key.properties diff --git a/packages/stream_chat_flutter/example/android/app/build.gradle b/packages/stream_chat_flutter/example/android/app/build.gradle index c5ff1b9e..5a4d759a 100644 --- a/packages/stream_chat_flutter/example/android/app/build.gradle +++ b/packages/stream_chat_flutter/example/android/app/build.gradle @@ -27,14 +27,13 @@ apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" android { compileSdkVersion 29 - ndkVersion '21.3.6528147' sourceSets { main.java.srcDirs += 'src/main/kotlin' } + lintOptions { disable 'InvalidPackage' - checkReleaseBuilds false } defaultConfig { @@ -44,7 +43,6 @@ android { targetSdkVersion 29 versionCode flutterVersionCode.toInteger() versionName flutterVersionName - testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } buildTypes { @@ -62,10 +60,4 @@ flutter { dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" - testImplementation 'junit:junit:4.12' - androidTestImplementation 'androidx.test:runner:1.1.1' - androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1' - implementation 'com.google.firebase:firebase-messaging:20.1.2' } - -apply plugin: 'com.google.gms.google-services' diff --git a/packages/stream_chat_flutter/example/android/app/src/main/AndroidManifest.xml b/packages/stream_chat_flutter/example/android/app/src/main/AndroidManifest.xml index 0492c6da..3197993b 100644 --- a/packages/stream_chat_flutter/example/android/app/src/main/AndroidManifest.xml +++ b/packages/stream_chat_flutter/example/android/app/src/main/AndroidManifest.xml @@ -6,14 +6,10 @@ additional functionality it is fine to subclass or reimplement FlutterApplication and put your custom class here. --> - - + android:name="io.flutter.app.FlutterApplication" + android:label="example" + android:icon="@mipmap/ic_launcher"> - - - - + + + + diff --git a/packages/stream_chat_flutter/example/android/app/src/main/kotlin/com/example/example/Application.kt b/packages/stream_chat_flutter/example/android/app/src/main/kotlin/com/example/example/Application.kt deleted file mode 100644 index dd47a03c..00000000 --- a/packages/stream_chat_flutter/example/android/app/src/main/kotlin/com/example/example/Application.kt +++ /dev/null @@ -1,27 +0,0 @@ -package com.example.example - -import com.dexterous.flutterlocalnotifications.FlutterLocalNotificationsPlugin -import io.flutter.app.FlutterApplication -import io.flutter.plugin.common.PluginRegistry -import io.flutter.plugin.common.PluginRegistry.PluginRegistrantCallback -import io.flutter.plugins.firebasemessaging.FirebaseMessagingPlugin -import io.flutter.plugins.firebasemessaging.FlutterFirebaseMessagingService -import io.flutter.plugins.sharedpreferences.SharedPreferencesPlugin -import io.flutter.plugins.pathprovider.PathProviderPlugin - -class Application : FlutterApplication(), PluginRegistrantCallback { - override fun onCreate() { - super.onCreate() - FlutterFirebaseMessagingService.setPluginRegistrant(this) - } - - override fun registerWith(registry: PluginRegistry?) { - PathProviderPlugin.registerWith(registry?.registrarFor( - "io.flutter.plugins.pathprovider.PathProviderPlugin")) - SharedPreferencesPlugin.registerWith(registry?.registrarFor( - "io.flutter.plugins.sharedpreferences.SharedPreferencesPlugin")) - FlutterLocalNotificationsPlugin.registerWith(registry?.registrarFor( - "com.dexterous.flutterlocalnotifications.FlutterLocalNotificationsPlugin")) - FirebaseMessagingPlugin.registerWith(registry?.registrarFor("io.flutter.plugins.firebasemessaging.FirebaseMessagingPlugin")) - } -} \ No newline at end of file diff --git a/packages/stream_chat_flutter/example/android/app/src/main/kotlin/com/example/example/MainActivity.kt b/packages/stream_chat_flutter/example/android/app/src/main/kotlin/com/example/example/MainActivity.kt index 1656503f..e793a000 100644 --- a/packages/stream_chat_flutter/example/android/app/src/main/kotlin/com/example/example/MainActivity.kt +++ b/packages/stream_chat_flutter/example/android/app/src/main/kotlin/com/example/example/MainActivity.kt @@ -1,12 +1,6 @@ package com.example.example -import androidx.annotation.NonNull; import io.flutter.embedding.android.FlutterActivity -import io.flutter.embedding.engine.FlutterEngine -import io.flutter.plugins.GeneratedPluginRegistrant class MainActivity: FlutterActivity() { - override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) { - GeneratedPluginRegistrant.registerWith(flutterEngine); - } } diff --git a/packages/stream_chat_flutter/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/packages/stream_chat_flutter/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png index 91797672c7ce9b88327a8f87325cb5895ca0c0d4..db77bb4b7b0906d62b1847e87f15cdcacf6a4f29 100644 GIT binary patch literal 544 zcmeAS@N?(olHy`uVBq!ia0vp^9w5xY3?!3`olAj~WQl7;NpOBzNqJ&XDuZK6ep0G} zXKrG8YEWuoN@d~6R2!h8bpbvhu0Wd6uZuB!w&u2PAxD2eNXD>P5D~Wn-+_Wa#27Xc zC?Zj|6r#X(-D3u$NCt}(Ms06KgJ4FxJVv{GM)!I~&n8Bnc94O7-Hd)cjDZswgC;Qs zO=b+9!WcT8F?0rF7!Uys2bs@gozCP?z~o%U|N3vA*22NaGQG zlg@K`O_XuxvZ&Ks^m&R!`&1=spLvfx7oGDKDwpwW`#iqdw@AL`7MR}m`rwr|mZgU`8P7SBkL78fFf!WnuYWm$5Z0 zNXhDbCv&49sM544K|?c)WrFfiZvCi9h0O)B3Pgg&ebxsLQ05GG~ AQ2+n{ literal 5905 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 diff --git a/packages/stream_chat_flutter/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/packages/stream_chat_flutter/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png index 103da98b58d1b062818d94e10cae84e7c85d04cf..17987b79bb8a35cc66c3c1fd44f5a5526c1b78be 100644 GIT binary patch literal 442 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 literal 8478 zcmV+(A>rPMP)0}oLL_uU&rY!%WV1WY4xHv9~f};Mo;<)P7tH@F=vX|@v z;#DrPsT5QY5oHLJ4m#4^q!~@yBfL84~dMlKjAa5U8;TauPAqr62I6sArhbOs;b6jmNM}ySe;$mC1={{H#JFJ&Xu4-c_18XP+^kr6txAAtu7>00d|6i3miFq(w zg~(4{!TJW5iaT^>6eAc}YZ2eMHz1S1X4DraS7hxzk;VLWpx~Q?qgJId7fL12z56W{ z#?2Q%Y%Fl$0{tH&+LIL8w&%1brESKKRs}@$DAY4tfu1O{o=|MCQi3ZBWw(!Loo1Jhwf9}X`D(HO~Dij?Ntj<7M z3?JRgD`sx**xqwLD#<#2IQ`VBrTK|l_K|X0K!uT(*33ny8!ayYs`2UR43nNAZQc8o zNx`FM%{1Bk+7#$4D9GUn(LAAsZEnKdL3n0qnGGp9@BrI$NW_pnLplukBw2H6@#5s9 z`Rj=wOo)i!Te?NGtN_%+#wR9twCOv0YH-|~ImM;2&}+q3QhO^4w-)85L1-NXIxEoy z-!}3tAAH`o=bSm3A3pk5a^k0JNgc|O-*P^pr3AoG%@4{m59u%|eLjqJ9u z?oIhE1ZftAQX32=&rt8K@BgP?&lxZMvFF8Ca$;ilIa)%q3!?c25E;pEg?wJy`DY(!}%>k;)o$Sh8u9s zHzEKws_Tu zCrt?%xO{o4#>)Pg$ag{z0#UrMp&K_dVwv~VQ|s5_I)rdN0-)qi4IZ#!Sw_Bvy_=kE zlR@g9k#A*N4Op?9ZV@4@K@)}0Q~@y2_l6%3PEU}3`uC%i>pl5%EO z0-E3x8ZCgxNs}1U_gDIa58J#xEyw!j*8Ex^Eg{d!MiOoe+5sA`hubEltzX|LAv96| zu}t>2XQO*RcYJ4Rj#cs(`E`JBLKIUH6MtamiRHZ?LTqdb65Zzs?gcBkfuvwp{=_5K3>e=Qh>)i_4 zeUYLI@ASabft1@2xkXmA8?kgj)~69&NoZPL zbBwvJ7QjUJo;9_gEU-NtLcBS}yo*7iBFZJ<^lvHYUoAroUr=2DRQuD?q^-uhHTPQK zU)tYX(3`9X@BP-Clus6}BOI4j^#?Uu0M-7<#U`)dzqG$O!LWqW(5SwzPD#z!`30)9 zf=U6<`8$b;qE@3`nR!ijXK24;vf>>PA(xa|5z*t-nW@L-uOM7ooW7t^0B6rK0Wo8T znGnz#u-^9CU!pI?_=l~KNf<0UAco4@<5m}`L6AtEHQM}I2X`JnOmp^s-@?%fDg_`G zBfR^w&lPAbx4lXk^jd6~CB^UueT7;K?^%Jz-YJ4grMT5aYY>Gx3qtPy`|}#jfp4Ar z1OX^Vj%4%)PKGF2^&VW1W4o={FE7>Nt+5~JEGIdK-u->rk#)8|$evmr3qMc`WZoDz5W?B>OEhrI=8wNSJfJF3`B&Cl&={w)<1 z=o&4;=hJZ2w^KZEAijBq)msF2R4_X(en^jjtL3(fbei$}4ALp~I;5gB(D|CHe zSVk4t=E2|0Tma!dkIPR;Kv1{o0}2fcE$wY507`C{JOlrIzpb$CB>dp1e6$YtL$EJ{ z13zi-XrBj;@;ujp{t8$Y5b^H~wj9 zqx*$#*`*<&&E(^Mix}9l3%!XWi^GO>7DJzSmDdI8ipUIHQ z17LG7D^&zy%zGI)_(?co!t6^Alrjd}-ff40ucbrm6?D4^ffof0@1@-~6&x$}_Vtph z+Bnu^xdr2BCqjkz7ML*aK#^95Z{G`Z5lS_`+`?n@J6B*9g^}l0jM;Eq*$T4fFXL}L8dea-DKhnWRQGa+^7m?KY zQ=#*=3NW@ZBIydU-%5_Nu<#zRGG6fZv_b7%hG3-yRvU{mX&mG-w-FdaSAa@G2X^Ar zp)nl|CU@rpW#&@66EDW|BmC@ykdjue?2^M^=8>o6p(*B(Lw*#sgh1R`ZndQ~96yBtA27Gm;v z1Smz2c}XA=dl7TyLAGTGQZd4hwlHsLrM}YVI3uyGM-6yol@Xp&S%ZAi<+tjPwjDU7 zQWZnj;kpw*d3ibh{;02DcdJGgPJ+B73?c*Q&!O#t=F&7nQmO5H_Q`n zAj&FujO|;!lXmvX0{n7?hgc$aS4`5{7+lDfV$6rd*!~Zdi5m_Hx^=aUo{b#HYvsSldq@44zc9EP#65Yz}*#t5# z8D3hFjb1U4@F$v6b73j1ho;yjG)-so6rz-RG)lO}aZFesTq9nm*B&{e#~W)cAez#c zB31(@@y4qCT6Abth>3&!T+emddY-Se^-K+6RBf?NQ%ld$8hMaJ*6!qMJda*$B(3?y z#c7bsLmCyFSUjV{I13l3ZtPS;#xn>{f1HQC{|c;DaA#p@tiE=i770fRk(^~lC~50~ zzGA_ys)Du+r=?5MKRp3-eU@9L)D#6>Gce`qAp%k}r`NM%aQSfN8$fB}6w z%d063HG4V}^;JBwi|qbOXRr|;WQ5*Sj(p;?sK3fBDnnMD0ry6UF)B6y69y`3)!iw$ ziG-U{CZuumJqhO(T#%Xwz*o`OSdv!YTn39Jy9@B*0}!`y?p3eD-u;$98rZ?h$;fOE7-Fr7QS-EWk)Y&+A!w*4EQPoZ#c|V z`uJev`#O>xONEHY`3x$65wniN#6^K;JV?~$NqifP+N9*K6y?Sucq_zsX0R6~KN2Ri zdfveSH8ZrXRfVwma1l;kAxh}R_E&|CaL@5PL*F{m=md;9!nZdTqu0GQbZcF?-kJmq zP>(!~r-p^&sYm?KC6dKk;}w`24;=c?*nUC;i9}4y8I43dU^8c9_qk$nUKl71qO_!QW9!gFt(Qs z@q>cU+YttnfC=ZX*|2_J5jGykBe_K+t+7k<{~!wU0&%=e%{Ay7UubJ-@*)kDN`-0j zQt->NHm>H_tAhv&XGG)G)n(XtI2&qTPfUBn15XX|#=y=Z47fKKi>C9~aHtet9xTDR zt6J=z*A~%1m5CO$`=j2z3O$MEn=>V+JaHr&jw4CjkwxuXt?k|j771^M;L$l((Y>Pr z@lUGo^gvH|I2bv3*@~odW^6cULUw_fD1|?Qg2Qp(ln%$v^XM2M!SDw}m^v?$2wB}! zg`rjCu4{=BeNaJJ5T2S>h%aCBbM2onP=y^yIXIo}2ck%rx7&jEH*3)UUSM>;0F002 z@a!-z;b*Q0fTy_9>`)A!n~PLk2r&cKQ!4jm*7D(a;;l3!E{t+1PTv@km+WW{PsfPn zVbWT+AI`y!A0#A8FcW94gePhBGKD<^)|y1vbV5nWPsb;UNb4YK?4_O18L#eSC-P(u{ALomw2KWly6coiItlV(WfHnKg$SJas@KFJo zgHu|UQnLltvSO6;GDt}ik$YNDVP#QlU?JwUBsY@6i-hObJA}?KyqRMyMI|_;IK`Y^Ke+6NhO-J+LXU6r4x(uz*%x=IswN$yGl6+JX zE!dfuMH9Na_ z!2}wJiLq2z5ZB9!u>*t9@1Dvi=4`4B8}=8Hd+;P2W+0cT;0#)vxgwoyF|Z4Rcb*PG z`%u<(tZKpt$F{#g?}eL<_IxSNAqzgqW~6Lm~c(GAqU}6HcWU@Nlc7H=ntZ0C^GOQ;?k3hxEy(f zW=KdYa`w?wRSGH~iA{q|b0RRPi`|>n>PD#oriw7=Um8rjN}fG=h!6g@AfG4<<;1;z z5SOK9aWGy^Wt5LHH|q41M4gBgdOEco}f zZ1j#{iHTCDyw6B8pNQB2*v zlNA;oZT<4GI$db-Sy|oaF{;P$Ttp2=!VaZj-ODSB5PJ7NP zTEv^ojT?}uw{YaAvxbs%oY=%S16&1rqOX$J+&r8}=7q6=rrghim?#foqRwf6pH}HG z>+@n_qOADjg?5MxWbJ)ORM5e!(2M%|vQ%s$Erjz_36=M$Vq)q7&CELn6kz|y5sh-B z8jS|))~$m`B&sF|v)PQAx#HT#J8rys z^=c9gRrgDO8{sERk=b#gb|6AQ-B?Q2g^Qdy>(F_*1hza!r=(j}+<=;zXFe-Nm$nMQ z1W}TxNm}_@6h@Fl%SYL;KcJvyrPNpmA8#pUjNphL2o=VKoqaJoj$5$qn=4o|r-RV! zhrRv>o_@3qCXhsrI>w3pLO@?Fvw_(E)%#5-(3*%Q`d3Sqw7Oz!|ERUl9qvy1o#bD> ze7V-K&6_tPK0dzoMWnC`p7X=cmokx6I}qVXfMzSxB%SAM6^0^{p*WeoSF^bmU@Hm9 zQ$EhX_X{Ijc9}Zo*`qwLbgxlx+BHGXG0>qo-imR3XkSbS9wb`NI-;0!j=q@9iB?#M zwd8F+#QE8M#>s2`IJ;bnSC?0hqFyCY)GQK3ok>;UtuIYDe@!F|CQ-W|A1e{gxe@ZW zY}tZwoaJ5M0iX_U)EyTo>RCBb>3TPdP(rTJ06_mN67l!&TqA}n+Jh5tDF-G*X2#J|<=GwY9g3*0?I&6#wR0>Z_e~f0s zA;R#W)5L5$MiQl?c{p&EC4_rHTBR?>oe!xUMP;FXR|zg^yo4TGDgfHTd}Ixqo*N~< zDxUj)0oeau4k?$t6)5B!pLOQ9gOqzZH4*vWBpi+zzR;>OG>;!}g2w-Uo0pE$UqlO| zWVFJq{8$nt(eYUsdbDM$b@$T2oUPwm1(Lm_DyXWsi&}-M!XCApEK^%J65@a*5C{A?#PE5=xye6)kL-nJ ze2Xn5#LR}^sgHB9``w_*9>~t#uHzd?*tqoD60oLJFw$T|1#+;rg_8R3OAeQ^2G_)_ z)_%p1deuD+OT+D~65?|l3;oNj95D&?cU?9&`A!8J)x(Vco}tl@jW5o<@{_{Tl1I6> zPfsUFlrd%VPS5sl_cE7X*PFNM1&usTB{SG~pa>HO`??Ax{3Sn{SWW0h_xsj+kGc`) z(&Cd#+tzu8^Z3Yja&TVbBZxJk%B+o=Xm0Xd{AE9bQ{_d?*sBx z+5N!}pG7r$Uw=ao!rL-2~2@W8c03rpP3YiTOz(=zpe z=>Ad;9)C!JmYY>t9Sp+~GbnLoyEa?x=LQD{3%{BIs7n6QrAzU`3oi%+(@APhbRpIw zF)_Fwoa z3OVQ$!qll#>m0Fv!yq!!oO%5H zkG#8mv_x-enO1Ns!Eqkgal(p;vGq^Apsj&+vehJ?3WnPHqeqXrH9M8}vQK8-z4q-7 zYQ85zC{L{`A|m*d#D%N-KQwcO-ss<6@M3on=-mBplk$iFLh3y3G)EIAOu)*OD_uT; zg6`Mr^@3o&{PN4jhNZToQ^}W-e_XYuruI|R765%sL((6dN~g6v(GSXv`BocxTotYQia95Lpv-w?mR5XGKQt z3(G&UixodSN_g|rT?E=G_U7t5Y<)Ax?YZ>{Vbi8f!pPYA23}uJgk(E(=+Lf97tig> zujj>m^&3KBt9~wg{-xe8Ug)2m%lo!Oa(1ggZSv7`z;{0zG2{W6+f2GXA#B*NL7;^W zQ`Q0cd8ndio_Xe_wCj9pB5(0ya?SalRDoLfj9` z)F%Ym0!m6suyf~5VY`Z+^1~k;H6ty}nA6aG8=i$pB$pNuv0a^i=n=7Wz$E%U%!Z43 zXF)3W$C!7M@y&;As?E@@4^#+0{`e!rRTipIU!c?JU^E(qt_Vk-W}EZzw)K1We6<~J za!&WtU@u&-{hTy<#*kOeK5(%xtP^vWMMZi(43E5?f=zRyg^@Fg`UFAA?$M)1oyY8& zFXR@sR~Mf-zhKU|8EC|-?A;3>KOcN-tm*KYaZmJm?)VRBIlTYfwyUoKCj#Ggp@v{1f`k+w=He)48&o zy(345J>ET~nO|Q|+=2auN%FnpCxs2!yqSJEqT%&|cOJwNFX$~^n7z_~*H)HbOm8dh zZR?LdF|088i!L~)!k|-Le!gPG>B}a3^+Or5^2_;lQT{f=iSd(iQ%)oy8KPSL9Wie>c65qFyqD05QBB&)A~0k$010~P}@<|0^mPFPgVF%|Z=07!ix z;lzCVD3MKbp? zhx&_b*@p@FC!7BL7>es%3?vAFFE^G%{Rux~MM1ddqk~1}v^^6ir{03kSW(zge%+Cv z*X87Nir<$&zpM3U5dtMYDhLJVwhkJde>EuyH!!|*qs!s={D)hAe_}=Nhhish`#N18 z7DK-@cZ2u5t>MAJ7Ny9%aAXDjlwp??Tur*6``!3@M3Rb^BR2KmqI(~DVBEIF2pBpg zUwe0b%u@i-dVe3HTlojq?O#3SW!}=mc%$Euq-drEp@}@NQX5WXESeT^e*3|QA*&W= z6~d2xg|vC@e`_IPd0VJI3a{;-_Hvp$b1PJG9{KK*tj3`ER^-yJ1(Ad;Ju-4@){;&~ zyNz1<85=low5HI)->Kafv^zQ2mt(AjM|YlB^6X5DAEUwP+x3IaPNb#r^qVOs(?1>) zbn1(t9Y!pfPd{m{H`(gW<8MpwHg72lKhOM2!Y9oGO7=mY4(RWMPnz2yOuNWY$9Sz?>T2~QK>B0V6x(N9pPfRX3?~i z0PM(5;1L^JmYlw0`PHO_U$*WuYf@PEmtQVLKpV$P!kcwA_H}}%%=`Ip@L~&-H9sv} zlyrQ-dOjko)INWw_Ap{|qGbg@VIRQY`N&9Pa>kA?l8=45GN4oZknrx)rYk~w56~3D z!(^s@g1wo-pvumBd2&pUiZ9n^|8h9%;L@d<-#70=WTXWVVZ1PVp`I@vH78nL08ZE| zLt8{e-i3qT=IuGSM`RR-Ms=SWr)oQ9lq#@Yk0JxZl^85^$t>T@t%G+=X=8l6Io{8k zw-o24pDg`j^Um*oT(!e0vt&8ShMFJQX=&U%0XR`vLEah{mz8{K<0710vPfhW2l{u6 z>lfO(^I&o4B_duf1?VC~qoFw2 zs@Z!Y^Vd@c&RtA6>Mg0r6{d)f=mXd1rEW6$6gOW0RZ-=;T0|JRxe4dDmGLLGX?Hvi zR_yI33GNdU*ea%@!bjB!^7fGxp3z|zQGnVa@>P%~LVL)Z<+sq6j6$F{( zJaZG%Q-e|yQz{EjrrIztFa`(sgt!6~Yi|1%a`XoT0ojZ}lNrNjb9xjc(B0U1_% zz5^97Xt*%oq$rQy4?0GKNfJ44uvxI)gC`h-NZ|&0-7(qS@?b!5r36oQ}zyZrNO3 zMO=Or+<~>+A&uN&E!^Sl+>xE!QC-|oJv`ApDhqC^EWD|@=#J`=d#Xzxs4ah}w&Jnc z$|q_opQ^2TrnVZ0o~wh<3t%W&flvYGe#$xqda2bR_R zvPYgMcHgjZ5nSA^lJr%;<&0do;O^tDDh~=pIxA#coaCY>&N%M2^tq^U%3DB@ynvKo}b?yu-bFc-u0JHzced$sg7S3zqI(2 z#Km{dPr7I=pQ5>FuK#)QwK?Y`E`B?nP+}U)I#c1+FM*1kNvWG|a(TpksZQ3B@sD~b zpQ2)*V*TdwjFOtHvV|;OsiDqHi=6%)o4b!)x$)%9pGTsE z-JL={-Ffv+T87W(Xpooq<`r*VzWQcgBN$$`u}f>-ZQI1BB8ykN*=e4rIsJx9>z}*o zo~|9I;xof literal 15150 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 diff --git a/packages/stream_chat_flutter/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/packages/stream_chat_flutter/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png index fc254c2599eae9c57035df9afa482e4a3fddf8c8..4d6372eebdb28e45604e46eeda8dd24651419bc0 100644 GIT binary patch literal 1443 zcmb`G{WsKk6vsdJTdFg%tJav9_E4vzrOaqkWF|A724Nly!y+?N9`YV6wZ}5(X(D_N(?!*n3`|_r0Hc?=PQw&*vnU?QTFY zB_MsH|!j$PP;I}?dppoE_gA(4uc!jV&0!l7_;&p2^pxNo>PEcNJv za5_RT$o2Mf!<+r?&EbHH6nMoTsDOa;mN(wv8RNsHpG)`^ymG-S5By8=l9iVXzN_eG%Xg2@Xeq76tTZ*dGh~Lo9vl;Zfs+W#BydUw zCkZ$o1LqWQO$FC9aKlLl*7x9^0q%0}$OMlp@Kk_jHXOjofdePND+j!A{q!8~Jn+s3 z?~~w@4?egS02}8NuulUA=L~QQfm;MzCGd)XhiftT;+zFO&JVyp2mBww?;QByS_1w! zrQlx%{^cMj0|Bo1FjwY@Q8?Hx0cIPF*@-ZRFpPc#bBw{5@tD(5%sClzIfl8WU~V#u zm5Q;_F!wa$BSpqhN>W@2De?TKWR*!ujY;Yylk_X5#~V!L*Gw~;$%4Q8~Mad z@`-kG?yb$a9cHIApZDVZ^U6Xkp<*4rU82O7%}0jjHlK{id@?-wpN*fCHXyXh(bLt* zPc}H-x0e4E&nQ>y%B-(EL=9}RyC%MyX=upHuFhAk&MLbsF0LP-q`XnH78@fT+pKPW zu72MW`|?8ht^tz$iC}ZwLp4tB;Q49K!QCF3@!iB1qOI=?w z7In!}F~ij(18UYUjnbmC!qKhPo%24?8U1x{7o(+?^Zu0Hx81|FuS?bJ0jgBhEMzf< zCgUq7r2OCB(`XkKcN-TL>u5y#dD6D!)5W?`O5)V^>jb)P)GBdy%t$uUMpf$SNV31$ zb||OojAbvMP?T@$h_ZiFLFVHDmbyMhJF|-_)HX3%m=CDI+ID$0^C>kzxprBW)hw(v zr!Gmda);ICoQyhV_oP5+C%?jcG8v+D@9f?Dk*!BxY}dazmrT@64UrP3hlslANK)bq z$67n83eh}OeW&SV@HG95P|bjfqJ7gw$e+`Hxo!4cx`jdK1bJ>YDSpGKLPZ^1cv$ek zIB?0S<#tX?SJCLWdMd{-ME?$hc7A$zBOdIJ)4!KcAwb=VMov)nK;9z>x~rfT1>dS+ zZ6#`2v@`jgbqq)P22H)Tx2CpmM^o1$B+xT6`(v%5xJ(?j#>Q$+rx_R|7TzDZe{J6q zG1*EcU%tE?!kO%^M;3aM6JN*LAKUVb^xz8-Pxo#jR5(-KBeLJvA@-gxNHx0M-ZJLl z;#JwQoh~9V?`UVo#}{6ka@II>++D@%KqGpMdlQ}?9E*wFcf5(#XQnP$Dk5~%iX^>f z%$y;?M0BLp{O3a(-4A?ewryHrrD%cx#Q^%KY1H zNre$ve+vceSLZcNY4U(RBX&)oZn*Py()h)XkE?PL$!bNb{N5FVI2Y%LKEm%yvpyTP z(1P?z~7YxD~Rf<(a@_y` literal 21173 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 Y0}D + + + diff --git a/packages/stream_chat_flutter/example/android/build.gradle b/packages/stream_chat_flutter/example/android/build.gradle index 8c57e18a..dc5cdbc9 100644 --- a/packages/stream_chat_flutter/example/android/build.gradle +++ b/packages/stream_chat_flutter/example/android/build.gradle @@ -6,9 +6,8 @@ buildscript { } dependencies { - classpath 'com.android.tools.build:gradle:3.6.2' + classpath 'com.android.tools.build:gradle:4.0.1' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" - classpath 'com.google.gms:google-services:4.3.2' } } diff --git a/packages/stream_chat_flutter/example/android/gradle.properties b/packages/stream_chat_flutter/example/android/gradle.properties index 38c8d454..a6738207 100644 --- a/packages/stream_chat_flutter/example/android/gradle.properties +++ b/packages/stream_chat_flutter/example/android/gradle.properties @@ -1,4 +1,4 @@ org.gradle.jvmargs=-Xmx1536M -android.enableR8=true android.useAndroidX=true android.enableJetifier=true +android.enableR8=true diff --git a/packages/stream_chat_flutter/example/android/gradle/wrapper/gradle-wrapper.properties b/packages/stream_chat_flutter/example/android/gradle/wrapper/gradle-wrapper.properties index 4a4c2043..493072b3 100644 --- a/packages/stream_chat_flutter/example/android/gradle/wrapper/gradle-wrapper.properties +++ b/packages/stream_chat_flutter/example/android/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Thu Oct 22 11:03:39 CEST 2020 +#Fri Jun 23 08:50:38 CEST 2017 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-6.1.1-all.zip diff --git a/packages/stream_chat_flutter/example/android/settings.gradle b/packages/stream_chat_flutter/example/android/settings.gradle index 5a2f14fb..44e62bcf 100644 --- a/packages/stream_chat_flutter/example/android/settings.gradle +++ b/packages/stream_chat_flutter/example/android/settings.gradle @@ -1,15 +1,11 @@ include ':app' -def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() +def localPropertiesFile = new File(rootProject.projectDir, "local.properties") +def properties = new Properties() -def plugins = new Properties() -def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') -if (pluginsFile.exists()) { - pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } -} +assert localPropertiesFile.exists() +localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) } -plugins.each { name, path -> - def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() - include ":$name" - project(":$name").projectDir = pluginDirectory -} +def flutterSdkPath = properties.getProperty("flutter.sdk") +assert flutterSdkPath != null, "flutter.sdk not set in local.properties" +apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle" diff --git a/packages/stream_chat_flutter/example/assets/android_icon.png b/packages/stream_chat_flutter/example/assets/android_icon.png deleted file mode 100644 index 3b85d6c36f7b5e617a7bca1c85d5c9b524890d5b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 15354 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 diff --git a/packages/stream_chat_flutter/example/assets/icon_arrow_right.svg b/packages/stream_chat_flutter/example/assets/icon_arrow_right.svg deleted file mode 100644 index 7cfa0c56..00000000 --- a/packages/stream_chat_flutter/example/assets/icon_arrow_right.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/packages/stream_chat_flutter/example/assets/ios_icon.png b/packages/stream_chat_flutter/example/assets/ios_icon.png deleted file mode 100644 index 314eb1db06c8771bc18c08234ab84940adfb033a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 40617 zcmeEt_aoK)`~M3?DM=aGIx2(|AtNKJvJxe`>@CS2hlY%-3dydJ9kMcx$~ef%p2wDT zj(v$*elXsOZBve7~iM0e|^@?8iz1pask zIzkOTkeq_gA&3XMrL3sum9#YK8*Mu0&%H%pN?pI?0=YK*36@T%cruweRd!b_oyw;lVjv|ra41>J6By!E&d zehzx}Sy6#ULFh=#A&N1`yu-ZmPylhN;TccEu}e6tH)h?hRxI__g}3P*9lnpZWHIz}LM1`TNkj&orbTrLa_)GQ{ zvI!K}r~?93MTj$>o={RibR7-Wb;V4*b(PwgSGO^5BR`cco{>RtUtb8|5+?~|i|Iu`&d>YSWC&JvS9!dZ?%et$$o zKDLhY&`@z&c`!|d8{~!{!}s9$hI)Ip3{FZamdRD@yZPj-45w}7X@8f-H<~kKEL4}F z3(gj9&wlY^AJVIlhQu<9BbOl7YNxCzA%$arKq?&j?xD$G&{SZ+Nzl%6S{{y}Px{6O zLEp{*LiX+bVn0*N=(eT6bMpLj4Gk~1Y{nrdkohC9II}47b4cFQOE1TMz3jsZ%F6jJ zLPNnVs0&bC18k7+2VZO93pox-7;FuY{fgU1T}Ox33hAJg9r$vT%+CCX#UXB^a>0Wuo}l&T4cpr$i$&00!olRipbXUmIxdVQcE8!c@ba(J;7bswtB zf-iU4NZJs%Tx;abx2mj7n5FH3^Stjp}pyDPxOYAT% zHN2dR7CW&ZqEkUlg#xHvGJ_ zO0e3uF%{n@lcV5_D)2$A+aELRZ!D=&9(+=9yM3t8%8G93WcFGVCBrOkChk< z=4uCuor;&P_$sacjm$>hm*ZYnYe6+a(eNAIIj%M$*04&h_+Pzj1Z|tvvSze2zVX@S zjF|&;GXccN?Qc)Ng;e9b{N@vptoIeh9nyZ z%7%S@bSOCN%VtFEbuN+f-nbuVnx`m^_+~5|n5X5sH zy!gFJf1x0vYPGqz38NX4xA^kCm@&zQ63PY~piU@3{;qQ0>J8a4hn%G%Pu=P5=8_m; z`MJ!jQbL>Y%BRSlm_S0Pja z>0$7Zx+4w@Vf!@~wjZ~EFURPgW@(Rx zQU_opinQBs04lfzhokkE1$+s{p_YX?9o>zF{w!2dEr{Q85ek%`m3fWZ0l#yMUji_rw$&j112 z`v1jR)Z3fGD^AW<;vP$wKoj~VtOY2Y;eI<^93-O{%V zpoB9-1we@!lr{(=VBAgUfthk&rAV2h*tSdKQ=|g`sDAV2%rzVnWNQs>w|zWZf)Rcy zf0&MxD1{>QuA=uap&5}hhXS=>3uzZw>N0rax*iahLyMcrpD;B0o=}$ax;O-KWhE4x zV&&+NS~v(A<>3z?T^(jl-Cbl4FH2v;aYMGM@Hf2Q>O!pj(2c=!3Hizj#>eEjc^a3O z5%!KiA0l7_-uXAgT=R^rBa^SO4{B;RRL890_#oR0umkGuDXH}AM!mZp94q+SqAC-y z=yev{oSZ@#Xq^s@=mr;_!Xe$QfqQK4goiKi0-Qc3`3~tqp&$k)&~&%vs-(72s8g{%q~J?E~>y{V5ys9aKI(|PDKS=GuZOFXU+59pn4AEg2JEwlmK>u zzLe81K2RlDmv2MRsZ1bb7=%kQgZ$$#Ba#3l=_b7F*=_vj^o6i@0&4jPett_GSZOb^ zDIUim;%hwANhl#NKGh}TTeSL$!~hQ<5osVRaN6i3*jxapB>X-ut=cNBN6262EKM|X z`HL*^SYKR?kk7w=G};pvUioVV^9s5=3|w$715gdW$Dkg(YT`@7(jN>5pnU!W4?U_Bj~*Vh~A5KFi?+uD%u@BZ51WR{$Us=&$+X} zn_6M*Uq%}Uj&no#%iQBD^zM zv?+lelvRen)a?6K(2=i>R1`&87x1gzZU0Z-4>C_^uye$nVXm*k z16XAJ6}yleC_8jSjIbEJ>}mjjTDf&YDg{Bn0q(GJWADn}-#SyAK6u^ZLUC-B1!>Mt z&_oq}u#%Tqf9dt8g$>&-%ETHwv^7`)NE06-8hb#hp@Sj-RY*HEdx9m#6DR2Vdtk-5rG3MS8ETc#FA1!i=mQ8ew)^rl z%fWkXz1P*kU=k69eSgundY}^|)}?vJ-Qr_`^zjcl?EiM$@fZr$R+f9b_EDY&vb_(C zZa8$1%@(a?3rou2PPrQ$H=idAf|SF^3dNz~wuO zGo#Xn4bv_DA`rEHHm(NU?TP98mOh`jPlAJR8do=L1Y`hiS8SasJPchu4Z=y-4rVpI zucmS_g?&8h2l%pGERo_62S*434j`NyV>vO+Fjd&QIn6mnROp@#gLGiaiXsGWzj@SW^{EV&*kTGt9rW8T8 z2NFgH-n~ll(s!4z9VuRJ31fr!;q;8t={1>6z5et9Xd5iX(6J_|)B=vDt1Z)GmSD#R4cY0x)Gd z;$VvwCRIauY)@5aP>+P7gDTFzH@m?^6U`8D-LxR#7>M*-gK=PV_MN(Bb?E|zeOOGJ zhijY>Nh2dOT1^>nH5IvQV_$z*l(0aX=Q*+vxa$L*sYOdycij#JCIA>s%NB+US`i5jWuNTD6!b~f8FxieD!K+_S35gXgao@AFG@$|g ze%6$we|&QI&X^kyU;uR2u?*0qc<@Dk+Bh#EaAW#g5Ap%jbB6gn_UofY=9@xEW|V*2 z($Y~%g9&Y?jzDs7;NI1Ap~U}|ZKd$(CX*Jyp|kSm7Qn-TFHc`XUG3D2DxB z3ODwxTn^&0`~8%*c$;L!JrOA9`-^jn1A|xl&ji|o2KVx(*$76sD*|NCXzN;Tx}6c| zUxQ9-ifx;fRqpPmM&iv{Cdm=Qe9d#~SpO@Y6@O-PS&OFr>VWzep}(7kIX1L^p{qHK zTHRA2u#i7vB?C|)Lv1c9V{Vs=nL1SaR?RJ8)r$CJdekBYU(M!?V~@etFnN#{RFIsS7^!4>N5lrx0;hqbZiR#C}pDTd^jik!pk_S&WUcyZ8D0@Ij!EHr6E3R0v| z4ylO*@L(jKVsUohZTK2i?~cVy{1R4a6Ti`36XRZea&V1Pr)s9=%cviLAhUWyGxJ=+1VAi)#mM~SA0{Eue6%bsB4^NgqkQ8nyLl*JfPF%OMkf*81{vp)by!O zQo`+1`Ww*pI3y@OXgOT>3O}A6Od?rj-D}~y+0aC@){V>J=0=;9WRf&mKzBVx_L%l> z60zqY<7;*5BaFh%kmjq1mv7`VdxRVPj4>Ro>^lTbFQ#fK~2s4iH=G zEv$EUV4}#@h0fV`1%H$qFx@n_OMJTQyQxvVmN^OKq=jK>Rh6f&(*Oaf_tbN;Rbux( z<1u~qM06+^kSdUr_4ptfcB7LhGhycO(n1QRUu<0?D$6 zI;x=%SrbA>UVA!17!9q!$21SD{c7IsYH#I6OCkUt3o|4O!c7lo_TzSjRV@UdQ&&AJ zU>yw>Z%WA1b_$F%oyPxAy}ho^6~K}K*C{t#NPN=+bAl|%bU$9|THRz#{-{)0_Q5q9 zbJNo<3P-If^Md>^Mw^~LQu-Hkr$so>gX;um56^d#PSZZhOSj@X>)@f{YM( zNtxyhN<6Gf4b$i7QvRdK*bVXWPuyP0Eidfxt64K-IN)$zyfuH#4H;T8kctGboGaB<$Vcyug4@FTRnFIkxEO<~`} zRkkT(hx)$bFW7BYb1u?NCyKx*(pRZ{H2UOW13)@BW68n;)AnCgJLu3zxABO z8ON5sLThC7qO9&gem(!uNG?6{9KO)8j8Bd9+l+}zOupez`7Vf{=9!0j%!Aw>QT3!= zYfGsr>s5zl%-I;BqZQVg;*xVY_Hwz`wmVSw<;Sch+)?6X!LYONYqb}rZ{y>xT#qdh1I^&zpT#^T2xSWs$TgcuAa&8zT(X)C zHfl0*M$)#p3fQ2{HoDvdJz$iuSHjg33X{TSJbS^hrqa7to9MM0{iC!Sd9{6Xelq>L z3!vSA9KtJV=wp04^N#?vl)b`EI5?rs?6^|ti!bXPJDv+5Q zMu+)80#zqXj(hpX4+r5v=S`X{y!LSDPuFf&x>;?BxFiEHZ#sAD8$oN4Hc(r_rlOXt z8T&`V5AL;7YC_+~1QCvNUFXYBV0X?JY3APxu(1|^E;_TEp{0W&bnxmF9^w*Fh%9$ zZAPdV9mWp7JA+m);WOLphxtD_|FRn+#N;tLv{18jbA7sJKIFL?6HWH^W04poD~u1F zc0TUT^z*6MiY!Jb6-hr=L&NUl59*8}d&HVXK{qU|L+BL4|P-Qhbr%@NAE5)p-I8%As?HE^0yfZKQ2~H~xY70nuD|vZkHs%J! z%8s`=`KgirGHTQ8h#qiOmxGqKi_F(MSie>TxQu&sXK|MP)f>N}Qe@<#^_Dw$7_XEDUT?8V!{sN8{2-13YfVu|oeifIxm$o$b>gK!-hj9Wd z6bO1Wmb}W@eCFHn>uroDcg~28J#Aok$v+%zZeqcY_#ISwkb6d?Ga@$V@T+QT*qSS- zm)Z>z-N3W9pa2%fcEl4$PTI}?wsd{G{9#vp=_eg`98KE;4!zamn;}3G16tCEQL~FW z6BO@-^u$Kw4+C%**?Jy|uA*=F_(nZYT}o+8!Su7#x;Cl28z_hTL<7w!`1PRkU02nP z1+Tv)nySx1NJbjhyAT2xN)s_*)pHLm1yhK&uASHKo9PbisS>R!K2N5}T^nLCx_I?k zScunnD4ut5KzGnZoDqt*Cf%&LOkOQmSc>n)^T9%QS2SJqB`Y3sR|NL>w2I+%ZPe2X zpf)_9zN1JRNDFFAy(Fo3zBrW~@#LtKyYys6e@A^xd3$53yf_p7x?D-akC!t)Hja@t zT1h|Mx+KVHy>{m%V6jvTZ;TsQL`3<5m5bzMOh5o}s6+ATqFh6R*(C?2^n z@{(%j7x!pUKtloA_k^m`-{kk?SluE*!LF*Or|eT{()L6%sGql}yknTP%hoDegkzN` z?nuExYK=?1f0X`WgNd@7RJ`y+~p#sw~oa4XYWo>QVY^z@%0Olr5- zEsDq91x7|d%B)K7&tC$=oyDpiJj%^Lt;6J6G;(@Ads}-?E+o`GpZZix$1QN6+wrs6 zAbx(s{Q7^ zT=$>a`&*ffgY%TAtZXRGPM!lX5gAYN%Pa!9Q(~#>KXr+L0W@~|V$|C+1d-u9sNyc* zeEv@Xk8}Ae&d6ZbkVj_80<)`oyCn&Y;0hWw(6+%~$1#SOKivn740|!VPwpM)>MYI{ zi~)Uc`D1ct5Qz9U$Za*1Q>}A%KS5vK?{Yz}CTApiBg!qgLYx5N&)}*nkm=kOWMk zdU*Cb;>~>z4%yRy$C=w968~l@Q`}L6#n${0lPx#!*nKdgx*d@Jk@DeefkR(WNqYZ1 z< zrMPuIM~mW)&bn$CS~^u^Z}2QabgJ2xUKQ57HFfo%-)a9R(5Cn6D}Nqb`;-hcHp0jT zISja~=Z{+!1pkHhaF~qc-ubR)= z_osn%BwSMA!KT+)co?(ijX?Z~b{qwxmN`=q{!|5u%fA1N80bm$cV!r|Ro8mu!*g8( z$U7~+??UGuwtuCgQ2ET}?KlTZ%H?9KS>U7vJG`3~p4`Jyy`2u15Te7Ca}&*IUsLf- zc?#OVLmD_^f?)aJx0}j_GT!*w_YM{x!Jy&2zuT*DbQNA=<3o7JZ|gBHyd!}44+il^ z4l4jQF9g&x%bbrP-yHvuS5vdvG$`&w{@X6NvoIv&_fQ95rBVTTx&iC`qZ{4DsaHT+ zBmrR?l+nn&Jr3HyC;J1hNHtJel?rP@&>A-5G5}F)=5Y=;7@^S0-8e9<5s4?}F)&pA zJ)qGuGt&rus70)1qyUT?l?qYdshQfQec6H184U~ zul=M7Ksc4;0a&Qk#~|%MpRf>I$QVOk&C<$2$B)pAt15$KsD4-Fctwg%S-__{%6!L< zX5m6^u3Pq}16t?RhZ%SQh`+#oezJxkb^{5gJUQp>wZo8W+Xo;e6}}^C*oP8ku-RUlPFA64jnA;2SA4dM zNxp*#YMVRIo7i?MLvGdsKz~Q%{iXpANxkuB*%v=T<0FF&{w@viwRZA>9jy~nHj^px zsjtm;_sBMcHu6F(y2|WznLDn51z8w^TzRE(+}{O(^|uto`ud5&t>3k^zCo|~O)=M& z>~KVCf*}U%Pc-=px&mpfE&E{90@_zPqN8%oJ5Z=e-L>?SF`zf7ZQ`4X;!b&u@n3nG zx5LdhSx)*AlB=erGFBoVFfU1VBD9GRc}R&eO;Z!8Ll#r!Z$~$DTNgvD5}BYRm}A58 z63$hI+00Q3#qB!P7mD^Ziv(tb2fIKVf|oF=@wQ-HM0L!ce+?VY3n~$qoGy~dJ||R{ zXUiwywj8w{6~3J>e{qtzA?RFE*~Do;ORjFaK!+99_ZJI*Oyq!Z{yWF}$B{Ml^%)tD z3uWY9J$ML<9W&)d)05Y`U8mv@q%p}b&{50UmshiZ1{-dr4d%vREdUHFcK38~U1;B^ z-c5omIKWgq=?608uo-LAuO|ORWOlPYS*V~kgD}U_rbtoe4G+w5V@6wIIp^2sv^5*R zTxt~^hYP8mn{(Y1-Xt;sy~CyKn$v3I?&=)?ycHgr#EkDwUjh(H04!@{|9Xpq8s2*G zgsJy>-u&Y~cXtj1TrB@bY8~im`93m6HP(4L)(WDR-8 z!2uI`)DZM8(U+@?s|ZYF+FbtWG80dGS;mPDQ|-*- z$5KS$^{3J&IME728Wf#u|Cwj*+}FJ% zmw!1LrKc{@i_rnI2+-ZJ0=?tslOF0!2`?c)y+~qFvmmoruCaYxg%32TkK>2&0A#KO z_AxQaG$D1J&P<2nrj+*qd9@Jx$eIS(f{FJ2^hSP6ytlJM{e%2H4zyWV#;48HD?qRW z0gsmUY%*#28a$`(%pT=8{(|VfeV7)K>ne?;PAVGNC5C>XA9FX=?t>>;C>XSBh1K(8siAOj z1D$N#z$%zs`+bB%xM;Ho5>w>fs2Y;>TN?ERV*AjReNlQmZ? znR_|O6tS{DQw6%L8KP5&k*4?7KRZZSV56h+!@)9&_=cOhI878AI^M}g300OpIf5CR zn;eePX#CuJspL)dTp%xbTLajqdvh@it&bDgGl@9%)Hm*kGB-kSkHWuX%;%wWqL z_I&pCK?8}MVFkoZbNSO;iXz~qyMv`qGHKT2hoqR`<_j+;$|{NUL`V=?yFpJT@)7vk zzC0<9ep(+}z@0E$SqM5Cg<8hBtZh73gyT-+_Rr<1)m<5IS?d72q8e!xEJ*nkfJzL& z>e609oNOw05Owvc4MB~jkssU%p zh1KV^NOJj-QU1hyjVC;yZOJwG2-!M;3_x99Ccj(2RQV>Yf$m7;U^pK&u@);QTkhrH4O zx=@0_Z|+rmPOR{t9_E`U?mF{eSn}%2;U-Sj(R088@i!>yR1(FEmHT%520N}v#jB;H zgrWS^7zV>^KrrZRx}&Ca7G?CdmU~tX_}%{Kelh9PVFmGn9TCa0`+prbur8VaSaK|y z4S%a;ZiCLOGEu96n`GdQZM_Hxg)x|&vpD(qPZo~M+SXaOPIdU7EG7MdH`x5fEq`+t zDW@?Rmt+EoAg0(QHFyqGM9{}h9r^eMD*(RfKa(qc_cATi!K8N$pWUpfy^7k6n;fZ? z@SSp?Pma8zOGp%rBuw2EfGW;yexjgncrNdH^`Y48{|9zaNoI(Lyq{;?4yIZ{dvOUd zV1a;Xz54aL8x(hh@A+wcqf7lNVEfjvIJ;I~bIel~UYQJ+*l^grwieZz4voKo+Y-Qs zt>o9I-PTw-G#U!Wbd<}Ucuo^tnvB&CeP|@a?540q-TRwZGjGXR<# z-MS!A9)LvHKUah6_*xL&JUxO+U96_eQ~j{n*Xo{lZHhaZ2g6rDb>foqEVA};z~J;>W;>qrS^ZDxT}L-^x4lY)jfe z`y7`uK0uVA0*t5i-z6r0-J+*YeZt6z@SG|@I7Wa3i{~&2L$0GpW|P|FRC}REZTicr zF0WcMq48pv^PY}c&TCAQs+yNq1vA{Wd%lyixcjK1tkZ(ElzI_lsWkhl+;@wMU^&6*p~Uk{$qfhgi$IIL zT-<(umX_kCqjF+E>tID~`EF)J!xJ${a+Li$uzTTeJ?yH&2pPxxhfP0Hf_<+7l#1PV z6(BD`ID-h@HX|#E4^4KoiwDbi&+k?G2(iip=Ou+b4K*|K7 zKD?kz8_Eo?-|x}HE{XlKv~^AN+mCkbRorzpK&0TTo!a!wAvUNg*DvCdBCN_IK)HDW zF99#l?lJ^><5P-}--4&HU_}OBZ9ginuS`+LR5>9CHXd;e#bF$D+cNYik$?z-eF|jP z2Qg!_h3I@QiGa;W1lOp}atk3lzP;XsqzIhL3Esfv=E&jI(5^kYeEq>z)9}hjjlU@1 zF>x_h89*ra#-HL0sS^D5?r(w9rcLvWjyHl&0+diBPu@kZD+vOmSCPq~@Pe^-|FM{S zAE}|>g}vn@WYi*{b5R3dEn8D{;#?bmF^galrq3N(NJ?YF+?=ivK~CR{ou7Bpr|U&_ z=t;Ehw2pGaOSd340fPzwo4Ras>U!|J*?GO-U#V?T<#RJX^ylkCfB&PVv60g?|F_hL z^fzjLsY_S~q}OcI+;2I(+x71QafzzEyrk4g3MQeNe*zMAQNvgN4UQFB_SYNric zLJsAccAhd7_d$Gr?~KSGAq(gW(_qV7{;<;x+Q6s3xw8wM3R>i385kr-qyfz|YMBlH z3P@#tzA)HX_!pc7*H3I2coUOLV4p9FG5JO{0t`rfz$VO@@8aRL?wPwf(*q9?aK7Cr zI<^}W3cq@2WI*%t+VLhAp?MGJn!CSU5OI#u(REIoMUpwj>?mPME}0ip)AoGaLl?lO`)_7IcseW?RXx1z?PNAMLh9#`Wi1B2nwGR{}9cB9RHiDpHxJi@F; z{br8(Auc5LIoSS;1Pe((7qlRSoTu!D`)<%DL@no-p4D5FH@`ek&j`&|TEi>b?ZE-F zU@rsK%UsXb&C+A8fDQq)0KK5=->;$;ncK*m-MpUU*aQZ!8FcS^_Z?b@%^oxbvj zTw>kjxZN&IB=s`JAE{oO9fW6M)1&g?VB)c^e#m+I_72{HbziN3S8MO#+zK}%yaimI z&<0*DrDKX6cKF<9M)tkCRVv*2MiYomQj)EY8``(c5$wArON?aglBeHH-#O-^FC;_~ zEG~e+saWj4XVcUR_q~f=6U81ENT1JB%I9<%wrRJR$%-+deAN6+?15tWThlSL?x!33 ziF-2*Q$G(x1FIFxG$Uk}!!7Ou=59c-DG}LMJA99x_siY;8-Iib5ED+%dtWt3UYBgb z$XRv(zsyV`tghf?m(cRo!IXilKsr<#9x87Q@Q{FuAf^J?UoGy)Mm5`@CX%WA+*jrC zKAg6)(~2!TdzD);70TOg4BA|;L~@xC1H>gbzF*#tPO^;Y4Z}c69uxHr;a^n~efC1X z!b1+W06q16eszIindAsuQO=jVzKocpCv931cKgAaw`uif0aB_p_F!9_Y)IG4j!TJf zY|!FczRb%A{SMiE__wqo|Arcsg!x7DJzJvDq)!$3E*Km(<}-0zHhr%@Cd;mbNdz)M zHvl4^fKY`&ye+RVkWg{Rth*v(-3f9Z1Tzvi@---;%Np1heY=1jG9NrfWi<)BZAh+3-x8LuGVK@XDgWoZITM+69Z^A>{5^xGO+!k zktlgrp4JKfz&$b?1Q5KSXCF$u`CnXIUa8-k1TT`w3-9$iKLA`9>~vn9I_QEbMKNHv z%PiEvX2R-P!+A<%mEG%KCERA7*N~~{@H4(*URyy}467|^|FqqCH zTBk6H@6k2KuE;zKLg?~rf1*o4i4vQ zQPefvbIrVa&_!vkOFjZ~EqDqs<|_mf$z$bF`qt!69W9QUtK_RYb-t^qL=SQ6_tI-o zgP);?ePH1gY{Weo>=+21F5?E8^J^rFpPv_pprFSOx11!UkbG7fQ=Jf~@srPWWpG_r;o#c+O z8fty-WbcnS7Xydz@Jd>fkw!7DtYxjcquh=D()W_JGQ0fMhkVs<964(z_BtZsitG19 z4$n8Pe#^I3GTurNgRW6$wI^j`>!ZOwPUQSRf|&R{i%XP8FCTe;q{kiLfFR08V_Ubcg6D;EpKTI&n1|ONf1}Haiw#&q&J>O>LB#YXGh`lY)#bA`Fr-U z&(PPM+R~LXIr>E1!|NE{k!wbc4oUB->a6wgSgy!gPBetRilHgLfECj!)QMI>HR&>Q zwQScPyMn$WqDC)VM-7dt`$TlVh^n^hV7rfzpp5b7$UW`%(9S2q?aRmGn>Q@En=Is{ zI&m|pO-04l5CWGJ$3WgQFva?1S$%a{GHh@=S($aVSX+VFRAH!$g0L#dBtd+9vWmX3 zXzmV2s`!}d?=w!*0$M+`R)2{&^61iz3*|Cg-@_UR}brg%G?7wDo z>TYh5K#n>Yc&XwWtLM71~4w^myA2z%;2 zUnvxBNy>$7cY4T#3Cu0eGfjOjhfh5nMZ>^9{|t?SSSv&ISX3F4i6vBhBOSRNy#MY3 zT#=P3tmS@%b{MZ!3J34OixtH-e>C5U#V1#F>#}%z`dIe}a3wR4)uVr`^Oq1hM~%vp z<5|gbNcLyPCC+%S6c}Yn9s_5NzZ-OS=IRkz5$U&wq_TLP&#h+6F{OBW9w}|(tw;z= zNf>zizJK`*vm+GE+}<0QKd_g5U7zX$A#kZln9|CH{)Q#zOQD4%ulEVKIgh!OJc&{A ztpYwBm$sWCATTdAx`^&XsAx`PAw`cE4AiETXR~&#GLYp$l61XB{xFbd3mBH97@KCf z>CWEyLlDDv>-otqsm7;c$_uKKK`wXx07R(u}U+4s6e^)m33izO%oG4@$kU zQ?DgVQx8M#`OSlp>dheJ+j-*PV{9SfOiA;py@C!ojXXgXF=>wL4=cDPvmOE3duejGhP(67(Fi zEgA6Cp8b3)D1$wDo`Kad2%XcQUz@Sg6Gda=c*O64%<&js>#pH@A);F|2X}|ckP}Kc2{F0(2r%FRq@QT5d(DfIm{ zQ}>AzPa7>3^DFbspHQYte73EYNjw!!2YnD>=S!wczmI-1pj;&5nr2qPjlk!L1AMy9 z>$TAIe7mLmotv#$7w#-?e^K#d`>_8gMg-;cICtF}lW?kH_Ua)Cjvp3Pj3f+s-qD-R zvAUUB)($w*ZqAs_iy9^8+%#-sup)Ke=cy~IL}mPfvZ5GeMopg!!*&Hp0vsfyni~CB zKJJ}B$ViFT{M;DwT2jh9eS;-82-w=j4(XVNwt@hcr+g=|kF}5@p;EeLhiz6zYR`Ua zchwl~A*}tq3}5niiks^0ul}!jBkf9i)y~yt$2E>@++a4@T3SCl_>vA1{n0WjO{jA$-0yV5p$kN;BkY-l*ct{n*p(9(LsiJrACa(rc|c>shWY7mgd#+d)LAP5VzrrU2AP&qMYy; zMZPs@9@BPFq&AAVpHFtv{G4rc$bPkyg(=c_WlK@rv?E2yHDpArPa@6M8UO%$QsN!0 z2}!vS2`!ML+I4LerQ19K#n;Zlo}`!ddVJ}Rnz$Djgo8k`;IG2CqF-qx6nLKzsCD< z8szlr=_Mt{Z<8se&`IwsKTq6ZJ#!G+9fa2dL#aTeO~1r)L7HJS#iwHKgPRoHce)?_gL)KMWpc}Z_=qyr zt^)?N5kz$Lp&L#&1-i*%eAfpcp7M-$0^lDC05s2~V^HhH5jVs`%P6;}P4MZV>p6LaAOJ8-F{D}l4 zTk#44q{w0igh1dPfh)$DPF0JKks>+gDA1G4LKDM-p{c^EoS;t)tK1ze762vt?6GzQW={)o{MPB1AKBDbwDXbpx-goLFSAMYE zWezGtYEPs_ePzAe&xqrCA%vZ*y=zVtc*?r^tl0*Y4BMLXXJDs;dh`7Frnz_%Arwso zUZ?%QwBY0s&%Y!i-0d;qG_&Q`mli={XE2D9{P&`NNH{aRS2~E^pVFx*B8s|26bhl! z9G$~2`soK;6>vA)=7;!6%VJkR2t~)R-<)9zP@X;utj}ku%4Au=ouEB*CE#yXE(Oa) zUTM2<1yd>jAcV!{;qS<&sx!U#sgvGx52{qi9pS$L?>Rp-ButAaq$sS#p)S-V|0D}h zW{hC8mB;F-A#YW~(r3rZ2HeCSIw#`_sExmDu)Snr8bMr^B0n)dgP3FN(_0|#L`w}o zX_gOkvw5CqO@5jpJ$NNkSiHiA@CC7$G6?`q3tti_IA3#xHbxgW49@k;=upx|lj`bA zlj5x4a$1MTfXcd;H@~11_ z*o<*L6Z&5NYnZvN!|2d$495#0dr)UPh*?(;vqSH0Cg|843lw4v1Z1RW0y(*pI^@ki zzDP3}{lhJKB3IVpWk}vna5*jDcV^E=O=D+AJ7@~dWlTx~HoG^sVC7kM#5fpT@avNd zQ-F65sjDZlwyWs$mneXgKi8hrrmq413J0K#iNW`-!Qk`95?6Y0`~*^1vJ1&=HmPdMbX*=b29HxiP z;?@iVG6vv0$f6{n)wAGRgjsc7_QukR_Rz$*(MI9!_9gug)AcEcLY%aJ4ovVfH6*VQ zT%|9J_Hc|*)?UJo*d?iHi!lC>!?l$rr_Uuyaa#PLcjbDy622oSgg*wheaq{MXf&Pdx6#O4 zid3(&)U4ls-VmlBd{==P20wY?WciWpBY=*Yc}8rrls*JS_mWwO?~{eCBP(sGCloEY zUkQb}I-NscK;4jSt7QAi!KQ= zsRS@*aAymL3GuOdCFR;*;HG0AVB+%?YeTF5XH=dx#^hD0(FU@hY>GL^6#ej+<*nn3 z6)JUX0P!6g6VtlY2#Hmy#>DpbaqYREwii4ZEgzk>>^d(rinilNtO2@*rd5}`c<6@k z_tY!K&0C(--r^76w0%<axK01N+=Hr21{UH~)F62URcIv=9jRrGR#hdiBNSQb?N2^aiqNj3PQI3?4IQxa`=3 z*Zpas05}^Rvp9kn*8wN303>KdJT-DVHR!m>kA>S@OKQqjSwU@!=(#vYPb!QWUY(88 zr&@?*a4(BTqa%uhDOpy>a7))5%*$R!QmRx{s?_BUKr7|Vyd=>9N&tj1c)Ik`CM*NF zwO_R;!1s9Z7ps;K`F>%<$0}gt`vwN-Jjdkvi9(aNlX5B8iy~uiJuA&URh@jiduBx z1rdpMct3!s!)17b!$gG&WIUEv#u`L!v#*GqMXXT*yGYNAw==mEE|*U!@}G2``&AxP zp^`=~IuNXoJ;_Y*{42%7@+wurvGz%+$nDb%U9tc`?i*IAfCy64N8vHQJvO5NdH?m{ zHZfJO?RTNkp%WZjjgqF|*|*@?tZ(*nHay|JJjGE{6Im92%f@lTjuRm$Nh?)OP(g8u zJ`w9g&HN`PGK>ww%)#Vyx0;Fed6YEo(j~Kn*weD^l|YrSQFhXU}a};K?GBh#1Y>2%> zmO95Mt@@*PxoKATkohYEmtN+OeUC87v;EBEZZDWrQ~E+ERNBssXCiGU(jwRTX|u_$ zP*AZ$w2JV_L3g-_u8Am68=VD2H+Ywaw?F3YEMYI>{;1uluZju*pxhY<^5*a;)f_=x z`LgHT7%ThjIyGzMk8*A<*M8=pn|!A756QoL)iC@wTwXgd@H;lW5p`y`3EI_ar`xBm z49w;-kYA-nN_8tYm~gC0D$i~p0pPF5Eb++wDb!28{DKpA;t?jRd?lRs zmo4@-$y0)v2BtQxpMH5cAvvnX+&)k{l%G&wmQb8ddd6=XEL44j_4_l0Y_VHk3l_92 z6!11$?~Vfm?d`iK5JFIOIH7vVJL~Jm8|1m$>u*iPJd{+vupqLy%to?T9_153AaHRu z0=!oC;4D9K?kGDn_RjRvN?oQ5FDYs%WI{Q2R0ZkKal`}5{_M9r9jl`vZQ@JA2$nsE z^4Ct1NAWT*1F(ak2o$jI_B^@bB{7xGqVtp5SQ6^$v!PiAxC^c&U4Q95OwChlpWLX> zbslEpu_Xcu9)L>amD`tq4)rf7aq9NMuqw|JZQfXYDxW_+AWzRepVQfrC_fVI3vwb7 z2pZmVUx9vr*-PMTTNo6zs+aeR;3cu4kaoROE?b4#7q{5=yV+5h7iJtqD4pvm>+z~9 zxkHbZMkHSp`l%~AUR!b$;K!<_^+>q{>IzsM18KzqU{4^iV1cwZdD~+N6i4hV)!Qc5 za0u9fk{zJLFCYO4|4$+CoVZcl!2V_yk5z5*3);VY93z47I|0%l$qK0 zqLcCxGwW-6TiQF1>&;SE%L!T~^R&tVr!9XN=n+C(0B3l>v8_4!fY`{iMf870zL;>oh+X8>q4YpsTg)?hUMwR6YA-0l17 zgi4jP>3l`>xHllF6zou_xSVs%(@)(m)<;8-TdwFyE+N6W5M(jRO~48WQ~RaJe_9!)i4zJvn=$zvi#l9T4@ye7%Ok%Q0P1qr8igslizuQi zFh#wwo~i`y;f%ZlM3w%v$-@5nVNwxpZ%^tHGDAnk^`P@~ zpj9!N(x;MJ$3|mO6a~u6CJMI`NFA{o6U;#}Mu!NyJPp)=zL}BRl8V#4Q%u~ijoj+Z z3V}KxE;~RSgJdhjmXl@X@Sw29Na8dO=Y1K+ahzucZ*|DN*FOAfjNOCrrl{A6T!}@p z@hy3I5dHqXC(VD^M5`p9Haf&Ll0&w61CUFIgl~-EB?0Yp1$`oNd+}Sr?X!1sc-Gif z{+3)xvMt?{Y5JYCUoxG}wTDfQD$ncQr;RK4ey~6$fwfE-#PsbgPb zrWi``*|uz8%OrpSFMPRI*zF>3IT|ekzD!_n{D2oEJhy-2N%h!UqBxac4c(3!kCTN? z=sD9O+AG3}@Q;PMrB@ppMvA5q@koB%wi{z`B)X$yDs|AQpS@m3+=XC523Y5{JA32?!1Uxc8yTTe%oT@ zA8oO&w(6ZM6Q7tC2n4^@CAp+-ENgMIx$|4>fPe7QXtf@p>)T~}B8?I%EOz8FNarhy zz9m8E`2g-JZIAUpYcaP1Hf4uF4_6F0Q6dy;gz1;*ryGn-_ZwEd61bVrpQXQny z+KIiDkkl(w#Z<)?XBY@*fNdk@zge`;1&E9%u06`Hx4=HV1XJ^*v7g$?UDBAJe8n6+ zVUO@n_i?XZ1vcvDA77lL&_chyJK*`b5{@OWzXbV5L zL;tsccVcG>Hw`D%J^aYvYi74-e-DO2bj3Hd zV%x>_TZX2|kC|F&fDZBt>H-#o{YTJhJ?j)#! zi!`to2Q^PE)-%2rrHUqT$;k5PpdKqn2A$zLTw; zkF%(T>px6AsO|OT|HF-*cjR%+gS?5i)AHSqRLZ?LPjhpP=2{f4MBp#GcABs$NoK$1*;qd*y04$t$<=s}@6oU}Y;iLgQ z1~tGS+El>mQa^PQa)(p`G+u8wq4<+#cE4`XCsaegHizZbmq5-C5qZos4^iq+DEL|f z{s-q@3Wk=kZz>q49+o+Ida!55=XKy(CiVz`{$5G??&LDPGF8}rO#`!ym(@n^B?P`J zvUn%A`rRuCvXCg;N%vv34K@N-v zx*Fe--&pN`X0%g`3>}gbV$t6J*@0x=m@m z!S_pVrtUrj%p)t)Ze^nT4-L); zOvrDM^<~K`HYIgLSgAbGAPd>*hUsA?Y!1}|HG~88y~k`rzuA1Auh~WQ?RE+k`eo2?x$Gg5+9Hf2W1A6 z&o#5-@HZ@@Z+Bi_k5_xID-h(OoIQ;Qg`Ca(GN7R)4tg))k0zw}U&l+Ab)Z-(&WU#J z`5|Xs9L-BGV5{b`ln-1KRtez$Au zY`g{=tWb>MvD4WHwUVVBw#Ips#3KzUCw4vAYr#zr%6W0}2)58IG+nxr7P474P+N{{L= zwGu5gssYc6*|SCxP3DN-_z9=;A+-E*=oQvtEz41}QiYIv;N`d03?^HZM_GJhJ!YHS zzw;IoI#pfS6u^N)XL;|Gc32zd0jekKdIpYUcrTb9n*&domf)lqV&G`AQZBvt7Tr(J zqpQi?H2!-HYK&1{{CRtV3NDZflSiF(;TE+Nvv?;wfwAc==pE<$&Ob4}7QPnFqExARRJa}T5_eG1;6k#+XLfIUQELF&&l zXKB@fT|QIA2mbiqnBsJK;ZS-@YULgcjNsPDNQh$S=kmcIv(cU)rJ z`q3ghC3E3+_nu|aOb12S)ZN@4B11=& zn>Xs?n06*8`WKD081K>fH^#F~Ll)f;Rx!mke`NUUQ0~Q#@e=}ya)-C5 zMAGk(C=qZRSMxkWZ#QHeE81YZZWR|D8aOa~!Yh)j*k1xk)#O0%Z|mO)rB;xp1T?5B z=V}EgMv~hTUoAeE&fXjSEQd@oAgU+DgiJn&N_e{PC4dDZ6b^8(vU~RXEL*_t1n*?} zUeKv@v8%yzf+TfTIAWlFzDXzeWq?G8YI^M!cp1`zQhdnC+rJw{ldnh>>kZx;#Hk?9 z7&BpEw-SUV1!pDezQLe;TYCjl*~5E<^@75RWJ~?;@mC>lZEXA$wN;qh6$)UuD4+(n zkXPZ4epbHn`%~9er)csUvOpwr(opzmT}XwaE`#?K!Z*e%-V>VHaqjwV(NHKWq!6LP zsWj;PkN+9PFlb3Yy*SmB9wE!;J9lmoqP?5W=0O{_BeG!xzOxl!(ehP%}i)3 zZ|=2xYC!|A)!Vo)YX#nJ$ZW5mmOiY2%!64DK+Kt4z%lpxs1L>FT6}3!49P3nSP!X) zwQigoh1h?NLeO*dSF8=HF2#%dofNSbhV^2-0!Jk$6bEq z>+Z{C(KB)KV&kk)Mg{=tiQkQs6bH-yxG4-fYz@U>X>)qS=_Am<)%x)GHtM*u;f9 zrT8sjpR9An9-JOh0)BH+Qn>V!VMulf($n+!iGr_l`G{Ryl8Dy#Sp!V z!kvE75mLTGMP!mxv5)up~NohDoKkm9^){ zO#B4E;&5I5i|xq%?nnXw8hQa);BcJRJ;-BRY95;@stqPXnR!Q&LztSW#SD`=Egg`&0`AIX<3GlS{7DvebJy*msr_6`qEo=Dp6e zn22PgQuqXymWQQp{3`MQs@DuUk$D;{){tU}+Lm zjz>^oK6sB+Q!a&6U5G7b>ROekdGL{-tl3QN-ZPioM-egiOF$9d5ll1lw{Sm*5ur69 zv;nH!^+HbsfAf}TS+dsY&@65cs1tm6x@BwLyTH%`6lj!A81z)MK8!A2H^6E>bJQyi zO7)AxZ^8c|I1E3#wnBSi+Yd}E)$J(|!C&q}?*Ps1*Ep{hWWCT`0@=y!RGKH`U!gSH zK$scO_o#arZ=h(d|9t8F5xZVWDiBJjPhjl$%}d&e)`~Ar9@%m5*l=PE8*5!#&qzLy zmIccZWJ2UVx>Rj$bcK04E!g1wp10kyMWL89eZhH3-Hy`@|}+yaCQ#>HUA1(Z^{YawoLH7>VN~P z^W8y>TGR1dM6V$?c>wYj?fijJ)k0ul#Z;su;|ygQ%Qz4UNbEVsg)uC{*yRL%mANcF z#cr~y1l4q9vH|a-0CXdDzUdSFnPIQzL?l;&%8dOcjsqH3&huFZFdl>r{vHX&GanYF z-sfUbEMbtQ`1E&3G6JXqsM8$@2U0Kg)<%VW>yMYZ)3~@e=~|ryJpgh?;?KXt>CHjk zPO!>q?)2`}^}(bAW#N(JPY-Va1>~}vRz+Mz;dcUzU<|#s_2MAI%U#g-=dz67wK0-) zs15r6w4P)VgdRYg_}#KRXlL((G`1s=&*vTxc$HU^O2a|BBF{s!4-+qP83;pXpX_Wd zs3RAX0P?WnfI1|wC4C{%$BPshPPPLce)@f$D+xU?lqFz-5V!YI%Vr{g*PY|hl8pEC z`?LjnoaV6%(8H-tEBrz+lnZ4>2lYyG_?yk8Kx#pAC=!~q>GoqFD-`BVm-}p!{c7KP zESvD6<0L;Z8`@-fh&U(0Hrw|#S7ex64D9u-wRe^gim;-ve|n`nzQjau58djpt%7wDGXjK~FJ|9M9e?mm~=O z{^^&S%nLXJA)7+=y1;{phCF?f#r!wyt#$YA5yPLvxS71TSG39YcfYzg{e14%Hn}(FK9I(#3oZe{X z(v_-gXcs&KIDMFEMeit6l`Selj|`BeV(-RFrlxANO&?jWU=FPk+$2iE0bpsjb`zyU zelaCl8^))G0?wKmwitJ)uD_iY?a;y$1-7l?_wiz&kcGi#YQx{6Vci$)s#wJ zB5rZaB_jhGVU+D^f@u`;O9p9Ez{H=wreosdLH&`?+j27nM~0jYphP_?*ps!KYK`SW zhfuMdTV?D`qgXH6jpiDN;+P>pewtQx?Vv{u{%@mprky6qSa=`~;GQaxnO_wPHtQ_& zpx-Ux*~-jRuMn`p-1+miB15?7mFwnr!clZ3oVY>J*acwP8H^iB!n7a>o2~A$f`InV zNM+WGcvn%M1(yi2&o8SFGb{lvg+NTW|5mVVyOfGgzI8fK$Fo!B(P$Apl+{9y=~Kp7 z6s0AEPgwu+rZ~%o&vP%3jgaFg+#K#=I-|3~i`cpm(v;K^!&uXOjTh}DxZZWbR8lol zRqub>Si7BHt{d>okoG=$4HZ2~_gm6E^({Jg(FGFUvEa7FG7HJ0iTo{~(5z&~rUFZ7 z<4sO?gjSj-G5esDtK=cl`a7lhd*3`|r=5~Ick|E9g18(8>9Tj%0!Kz#c;NjGDTrjw zAQq-48>h6lDQ<}(T>0a5E@;{C_bXKnPXEow-ptw3Frz4U-ugccL{p)tE3x=lne|dI z4XAFlL!(ng&)piq&~q5_W>f5RR%Y(81eBEgPyc8VAZ7~-g0{m!3$3%}0JA`a+AF{z z*NQ~veC*H$X+=orOs}mabl9?oK+piz%j4JosPWLCb1NtfEFNdxEhLy1!Q-b85@x1z z*O{ie6G_BzOB!Z65*B#^!o#{8{w}Bb-6z=`5wM(-t{j<6Ln~WNS6RpG{q_&>pWX;Ct!zAD*#kM`)IS zuKZOxpQ44g051mpm|jiqv;^PzY)g&zGV*gtYya9#S?oFS?CbzR#YU(72OC}CzF*&B z>4~=L^zAa#q_2G>J@?K#3PaKn&X4(=$zY~0A265^R zm}2MujraoS4pHtqcPSNC3!S-UrI+h}$Q9m$Sc*%i-WTu#0D<9kfX~>vgrZ&i0usgq zKh=V;1G$lbwEu-bQ<0ldz-+hwiM@5+cSNKI3&C2eGO3mK^&syY|(ALJIgF4x08~CKT&& z6QzFEd%cxf z&KuZ(xBT_u)4GHmj03F3v;=NaHOl@7LJGS^3){FM?H?8v-@ik%Z(r|ZuJ{d7^aV(p z?6aB5fgVXu)?RV@x%-&kE@JXV1hrH0V+2Z`;{5p0 zV=jYb5Ru9J*;npxi(lAV8dtM(ISkSj#Mgh!DqTvn>0v>p>96NA1C6bw_7+&l9T1(= zhRj$xL;RAvfJ+tZxi!Ksr4K+&y7*38G7t2z0jg-#x?3QEtm6ctfo?i!18sL;aLbvX z|CQVkT{O0`n4m_Ls-}o7y?>TYP^zn-`!$lvl0#F`n0D`0^o)0}P6G~n?8ye_$7OVk zFvl~L+UlVOm9>4*Az^CDvkkJ4sk+uAWAC$I@?XN`j@;3Ft*T)n4Q_}CjlD=GD6UT2 ziUCGi@Q$Nzi8P9>Y6Tf)ySF)YR2(RKI5ooz9gebFF8RgDmQ30<#8MsPD!~LfWHT=S;wwpe3br>7or* z06Dn0G7bSI&6a)qOoxy!PQI{~X*I8rpV5UIl7y)cU)tX;7OMY%ey?Mfzg}g^kRwyC zaZl@@$S#<_7g>`Wsb#3_>6l!veHyCng&*P39AJ$qxhKSNtjv&=Gg)zNoiSppIzT6>4eZiin+1r2g}aIj)+hp5ilC|S0{V&SeyXSdNq;A@29h3LI9rgK3Tu)YzGcDgM) ziT)(`bt%mS7Xox&EQDE(LG%7f`?d{|z@=eOH}V@Wz{%I?1gXpZbitdN zK_i^t?*y|SLO+erL5893t(_en+3i`wKPrv^{dlIXQxv6eQ154#JLB5ePV&;(SiBbW zplWW3+3!p7*+uK1M`3QSL6ReeJ`Xr?8M0lUM^WtOM;fnLPSo{XhyJ%jXvn7%KdQo| zwE68x&=N|VZI^*NHw}YX_t|m11UXmeK8g{88F`V~bCdqgsJfPYn31UbWYj?W!Gixb zAQ{wgC0aQ7(=)k2d=_+vDgbD|y;g~WZ}~QZm80int;GqU#w&ijAOX#T>2P!4)<0>} z1znF;vYBw@B{zx5gD7eUkpRl_1KTkB2yV<&&- zZ=1K|x0%&1iVBUzNTuyX`m1ySpc@3~ zbW}Fo|IV(GcSo3tND?taLOP&i7b)g4a;tm3v03u~DzfAiz?HxkKXG+$ETu>G_#|`{ zvPC`!_=F$uL??jXA=!NGSV${9+e_CfT_?}!xiOCbqzL7ITR?`YEmMB~ZXGf)mBU1N zMZkllprx`KT1YfobdB+6n%2JS5B+O_%!NzS+;G)ND82}RrZX|q9^G$IOPXc0+w9}% zWceEqiiQi}Z|SM);O0i`8~TIWIHQb0J&cw*x@-Xf4IY)0dkgTcw|u`4^hmgZT!)vu z_V+}N^$itfYa+M-r|k^4;b@d_(3)T@s#$j~drSQ(pZmBB;78)N#c&{ujlnfIxh~MW z`mb;l`R)~>dxoWao0)C4OOCz(dWGqD?YFB@{~G#e zCrm;@lMGU6HT1{Uh3zVlW;E@bPUl3tTU(06-=+%fR|R%8N>+va61G+wPk(%RYzO6! zPS8U;U;CC<0;N6|yPqT(L*hWg3G5|&+!FZCv4=L}Np~+zAq`3s>FJNqL2Gg2d1g(` zSq??fCh;ssu<}Q3JC0!C0@T~tDv>~=gq`P%x9_d{xMj>s=J%^ImH+@>1*<#A6ukgw zU$QTX?cTv0vwx))cP`66d4->Dh;!S;ChFccFLm_TLd6%1bwpK(eHDmTI*HKHVywJM?}2Ws0k+s1$e4@FZH6^t`75L4rkJ-}Qoophp> zZDVdvjvE#doRnwWoCoGG8j7f}R=06l*cEaNK(SFQvGPly!eVuzW9-vOi> zRh=@i{RlFOsL9oUGy)r`OUtxd4;1d#@qKIY3X>JxT8lmms95`?1&!*FUuNZ1!$}UB^g6hS^|wXIehdimR>@ zDgZlt#q|8mJk(fbl{y_+=SH_PqNk=g^eW||hF;B>Q;2BLGxo@yfcMwiiNr~lqq z`i;KEg}E}#bBno<>l+5{Ji}#`r}!GCDhK*Ta-~GfKdpZ0%L^lAuM_y?M#)}#m1^m* zg|7;c8dy)R`J6cOR6$qu4oVvrAN`b+-G*=HizIxF(L+q8*qd{Xqw}XhU;%N?38=3; zBNdd<29+f0HqO>AaQhkZq~Hd}wbIQa$%;$c-cum#SWwm#i)hgcrq3U|&pa=>J2P09jZl z{rl?#)9trFbH4nota#btt-0!wp;dDS^j72f4X|QHU zgI*wg_iyJGTxPVGR(=ARMH4 zlNA2f1;S#B*QqmS?(~*o*)3g;RAxjlwkP~GINuVvDvt^ctmLIILJHyfUeE@ zKdDz9@?dFa;!dxO4G&+TNu2z!M+$BoKX`vG_50-_bf$H>@J@q3PU2VPJEb&MX^`=r z=8G@@o60Yn$fQv*9Vv3vim3i*UoGv+%M%4Stccaagso4SFC_E=rOM8Ibqc!yE>cZX z4SR80xq__B3{Di?V2iu@t)+DGUJg0=W6YohY0Q#GWbuA2Llo})>w+Js0*T6f{74)w zaFx=q@XTU<8(s|Z?(ui;)zZ#_riCEg&Od`n;XApUMS%76tN;Yi`0cd z8l`C)KyMOQpMYVmHepX=u>5XxMnMsC?b@|>oL;Xi(YUAdalvRD>7aSHKnJDh7DNR@ z82}5Gu>nuaZ|eF)rSXR1gW!f!_C;b4 zr5jQ%$5g07xebRT2ZuBo)5n_%ab#2;lQ#+5)4iV@4^8LIHL-DSiNf19G;3!zJ0T~o zA}M$H`zFMT;R7^&7_HoUvV%IUv8(=q_UAt3+mD@ugyh~WggqnGiK!`h@XGocE%O{U zh1XsTg;)&U6TzUJjlL@RRL*<82Wg9`FudMCOd80bpe(p0ahJJJ|I1O$7j2#A&vvqM zS6=H0e$$RQ^k#Wc`Au%g=Bh!$$*><+Cls809(SXRLR_`@TO4bHppfi?X?a%>lyZ|Y zrpIPp)Yq*&Yi#h5VS{Bt?&LdO^ac2&F+2csoGW_V`E@=0Pnk4n?{nw7cYta7F5Y;#%-vHQ zyC$^=DEVF(O|Hcc*vN+^M+8(s##oyCK0Ivm>U_WMH&Av>$S-va(w#o6FULROD7<1t z;#wPp*~!6uRXcM@6g`B7+K2X^%UeI;llw99Pmz- ze@OYob`OKs=CkW9WXQ<)jAs%Bd>V~9Xr&eS;pcb&Jk_AKd3Dr+4)jHq?x)!Q&s?Zy z(JC4Swbq8O4H^qF$ikT6k-vja{GJMJKuo_=RHhpxUacB}x@*SO^?5nfOT3ux&d4_5 zBhm=9oaI(Xh27PoePp*@Wy}GGHk6F+oY}r+V{`iUpS8U&+5C(bic$|4sxY@UG#jDD zh|yH!UOk4CeNPiGOlZtux3w{N@(2^aCu@Jd>dg_L9GAJaDB-+oelF{(mevla?I0i) zd9O`LawR+C-mHyr8~D8mFc~Q)jLE+n6hRwItnZiXjU4r~b>-+Eid6qj$zDf~w3k&@ zYv=zxbIXx{iz=Hw*E;l-bI(*RXHDZ+z-IwI7M)L=*|_@z)4S}lM&uvi)2sEE*>Wy2 z$Xz`_?tqS0t|L#7X_*H`+}9P;|L6o4Sq`!ilS=h97_d(`$7`R3GU%v1*?r}_T`z&+=-^P?wsAPtYV2Ol<3{? z`kkpsM>?(r8Y1^_z`is0$r#34sWjBFUAk%5cjN-JnapPwG$Nb;KFwE5OFqEsN!-;_ z<+iS_OHLK;Y)roW^WQviWtcs_x?-P8a0L_fV&*m?e~l#B4ppnhaNe|?$7R;Giw+4v zR+mE?lmg#fqu4v-tyu>t26$$aJZH4@h_0^2VbN$x8t!Y^E;;=7fdD!~qD$Apd^u7u zUFvT5mDEp(RvibviSlJ7Wm9E-(T(AF2M8bLFg`o5l|m z>Qzg->8_!ESu|d_tUwpyeyGGk4-?ynR=us$O(v_`D-nU_X2fWD7;&ynGhPWVeNf30 zezp7~kpTfeP1f7RrfN~$eD>m+#xJ8X5nC|s?@97oooDd{!2ggNezE_P{iYN}dH9g% zi76-1O0tMyylJYtsDQIqdIktxzA%0^r!&y3nM$Hjb(<=*o>ifw)(H1rmObAzq+2ut>La{j43_<_%&l zB+lY>*EV^BSDkrwew_;Q=i%`K<$51P0%#wqY13;8F4+LDLqhMZvGW~OYrE*3a90n5 z(;9v{Jb-IoJK3!dApy`z>~sr0gL$R1x~-L{&%Afw8h%%Y?!Utd-BUjdmBmck`5{xG z&$KL@7a{b>nKrZLm?TY5LTX>N*L?H%{k7Fp41B|p{;uZu@wg9ozaV4An|oJJ&C?d+Oy zrGy(Wn3aFnhml%4@^XPn3SNEHAR2bUrFI-K`G#;n$C|+VSP4`Dyu}46^!L5hst%By?oPn?~i^{nkFYj8(E zQR=D|_x&U28|6$J16USmitElaO!?ZuN-IlIBv_$Zf+^QLWyyh;CkLYVV6(1ko9$VD zJlhh%psnJohcDEDXx0@GXb3d%@~e^%S`(^yh!@+@prr?Bwl&f3twB^{lzy)~V}8Th z229ya3;xOcg8zO45nk|#*@l|l+&2TkIhn-~tEIiF4NVQnxC_8tU$Yo1M|2N-j>kgY zFY9gYm04B14e6%Z;xI?AI;+JP+{c5-N(P_$}zN+#VKc8 z`f~k1_iPtFa4pzx-;Y9({Ijvc*&E*NUfsuo74-HRQ}_EFRLO0tE2QCkNSqh!{0J^9 z3pXNmAH2H#sP)`+4v09mznHQXciC>EOy#KO60OPT+H(Gh?A0y-M?vVV zxZ;5Lk?I>S2+FMj=chw*_w(G5dZDJ=sUkW5zD!>;An>9~ub0i@t3Ms@JojSYSCw7I zEH-(Qs?9fb?mOW(o5jIyX|-@GQcp+8Rd#VcBXKi~kq911cq?{JJ!*;BYOeU}#+k$H z4Cl+TRXq-e^i`Ozc->zQgRm!+WcfOJeg+04zFQkoRM&7;g5LngV($gNCXd;AdF1i_ zkChZ+AnnkjC6#}t8pRz;PQ33r`;WU1k+7EoMw*-6HvL6ilUYT3o>xZHJ^b>W4{O6RZEC)8Yq*m`RKK zMoG)go6#PJABPzmE==kBE#zR=4$-TxBk3?-ZC9epO9N^_7@AGeJ^Y*@>n}Y&rrf`y zEXsc`CFa_yPzqj0qhtK~;cesokMFBx{=~(79ouH#wklZik4Ni#Qtb~?JYKicht-8N z8||p@8KgQV9{1z_ce+s~bvcfaeydiB6b7y9ys3hrR_;<`>|uX}`I4IR^iywCW$dB$ zo59y@0>`MFchSbuH?8}=e|V|p-Jz?`{!FG={bSTb z@zUs@j`*jW&_2H#DH?&qB9)7pU#exBY<;rSe^FFPGa!pMLR)F&yt~f?;WkpU*9Azg zzfb?U6u@eM)WY3$eerzd53!A`bsr@svL%(aqfr%?IE;4KC*9X6O4j%D&&3`ZM2-Iz8lG-FvqqWbk^&qTv&lO+QDz~P-Gf)D7L5>e2zYgHBt3ye)J4YJcZL<8%B%X~^!$zjzoj&h@Nj`gOV)B== zO-LstcuwFd`X!N`I_j>MPM--W=pOnVK9S9_B0=B8UdGsO&hWex`*-l$u==?0emkTT z@8sF5GSuvu`GQ?-50{FzTkw)^&?hliFMR@U-7D87e_m;&BNm2g=xk$X`jTlv3bUhj z2cZ8^5B~$}8R?+TcZuNSyzI<@zR5Szyh++!aQ;U_Mk*9rS0U z4xhBs#cn2tR%a*b`RU6}7Sjc3pA`O*V*)p0b_gvvqQJX61f<|XP&9a{CKcz=G~J`X zSzCHBw`l-Bh19|Q-Ai3Q7^u-JHJ!MEUY=u8T1qQ7GkP9U zi<)ZDxi)~_7{yd)FP?n%W5aZtTk>L=!@EV-=C63G1L5#@jdLxy-Oqk?^MTP;dF`$@(FTv+}S)4X0<<{3jX65eG|yLH)XKa$rk z4})_qwI(~YS{I7jg&7_X_%CO_N*(Xz{Uq{*#($L$#$Z}Z!42Sc1sGe}cQjw^5wSnh}uyXjf8)5dABH4uhj@Kq0q z`$Ig+tcUaE-n3r5JXe`TETM&LJyhm&*3=DC5DXscEL11%e+z1vZ&< z#oS2CzfA(ZS>A)6F?Xd@ifuHHc*)URZ*-cb@LB*# zdGyF!ZomYrbZ2!X)^h8+Cl;!__?wgN;3-OalP%zS6(-<@`^YE+sUbMT-r_OwJ~qqD z?$361DJF9i5D?Srue7N%IAkvGH0CH6_3*le=fxzM-BqK`Ug|2GwK|nUO1M5b^tAJ~ z-)wh=)~AatvuWClzx4hZ$~d*%v;LTyp*da-6kTnyUJEVzS#1kmEaw+a29&!NuP(X1 zGjOKG(V1_hqCfHkUDk{@#MhVa2#L)dRbS708@r+S3u&n)b0=e}MXlrRsL%ZaLjyERMO*#kEyy2e*sDunLu;csg0vk>R^< zC2b>$@t?H)S|YzAxBX1}oRbo1B;eK^!wi3+I;x9^`QgE=0R1k5$i#4ql1qm}lBNt< z`RRvp^fawVXABwev!K44D*Xj+UK@4=Z>;p&KmX&~0oP@=#QTvr7ln^~V=2G7IWML* zm#L``T948nGul@!Zb>-{!ECTY&Ahh5?|6>n!h}?7?LFu86q9A&m}B)Tj_SI|iGCI- z6-~g|`~Da&(OF*;aDKY4esr)a(`ZhQItjm7D$}}fhK+uhyJeoKEfdA<2D2R9h|jxQ z1mF$bpA<`Llb7g6)J!pBHkosfNL1l2^0iVhSMe2@Un~|T&64!%$zyh@<*RXr9Wq!(VXrNrW;46Mv(^Gi_rQ}Bo#7Q$=TtQIe5!CIYfYRc3W{Q-=Uid)M1Ou zgNoGhYn2taeo;eKJpU(=_?au$$J6+b!G3;!F0o9x|97}i%p{vUt+14)<1+PqKm4`` zr_`?P>;2pKseKcjOI7r>X|=YaDC{~OiyukLL;`qlf4cGVHj~N;vu#`|+rfs#ZYD+S z6j0^H)4Ys&z**%w@6Q&SRWBn1OHsz&knb3vIDV}%7YEMho^xDI4(8Ce_te5vsC9F`;Q~ck&Hcj83j(p>J^~5$%hIz1m=gXoG?T5V z4js%d0tci|h6{MEk)>l0yGmXrM~J|r80W*dCsiLMo0T_U!;K7ClY?C;XXThP{0@Ai zR=9lAF{mrJkX}4>BA-ZNYpFe>uEw$as-?zWZi1Cen_uB2eoND@zt}x$Jv4UNx_Qdz zpu(>EkW+#dCn}E{Xes#$VZ-HVlygp3smq6Fqt_wJB){zAXUgj7DYpT+jty4z4}gsx z6c8Qng(V7Tw&knx@LELH1yvIhaE7%T)eUO}{NIM$$Hj-U(4;v?zLyS6cP&g$FMc%h zT?x(4CA!JUP#1p`PbAw7-AR5u_)+~ZcX*o((&sU>Ue^4eaUKj7R9VM6%Ps3cv1!DKi9r?d* zj4Z#Cs&}kDb(ep|BAz!cLd&LEYL`Ufm7w4vf$3I(+3ZRs3QhEs4pP4dHQyBRWnXE& zpRb}+1=A3K{>5;kgTx4~LqjmO8tC5uW~6AC2MkCy7+FE|uLeC8`oAyzpCJBEBmRGC c8n - - diff --git a/packages/stream_chat_flutter/example/ios/Gemfile b/packages/stream_chat_flutter/example/ios/Gemfile deleted file mode 100644 index cdd3a6b3..00000000 --- a/packages/stream_chat_flutter/example/ios/Gemfile +++ /dev/null @@ -1,6 +0,0 @@ -source "https://rubygems.org" - -gem "fastlane" - -plugins_path = File.join(File.dirname(__FILE__), 'fastlane', 'Pluginfile') -eval_gemfile(plugins_path) if File.exist?(plugins_path) diff --git a/packages/stream_chat_flutter/example/ios/Gemfile.lock b/packages/stream_chat_flutter/example/ios/Gemfile.lock deleted file mode 100644 index dc0ee04f..00000000 --- a/packages/stream_chat_flutter/example/ios/Gemfile.lock +++ /dev/null @@ -1,180 +0,0 @@ -GEM - remote: https://rubygems.org/ - specs: - CFPropertyList (3.0.2) - addressable (2.7.0) - public_suffix (>= 2.0.2, < 5.0) - atomos (0.1.3) - aws-eventstream (1.1.0) - aws-partitions (1.380.0) - aws-sdk-core (3.109.1) - aws-eventstream (~> 1, >= 1.0.2) - aws-partitions (~> 1, >= 1.239.0) - aws-sigv4 (~> 1.1) - jmespath (~> 1.0) - aws-sdk-kms (1.39.0) - aws-sdk-core (~> 3, >= 3.109.0) - aws-sigv4 (~> 1.1) - aws-sdk-s3 (1.83.0) - aws-sdk-core (~> 3, >= 3.109.0) - aws-sdk-kms (~> 1) - aws-sigv4 (~> 1.1) - aws-sigv4 (1.2.2) - aws-eventstream (~> 1, >= 1.0.2) - babosa (1.0.3) - claide (1.0.3) - colored (1.2) - colored2 (3.1.2) - commander-fastlane (4.4.6) - highline (~> 1.7.2) - declarative (0.0.20) - declarative-option (0.1.0) - digest-crc (0.6.1) - rake (~> 13.0) - domain_name (0.5.20190701) - unf (>= 0.0.5, < 1.0.0) - dotenv (2.7.6) - emoji_regex (3.0.0) - excon (0.76.0) - faraday (1.0.1) - multipart-post (>= 1.2, < 3) - faraday-cookie_jar (0.0.7) - faraday (>= 0.8.0) - http-cookie (~> 1.0.0) - faraday_middleware (1.0.0) - faraday (~> 1.0) - fastimage (2.2.0) - fastlane (2.162.0) - CFPropertyList (>= 2.3, < 4.0.0) - addressable (>= 2.3, < 3.0.0) - aws-sdk-s3 (~> 1.0) - babosa (>= 1.0.3, < 2.0.0) - bundler (>= 1.12.0, < 3.0.0) - colored - commander-fastlane (>= 4.4.6, < 5.0.0) - dotenv (>= 2.1.1, < 3.0.0) - emoji_regex (>= 0.1, < 4.0) - excon (>= 0.71.0, < 1.0.0) - faraday (~> 1.0) - faraday-cookie_jar (~> 0.0.6) - faraday_middleware (~> 1.0) - fastimage (>= 2.1.0, < 3.0.0) - gh_inspector (>= 1.1.2, < 2.0.0) - google-api-client (>= 0.37.0, < 0.39.0) - google-cloud-storage (>= 1.15.0, < 2.0.0) - highline (>= 1.7.2, < 2.0.0) - json (< 3.0.0) - jwt (>= 2.1.0, < 3) - mini_magick (>= 4.9.4, < 5.0.0) - multipart-post (~> 2.0.0) - plist (>= 3.1.0, < 4.0.0) - rubyzip (>= 2.0.0, < 3.0.0) - security (= 0.1.3) - simctl (~> 1.6.3) - slack-notifier (>= 2.0.0, < 3.0.0) - terminal-notifier (>= 2.0.0, < 3.0.0) - terminal-table (>= 1.4.5, < 2.0.0) - tty-screen (>= 0.6.3, < 1.0.0) - tty-spinner (>= 0.8.0, < 1.0.0) - word_wrap (~> 1.0.0) - xcodeproj (>= 1.13.0, < 2.0.0) - xcpretty (~> 0.3.0) - xcpretty-travis-formatter (>= 0.0.3) - fastlane-plugin-firebase_app_distribution (0.2.3) - gh_inspector (1.1.3) - google-api-client (0.38.0) - addressable (~> 2.5, >= 2.5.1) - googleauth (~> 0.9) - httpclient (>= 2.8.1, < 3.0) - mini_mime (~> 1.0) - representable (~> 3.0) - retriable (>= 2.0, < 4.0) - signet (~> 0.12) - google-cloud-core (1.5.0) - google-cloud-env (~> 1.0) - google-cloud-errors (~> 1.0) - google-cloud-env (1.3.3) - faraday (>= 0.17.3, < 2.0) - google-cloud-errors (1.0.1) - google-cloud-storage (1.29.1) - addressable (~> 2.5) - digest-crc (~> 0.4) - google-api-client (~> 0.33) - google-cloud-core (~> 1.2) - googleauth (~> 0.9) - mini_mime (~> 1.0) - googleauth (0.13.1) - faraday (>= 0.17.3, < 2.0) - jwt (>= 1.4, < 3.0) - memoist (~> 0.16) - multi_json (~> 1.11) - os (>= 0.9, < 2.0) - signet (~> 0.14) - highline (1.7.10) - http-cookie (1.0.3) - domain_name (~> 0.5) - httpclient (2.8.3) - jmespath (1.4.0) - json (2.3.1) - jwt (2.2.2) - memoist (0.16.2) - mini_magick (4.10.1) - mini_mime (1.0.2) - multi_json (1.15.0) - multipart-post (2.0.0) - nanaimo (0.3.0) - naturally (2.2.0) - os (1.1.1) - plist (3.5.0) - public_suffix (4.0.6) - rake (13.0.1) - representable (3.0.4) - declarative (< 0.1.0) - declarative-option (< 0.2.0) - uber (< 0.2.0) - retriable (3.1.2) - rouge (2.0.7) - rubyzip (2.3.0) - security (0.1.3) - signet (0.14.0) - addressable (~> 2.3) - faraday (>= 0.17.3, < 2.0) - jwt (>= 1.5, < 3.0) - multi_json (~> 1.10) - simctl (1.6.8) - CFPropertyList - naturally - slack-notifier (2.3.2) - terminal-notifier (2.0.0) - terminal-table (1.8.0) - unicode-display_width (~> 1.1, >= 1.1.1) - tty-cursor (0.7.1) - tty-screen (0.8.1) - tty-spinner (0.9.3) - tty-cursor (~> 0.7) - uber (0.1.0) - unf (0.1.4) - unf_ext - unf_ext (0.0.7.7) - unicode-display_width (1.7.0) - word_wrap (1.0.0) - xcodeproj (1.18.0) - CFPropertyList (>= 2.3.3, < 4.0) - atomos (~> 0.1.3) - claide (>= 1.0.2, < 2.0) - colored2 (~> 3.1) - nanaimo (~> 0.3.0) - xcpretty (0.3.0) - rouge (~> 2.0.7) - xcpretty-travis-formatter (1.0.0) - xcpretty (~> 0.2, >= 0.0.7) - -PLATFORMS - ruby - -DEPENDENCIES - fastlane - fastlane-plugin-firebase_app_distribution - -BUNDLED WITH - 2.0.2 diff --git a/packages/stream_chat_flutter/example/ios/Notifications/Info.plist b/packages/stream_chat_flutter/example/ios/Notifications/Info.plist deleted file mode 100644 index a225b5ca..00000000 --- a/packages/stream_chat_flutter/example/ios/Notifications/Info.plist +++ /dev/null @@ -1,31 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleDisplayName - Notifications - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - $(PRODUCT_BUNDLE_PACKAGE_TYPE) - CFBundleShortVersionString - 1.0 - CFBundleVersion - 1 - NSExtension - - NSExtensionPointIdentifier - com.apple.usernotifications.service - NSExtensionPrincipalClass - $(PRODUCT_MODULE_NAME).NotificationService - - - diff --git a/packages/stream_chat_flutter/example/ios/Notifications/NotificationService.swift b/packages/stream_chat_flutter/example/ios/Notifications/NotificationService.swift deleted file mode 100644 index 976e8d6a..00000000 --- a/packages/stream_chat_flutter/example/ios/Notifications/NotificationService.swift +++ /dev/null @@ -1,182 +0,0 @@ -// -// NotificationService.swift -// Notifications -// -// Created by Salvatore Giordano on 25/03/2020. -// Copyright © 2020 The Chromium Authors. All rights reserved. -// - -import UserNotifications -//import StreamChatClient - -final class NotificationService: UNNotificationServiceExtension { - - var contentHandler: ((UNNotificationContent) -> Void)? - var bestAttemptContent: UNMutableNotificationContent? - - override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) { - self.contentHandler = contentHandler - bestAttemptContent = (request.content.mutableCopy() as? UNMutableNotificationContent) - - guard let sharedDefaults = UserDefaults(suiteName: "group.io.getstream.flutter"), - let apiKey = sharedDefaults.string(forKey: "KEY_API_KEY"), - let userId = sharedDefaults.string(forKey: "KEY_USER_ID"), - let token = sharedDefaults.string(forKey: "KEY_TOKEN"), - let messageId = bestAttemptContent?.userInfo["message_id"] as? String else { - return - } - -// Client.config = .init(apiKey: apiKey, logOptions: .error) -// Client.shared.set(user: User(id: userId), token: token) { res in -// guard res.isConnected else { -// return -// } -// -// Client.shared.message(withId: messageId) { [weak self] res in -// if let message = res.value?.message, -// let channel = res.value?.channel { -// let messageWrapper = MessageWrapper(channel: channel, message: message) -// if let encodedData = try? JSONEncoder.stream.encode(messageWrapper), -// let encodedString = String(data: encodedData, encoding: .utf8) { -// let storedMessages = sharedDefaults.stringArray(forKey: "messageQueue") ?? [] -// sharedDefaults.setValue(storedMessages + [encodedString], forKey: "messageQueue") -// -// // Modify the notification content here... -// self?.bestAttemptContent?.title = "[modified] \(self?.bestAttemptContent?.title ?? "")" -// contentHandler(self?.bestAttemptContent ?? request.content) -// } -// Client.shared.disconnect() -// } -// } -// } - } - - override func serviceExtensionTimeWillExpire() { - if let contentHandler = contentHandler, let bestAttemptContent = bestAttemptContent { - contentHandler(bestAttemptContent) - } - } -} - -//public struct MessageWrapper: Encodable { -// private enum CodingKeys: String, CodingKey { -// case id -// case channel -// case type -// case user -// case created = "created_at" -// case updated = "updated_at" -// case text -// case command -// case args -// case attachments -// case parentId = "parent_id" -// case showReplyInChannel = "show_in_channel" -// case mentionedUsers = "mentioned_users" -// } -// -// init(channel: Channel, message: Message) { -// id = message.id -// type = message.type -// user = message.user -// created = message.created -// updated = message.updated -// text = message.text -// command = message.command -// args = message.args -// attachments = message.attachments -// parentId = message.parentId -// showReplyInChannel = message.showReplyInChannel -// mentionedUsers = message.mentionedUsers -// extraData = message.extraData -// self.channel = ChannelWrapper(channel: channel) -// } -// -// /// A message id. -// public let id: String -// /// The channel cid. -// public let channel: ChannelWrapper? -// /// A message type (see `MessageType`). -// public let type: MessageType -// /// A user (see `User`). -// public let user: User -// /// A created date. -// public let created: Date -// /// A updated date. -// public let updated: Date -// /// A text. -// public let text: String -// /// A used command name. -// public let command: String? -// /// A used command args. -// public let args: String? -// /// Attachments (see `Attachment`). -// public let attachments: [Attachment] -// /// A parent message id. -// public let parentId: String? -// /// Check if this reply message needs to show in the channel. -// public let showReplyInChannel: Bool -// /// Mentioned users (see `User`). -// public let mentionedUsers: [User] -// /// An extra data for the message. -// public let extraData: Codable? -//} -// -//public struct ChannelWrapper: Encodable { -// /// Coding keys for the encoding. -// private enum CodingKeys: String, CodingKey { -// case id -// case cid -// case type -// case name -// case imageURL = "image" -// case members -// case lastMessageDate = "last_message_at" -// case createdBy = "created_by" -// case created = "created_at" -// case deleted = "deleted_at" -// case frozen -// } -// -// init(channel: Channel) { -// id = channel.id -// cid = channel.cid -// type = channel.type -// name = channel.name -// imageURL = channel.imageURL -// lastMessageDate = channel.lastMessageDate -// created = channel.created -// deleted = channel.deleted -// createdBy = channel.createdBy -// config = channel.config -// frozen = channel.frozen -// extraData = channel.extraData -// } -// -// /// A channel id. -// public let id: String -// /// A channel type + id. -// public let cid: ChannelId -// /// A channel type. -// public let type: ChannelType -// /// A channel name. -// public let name: String? -// /// An image of the channel. -// public let imageURL: URL? -// /// The last message date. -// public let lastMessageDate: Date? -// /// A channel created date. -// public let created: Date -// /// A channel deleted date. -// public let deleted: Date? -// /// A creator of the channel. -// public let createdBy: User? -// /// A config. -// public let config: Channel.Config -// /// Checks if the channel is frozen. -// public let frozen: Bool -// /// A list of user ids of the channel members. -// public let members = Set() -// /// An extra data for the channel. -// public let extraData: Codable? -//} diff --git a/packages/stream_chat_flutter/example/ios/Notifications/Notifications.entitlements b/packages/stream_chat_flutter/example/ios/Notifications/Notifications.entitlements deleted file mode 100644 index e5b71890..00000000 --- a/packages/stream_chat_flutter/example/ios/Notifications/Notifications.entitlements +++ /dev/null @@ -1,10 +0,0 @@ - - - - - com.apple.security.application-groups - - group.io.getstream.flutter - - - diff --git a/packages/stream_chat_flutter/example/ios/Runner.xcodeproj/project.pbxproj b/packages/stream_chat_flutter/example/ios/Runner.xcodeproj/project.pbxproj index 1e7527eb..1aec2aa0 100644 --- a/packages/stream_chat_flutter/example/ios/Runner.xcodeproj/project.pbxproj +++ b/packages/stream_chat_flutter/example/ios/Runner.xcodeproj/project.pbxproj @@ -7,39 +7,15 @@ objects = { /* Begin PBXBuildFile section */ - 0BC14C50242B5A7A0028DE94 /* NotificationService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0BC14C4F242B5A7A0028DE94 /* NotificationService.swift */; }; - 0BC14C54242B5A7A0028DE94 /* Notifications.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = 0BC14C4D242B5A7A0028DE94 /* Notifications.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; - 7DEC2743BD66C91B700A3B97 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8BB2E5E4E236267EDF0D8817 /* Pods_Runner.framework */; }; 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; /* End PBXBuildFile section */ -/* Begin PBXContainerItemProxy section */ - 0BC14C52242B5A7A0028DE94 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 97C146E61CF9000F007C117D /* Project object */; - proxyType = 1; - remoteGlobalIDString = 0BC14C4C242B5A7A0028DE94; - remoteInfo = Notifications; - }; -/* End PBXContainerItemProxy section */ - /* Begin PBXCopyFilesBuildPhase section */ - 0BC14C55242B5A7A0028DE94 /* Embed App Extensions */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 2147483647; - dstPath = ""; - dstSubfolderSpec = 13; - files = ( - 0BC14C54242B5A7A0028DE94 /* Notifications.appex in Embed App Extensions */, - ); - name = "Embed App Extensions"; - runOnlyForDeploymentPostprocessing = 0; - }; 9705A1C41CF9048500538489 /* Embed Frameworks */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 2147483647; @@ -53,21 +29,12 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ - 0BC14C4D242B5A7A0028DE94 /* Notifications.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = Notifications.appex; sourceTree = BUILT_PRODUCTS_DIR; }; - 0BC14C4F242B5A7A0028DE94 /* NotificationService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationService.swift; sourceTree = ""; }; - 0BC14C51242B5A7A0028DE94 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 0BC14C5A242B5ED90028DE94 /* Notifications.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Notifications.entitlements; sourceTree = ""; }; - 0BC14C5B242B5FF50028DE94 /* Runner.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Runner.entitlements; sourceTree = ""; }; 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; - 2452A9E77396497EB4CF3072 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; - 68F846A6DB42D92393F5F7E0 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; - 7BF51EE28C89025F73A5211F /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; - 8BB2E5E4E236267EDF0D8817 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -78,34 +45,16 @@ /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ - 0BC14C4A242B5A7A0028DE94 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; 97C146EB1CF9000F007C117D /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 7DEC2743BD66C91B700A3B97 /* Pods_Runner.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ - 0BC14C4E242B5A7A0028DE94 /* Notifications */ = { - isa = PBXGroup; - children = ( - 0BC14C5A242B5ED90028DE94 /* Notifications.entitlements */, - 0BC14C4F242B5A7A0028DE94 /* NotificationService.swift */, - 0BC14C51242B5A7A0028DE94 /* Info.plist */, - ); - path = Notifications; - sourceTree = ""; - }; 9740EEB11CF90186004384FC /* Flutter */ = { isa = PBXGroup; children = ( @@ -120,12 +69,9 @@ 97C146E51CF9000F007C117D = { isa = PBXGroup; children = ( - 97C146F01CF9000F007C117D /* Runner */, 9740EEB11CF90186004384FC /* Flutter */, - 0BC14C4E242B5A7A0028DE94 /* Notifications */, + 97C146F01CF9000F007C117D /* Runner */, 97C146EF1CF9000F007C117D /* Products */, - CF168B61BAB91958681C7C21 /* Pods */, - BC09A38346C8B2CD72199469 /* Frameworks */, ); sourceTree = ""; }; @@ -133,7 +79,6 @@ isa = PBXGroup; children = ( 97C146EE1CF9000F007C117D /* Runner.app */, - 0BC14C4D242B5A7A0028DE94 /* Notifications.appex */, ); name = Products; sourceTree = ""; @@ -141,12 +86,10 @@ 97C146F01CF9000F007C117D /* Runner */ = { isa = PBXGroup; children = ( - 0BC14C5B242B5FF50028DE94 /* Runner.entitlements */, 97C146FA1CF9000F007C117D /* Main.storyboard */, 97C146FD1CF9000F007C117D /* Assets.xcassets */, 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, 97C147021CF9000F007C117D /* Info.plist */, - 97C146F11CF9000F007C117D /* Supporting Files */, 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, @@ -155,69 +98,23 @@ path = Runner; sourceTree = ""; }; - 97C146F11CF9000F007C117D /* Supporting Files */ = { - isa = PBXGroup; - children = ( - ); - name = "Supporting Files"; - sourceTree = ""; - }; - BC09A38346C8B2CD72199469 /* Frameworks */ = { - isa = PBXGroup; - children = ( - 8BB2E5E4E236267EDF0D8817 /* Pods_Runner.framework */, - ); - name = Frameworks; - sourceTree = ""; - }; - CF168B61BAB91958681C7C21 /* Pods */ = { - isa = PBXGroup; - children = ( - 2452A9E77396497EB4CF3072 /* Pods-Runner.debug.xcconfig */, - 7BF51EE28C89025F73A5211F /* Pods-Runner.release.xcconfig */, - 68F846A6DB42D92393F5F7E0 /* Pods-Runner.profile.xcconfig */, - ); - path = Pods; - sourceTree = ""; - }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ - 0BC14C4C242B5A7A0028DE94 /* Notifications */ = { - isa = PBXNativeTarget; - buildConfigurationList = 0BC14C59242B5A7A0028DE94 /* Build configuration list for PBXNativeTarget "Notifications" */; - buildPhases = ( - 0BC14C49242B5A7A0028DE94 /* Sources */, - 0BC14C4A242B5A7A0028DE94 /* Frameworks */, - 0BC14C4B242B5A7A0028DE94 /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = Notifications; - productName = Notifications; - productReference = 0BC14C4D242B5A7A0028DE94 /* Notifications.appex */; - productType = "com.apple.product-type.app-extension"; - }; 97C146ED1CF9000F007C117D /* Runner */ = { isa = PBXNativeTarget; buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; buildPhases = ( - 9E02B5C38D6CC2455D9E48E9 /* [CP] Check Pods Manifest.lock */, 9740EEB61CF901F6004384FC /* Run Script */, 97C146EA1CF9000F007C117D /* Sources */, 97C146EB1CF9000F007C117D /* Frameworks */, 97C146EC1CF9000F007C117D /* Resources */, 9705A1C41CF9048500538489 /* Embed Frameworks */, 3B06AD1E1E4923F5004D2608 /* Thin Binary */, - 5702861DACEDB848A3E454E8 /* [CP] Embed Pods Frameworks */, - 0BC14C55242B5A7A0028DE94 /* Embed App Extensions */, ); buildRules = ( ); dependencies = ( - 0BC14C53242B5A7A0028DE94 /* PBXTargetDependency */, ); name = Runner; productName = Runner; @@ -230,25 +127,17 @@ 97C146E61CF9000F007C117D /* Project object */ = { isa = PBXProject; attributes = { - LastSwiftUpdateCheck = 1140; LastUpgradeCheck = 1020; - ORGANIZATIONNAME = "The Chromium Authors"; + ORGANIZATIONNAME = ""; TargetAttributes = { - 0BC14C4C242B5A7A0028DE94 = { - CreatedOnToolsVersion = 11.4; - DevelopmentTeam = EHV7XZLAHA; - ProvisioningStyle = Manual; - }; 97C146ED1CF9000F007C117D = { CreatedOnToolsVersion = 7.3.1; - DevelopmentTeam = EHV7XZLAHA; LastSwiftMigration = 1100; - ProvisioningStyle = Manual; }; }; }; buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; - compatibilityVersion = "Xcode 3.2"; + compatibilityVersion = "Xcode 9.3"; developmentRegion = en; hasScannedForEncodings = 0; knownRegions = ( @@ -261,19 +150,11 @@ projectRoot = ""; targets = ( 97C146ED1CF9000F007C117D /* Runner */, - 0BC14C4C242B5A7A0028DE94 /* Notifications */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ - 0BC14C4B242B5A7A0028DE94 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; 97C146EC1CF9000F007C117D /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; @@ -302,84 +183,6 @@ shellPath = /bin/sh; shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; }; - 5702861DACEDB848A3E454E8 /* [CP] Embed Pods Frameworks */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh", - "${BUILT_PRODUCTS_DIR}/Starscream-framework/Starscream.framework", - "${BUILT_PRODUCTS_DIR}/StreamChatClient-framework/StreamChatClient.framework", - "${BUILT_PRODUCTS_DIR}/DKImagePickerController/DKImagePickerController.framework", - "${BUILT_PRODUCTS_DIR}/DKPhotoGallery/DKPhotoGallery.framework", - "${BUILT_PRODUCTS_DIR}/FMDB/FMDB.framework", - "${PODS_ROOT}/../Flutter/Flutter.framework", - "${BUILT_PRODUCTS_DIR}/GoogleUtilities/GoogleUtilities.framework", - "${BUILT_PRODUCTS_DIR}/PromisesObjC/FBLPromises.framework", - "${BUILT_PRODUCTS_DIR}/Protobuf/Protobuf.framework", - "${BUILT_PRODUCTS_DIR}/SDWebImage/SDWebImage.framework", - "${BUILT_PRODUCTS_DIR}/SwiftyGif/SwiftyGif.framework", - "${BUILT_PRODUCTS_DIR}/esys_flutter_share/esys_flutter_share.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}/flutter_secure_storage/flutter_secure_storage.framework", - "${BUILT_PRODUCTS_DIR}/image_gallery_saver/image_gallery_saver.framework", - "${BUILT_PRODUCTS_DIR}/image_picker/image_picker.framework", - "${BUILT_PRODUCTS_DIR}/nanopb/nanopb.framework", - "${BUILT_PRODUCTS_DIR}/path_provider/path_provider.framework", - "${BUILT_PRODUCTS_DIR}/photo_manager/photo_manager.framework", - "${BUILT_PRODUCTS_DIR}/shared_preferences/shared_preferences.framework", - "${BUILT_PRODUCTS_DIR}/sqflite/sqflite.framework", - "${BUILT_PRODUCTS_DIR}/sqlite3/sqlite3.framework", - "${BUILT_PRODUCTS_DIR}/sqlite3_flutter_libs/sqlite3_flutter_libs.framework", - "${BUILT_PRODUCTS_DIR}/url_launcher/url_launcher.framework", - "${BUILT_PRODUCTS_DIR}/video_compress/video_compress.framework", - "${BUILT_PRODUCTS_DIR}/video_player/video_player.framework", - "${BUILT_PRODUCTS_DIR}/wakelock/wakelock.framework", - ); - name = "[CP] Embed Pods Frameworks"; - outputPaths = ( - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Starscream.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/StreamChatClient.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/DKImagePickerController.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/DKPhotoGallery.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FMDB.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Flutter.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GoogleUtilities.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FBLPromises.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Protobuf.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SDWebImage.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SwiftyGif.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/esys_flutter_share.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}/flutter_secure_storage.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/image_gallery_saver.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/image_picker.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/nanopb.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/path_provider.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/photo_manager.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/shared_preferences.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/sqflite.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/sqlite3.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/sqlite3_flutter_libs.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/url_launcher.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/video_compress.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/video_player.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/wakelock.framework", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; - showEnvVarsInLog = 0; - }; 9740EEB61CF901F6004384FC /* Run Script */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; @@ -394,39 +197,9 @@ shellPath = /bin/sh; shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; }; - 9E02B5C38D6CC2455D9E48E9 /* [CP] Check Pods Manifest.lock */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - ); - inputPaths = ( - "${PODS_PODFILE_DIR_PATH}/Podfile.lock", - "${PODS_ROOT}/Manifest.lock", - ); - name = "[CP] Check Pods Manifest.lock"; - outputFileListPaths = ( - ); - outputPaths = ( - "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; - showEnvVarsInLog = 0; - }; /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ - 0BC14C49242B5A7A0028DE94 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 0BC14C50242B5A7A0028DE94 /* NotificationService.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; 97C146EA1CF9000F007C117D /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -438,14 +211,6 @@ }; /* End PBXSourcesBuildPhase section */ -/* Begin PBXTargetDependency section */ - 0BC14C53242B5A7A0028DE94 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 0BC14C4C242B5A7A0028DE94 /* Notifications */; - targetProxy = 0BC14C52242B5A7A0028DE94 /* PBXContainerItemProxy */; - }; -/* End PBXTargetDependency section */ - /* Begin PBXVariantGroup section */ 97C146FA1CF9000F007C117D /* Main.storyboard */ = { isa = PBXVariantGroup; @@ -466,90 +231,6 @@ /* End PBXVariantGroup section */ /* Begin XCBuildConfiguration section */ - 0BC14C56242B5A7A0028DE94 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; - CLANG_ENABLE_OBJC_WEAK = YES; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; - CODE_SIGN_ENTITLEMENTS = Notifications/Notifications.entitlements; - CODE_SIGN_IDENTITY = "iPhone Distribution"; - CODE_SIGN_STYLE = Manual; - DEVELOPMENT_TEAM = EHV7XZLAHA; - ENABLE_BITCODE = NO; - GCC_C_LANGUAGE_STANDARD = gnu11; - INFOPLIST_FILE = Notifications/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 13.3; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks"; - MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; - MTL_FAST_MATH = YES; - PRODUCT_BUNDLE_IDENTIFIER = io.getstream.flutter.Notifications; - PRODUCT_NAME = "$(TARGET_NAME)"; - PROVISIONING_PROFILE_SPECIFIER = "match AdHoc io.getstream.flutter.Notifications"; - SKIP_INSTALL = YES; - SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Debug; - }; - 0BC14C57242B5A7A0028DE94 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; - CLANG_ENABLE_OBJC_WEAK = YES; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; - CODE_SIGN_ENTITLEMENTS = Notifications/Notifications.entitlements; - CODE_SIGN_IDENTITY = "iPhone Distribution"; - CODE_SIGN_STYLE = Manual; - DEVELOPMENT_TEAM = EHV7XZLAHA; - ENABLE_BITCODE = NO; - GCC_C_LANGUAGE_STANDARD = gnu11; - INFOPLIST_FILE = Notifications/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 13.3; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks"; - MTL_FAST_MATH = YES; - PRODUCT_BUNDLE_IDENTIFIER = io.getstream.flutter.Notifications; - PRODUCT_NAME = "$(TARGET_NAME)"; - PROVISIONING_PROFILE_SPECIFIER = "match AdHoc io.getstream.flutter.Notifications"; - SKIP_INSTALL = YES; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Release; - }; - 0BC14C58242B5A7A0028DE94 /* Profile */ = { - isa = XCBuildConfiguration; - buildSettings = { - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; - CLANG_ENABLE_OBJC_WEAK = YES; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; - CODE_SIGN_ENTITLEMENTS = Notifications/Notifications.entitlements; - CODE_SIGN_IDENTITY = "iPhone Distribution"; - CODE_SIGN_STYLE = Manual; - DEVELOPMENT_TEAM = EHV7XZLAHA; - ENABLE_BITCODE = NO; - GCC_C_LANGUAGE_STANDARD = gnu11; - INFOPLIST_FILE = Notifications/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 13.3; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks"; - MTL_FAST_MATH = YES; - PRODUCT_BUNDLE_IDENTIFIER = io.getstream.flutter.Notifications; - PRODUCT_NAME = "$(TARGET_NAME)"; - PROVISIONING_PROFILE_SPECIFIER = "match AdHoc io.getstream.flutter.Notifications"; - SKIP_INSTALL = YES; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Profile; - }; 249021D3217E4FDB00AE95B9 /* Profile */ = { isa = XCBuildConfiguration; buildSettings = { @@ -591,7 +272,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SUPPORTED_PLATFORMS = iphoneos; @@ -604,29 +285,22 @@ isa = XCBuildConfiguration; baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; buildSettings = { - ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; - CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; - CODE_SIGN_IDENTITY = "iPhone Distribution"; - CODE_SIGN_STYLE = Manual; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; - DEVELOPMENT_TEAM = EHV7XZLAHA; ENABLE_BITCODE = NO; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", "$(PROJECT_DIR)/Flutter", ); INFOPLIST_FILE = Runner/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 11.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; LIBRARY_SEARCH_PATHS = ( "$(inherited)", "$(PROJECT_DIR)/Flutter", ); - PRODUCT_BUNDLE_IDENTIFIER = io.getstream.flutter; + PRODUCT_BUNDLE_IDENTIFIER = com.example.example; PRODUCT_NAME = "$(TARGET_NAME)"; - PROVISIONING_PROFILE_SPECIFIER = "match AdHoc io.getstream.flutter"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_VERSION = 5.0; VERSIONING_SYSTEM = "apple-generic"; @@ -680,7 +354,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; @@ -729,7 +403,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SUPPORTED_PLATFORMS = iphoneos; @@ -743,29 +417,22 @@ isa = XCBuildConfiguration; baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; buildSettings = { - ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; - CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; - CODE_SIGN_IDENTITY = "iPhone Distribution"; - CODE_SIGN_STYLE = Manual; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; - DEVELOPMENT_TEAM = EHV7XZLAHA; ENABLE_BITCODE = NO; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", "$(PROJECT_DIR)/Flutter", ); INFOPLIST_FILE = Runner/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 11.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; LIBRARY_SEARCH_PATHS = ( "$(inherited)", "$(PROJECT_DIR)/Flutter", ); - PRODUCT_BUNDLE_IDENTIFIER = io.getstream.flutter; + PRODUCT_BUNDLE_IDENTIFIER = com.example.example; PRODUCT_NAME = "$(TARGET_NAME)"; - PROVISIONING_PROFILE_SPECIFIER = "match AdHoc io.getstream.flutter"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 5.0; @@ -777,29 +444,22 @@ isa = XCBuildConfiguration; baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; buildSettings = { - ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; - CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; - CODE_SIGN_IDENTITY = "iPhone Distribution"; - CODE_SIGN_STYLE = Manual; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; - DEVELOPMENT_TEAM = EHV7XZLAHA; ENABLE_BITCODE = NO; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", "$(PROJECT_DIR)/Flutter", ); INFOPLIST_FILE = Runner/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 11.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; LIBRARY_SEARCH_PATHS = ( "$(inherited)", "$(PROJECT_DIR)/Flutter", ); - PRODUCT_BUNDLE_IDENTIFIER = io.getstream.flutter; + PRODUCT_BUNDLE_IDENTIFIER = com.example.example; PRODUCT_NAME = "$(TARGET_NAME)"; - PROVISIONING_PROFILE_SPECIFIER = "match AdHoc io.getstream.flutter"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_VERSION = 5.0; VERSIONING_SYSTEM = "apple-generic"; @@ -809,16 +469,6 @@ /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ - 0BC14C59242B5A7A0028DE94 /* Build configuration list for PBXNativeTarget "Notifications" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 0BC14C56242B5A7A0028DE94 /* Debug */, - 0BC14C57242B5A7A0028DE94 /* Release */, - 0BC14C58242B5A7A0028DE94 /* Profile */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { isa = XCConfigurationList; buildConfigurations = ( diff --git a/packages/stream_chat_flutter/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Notifications.xcscheme b/packages/stream_chat_flutter/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Notifications.xcscheme deleted file mode 100644 index 9387f0d0..00000000 --- a/packages/stream_chat_flutter/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Notifications.xcscheme +++ /dev/null @@ -1,96 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/packages/stream_chat_flutter/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/packages/stream_chat_flutter/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index fb2dffc4..a28140cf 100644 --- a/packages/stream_chat_flutter/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/packages/stream_chat_flutter/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -27,6 +27,8 @@ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" shouldUseLaunchSchemeArgsEnv = "YES"> + + - - + + + + - - diff --git a/packages/stream_chat_flutter/example/ios/Runner/AppDelegate.swift b/packages/stream_chat_flutter/example/ios/Runner/AppDelegate.swift index e024c1ef..70693e4a 100644 --- a/packages/stream_chat_flutter/example/ios/Runner/AppDelegate.swift +++ b/packages/stream_chat_flutter/example/ios/Runner/AppDelegate.swift @@ -3,43 +3,11 @@ import Flutter @UIApplicationMain @objc class AppDelegate: FlutterAppDelegate { - let sharedDefaults = UserDefaults(suiteName: "group.io.getstream.flutter") - - override func application( - _ application: UIApplication, - didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? - ) -> Bool { - if let messageQueue = sharedDefaults?.stringArray(forKey: "messageQueue") { - UserDefaults.standard.setValue(messageQueue, forKey: "flutter.messageQueue") - sharedDefaults?.removeObject(forKey: "messageQueue") - } - - if #available(iOS 10.0, *) { - UNUserNotificationCenter.current().delegate = self - } - - GeneratedPluginRegistrant.register(with: self) - return super.application(application, didFinishLaunchingWithOptions: launchOptions) - } - - override func applicationDidEnterBackground(_ application: UIApplication) { - if let apiKey = UserDefaults.standard.string(forKey: "flutter.KEY_API_KEY") { - sharedDefaults?.setValue(apiKey, forKey: "KEY_API_KEY") - } - - if let token = UserDefaults.standard.string(forKey: "flutter.KEY_TOKEN") { - sharedDefaults?.setValue(token, forKey: "KEY_TOKEN") - } - - if let userId = UserDefaults.standard.string(forKey: "flutter.KEY_USER_ID") { - sharedDefaults?.setValue(userId, forKey: "KEY_USER_ID") - } - } - - override func applicationWillEnterForeground(_ application: UIApplication) { - if let messageQueue = sharedDefaults?.stringArray(forKey: "messageQueue") { - UserDefaults.standard.setValue(messageQueue, forKey: "flutter.messageQueue") - sharedDefaults?.removeObject(forKey: "messageQueue") - } - } + override func application( + _ application: UIApplication, + didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? + ) -> Bool { + GeneratedPluginRegistrant.register(with: self) + return super.application(application, didFinishLaunchingWithOptions: launchOptions) + } } diff --git a/packages/stream_chat_flutter/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png b/packages/stream_chat_flutter/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png index 6286cc9f763187f78f678193a66633449b2b2484..dc9ada4725e9b0ddb1deab583e5b5102493aa332 100644 GIT binary patch literal 10932 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 NeyIK+|DM^q{{wI=gKz)< diff --git a/packages/stream_chat_flutter/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png b/packages/stream_chat_flutter/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png index 95d13de016c50adba90f2c7c7cd635453462c743..28c6bf03016f6c994b70f38d1b7346e5831b531f 100644 GIT binary patch delta 540 zcmV+%0^|L>1hfQ@BYyw^b5ch_0Itp)=>Px$?ny*JR5%f>l)FnDQ543{x%ZCiu33$W zg!pQFfT_}?5Q|_VSlIbLC`dpoMXL}9Hfd9&47Mo(7D231gb+kjFxZHS4-m~7WurTH z&doVX2KI5sU4v(sJ1@T9eCIKPjsqSr)C01LsCxk=72-vXmVcK>PAbAwTqj;`=7>HX zM93AwkN~n3*c#^KTQF}AzdqL{zi@>Zh*Ssn#E}f z?2!Tdd=!N|E`LQqfZ!&&jLDjEQ&kRm2Au4n1MK0N35-SfX2&{q-XJr=-ElMh0X1pR zv9tJC^8;Ev)6EqkFe?kk}Ykyy<_40BYy$|NklTI|{! zsO%@+d-N9FxdHAM73=FQCO>)NR92;6``Q2}t~h85TH~6UrHZm(h8HXG@9XeOmu!Fe zSHOW6E=L-J^gT9c5wu(aBkKa}J@Xa2M&Zd>s@vgOTZl)`TwKo+62*oFi%WM*wZf5C z9_R87;U$Xe4}T52w`vN5278(M`LVz6e_AFWK=+4T8tN?W4mp+BS!>uMOg*U(4(RIsEC#g=! zQ$O45R8-Z5q25-UY7R2`e1upmMkbSC&59t$n-uA+Q-9rMpQZDr;n*I{;M#qfxpG^8}P>q2>HEM;kSV4xi?o%xfxRxc$VPAE0j^ mzQD<={v8yUs=I&xZ}SZ?Ji0oR_DVPa00007ip7{`C_J2TxPmfw%h$|%acrYHt)Re^PB%O&&=~ahS(%I#+V>J-vjIic7FmrfXn)08SZW zzL?HZgo}SSNcu|m&n`&XRLWEe_q?Rh_`)DQ!Ucc|OZ-XFn511rB_$bP9dH@wh-Ggo zqynVM3)3?_gVf#>E5u8iY)EMfQ#c-AONh%-O{IL)jaDpDp>fGZ;* z&NNa1u7PwxJb%(=S<`N2yPs}=Qd>tT)H6o27G=V5iPc4VS!_#@l|b>qnm9t zrveTdNw3GcyxNRs+YhS;I5HWpo!3ygInT3 zP$EweZn5FmW{(G2OmSWnlaVUrTdi!)jr#2-s*s1Y*W_xKW$+MV)+W zCJONO)jWe^^@a6LPGuFcfUl@%=t@<;i?RwP48wWx&VbMLbZu~j*zqUV3tSiqXmuv* zLdA3PVSjYZn;Sj4Qq`Z+ib)a*a^cJc%E9^JB;4s+K@rARbcBLT5P=@r;IVnBMKvT* z)ew*R;&8vu%?Z&S>s?8?)3*YawM0P4!q$KvMmKh3lgE~&w&v%wVzH3Oe=jeNT=n@Y z6J6TdHWTjXfX~-=1A1Bw`EW8rn}MqeI34nhet(}(@b2R=TnMg(!~JoOB@~U_c{58&x0vLE`&u6Jl1aUEMx=WS<^6F&44hq+zu3- z_YL@*xZ%^Cib8GTu|*xK0`9Mn-Pm>9AUJNoFl&j-KxEN_kAlACY{ z$$uG-fx8)AdpOV5PKzI?;TLyZ)r=v66R`IomuI>x!+GH*&chH~4;$pUapo+qzkiN9 z<5@h%5QL2t?hTdv#T`vf9JrKYa7=W%A%T-Zg*<e+2=O{vx$^4} zFC06^KjT>(Tk|t13k)ZJ8iKTjKw?FACl`;u#Kx8F_~|Syo`Y)*u46%BQD+-het*Bi z?&DuFlF8#(Lxtca1NV%iv%qemMnJ6c{JImlNL(npL!W|Gr_kxl1GVmF5&^$^YherS7+~q$pt}{a=*RiD2Ikv6o=IM1kgc7zq zpaZ;OB)P!1zz*i3{U()Dq#jG)erW`rGV!8YiTcE;xq_^g1lF2L%K5-fW6V#bE#SS9 zvT+;sezt(~lJ><+Gy2p|Ncw&Opk}j6l6FjiD+x;i=}0=DsM|lR`BgEDeVmu{s-k?D a0{1_&;gnn2jcRKE0000lNklWoUqHR^*Ry6wOA> zoEp%`|jtSbMCq4SstBx!^Ax-%YT0j(3ZLZ{Z%)hzv>3` zSKWaAsvFQ>bt>S@XGH`C2-tQ=hahy$Gdm4%$_NpwX3G#o0jlQ0&LX2zp4%yaW1bMO zE>=c86-Ml{B1*=UIt2$S{fG1$@W~JXY46x@{*r+mg*t3jW=#nj=gEj#>%y_~{#A3$ z0D}U6mq$uyY=1IQ*Jz^l22k5T-|1dQ7BURM6JL)61KSqK{QuaE3PwC8@wR!J736(j zL;6A)(^t9h`xSS8lUPN;#Qi-4^b7lU@7=m`hgu zf&hnwizq&+;iq4jR~U#1`+dNK!4e$(M6$Yol2aP?AJb{1FMKmVlR7Nfs$$;?5t0aG z9@Oys5Pu0hY`{0=Iu2CoST|ROZkSkk zTq17(oAzj!I8?;YFp} zkD#C+-nNoXp&zQ7=pixnGhjHQ$4TfO~&Y^O3y3<(vn=oJ~4YYo1_ z1(QX(te##hN3t9|Yn=PBe_k~x&8UccT=Kxh#Kd^u3JVK;;BG0>!TNUy5U8g_9iOIP z;S>v6IS6pI&iD7F8h0%9c6$$5S$|o`&d%m=1qB62OiV;sSs4Zn9EiNUJlO4a-Y?kh zeMX0hh2u^WZ*5XLGKA~eb@x3sHWp5&lUp$%Ap!aM`3MgWM|yg?2af6Xbkijjb?GUc zaw%C}6p@^qjI^{g4#$*{k%9jG`}_7kt#>UTJ1r7kGw^V4_eP0}i$i5)C4UEvii*PF z!-wH;IC$Ijn+(&2DVjEa?B)Of002ov JPDHLkV1fsgxb*-4 diff --git a/packages/stream_chat_flutter/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/packages/stream_chat_flutter/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png index 6e6c85b6a01e6b882444ef9d8b0d790809604aa9..f091b6b0bca859a3f474b03065bef75ba58a9e4c 100644 GIT binary patch delta 1572 zcmV+<2HW|z60{7EBYy?^Nklc)UfJ<2uenUn3ARN>mf|M z+(eagCX~wv_9N9Br6dE4W@{R1X8yU75JVAXqB_2?1W&7xoYHg zkR5NEVWsUG^?wLzRHH9Aa#eCDK9NvdPE(De9-HaQc(6~^lpTe2pm3&x9G1K5Xawdi z4F*DRWI%>vgEBPFqaRR51|&E>B!fiay027YsK+Vrn=1PqDKdi{m<&P1nQ3_Gw<%cH zHU+slT8moWCbIKH=(W3t1j5BNfsIKQ#Mzi(J59kx zT!xVJ&SKqb4XjdxWQV7$IrZ-{l-x3`7M}qzHsPzP1S_$c=96h(q%b9ZXPvcV z;D5oPsau6Q(U`-YLD*G41z_cgz)a99av0W_U=aHAj?mj@2KZI50efIA zO8^kn_?FjaZ_hfbhSh@3^GzxJx*P{Jc7Hi*OHPZ!wvEV2a9XKq###zPPeRs75i0(W zU?doBGb9yqT58~qn?wQ4oCi3oWdc^W%JAgTVR)*l33@Ky3ip4Rqz14Wx_gwsGYGq) zMY~B;*z8j>WF8xV`^#!USYHDVZf}I{OZGzBnutHA1D(}!4{};5>;)mO27l7F zHh@r23lDAk8oF(C+P0rsBpv85EP>4CVMx#04MOfG;P%vktHcXwTj~+IE(~px)3*MY z77e}p#|c>TD?sMatC0Tu4iKKJ0(X8jxQY*gYtxsC(zYC$g|@+I+kY;dg_dE>scBf& zbP1Nc@Hz<3R)V`=AGkc;8CXqdi+`PV3Vc;#lxQO~AoO*}pfE+=*r3ffZ_YMC zflq>i%a-`Xw)YRuK;MUtq{SGa7vtY^gg0bKSp&F>y|A>h5qhqSvgdtV{(lh0c$xz5 z;*U?KQl%W)htLmD=yhL!@aldLHW(=H00^&qu7J0mA5v0IaX@pn_bKobsC(e>(nAjI zzjyto3Dmc!oOxjlw&JZqeL%+vsN0Zy8@1@rs~rRNAqO?umG&QV WYK#ibz}*4>0000tiPUY+iMC<^G> zQ9;%ovsK^Us)R=k5b)wO7g>h+kJ|CoMFl(m*?OPVT8;34UO?6?I~+CvmgOSI-1#q4 z9jLgh;P9!|A%EQ}gd@U$oH-733K4Pcl8L<^83=I*xTm*(0g)0i$q>nZR&cuf_Rr39V-GP4L5^vY47A{qpsH_4i$pDqr?q93HHH(bn zIe$LQhLQbc9<%e-DmZYWah#Tt0j857*a{EnBjNR5+c7U&MJFm-p&jUG4{r3(_OA0V z_S=E3g@3s33kaiM79tE6Doy-gK^@JvY0|z4Q-7!3^H4iFZ`VaauP#1~=M&5FRctS@ ze0s-0GQ{uKC|L1J2kwuSQL_BTBh6t$vtHr1q_O^dG%kg zPDM>KA zC4sDNVA`uH6#e>jGBeQJ)f!JkV+PB3g=DBn>T}ycoxAHtUsw%-RKU_L2Ad^ceSbX3 zuk3J+%E$a16&W*}Bo-uEMH%TE4W0?N9yDnaV4`Fw>689uGDyvQW;|*+wO|%} zK3Bs?is!o{BrKb3M{If>uGCyRx_~33i;tYr@h6I@*kLZ0pAl!n2d52ed7sHjSNVt= zL901h#@Hbe{`IMWReN;2b;Ka?;Bi@ofsx>wjzLjUlXGLCHZexT1WIJg^?#q+s8JTb z&N|!_n1Y#|sbbp#CzTKpOCPskW`^d|q^$q;5|buj(#mNxDGAT~%tmEQgYjo=tV&CnIb~8EYcqGP z5)szx+c!m+ts0YaBdG4)*;ArKB+$A4L-y__dbNv>xhBTqKRndq5pJ^8)z!T1CVTSa zNt{3LNgmPB(FhL@_Zl;*`z=UX4Z(IM(_U6-H6=)5%l(@}=~-8{x5k zjpbx_?b?Nulz$Xxn#QkBm@omkxw(zTba*?_t@*^mGW4R&M#~-jM0Fjj;a2^AJS!`U zyE3b}`T6-i$=dDqMq_<_#k<`m|MS3BmzA+$ce&zNmSt?%umP&7qPV!&Z?X(*oQ7zV zgc+Egb`xe`q}j1!$Bufk45_K9KFPA=x98|Bsl&G)Z-4AFF*DBMb-p1oGBQwGTZ{GU z*YkE-S{nalt9~usq4N0YIdApWW(i-Z1y^E=ANMXhk|ZHJJDZ;~(uQGR(xgfJdUA4d zeZLyT!lGQQk<4$igc&yOGcfc{jr6*As&$i&ii$#6SsA}pP*8xFm>5JxMv~aEFn5)L zvWmuIwts2DOoq;1r_mPF!nB8NUZskWUb19KqbFG3xvLd&=cfO4)5ZzAKKU%BlK0Ms zCgvr|7}kWoX3%sCI}YnuzE#J$O5fwPdBO~AVGq#`Dsicb0lhSg9xS3ycM(pTz`u5| zFQ@xHHt75oebZ_yU@m>C9CWbSdhH(k7Jt(U6eR=+2Red;106xafsSt-;r{~zucsQm SrJ%e300000sYywyRT@!HH?E|j zMhb#%s#4upT=)UH*V?AKa$!XfDp{yYMM4EjBZ*)|sUM-0QcIzVVEUzzCX>V@GwETqrXGsdu zA8$)?`v2seloOCza43C{NQ$$gAOH**MCn0Q?+L7dl7qnb zRdqZ8LSVp1ItDxhxD?t@5_yHg6A8yIC*%Wgg22K|8E#!~c zTNYR~@Y9Kep?_ava@M;M8kmViU%_&qKVn19EJb6L%o<5ryPpl%8u^fhsfT?9!(e|z zYg7{msk{Fg=+Yccm!Y>{*q;KO>K8^PXf0r1U?zrb1;c^{Splu&<;=9>z4K+dat5se?oWZUF&sQo;?$JL1+gmMrdqaw4-)Uy6fE`VS`NRWHPm9hb$Oljeq3qzfzL34WA)&3E*EQj_ z#)s*NZh!yi@GmiUwp(6LfzxI2{CJ7UMd-?TP+;I{8J_M5c&a;WSjjcpVCBWnFDBgE zY1z>1fzN(l;@ioDEiIOtTMPkWDu!pahV1DHm#V&=)a||1#W682UO8Ff#AHHe&ajZc zxl(1kEaPYZ6hwubN6i<8QHgsu0oE)iJ(p;Wxm>sf!K+cw>R-(^Y2_bahB+& zK7ZsKxz;@6=dLht@F-X3N(9#6>iA+L6@m3xzycB{LJO~c@)K`<_zg5y-Q>ju`fuOJ z$ZNaU+|lB5Y}R-@XC#dRJIOdB32iJUA<4bXt Z%s>0@A=V4gM}zB8us0F~tW_Y#5{ z>Y&A^-v(oCn%nrY;bMBSWI_B}lR!&W%Jp~c1%E5o>6|4ED=kr^k%pttL$78z zTaIaxu=l6oKL5u>dLw2qXS%_?^Ia?oXB=PH@XE_o9`L(p>oVBYXAb(y;?naJZn|0} zvCrazT?RX(ar3THxKk=-t7NMsFtHH%p|*4nzn0~lM?Ea5bV>gi#J;v<)j6dAxuGh@ zRW2%4rGG!+vmT3Q-_<$%2VCM6Y<bGKKP~_N}#WsV2QYTTGuK_+h``%kL~+x=*8cl0rJ2rnIN6MS=FXH z@}GH{z&}eJ0@l>j5RFD@Z*P~t3TM9?%3b)pIz372*vVn_7M)o>m8Cbjo&Ftj-NW85 zt;+RpZyI36)Ev<7_dCGW)>cxf6tP%r2t4CLF*?-FtqY${bLxa+=h%Mvn>Bx?bb+Q( zR)1DTeSJNlP>5tQNk>P=&^&!Gaz;&qx&$BieY9DE?R!jaog-*$Y^1rlnRq--Lqh{T zpU;_L%A5ZA9`pF1$6K~^nbcJoGK5qDfdGj_f?zO+*XyOWww4Va>HPRBV+*yVyGzFP znq?YSPE!eo!_Gw01{XvNDI|MgBm1gF}3YSf>vy&o|gF){v<`8hq qp}8XH+H1*bxrB{?psZQs88ZaedDoagm^KF{a*>G|dJWRSe^I$DNW008I^+;Kjt z>9p3GNR^I;v>5_`+91i(*G;u5|L+Bu6M=(afLjtkya#yZ175|z$pU~>2#^Z_pCZ7o z1c6UNcv2B3?; zX%qdxCXQpdKRz=#b*q0P%b&o)5ZrNZt7$fiETSK_VaY=mb4GK`#~0K#~9^ zcY!`#Af+4h?UMR-gMKOmpuYeN5P*RKF!(tb`)oe0j2BH1l?=>y#S5pMqkx6i{*=V9JF%>N8`ewGhRE(|WohnD59R^$_36{4>S zDFlPC5|k?;SPsDo87!B{6*7eqmMdU|QZ84>6)Kd9wNfh90=y=TFQay-0__>=<4pk& zYDjgIhL-jQ9o>z32K)BgAH+HxamL{ZL~ozu)Qqe@a`FpH=oQRA8=L-m-1dam(Ix2V z?du;LdMO+ooBelr^_y4{|44tmgH^2hSzPFd;U^!1p>6d|o)(-01z{i&Kj@)z-yfWQ)V#3Uo!_U}q3u`(fOs`_f^ueFii1xBNUB z6MecwJN$CqV&vhc+)b(p4NzGGEgwWNs z@*lUV6LaduZH)4_g!cE<2G6#+hJrWd5(|p1Z;YJ7ifVHv+n49btR}dq?HHDjl{m$T z!jLZcGkb&XS2OG~u%&R$(X+Z`CWec%QKt>NGYvd5g20)PU(dOn^7%@6kQb}C(%=vr z{?RP(z~C9DPnL{q^@pVw@|Vx~@3v!9dCaBtbh2EdtoNHm4kGxp>i#ct)7p|$QJs+U z-a3qtcPvhihub?wnJqEt>zC@)2suY?%-96cYCm$Q8R%-8$PZYsx3~QOLMDf(piXMm zB=<63yQk1AdOz#-qsEDX>>c)EES%$owHKue;?B3)8aRd}m~_)>SL3h2(9X;|+2#7X z+#2)NpD%qJvCQ0a-uzZLmz*ms+l*N}w)3LRQ*6>|Ub-fyptY(keUxw+)jfwF5K{L9 z|Cl_w=`!l_o><384d&?)$6Nh(GAm=4p_;{qVn#hI8lqewW7~wUlyBM-4Z|)cZr?Rh z=xZ&Ol>4(CU85ea(CZ^aO@2N18K>ftl8>2MqetAR53_JA>Fal`^)1Y--Am~UDa4th zKfCYpcXky$XSFDWBMIl(q=Mxj$iMBX=|YmI251~yivIq~R&BEMfj?csA(oV`># zs3(V(&Jez0KXStU_s_4VlrMMwcxN^M*&1zonMU3RnW^USAxm3|-EL&WqH56Klf zH7wg<29Vg2Z=+eHhF?DC#KisziZ9q$^A{7YaNvP(0gW5dMeW8B0$dTGOW^IstQ{`g zxcB_7o4^b6ReW{sE{Qg22(*e4AyU$da#d}q%D`mGjLe8_&(|^Q)2cnSG{;2qCK|?) z=QCbZFzZF!lUEs{TmliT{5-x&qQ^^sk3QG&(`3c_%&l42d&ESU3U2KtWJzX_Ce)4y z6TR=TiL$94JZ|8%e$4N0u$vb>)3{adTJjn zAZw}<;Z709icO4Ls6jRE>>Xx^$xC%)PZiLGqI0=sW6b+*6r8Z38{8a3%0^O03B!6w z6u>0>tp%>QqH`8zeyrbC3AZJx(Ih7>(XeGk7$tmxtP1p;R*u2lCGxb4*(9|s z2Mm0cXX3nerK(Q`Qw~O>>y*$zf6*}h2^;_ z7erH29jyt_Bx*J>_GZ+3jS8;CJzcIJPo|P*1+s_IuhHH<>O_N zwuHByckpkv<+Jr1oL5=()UShtl%5igsC$nX*hqbBJz(A_CP=1Ke6)-b(6o`jCH?hz zi>oXc1Vxlt?9D6#o!UrvxQU1bsS1Y9QDIsh5<1Cl`$3y7ozjwqVMKVsvobP%qF`&j zfsgkX6qo`n&%E&jsbU1FVhAk<=FxR~4H`>B$wlEtUKG&g5z5KbUox%HM&Y90_bhIF zLjAAXYu>iH3c517LX()hRKwb7PQ*q__{A`piU2bpNnf}o@SM49he5$YotR|f!$}Gf;sU2wR8)lA++6Q{Y-}vLb?b(8)5FMMD#<=@ zPIq1FF4|(yBqelcEn(hR1xataX`NIq878f`XeLbu26dIVDo&p_c`9BHqpNuD`#27UVU!O4>+`F-ckow0N0PTmf83Rp7Hi2)gIiqO?0YLT>F zTkc6Y54uFWJ4WHM^PS|wE>;3c{Av*?QcyDR3cbS=kT%G{3yc|SG%}Weq1`EJ(-w}E zkdqdxIPx{nwk1X1#K7W#k?h;Iua{)UjvbMclLMElqI8R(l6B@t2TyOlG2xzeFQ>>_ z>8n&M8XrbUT*lbGCO-YE$#dOM3M$@$a#|D!dttTq{FdGz)t7 zfhfauw}2_jRD3cmj8{d~!R6~75Bu(vN=i!5yLayZxgI=t5UW?O_P#f2)F>n+CHeKo zb~3)G_6Y-9XYo}3vH(*ZT;fCp7*@rzsHiA(>C%N0y(!m2hYn%z;K6Xa-Ta-@)Kv8A z*Ds(y!}PzuFGndCDZN|_vJ|Tt9z&fuU$J&&S;m?*YY-C?gS50XPIBPDfnJiMM~}vm zB}*!;bx)u7&!u(lr2c3z+kaYA&w2_AMt0V$StuwdK>z;zy(Ago%*;$kl2mCw`;Yp& zw9XM_d3xhM!*9dS5EmDRl#~=?XJ_;KUAuN6FE08N9d2Z#(m9)_ok(HH&($Z247%+gBf~@@W#p>M#)zJpcdz diff --git a/packages/stream_chat_flutter/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png b/packages/stream_chat_flutter/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png index 3ab319af19f5e751718d55411b14d25ff4610565..dcdc2306c28505ebc0b6c3a359c4d252bf626b9f 100644 GIT binary patch delta 1906 zcmV-&2aWik9e@vzBYy`+Nkl^fDmF(5(5$|?Cx}D zKEJa&XZP%OyE`*GvvYQ4PV&!g2|L^Q?YG}tx;sY@GzV#^0C$Z`m}blr)&(OPMHT6T@%AxHOWYGG zm>@=0?<)?0r0XK9>leRXyD^j4O4bXT!@LESVI<~>`yB+S2b_f__vvyMHkwGyyXedq3usx&X*}E{O;}+nJ#G_xm zJbQX5 zuFrVK*|x9RQeZ1J@1v9MX;>n34(i>=YE@Iur`0Vah(inE3VUFZNqf~ ztSz{1fz3Fsn_x4F>o(Yo;kpqvBe-sbwH(*Yuz!}~S^-;|MX;9Py1im8!}VY-!u4P+ z!nLEvx?+Rogo+Kw9OBXy&lGIvJ51_7Hl6Q>*MAJa!lMDGGML530`Te&0ciU({DC7` z;RKg{uC>($*mdXnVQQBjiVyqYC7mf!Z%e-Q!?Oo{ufu`G3CAC=UjiTpU<94UTFz2KEDuNS@KKkg)K8!v1L8RUP$_! z({LG$Dy&JLEVpiNVe^G(HCbA*SpsX?292)#=JVQDUMp-cOJPl`+yTHTD!AOit-zAD zptXYa!q%OVLa^mo25b7^Z>kE`3rqgr-G4i;Lw<+P(8khESW8aaBmxfY`WS#6j<92Q z-++&Y z$gbH4#2sT0cU0SdFs=*W*4hKGpuR1QGacHFy;`# zR&NJkbTNp}Ee5f08HmLzK%D(q3@lH;Tzx$?VT;&xJq-KyHV__o3dD)?KrE<6*iXV0 z8;6<{IKw@dyDwJ90H5^3h;|9?twz{UGr|>1Pzhdn6W(r0ifeZd=JI+AAz<~yL(QJk zAWW))+=`8mGj|J!70oF@d4B;WxB=jBM1bWWRBb&1!ie3BUzOdm}yC-xA%SY``k$rbfk;CHqifhU*jfGM@DkYCec zD9&E@F9*za0?~OQZiDE|Cf;;0 z`uZ%H=IeGyG^H0ruev{yIVARgwZUG)j7>F#3~dh+8DOtPByR=(VDhz2enf#EjcXCI z=NUPYr4@S)GhX!?s(0Eh(nGe!y$#$r1B$||I~`wPhUuCQEo;#Xb$EXk=6HgBBRd#c ziK|jN$e~{zV~|;*E@Ij-Z(+tI^B8RW51ptE!nMnPyZ`_I07*qoM6N<$f^^1=6#xJL literal 3744 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 R{*OF~bU=ohwa=ij{{u=RJS+eJ diff --git a/packages/stream_chat_flutter/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png b/packages/stream_chat_flutter/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png index 5ad80187a2b9d75d67946055753881cefd525c76..2ccbfd967d9697cd4b83225558af2911e9571c9b 100644 GIT binary patch delta 1264 zcmV7ip7{`C_J2TxPmfw%h$|%acrYHt)Re^PB%O&&=~ahS(%I#+V>J-vjIic7FmrfXn)08SZW zzL?HZgo}SSNcu|m&n`&XRLWEe_q?Rh_`)DQ!Ucc|OZ-XFn511rB_$bP9dH@wh-Ggo zqynVM3)3?_gVf#>E5u8iY)EMfQ#c-AONh%-O{IL)jaDpDp>fGZ;* z&NNa1u7PwxJb%(=S<`N2yPs}=Qd>tT)H6o27G=V5iPc4VS!_#@l|b>qnm9t zrveTdNw3GcyxNRs+YhS;I5HWpo!3ygInT3 zP$EweZn5FmW{(G2OmSWnlaVUrTdi!)jr#2-s*s1Y*W_xKW$+MV)+W zCJONO)jWe^^@a6LPGuFcfUl@%=t@<;i?RwP48wWx&VbMLbZu~j*zqUV3tSiqXmuv* zLdA3PVSjYZn;Sj4Qq`Z+ib)a*a^cJc%E9^JB;4s+K@rARbcBLT5P=@r;IVnBMKvT* z)ew*R;&8vu%?Z&S>s?8?)3*YawM0P4!q$KvMmKh3lgE~&w&v%wVzH3Oe=jeNT=n@Y z6J6TdHWTjXfX~-=1A1Bw`EW8rn}MqeI34nhet(}(@b2R=TnMg(!~JoOB@~U_c{58&x0vLE`&u6Jl1aUEMx=WS<^6F&44hq+zu3- z_YL@*xZ%^Cib8GTu|*xK0`9Mn-Pm>9AUJNoFl&j-KxEN_kAlACY{ z$$uG-fx8)AdpOV5PKzI?;TLyZ)r=v66R`IomuI>x!+GH*&chH~4;$pUapo+qzkiN9 z<5@h%5QL2t?hTdv#T`vf9JrKYa7=W%A%T-Zg*<e+2=O{vx$^4} zFC06^KjT>(Tk|t13k)ZJ8iKTjKw?FACl`;u#Kx8F_~|Syo`Y)*u46%BQD+-het*Bi z?&DuFlF8#(Lxtca1NV%iv%qemMnJ6c{JImlNL(npL!W|Gr_kxl1GVmF5&^$^YherS7+~q$pt}{a=*RiD2Ikv6o=IM1kgc7zq zpaZ;OB)P!1zz*i3{U()Dq#jG)erW`rGV!8YiTcE;xq_^g1lF2L%K5-fW6V#bE#SS9 zvT+;sezt(~lJ><+Gy2p|Ncw&Opk}j6l6FjiD+x;i=}0=DsM|lR`BgEDeVmu{s-k?D a0{1_&;gnn2jcRKE0000lNklWoUqHR^*Ry6wOA> zoEp%`|jtSbMCq4SstBx!^Ax-%YT0j(3ZLZ{Z%)hzv>3` zSKWaAsvFQ>bt>S@XGH`C2-tQ=hahy$Gdm4%$_NpwX3G#o0jlQ0&LX2zp4%yaW1bMO zE>=c86-Ml{B1*=UIt2$S{fG1$@W~JXY46x@{*r+mg*t3jW=#nj=gEj#>%y_~{#A3$ z0D}U6mq$uyY=1IQ*Jz^l22k5T-|1dQ7BURM6JL)61KSqK{QuaE3PwC8@wR!J736(j zL;6A)(^t9h`xSS8lUPN;#Qi-4^b7lU@7=m`hgu zf&hnwizq&+;iq4jR~U#1`+dNK!4e$(M6$Yol2aP?AJb{1FMKmVlR7Nfs$$;?5t0aG z9@Oys5Pu0hY`{0=Iu2CoST|ROZkSkk zTq17(oAzj!I8?;YFp} zkD#C+-nNoXp&zQ7=pixnGhjHQ$4TfO~&Y^O3y3<(vn=oJ~4YYo1_ z1(QX(te##hN3t9|Yn=PBe_k~x&8UccT=Kxh#Kd^u3JVK;;BG0>!TNUy5U8g_9iOIP z;S>v6IS6pI&iD7F8h0%9c6$$5S$|o`&d%m=1qB62OiV;sSs4Zn9EiNUJlO4a-Y?kh zeMX0hh2u^WZ*5XLGKA~eb@x3sHWp5&lUp$%Ap!aM`3MgWM|yg?2af6Xbkijjb?GUc zaw%C}6p@^qjI^{g4#$*{k%9jG`}_7kt#>UTJ1r7kGw^V4_eP0}i$i5)C4UEvii*PF z!-wH;IC$Ijn+(&2DVjEa?B)Of002ov JPDHLkV1fsgxb*-4 diff --git a/packages/stream_chat_flutter/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/packages/stream_chat_flutter/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png index 0a94384d619884c1e08692ac2e54434601202c9e..c8f9ed8f5cee1c98386d13b17e89f719e83555b2 100644 GIT binary patch delta 1881 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 P00000NkvXXu0mjfs#qFw literal 5281 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 diff --git a/packages/stream_chat_flutter/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/packages/stream_chat_flutter/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png index f049762f057fca745ca451c25a3f1052195be542..a6d6b8609df07bf62e5100a53a01510388bd2b22 100644 GIT binary patch delta 2657 zcmV-n3ZC_$Dd`lDBYz4oNkloFh3q0M zFesq&64WThn3$;G69TfjsAv=f2G9}pgSx99+!YO}2Uveik)GA5ewEg1Va|1@=x;Pyj3t}zC)T-c zzoz+u9TyK|)jteh(` z;D6}gLagCR0hn*76kN#wCv*`b8GyswI1s7kNaT!{fEXv;5ofK|nu3vU_1cRKLBd@TQ@Ei6F6QJ?HM!O!+{x(L<6rNAv)=55QOzlPWhqI{ zjSR5c$#aW1xy}c;$06La(Y*xlX>0w3EDGGn02k}7*%ZplRLFsw%E3MJO@BuPkU#Ja zcbp(_BL!RxGHHe;wff^+2G>u>ah(dq7O)#K0ekx={yBF*$P%aJSOMmjHHmAxvW0cp zt8@K;ETVH`1(=8Ie(Z;Hy+9V#xv>Mxz*+%0w;aeKJ2#eqVJL7nrpksp7|5bKS2)0a zId?FSYb0>4P=MLsl6(J^Q-5;@54jg=+fq2sO~Hz-hVXEO0L<$0j+BKdGX;Npqt{os zJmk~Y_Q1L83|RfW)5G^!;(u>i7{EI*HIqAp9`Cbzna*hHhI2Lm9I{{?%y{Hgdzxli z7Fd?00Ed;L$qk&zI`y$@{Dn;5j(iW`=!aXNV*G=kjb8%Qi`UtJMSq7ZT$4qCb{TaXHjb$QA{y0EYy*+b1XI;6Ah-w13P)xT`>~eFoJC!>{2X zL(a_#upp3gaR1#5+L(Jmzp4TBnx{~WHedpJ1ch8JFk~Sw>F+gN+i+VD?gMXwcIhn8 zrz`>e>J^TI3E-MW>VM=sWZual)ns9B%8_$25BcpOz+KP;+J(1(UiAp*Q=dc!FQL}*R43bTaVm7wy#IrC-VD&k-4FWYMd;wg6!1z8a3SP;O>P#-$->_l zEAM2>hI~v3$Y(TlIdJE^0@|6AK_7#uc{~E1^f2gGJ^}i)rGJ>FDPRt4F~}m-WGQZK zw?8N6;NJH#XeW;Webf!0kG=!+v2#G5xX^L14Y#o*Tz9&z7NjOib92f(6aq==Ntoo74a!u6w~r!$mq|FDi7h6+6fTa4$$0Y>@Y*O}J#< z8ic&ucAQ^e_cw)#3uFTLcly|p7IMmPAXha6205mSA%EQja0eR?DV=N%;eS$2zHI*MpiObUuA|j7`m5?j`@^G6SO!-;(G1aCOu{sGli$ zGck~Eqx{gt?U$`9P3JRJO>}Ku- zRew#6AKb$jGi@lro`A;#P%m@cnyJP&(r%f}Zq^V3mIc=hnLfVXHRn=pj;2#4v8WiM zav|%So5|ksmkM-bV7H;F_%f>b72G`eFJ!d@wTC-#ALO^GRCtHl=K|Y}dX%fTm0A$N zzc4;N3AGsYM~OOND&T_#%8wZzWYfL@by`|620=mAU7(LZ-At!cdlWCvu@AK#bt~#< z9;~k^d5}}7VXmK@h?&@_rUHYJ9zD=M%4AFQ`}k8OC$9ssPq=LnkwKG P00000NkvXXu0mjfs#qFw literal 5281 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 diff --git a/packages/stream_chat_flutter/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/packages/stream_chat_flutter/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png index b51e00a7e59da211b022b622a91217b0dab107fb..75b2d164a5a98e212cca15ea7bf2ab5de5108680 100644 GIT binary patch literal 3831 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 literal 8289 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 diff --git a/packages/stream_chat_flutter/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/packages/stream_chat_flutter/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png index 8c4973081f22d5f81b781442cb0eb6b18514317a..c4df70d39da7941ef3f6dcb7f06a192d8dcb308d 100644 GIT binary patch delta 1874 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 diff --git a/packages/stream_chat_flutter/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png b/packages/stream_chat_flutter/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png index c59c5739cdf36e1185d8a74be7e78ddfee41238e..6a84f41e14e27f4b11f16f9ee39279ac98f8d5ac 100644 GIT binary patch delta 3291 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 iW828*gmX;8ZTbMgPiBcccDL#uI! zgTv&bs;FS#k9(9uoC%zv?ZalNiY-6}dnTpP!0&4MEn(0wJpyioY**CV{7+}x2ooG# zY65Cp-HNoQ^G(*NbSA zt;mdq34i5^i`#&NgGQiBGR5-4)|2t>solgqRq0o@^l(OM-#@D z&ZF1aQzvtxj6Q@Xyy~Zd*ayLfS)B=js2GP^ez(g_xMS5 ztH2Rcl*6y{GId{5J<(U}C18&woZ5 zGn0YFwTTxeeB&ADnZMza6VW+7ar*0M;s|IFuOnV@yb>hQ*6fgtR>j2(Z;=jCpRU&$ zUFUYzR~Xjyx36tVj$3MHv7o)PJ#=JMtIn=r$s%ZHOpM+v%GVwvXBR3S+14@a9b44APN}IIf;EVpXrs!WY_gfaRBiLatxv~Mu zR6wB@nn9(5v|b;j5UE)mvta3V@Hc>K8H#j&(*h=U69j=?ccFX;Gc4pufsI2ign8Ni z`?*DT&)xtwSZM2ZOa?1sEcf-p`}(cNS4!8)a4M0eyupbmPVp2 zU&}_R8oN<`K)bCjUiI$vRV~O>@~MokvLT#8tj>YT;UC)~e^V&|B&k9%Sky-lBw@&3 zpSq#vd5y4YDmG=y**M#S$FE8ImPwK zaI~esSNhWc`zZHs9&_e8VhgdjIe&%m8oy8p9+^r9#-G>VXoT~Rf`zDb-s3tDWD>qO zNDoTz^6&50`2%*5@hTkt8)=9GeA2_bHAo4i-=eS4l4N1UyA&fxv{j4Ab;I8<&60mXJ4y#1p%`Y+^*PbkJa z7PE_IHakgY-2JF!zRhljlDq5^i7w5~vM*`i3cDZ+TZ6Cxb8ejMv82~ui%}x>-#mZ6 z?xU9J!k*C#+uX6DjtoyPuViOam8wS&Wvsb;dB?==!;T8N-HPYMum5@mWTN2fJ!>jG zL-xvX(amHseK#j7u=LE1QsNQMjq$AA2GeQtO`W)y@Trx|g|&G`2G%Voot$gB=Wj9? zE3ksgD2WPv-=8u`tBP?u6a~2Ip4tC+JI_ZUcAV(0#zwv84ok;}ywsD|>wveHvS$${ zI`e=mQZmQfx+O2K*y%nVu_A|62J8TfbB^7H8xlX)FsDLv>8_tc_Q5LdGc-$K7>2gp z>8^PaTFtoExviU?>tEs}UE2H|JD}4(SS5r-HKHkBNM*?Zs9O;h7eqo!&2O!sP=v*c z4Tm!VMPW`rM!YyqT{GB`{`erMK@LZ-=L-tNw_NgURW2JY0bZZD%K7)s1hL`#U+Est zc>=q|@QEXQDZM69!AHC-*~X1g_9Q%MPfp*?`IB{6p;9!5>C8E8kF?U1 zLJy@CLkn_L&pn8>31tgw5}qk{+=fc(cZ`*9-KcQ_Oiogm*a5^I{{lJ#1foRWTN)9& zNphjHO10eZAOfR>15VodGNW8(Jn`?Vr&o=U3P@Lr2Y!5EWOPY*Afw{vIn_Z1Kk@H#YBHR0b@~{jC>C?cZ zvXb9;tg<2Lq-ipqkfdIGd1ndG>TDqcXPkpPpt5wZOwWzkR8|57{Z7a#wbQ+vMgno zrggZ5S7P62l*kS*<#p|ysw^0^ohZ5h0@s)w*&cftGT@wiIG)?#z{;Z6`uQjE)E8g~RoZDTaLwv46l`Q)Ej7f|%&HYyi?36h z^3`|lI>ewg(98dfnPe&*k^?U2lsO!|-_v&LsUwwL{@5C3$zOSRQ)NQL06>_{e6}^8 z?L%Lb?p{>stN-Z3)2fbt@5 zsE^D3XMCJzJY8boNdJ5;imhac{-SUgnmT^JQ)PS2sZFkg+tsrcj_JghTy5GXccl5+ z7|jyW1D9eJK&~=hqzmLGpy@h6K`F#?@zhCjvMx5`;|Fx*ZJ8azFkq?Ch*aDA+_))iUYI%C{ABY&L&s4?tPS{w;U`^{OtR8*z8

    wfbU}SOG#?y4 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 z?Id5vRSfdlyiCFBundleInfoDictionaryVersion 6.0 CFBundleName - ChatSample + example CFBundlePackageType APPL CFBundleShortVersionString @@ -22,19 +22,6 @@ $(FLUTTER_BUILD_NUMBER) LSRequiresIPhoneOS - NSAppleMusicUsageDescription - Used to send message attachments - NSCameraUsageDescription - Used to send message attachments - NSMicrophoneUsageDescription - Used to send message attachments - NSPhotoLibraryUsageDescription - Used to send message attachments - UIBackgroundModes - - fetch - remote-notification - UILaunchStoryboardName LaunchScreen UIMainStoryboardFile @@ -56,9 +43,21 @@ UIBackgroundModes - remote-notification + fetch + remote-notification - UIViewControllerBasedStatusBarAppearance - + NSPhotoLibraryUsageDescription + Explain why your app uses photo library + NSAppTransportSecurity + + NSAllowsArbitraryLoads + + + + NSCameraUsageDescription + Explain why your app uses the camera + + NSMicrophoneUsageDescription + Explain why your app uses the mic diff --git a/packages/stream_chat_flutter/example/ios/Runner/Runner-Bridging-Header.h b/packages/stream_chat_flutter/example/ios/Runner/Runner-Bridging-Header.h index 7335fdf9..308a2a56 100644 --- a/packages/stream_chat_flutter/example/ios/Runner/Runner-Bridging-Header.h +++ b/packages/stream_chat_flutter/example/ios/Runner/Runner-Bridging-Header.h @@ -1 +1 @@ -#import "GeneratedPluginRegistrant.h" \ No newline at end of file +#import "GeneratedPluginRegistrant.h" diff --git a/packages/stream_chat_flutter/example/ios/Runner/Runner.entitlements b/packages/stream_chat_flutter/example/ios/Runner/Runner.entitlements deleted file mode 100644 index 433bdfe0..00000000 --- a/packages/stream_chat_flutter/example/ios/Runner/Runner.entitlements +++ /dev/null @@ -1,12 +0,0 @@ - - - - - aps-environment - development - com.apple.security.application-groups - - group.io.getstream.flutter - - - diff --git a/packages/stream_chat_flutter/example/ios/fastlane/Appfile b/packages/stream_chat_flutter/example/ios/fastlane/Appfile deleted file mode 100644 index 18030630..00000000 --- a/packages/stream_chat_flutter/example/ios/fastlane/Appfile +++ /dev/null @@ -1,6 +0,0 @@ -# app_identifier("[[APP_IDENTIFIER]]") # The bundle identifier of your app -# apple_id("[[APPLE_ID]]") # Your Apple email address - - -# For more information about the Appfile, see: -# https://docs.fastlane.tools/advanced/#appfile diff --git a/packages/stream_chat_flutter/example/ios/fastlane/Fastfile b/packages/stream_chat_flutter/example/ios/fastlane/Fastfile deleted file mode 100644 index ec2adc81..00000000 --- a/packages/stream_chat_flutter/example/ios/fastlane/Fastfile +++ /dev/null @@ -1,46 +0,0 @@ -fastlane_version "2.162.0" -default_platform :ios - -before_all do - if is_ci - setup_ci() - end -end - -desc "Installs all Certs and Profiles necessary for development and ad-hoc" -lane :match_me do - match( - type: "adhoc", - app_identifier: [ - "io.getstream.flutter", - "io.getstream.flutter.Notifications" - ], - readonly: is_ci, - force_for_new_devices: true - ) -end - -platform :ios do - desc "Deploy build to Firebase" - lane :deploy_to_firebase do - match_me - - gym( - workspace: "./Runner.xcworkspace", - scheme: "Runner", - export_method: "ad-hoc", - export_options: "./fastlane/beta_gym_export_options.plist", - silent: true, - clean: true, - include_symbols: true, - output_directory: "./dist" - ) - - message = changelog_from_git_commits(commits_count: 10) - - firebase_app_distribution( - app: "1:674907137625:ios:cafb9fb076a453c4d7f348", - groups: "ios-stream-testers" - ) - end -end \ No newline at end of file diff --git a/packages/stream_chat_flutter/example/ios/fastlane/Matchfile b/packages/stream_chat_flutter/example/ios/fastlane/Matchfile deleted file mode 100644 index cc976de1..00000000 --- a/packages/stream_chat_flutter/example/ios/fastlane/Matchfile +++ /dev/null @@ -1,16 +0,0 @@ -git_url("https://github.com/GetStream/ios-certificates") - -storage_mode("git") - -username("salvatore@getstream.io") - -team_id("EHV7XZLAHA") - -# app_identifier(["tools.fastlane.app", "tools.fastlane.app2"]) - -# username("user@fastlane.tools") # Your Apple Developer Portal username - -# For all available options run `fastlane match --help` -# Remove the # in the beginning of the line to enable the other options - -# The docs are available on https://docs.fastlane.tools/actions/match diff --git a/packages/stream_chat_flutter/example/ios/fastlane/Pluginfile b/packages/stream_chat_flutter/example/ios/fastlane/Pluginfile deleted file mode 100644 index b18539bc..00000000 --- a/packages/stream_chat_flutter/example/ios/fastlane/Pluginfile +++ /dev/null @@ -1,5 +0,0 @@ -# Autogenerated by fastlane -# -# Ensure this file is checked in to source control! - -gem 'fastlane-plugin-firebase_app_distribution' diff --git a/packages/stream_chat_flutter/example/ios/fastlane/README.md b/packages/stream_chat_flutter/example/ios/fastlane/README.md deleted file mode 100644 index e464ef24..00000000 --- a/packages/stream_chat_flutter/example/ios/fastlane/README.md +++ /dev/null @@ -1,37 +0,0 @@ -fastlane documentation -================ -# Installation - -Make sure you have the latest version of the Xcode command line tools installed: - -``` -xcode-select --install -``` - -Install _fastlane_ using -``` -[sudo] gem install fastlane -NV -``` -or alternatively using `brew install fastlane` - -# Available Actions -### match_me -``` -fastlane match_me -``` -Installs all Certs and Profiles necessary for development and ad-hoc - ----- - -## iOS -### ios deploy_to_firebase -``` -fastlane ios deploy_to_firebase -``` -Deploy build to Firebase - ----- - -This README.md is auto-generated and will be re-generated every time [fastlane](https://fastlane.tools) is run. -More information about fastlane can be found on [fastlane.tools](https://fastlane.tools). -The documentation of fastlane can be found on [docs.fastlane.tools](https://docs.fastlane.tools). diff --git a/packages/stream_chat_flutter/example/ios/fastlane/beta_gym_export_options.plist b/packages/stream_chat_flutter/example/ios/fastlane/beta_gym_export_options.plist deleted file mode 100644 index 53c74098..00000000 --- a/packages/stream_chat_flutter/example/ios/fastlane/beta_gym_export_options.plist +++ /dev/null @@ -1,15 +0,0 @@ - - - - - iCloudContainerEnvironment - Development - provisioningProfiles - - io.getstream.flutter - match AdHoc io.getstream.flutter - io.getstream.flutter.Notifications - match AdHoc io.getstream.flutter.Notifications - - - \ No newline at end of file diff --git a/packages/stream_chat_flutter/example/ios/fastlane/report.xml b/packages/stream_chat_flutter/example/ios/fastlane/report.xml deleted file mode 100644 index b6e7bdcb..00000000 --- a/packages/stream_chat_flutter/example/ios/fastlane/report.xml +++ /dev/null @@ -1,33 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/packages/stream_chat_flutter/example/lib/advanced_options_page.dart b/packages/stream_chat_flutter/example/lib/advanced_options_page.dart deleted file mode 100644 index ee505148..00000000 --- a/packages/stream_chat_flutter/example/lib/advanced_options_page.dart +++ /dev/null @@ -1,328 +0,0 @@ -import 'package:example/routes/routes.dart'; -import 'package:example/stream_version.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; -import 'package:flutter_secure_storage/flutter_secure_storage.dart'; -import 'package:stream_chat_flutter/stream_chat_flutter.dart'; - -import 'choose_user_page.dart'; -import 'main.dart'; - -class AdvancedOptionsPage extends StatefulWidget { - @override - _AdvancedOptionsPageState createState() => _AdvancedOptionsPageState(); -} - -class _AdvancedOptionsPageState extends State { - final _formKey = GlobalKey(); - - final TextEditingController _apiKeyController = TextEditingController(); - String _apiKeyError; - - final TextEditingController _userIdController = TextEditingController(); - String _userIdError; - - final TextEditingController _userTokenController = TextEditingController(); - String _userTokenError; - - final TextEditingController _usernameController = TextEditingController(); - - bool loading = false; - - @override - Widget build(BuildContext context) { - return Scaffold( - backgroundColor: StreamChatTheme.of(context).colorTheme.whiteSnow, - resizeToAvoidBottomPadding: false, - appBar: AppBar( - backgroundColor: StreamChatTheme.of(context).colorTheme.white, - elevation: 1, - centerTitle: true, - brightness: Theme.of(context).brightness, - title: Text( - 'Advanced Options', - style: StreamChatTheme.of(context) - .textTheme - .headlineBold - .copyWith(color: StreamChatTheme.of(context).colorTheme.black), - ), - leading: IconButton( - icon: StreamSvgIcon.left( - color: StreamChatTheme.of(context).colorTheme.black, - ), - onPressed: () { - Navigator.pop(context); - }, - ), - ), - body: Builder( - builder: (context) { - return Padding( - padding: const EdgeInsets.fromLTRB(16, 16, 16, 0), - child: Form( - key: _formKey, - child: Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - TextFormField( - controller: _apiKeyController, - onChanged: (_) { - if (_apiKeyError != null) { - setState(() { - _apiKeyError = null; - }); - } - }, - validator: (value) { - if (value.isEmpty) { - setState(() { - _apiKeyError = 'Please enter the Chat API Key'; - }); - return _apiKeyError; - } - return null; - }, - style: TextStyle( - fontSize: 14, - color: StreamChatTheme.of(context).colorTheme.black, - ), - decoration: InputDecoration( - errorStyle: TextStyle(height: 0, fontSize: 0), - labelStyle: TextStyle( - fontSize: 14, - fontWeight: FontWeight.bold, - color: _apiKeyError != null - ? StreamChatTheme.of(context).colorTheme.accentRed - : StreamChatTheme.of(context).colorTheme.grey, - ), - border: UnderlineInputBorder( - borderRadius: BorderRadius.circular(8), - borderSide: BorderSide.none, - ), - fillColor: - StreamChatTheme.of(context).colorTheme.whiteSmoke, - filled: true, - labelText: - 'Chat API Key ${_apiKeyError != null ? ': $_apiKeyError' : ''}', - ), - textInputAction: TextInputAction.next, - ), - SizedBox(height: 8), - TextFormField( - controller: _userIdController, - onChanged: (_) { - if (_userIdError != null) { - setState(() { - _userIdError = null; - }); - } - }, - validator: (value) { - if (value.isEmpty) { - setState(() { - _userIdError = 'Please enter the User ID'; - }); - return _userIdError; - } - return null; - }, - style: TextStyle( - fontSize: 14, - color: StreamChatTheme.of(context).colorTheme.black, - ), - textInputAction: TextInputAction.next, - decoration: InputDecoration( - errorStyle: TextStyle(height: 0, fontSize: 0), - labelStyle: TextStyle( - fontWeight: FontWeight.bold, - fontSize: 14, - color: _userIdError != null - ? StreamChatTheme.of(context).colorTheme.accentRed - : StreamChatTheme.of(context).colorTheme.grey, - ), - border: UnderlineInputBorder( - borderRadius: BorderRadius.circular(8), - borderSide: BorderSide.none, - ), - fillColor: - StreamChatTheme.of(context).colorTheme.whiteSmoke, - filled: true, - labelText: - 'User ID ${_userIdError != null ? ': $_userIdError' : ''}', - ), - ), - SizedBox(height: 8), - TextFormField( - onChanged: (_) { - if (_userTokenError != null) { - setState(() { - _userTokenError = null; - }); - } - }, - controller: _userTokenController, - validator: (value) { - if (value.isEmpty) { - setState(() { - _userTokenError = 'Please enter the user token'; - }); - return _userTokenError; - } - return null; - }, - style: TextStyle( - fontSize: 14, - color: StreamChatTheme.of(context).colorTheme.black, - ), - textInputAction: TextInputAction.next, - decoration: InputDecoration( - errorStyle: TextStyle(height: 0, fontSize: 0), - labelStyle: TextStyle( - fontWeight: FontWeight.bold, - fontSize: 14, - color: _userTokenError != null - ? StreamChatTheme.of(context).colorTheme.accentRed - : StreamChatTheme.of(context).colorTheme.grey, - ), - border: UnderlineInputBorder( - borderRadius: BorderRadius.circular(8), - borderSide: BorderSide.none, - ), - fillColor: - StreamChatTheme.of(context).colorTheme.whiteSmoke, - filled: true, - labelText: - 'User Token ${_userTokenError != null ? ': $_userTokenError' : ''}', - ), - ), - SizedBox(height: 8), - TextFormField( - controller: _usernameController, - textInputAction: TextInputAction.done, - decoration: InputDecoration( - labelStyle: TextStyle( - fontSize: 14, - fontWeight: FontWeight.bold, - color: StreamChatTheme.of(context).colorTheme.grey, - ), - border: UnderlineInputBorder( - borderRadius: BorderRadius.circular(8), - borderSide: BorderSide.none, - ), - fillColor: - StreamChatTheme.of(context).colorTheme.whiteSmoke, - filled: true, - labelText: 'Username (optional)', - ), - ), - Spacer(), - RaisedButton( - color: Theme.of(context).brightness == Brightness.light - ? StreamChatTheme.of(context).colorTheme.accentBlue - : Colors.white, - elevation: 0, - padding: const EdgeInsets.symmetric(vertical: 16), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(26), - ), - child: Text( - 'Login', - style: TextStyle( - fontSize: 16, - color: Theme.of(context).brightness != Brightness.light - ? StreamChatTheme.of(context).colorTheme.accentBlue - : Colors.white, - ), - ), - onPressed: () async { - if (loading) { - return; - } - if (_formKey.currentState.validate()) { - final apiKey = _apiKeyController.text; - final userId = _userIdController.text; - final userToken = _userTokenController.text; - final username = _usernameController.text; - - loading = true; - showDialog( - barrierDismissible: false, - context: context, - barrierColor: - StreamChatTheme.of(context).colorTheme.overlay, - builder: (context) => Center( - child: Container( - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(16), - color: StreamChatTheme.of(context) - .colorTheme - .white, - ), - height: 100, - width: 100, - child: Center( - child: CircularProgressIndicator(), - ), - ), - ), - ); - - final client = StreamChatClient( - apiKey, - logLevel: Level.INFO, - )..chatPersistenceClient = chatPersistentClient; - - try { - await client.setUser( - User(id: userId, extraData: { - 'name': username, - }), - userToken, - ); - - final secureStorage = FlutterSecureStorage(); - secureStorage.write( - key: kStreamApiKey, - value: apiKey, - ); - secureStorage.write( - key: kStreamUserId, - value: userId, - ); - secureStorage.write( - key: kStreamToken, - value: userToken, - ); - } catch (e) { - var errorText = 'Error connecting, retry'; - if (e is Map) { - errorText = e['message'] ?? errorText; - } - Navigator.pop(context); - setState(() { - _apiKeyError = errorText; - }); - loading = false; - await client.disconnect(); - return; - } - loading = false; - await Navigator.pushNamedAndRemoveUntil( - context, - Routes.APP, - ModalRoute.withName(Routes.APP), - arguments: client, - ); - } - }, - ), - StreamVersion(), - ], - ), - ), - ); - }, - ), - ); - } -} diff --git a/packages/stream_chat_flutter/example/lib/chat_info_screen.dart b/packages/stream_chat_flutter/example/lib/chat_info_screen.dart deleted file mode 100644 index 8db438c3..00000000 --- a/packages/stream_chat_flutter/example/lib/chat_info_screen.dart +++ /dev/null @@ -1,599 +0,0 @@ -import 'package:flutter/cupertino.dart'; -import 'package:flutter/material.dart'; -import 'package:jiffy/jiffy.dart'; -import 'package:stream_chat_flutter/stream_chat_flutter.dart'; - -import 'main.dart'; -import 'routes/routes.dart'; - -/// Detail screen for a 1:1 chat correspondence -class ChatInfoScreen extends StatefulWidget { - /// User in consideration - final User user; - - const ChatInfoScreen({Key key, this.user}) : super(key: key); - - @override - _ChatInfoScreenState createState() => _ChatInfoScreenState(); -} - -class _ChatInfoScreenState extends State { - @override - Widget build(BuildContext context) { - final channel = StreamChannel.of(context).channel; - return Scaffold( - backgroundColor: StreamChatTheme.of(context).colorTheme.whiteSnow, - body: ListView( - children: [ - _buildUserHeader(), - Container( - height: 8.0, - color: StreamChatTheme.of(context).colorTheme.greyGainsboro, - ), - _buildOptionListTiles(), - Container( - height: 8.0, - color: StreamChatTheme.of(context).colorTheme.greyGainsboro, - ), - if ([ - 'admin', - 'owner', - ].contains(channel.state.members - .firstWhere((m) => m.userId == channel.client.state.user.id, - orElse: () => null) - ?.role)) - _buildDeleteListTile(), - ], - ), - ); - } - - Widget _buildUserHeader() { - return Material( - color: StreamChatTheme.of(context).colorTheme.whiteSnow, - child: SafeArea( - child: Stack( - children: [ - Column( - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Padding( - padding: const EdgeInsets.all(16.0), - child: UserAvatar( - user: widget.user, - constraints: BoxConstraints( - maxWidth: 72.0, - maxHeight: 72.0, - ), - borderRadius: BorderRadius.circular(36.0), - showOnlineStatus: false, - ), - ), - //SizedBox(height: 4.0), - Text( - widget.user.name, - style: TextStyle(fontSize: 16.0, fontWeight: FontWeight.bold), - ), - SizedBox(height: 7.0), - _buildConnectedTitleState(), - SizedBox(height: 15.0), - OptionListTile( - title: '@${widget.user.id}', - tileColor: StreamChatTheme.of(context).colorTheme.whiteSnow, - trailing: Padding( - padding: const EdgeInsets.symmetric(horizontal: 8.0), - child: Text( - widget.user.name, - style: TextStyle( - color: StreamChatTheme.of(context) - .colorTheme - .black - .withOpacity(0.5), - fontSize: 16.0), - ), - ), - onTap: () {}, - ), - ], - ), - Positioned( - top: 21, - left: 16, - child: InkWell( - child: StreamSvgIcon.left( - color: StreamChatTheme.of(context).colorTheme.black, - ), - onTap: () { - Navigator.of(context).pop(); - }, - ), - ), - ], - ), - ), - ); - } - - Widget _buildOptionListTiles() { - var channel = StreamChannel.of(context); - - return Column( - children: [ - // _OptionListTile( - // title: 'Notifications', - // leading: StreamSvgIcon.Icon_notification( - // size: 24.0, - // color: StreamChatTheme.of(context).colorTheme.black.withOpacity(0.5), - // ), - // trailing: CupertinoSwitch( - // value: true, - // onChanged: (val) {}, - // ), - // onTap: () {}, - // ), - StreamBuilder( - stream: StreamChannel.of(context).channel.isMutedStream, - builder: (context, snapshot) { - return OptionListTile( - tileColor: StreamChatTheme.of(context).colorTheme.whiteSnow, - title: 'Mute user', - titleTextStyle: StreamChatTheme.of(context).textTheme.body, - leading: Padding( - padding: const EdgeInsets.symmetric(horizontal: 22.0), - child: StreamSvgIcon.mute( - size: 24.0, - color: StreamChatTheme.of(context) - .colorTheme - .black - .withOpacity(0.5), - ), - ), - trailing: snapshot.data == null - ? CircularProgressIndicator() - : CupertinoSwitch( - value: snapshot.data, - onChanged: (val) { - if (snapshot.data) { - channel.channel.unmute(); - } else { - channel.channel.mute(); - } - }, - ), - onTap: () {}, - ); - }), - // _OptionListTile( - // title: 'Block User', - // leading: StreamSvgIcon.Icon_user_delete( - // size: 24.0, - // color: StreamChatTheme.of(context).colorTheme.black.withOpacity(0.5), - // ), - // trailing: CupertinoSwitch( - // value: widget.user.banned, - // onChanged: (val) { - // if (widget.user.banned) { - // channel.channel.shadowBan(widget.user.id, {}); - // } else { - // channel.channel.unbanUser(widget.user.id); - // } - // }, - // ), - // onTap: () {}, - // ), - OptionListTile( - title: 'Photos & Videos', - tileColor: StreamChatTheme.of(context).colorTheme.whiteSnow, - titleTextStyle: StreamChatTheme.of(context).textTheme.body, - leading: Padding( - padding: const EdgeInsets.symmetric(horizontal: 16.0), - child: StreamSvgIcon.pictures( - size: 36.0, - color: - StreamChatTheme.of(context).colorTheme.black.withOpacity(0.5), - ), - ), - trailing: StreamSvgIcon.right( - color: StreamChatTheme.of(context).colorTheme.grey, - ), - onTap: () { - final channel = StreamChannel.of(context).channel; - - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => StreamChannel( - channel: channel, - child: MessageSearchBloc( - child: ChannelMediaDisplayScreen( - sortOptions: [ - SortOption( - 'created_at', - direction: SortOption.ASC, - ), - ], - paginationParams: PaginationParams(limit: 20), - onShowMessage: (m, c) async { - final client = StreamChat.of(context).client; - final message = m; - final channel = client.channel( - c.type, - id: c.id, - ); - if (channel.state == null) { - await channel.watch(); - } - Navigator.pushNamed( - context, - Routes.CHANNEL_PAGE, - arguments: ChannelPageArgs( - channel: channel, - initialMessage: message, - ), - ); - }, - ), - ), - ), - ), - ); - }, - ), - OptionListTile( - title: 'Files', - tileColor: StreamChatTheme.of(context).colorTheme.whiteSnow, - titleTextStyle: StreamChatTheme.of(context).textTheme.body, - leading: Padding( - padding: const EdgeInsets.symmetric(horizontal: 18.0), - child: StreamSvgIcon.files( - size: 32.0, - color: - StreamChatTheme.of(context).colorTheme.black.withOpacity(0.5), - ), - ), - trailing: StreamSvgIcon.right( - color: StreamChatTheme.of(context).colorTheme.grey, - ), - onTap: () { - final channel = StreamChannel.of(context).channel; - - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => StreamChannel( - channel: channel, - child: MessageSearchBloc( - child: ChannelFileDisplayScreen( - sortOptions: [ - SortOption( - 'created_at', - direction: SortOption.ASC, - ), - ], - paginationParams: PaginationParams(limit: 20), - ), - ), - ), - ), - ); - }, - ), - OptionListTile( - title: 'Shared groups', - tileColor: StreamChatTheme.of(context).colorTheme.whiteSnow, - titleTextStyle: StreamChatTheme.of(context).textTheme.body, - leading: Padding( - padding: const EdgeInsets.symmetric(horizontal: 22.0), - child: StreamSvgIcon.iconGroup( - size: 24.0, - color: - StreamChatTheme.of(context).colorTheme.black.withOpacity(0.5), - ), - ), - trailing: StreamSvgIcon.right( - color: StreamChatTheme.of(context).colorTheme.grey, - ), - onTap: () { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => _SharedGroupsScreen( - StreamChat.of(context).user, widget.user))); - }, - ), - ], - ); - } - - Widget _buildDeleteListTile() { - return OptionListTile( - title: 'Delete Conversation', - tileColor: StreamChatTheme.of(context).colorTheme.whiteSnow, - titleTextStyle: StreamChatTheme.of(context).textTheme.body.copyWith( - color: StreamChatTheme.of(context).colorTheme.accentRed, - ), - leading: Padding( - padding: const EdgeInsets.symmetric(horizontal: 22.0), - child: StreamSvgIcon.delete( - color: StreamChatTheme.of(context).colorTheme.accentRed, - size: 24.0, - ), - ), - onTap: () { - _showDeleteDialog(); - }, - titleColor: StreamChatTheme.of(context).colorTheme.accentRed, - ); - } - - void _showDeleteDialog() async { - final res = await showConfirmationDialog( - context, - title: 'Delete Conversation', - okText: 'DELETE', - question: 'Are you sure you want to delete this conversation?', - cancelText: 'CANCEL', - icon: StreamSvgIcon.delete( - color: StreamChatTheme.of(context).colorTheme.accentRed, - ), - ); - var channel = StreamChannel.of(context).channel; - if (res == true) { - await channel.delete().then((value) { - Navigator.pop(context); - }); - } - } - - Widget _buildConnectedTitleState() { - var alternativeWidget; - - final otherMember = widget.user; - - if (otherMember != null) { - if (otherMember.online) { - alternativeWidget = Text( - 'Online', - style: TextStyle( - color: StreamChatTheme.of(context) - .colorTheme - .black - .withOpacity(0.5)), - ); - } else { - alternativeWidget = Text( - 'Last seen ${Jiffy(otherMember.lastActive).fromNow()}', - style: TextStyle( - color: StreamChatTheme.of(context) - .colorTheme - .black - .withOpacity(0.5)), - ); - } - } - - return Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - if (widget.user.online) - Material( - type: MaterialType.circle, - child: Container( - padding: const EdgeInsets.symmetric(horizontal: 8.0), - constraints: BoxConstraints.tightFor( - width: 24, - height: 12, - ), - child: Material( - shape: CircleBorder(), - color: StreamChatTheme.of(context).colorTheme.accentGreen, - ), - ), - color: StreamChatTheme.of(context).colorTheme.white, - ), - alternativeWidget, - if (widget.user.online) - SizedBox( - width: 24.0, - ), - ], - ); - } -} - -class _SharedGroupsScreen extends StatefulWidget { - final User mainUser; - final User otherUser; - - _SharedGroupsScreen(this.mainUser, this.otherUser); - - @override - __SharedGroupsScreenState createState() => __SharedGroupsScreenState(); -} - -class __SharedGroupsScreenState extends State<_SharedGroupsScreen> { - @override - Widget build(BuildContext context) { - var chat = StreamChat.of(context); - - return Scaffold( - backgroundColor: StreamChatTheme.of(context).colorTheme.whiteSnow, - appBar: AppBar( - brightness: Theme.of(context).brightness, - elevation: 1, - centerTitle: true, - title: Text( - 'Shared Groups', - style: TextStyle( - color: StreamChatTheme.of(context).colorTheme.black, - fontSize: 16.0), - ), - leading: Center( - child: InkWell( - onTap: () { - Navigator.of(context).pop(); - }, - child: Container( - child: StreamSvgIcon.left( - color: StreamChatTheme.of(context).colorTheme.black, - size: 24.0, - ), - width: 24.0, - height: 24.0, - ), - ), - ), - backgroundColor: StreamChatTheme.of(context).colorTheme.white, - ), - body: FutureBuilder>( - future: chat.client.queryChannels( - filter: { - r'$and': [ - { - 'members': { - r'$in': [widget.otherUser.id], - }, - }, - { - 'members': { - r'$in': [widget.mainUser.id], - }, - } - ], - }, - ), - builder: (context, snapshot) { - if (!snapshot.hasData) { - return Center( - child: CircularProgressIndicator(), - ); - } - - if (snapshot.data.isEmpty) { - return Center( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - StreamSvgIcon.message( - size: 136.0, - color: StreamChatTheme.of(context).colorTheme.greyGainsboro, - ), - SizedBox(height: 16.0), - Text( - 'No Shared Groups', - style: TextStyle( - fontSize: 14.0, - color: StreamChatTheme.of(context).colorTheme.black, - ), - ), - SizedBox(height: 8.0), - Text( - 'Group shared with User will appear here.', - textAlign: TextAlign.center, - style: TextStyle( - fontSize: 14.0, - color: StreamChatTheme.of(context) - .colorTheme - .black - .withOpacity(0.5), - ), - ), - ], - ), - ); - } - - return ListView.builder( - itemCount: snapshot.data.length, - itemBuilder: (context, position) { - return StreamChannel( - channel: snapshot.data[position], - child: _buildListTile(snapshot.data[position]), - ); - }, - ); - }, - ), - ); - } - - Widget _buildListTile(Channel channel) { - var extraData = channel.extraData; - var members = channel.state.members; - - var textStyle = TextStyle(fontSize: 14.0, fontWeight: FontWeight.bold); - - return Container( - height: 64.0, - child: LayoutBuilder(builder: (context, constraints) { - String title; - if (extraData['name'] == null) { - final otherMembers = members.where( - (member) => member.userId != StreamChat.of(context).user.id); - if (otherMembers.isNotEmpty) { - final maxWidth = constraints.maxWidth; - final maxChars = maxWidth / textStyle.fontSize; - var currentChars = 0; - final currentMembers = []; - otherMembers.forEach((element) { - final newLength = currentChars + element.user.name.length; - if (newLength < maxChars) { - currentChars = newLength; - currentMembers.add(element); - } - }); - - final exceedingMembers = - otherMembers.length - currentMembers.length; - title = - '${currentMembers.map((e) => e.user.name).join(', ')} ${exceedingMembers > 0 ? '+ $exceedingMembers' : ''}'; - } else { - title = 'No title'; - } - } else { - title = extraData['name']; - } - - return Column( - children: [ - Expanded( - child: Row( - children: [ - Padding( - padding: const EdgeInsets.all(8.0), - child: ChannelImage( - channel: channel, - constraints: - BoxConstraints(maxWidth: 40.0, maxHeight: 40.0), - ), - ), - Expanded( - child: Text( - title, - style: textStyle, - )), - Padding( - padding: const EdgeInsets.all(8.0), - child: Text( - '${channel.memberCount} members', - style: TextStyle( - color: StreamChatTheme.of(context) - .colorTheme - .black - .withOpacity(0.5)), - ), - ) - ], - ), - ), - Container( - height: 1.0, - color: - StreamChatTheme.of(context).colorTheme.black.withOpacity(.08), - ), - ], - ); - }), - ); - } -} diff --git a/packages/stream_chat_flutter/example/lib/chips_input_text_field.dart b/packages/stream_chat_flutter/example/lib/chips_input_text_field.dart deleted file mode 100644 index 7291ef03..00000000 --- a/packages/stream_chat_flutter/example/lib/chips_input_text_field.dart +++ /dev/null @@ -1,169 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:stream_chat_flutter/stream_chat_flutter.dart'; - -typedef ChipBuilder = Widget Function(BuildContext context, T chip); -typedef OnChipAdded = void Function(T chip); -typedef OnChipRemoved = void Function(T chip); - -class ChipsInputTextField extends StatefulWidget { - final TextEditingController controller; - final FocusNode focusNode; - final ValueChanged onInputChanged; - final ChipBuilder chipBuilder; - final OnChipAdded onChipAdded; - final OnChipRemoved onChipRemoved; - final String hint; - - const ChipsInputTextField({ - Key key, - @required this.chipBuilder, - @required this.controller, - this.onInputChanged, - this.focusNode, - this.onChipAdded, - this.onChipRemoved, - this.hint = 'Type a name', - }) : super(key: key); - - @override - ChipInputTextFieldState createState() => ChipInputTextFieldState(); -} - -class ChipInputTextFieldState extends State> { - final _chips = {}; - bool _pauseItemAddition = false; - - void addItem(T item) { - setState(() => _chips.add(item)); - if (widget.onChipAdded != null) widget.onChipAdded(item); - } - - void removeItem(T item) { - setState(() { - _chips.remove(item); - if (_chips.isEmpty) resumeItemAddition(); - }); - if (widget.onChipRemoved != null) widget.onChipRemoved(item); - } - - void pauseItemAddition() { - if (!_pauseItemAddition) { - setState(() => _pauseItemAddition = true); - } - widget.focusNode?.unfocus(); - } - - void resumeItemAddition() { - if (_pauseItemAddition) { - setState(() => _pauseItemAddition = false); - } - widget.focusNode?.requestFocus(); - } - - @override - Widget build(BuildContext context) { - return GestureDetector( - onTap: _pauseItemAddition ? resumeItemAddition : null, - child: Material( - elevation: 1, - color: StreamChatTheme.of(context).colorTheme.white, - child: Container( - child: Padding( - padding: const EdgeInsets.fromLTRB(16, 16, 16, 16), - child: IntrinsicHeight( - child: Row( - crossAxisAlignment: CrossAxisAlignment.baseline, - children: [ - Padding( - padding: const EdgeInsets.symmetric(vertical: 4.0), - child: Text( - 'TO:', - style: StreamChatTheme.of(context) - .textTheme - .footnote - .copyWith( - color: StreamChatTheme.of(context) - .colorTheme - .black - .withOpacity(.5)), - ), - ), - SizedBox(width: 12), - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisSize: MainAxisSize.min, - children: [ - Wrap( - spacing: 8.0, - runSpacing: 4.0, - children: _chips.map((item) { - return widget.chipBuilder(context, item); - }).toList(), - ), - if (!_pauseItemAddition) - TextField( - controller: widget.controller, - onChanged: widget.onInputChanged, - focusNode: widget.focusNode, - decoration: InputDecoration( - isDense: true, - border: InputBorder.none, - focusedBorder: InputBorder.none, - enabledBorder: InputBorder.none, - errorBorder: InputBorder.none, - disabledBorder: InputBorder.none, - contentPadding: const EdgeInsets.only(top: 4.0), - hintText: widget.hint, - hintStyle: StreamChatTheme.of(context) - .textTheme - .body - .copyWith( - color: StreamChatTheme.of(context) - .colorTheme - .black - .withOpacity(.5)), - ), - ), - ], - ), - ), - SizedBox(width: 12), - Align( - alignment: Alignment.bottomCenter, - child: IconButton( - icon: _chips.isEmpty - ? StreamSvgIcon.user( - color: StreamChatTheme.of(context) - .colorTheme - .black - .withOpacity(0.5), - size: 24, - ) - : StreamSvgIcon.userAdd( - color: StreamChatTheme.of(context) - .colorTheme - .black - .withOpacity(0.5), - size: 24, - ), - onPressed: resumeItemAddition, - alignment: Alignment.topRight, - visualDensity: VisualDensity.compact, - padding: const EdgeInsets.all(0), - splashRadius: 24, - constraints: BoxConstraints.tightFor( - height: 24, - width: 24, - ), - ), - ), - ], - ), - ), - ), - ), - ), - ); - } -} diff --git a/packages/stream_chat_flutter/example/lib/choose_user_page.dart b/packages/stream_chat_flutter/example/lib/choose_user_page.dart deleted file mode 100644 index a23db661..00000000 --- a/packages/stream_chat_flutter/example/lib/choose_user_page.dart +++ /dev/null @@ -1,267 +0,0 @@ -import 'package:example/stream_version.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_secure_storage/flutter_secure_storage.dart'; -import 'package:flutter_svg/flutter_svg.dart'; -import 'package:stream_chat_flutter/stream_chat_flutter.dart'; - -import 'routes/routes.dart'; - -const kStreamApiKey = 'STREAM_API_KEY'; -const kStreamUserId = 'STREAM_USER_ID'; -const kStreamToken = 'STREAM_TOKEN'; -const kDefaultStreamApiKey = 'kv7mcsxr24p8'; - -class ChooseUserPage extends StatelessWidget { - @override - Widget build(BuildContext context) { - final users = { - 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoic2FsdmF0b3JlIn0.pgiJz7sIc7iP29BHKFwe3nLm5-OaR_1l2P-SlgiC9a8': - User( - id: 'salvatore', - extraData: { - 'name': 'Salvatore Giordano', - 'image': - 'https://ca.slack-edge.com/T02RM6X6B-USKK9FFRT-30c415e207a9-512', - }, - ), - 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoic2FoaWwifQ.WnIUoB5gR2kcAsFhiDvkiD6zdHXZ-VSU2aQWWkhsvfo': - User( - id: 'sahil', - extraData: { - 'name': 'Sahil Kumar', - 'image': - 'https://ca.slack-edge.com/T02RM6X6B-U01EYU51M89-bbc152b40321-512', - }, - ), - 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoiYmVuIn0.nAz2sNFGQwY7rl2Og2z3TGHUsdpnN53tOsUglJFvLmg': - User( - id: 'ben', - extraData: { - 'name': 'Ben Golden', - 'image': - 'https://ca.slack-edge.com/T02RM6X6B-U01AXAF23MG-f57403a3cb0d-512', - }, - ), - 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoidGhpZXJyeSJ9.lEq6TrZtHzjoNtf7HHRufUPyGo_pa8vg4_XhEBp4ckY': - User( - id: 'thierry', - extraData: { - 'name': 'Thierry Schellenbach', - 'image': - 'https://ca.slack-edge.com/T02RM6X6B-U02RM6X6D-g28a1278a98e-512', - }, - ), - 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoidG9tbWFzbyJ9.GLSI0ESshERMo2WjUpysD709NEtn1zmGimUN2an7g9o': - User( - id: 'tommaso', - extraData: { - 'name': 'Tommaso Barbugli', - 'image': - 'https://ca.slack-edge.com/T02RM6X6B-U02U7SJP4-0f65a5997877-512', - }, - ), - 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoiZGV2ZW4ifQ.z3zI4PqJnNhc-1o-VKcmb6BnnQ0oxFNCRHwEulHqcWc': - User( - id: 'deven', - extraData: { - 'name': 'Deven Joshi', - 'image': - 'https://ca.slack-edge.com/T02RM6X6B-U01AM7ELPTL-8a60da32704c-512', - }, - ), - 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoibmVldmFzaCJ9.3EdHegTxibrz3A9cTiKmpEyawwcCVB8FXnoFzr4eKvw': - User( - id: 'neevash', - extraData: { - 'name': 'Neevash Ramdial', - 'image': - 'https://ca.slack-edge.com/T02RM6X6B-U01DZ046DS8-b00d321d2880-512', - }, - ), - 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoicWF0ZXN0MSJ9.fnelU7HcP7QoEEsCGteNlF1fppofzNlrnpDQuIgeKCU': - User( - id: 'qatest1', - extraData: { - 'name': 'QA test 1', - }, - ), - 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoicWF0ZXN0MiJ9.vSCqAEbs2WVmMWsOsa7065Fsjq-rsTih6qsHPynl7XM': - User( - id: 'qatest2', - extraData: { - 'name': 'QA test 2', - }, - ), - }; - - return Scaffold( - backgroundColor: StreamChatTheme.of(context).colorTheme.whiteSnow, - body: SafeArea( - child: Column( - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Padding( - padding: const EdgeInsets.only( - top: 34, - bottom: 20, - ), - child: Center( - child: SvgPicture.asset( - 'assets/logo.svg', - height: 40, - color: StreamChatTheme.of(context).colorTheme.accentBlue, - ), - ), - ), - Padding( - padding: const EdgeInsets.only(bottom: 13.0), - child: Text( - 'Welcome to Stream Chat', - style: StreamChatTheme.of(context).textTheme.title, - ), - ), - Text( - 'Select a user to try the Flutter SDK:', - style: StreamChatTheme.of(context).textTheme.body, - ), - Expanded( - child: Padding( - padding: const EdgeInsets.only(top: 32), - child: ListView.separated( - separatorBuilder: (context, i) { - return Container( - height: 1, - color: StreamChatTheme.of(context).colorTheme.greyWhisper, - ); - }, - itemCount: users.length + 1, - itemBuilder: (context, i) { - return [ - ...users.entries.map((entry) { - final token = entry.key; - final user = entry.value; - return ListTile( - onTap: () async { - showDialog( - barrierDismissible: false, - context: context, - barrierColor: StreamChatTheme.of(context) - .colorTheme - .overlay, - builder: (context) => Center( - child: Container( - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(16), - color: StreamChatTheme.of(context) - .colorTheme - .white, - ), - height: 100, - width: 100, - child: Center( - child: CircularProgressIndicator(), - ), - ), - ), - ); - - final secureStorage = FlutterSecureStorage(); - final client = StreamChat.of(context).client; - client.apiKey = kDefaultStreamApiKey; - await client.setUser( - user, - token, - ); - - secureStorage.write( - key: kStreamApiKey, - value: kDefaultStreamApiKey, - ); - secureStorage.write( - key: kStreamUserId, - value: user.id, - ); - secureStorage.write( - key: kStreamToken, - value: token, - ); - Navigator.pushNamedAndRemoveUntil( - context, - Routes.HOME, - ModalRoute.withName(Routes.HOME), - ); - }, - leading: UserAvatar( - user: user, - constraints: BoxConstraints.tight( - Size.fromRadius(20), - ), - ), - title: Text( - user.name, - style: - StreamChatTheme.of(context).textTheme.bodyBold, - ), - subtitle: Text( - 'Stream test account', - style: StreamChatTheme.of(context) - .textTheme - .footnote - .copyWith( - color: StreamChatTheme.of(context) - .colorTheme - .grey, - ), - ), - trailing: StreamSvgIcon.arrowRight( - color: StreamChatTheme.of(context) - .colorTheme - .accentBlue, - ), - ); - }), - ListTile( - onTap: () { - Navigator.pushNamed(context, Routes.ADVANCED_OPTIONS); - }, - leading: CircleAvatar( - child: StreamSvgIcon.settings( - color: StreamChatTheme.of(context).colorTheme.black, - ), - backgroundColor: StreamChatTheme.of(context) - .colorTheme - .greyWhisper, - ), - title: Text( - 'Advanced Options', - style: StreamChatTheme.of(context).textTheme.bodyBold, - ), - subtitle: Text( - 'Custom settings', - style: StreamChatTheme.of(context) - .textTheme - .footnote - .copyWith( - color: - StreamChatTheme.of(context).colorTheme.grey, - ), - ), - trailing: SvgPicture.asset( - 'assets/icon_arrow_right.svg', - height: 24, - width: 24, - clipBehavior: Clip.none, - ), - ), - ][i]; - }, - ), - ), - ), - StreamVersion(), - ], - ), - ), - ); - } -} diff --git a/packages/stream_chat_flutter/example/lib/group_chat_details_screen.dart b/packages/stream_chat_flutter/example/lib/group_chat_details_screen.dart deleted file mode 100644 index afc9d12f..00000000 --- a/packages/stream_chat_flutter/example/lib/group_chat_details_screen.dart +++ /dev/null @@ -1,331 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:stream_chat_flutter/stream_chat_flutter.dart'; -import 'package:uuid/uuid.dart'; - -import 'main.dart'; -import 'routes/routes.dart'; - -class GroupChatDetailsScreen extends StatefulWidget { - final List selectedUsers; - - const GroupChatDetailsScreen({ - Key key, - @required this.selectedUsers, - }) : super(key: key); - - @override - _GroupChatDetailsScreenState createState() => _GroupChatDetailsScreenState(); -} - -class _GroupChatDetailsScreenState extends State { - final _selectedUsers = []; - - TextEditingController _groupNameController; - - bool _isGroupNameEmpty = true; - - int get _totalUsers => _selectedUsers.length; - - void _groupNameListener() { - final name = _groupNameController.text; - if (mounted) { - setState(() { - _isGroupNameEmpty = name.isEmpty; - }); - } - } - - @override - void initState() { - super.initState(); - _selectedUsers.addAll(widget.selectedUsers); - _groupNameController = TextEditingController() - ..addListener(_groupNameListener); - } - - @override - void dispose() { - _groupNameController?.removeListener(_groupNameListener); - _groupNameController?.clear(); - _groupNameController?.dispose(); - super.dispose(); - } - - @override - Widget build(BuildContext context) { - return WillPopScope( - onWillPop: () async { - Navigator.pop(context, _selectedUsers); - return false; - }, - child: Scaffold( - backgroundColor: StreamChatTheme.of(context).colorTheme.whiteSnow, - appBar: AppBar( - brightness: Theme.of(context).brightness, - elevation: 1, - backgroundColor: StreamChatTheme.of(context).colorTheme.white, - leading: const StreamBackButton(), - title: Text( - 'Name of Group Chat', - style: TextStyle( - color: StreamChatTheme.of(context).colorTheme.black, - fontSize: 16, - ), - ), - centerTitle: true, - bottom: PreferredSize( - preferredSize: Size.fromHeight(kToolbarHeight), - child: Padding( - padding: const EdgeInsets.symmetric(vertical: 18, horizontal: 16), - child: Row( - children: [ - Text( - 'NAME', - style: TextStyle( - fontSize: 12, - color: StreamChatTheme.of(context).colorTheme.grey, - ), - ), - SizedBox(width: 16), - Expanded( - child: TextField( - controller: _groupNameController, - decoration: InputDecoration( - isDense: true, - border: InputBorder.none, - focusedBorder: InputBorder.none, - enabledBorder: InputBorder.none, - errorBorder: InputBorder.none, - disabledBorder: InputBorder.none, - contentPadding: const EdgeInsets.all(0), - hintText: 'Choose a group chat name', - hintStyle: TextStyle( - fontSize: 14, - color: StreamChatTheme.of(context).colorTheme.grey, - ), - ), - ), - ), - ], - ), - ), - ), - actions: [ - StreamNeumorphicButton( - child: IconButton( - padding: const EdgeInsets.all(0), - icon: StreamSvgIcon.check( - size: 24, - color: _isGroupNameEmpty - ? StreamChatTheme.of(context).colorTheme.grey - : StreamChatTheme.of(context).colorTheme.accentBlue, - ), - onPressed: _isGroupNameEmpty - ? null - : () async { - try { - final groupName = _groupNameController.text; - final client = StreamChat.of(context).client; - final channel = client.channel('messaging', - id: Uuid().v4(), - extraData: { - 'members': [ - client.state.user.id, - ..._selectedUsers.map((e) => e.id), - ], - 'name': groupName, - }); - await channel.watch(); - Navigator.pushNamedAndRemoveUntil( - context, - Routes.CHANNEL_PAGE, - ModalRoute.withName(Routes.HOME), - arguments: ChannelPageArgs(channel: channel), - ); - } catch (err) { - _showErrorAlert(); - } - }, - ), - ), - ], - ), - body: ConnectionStatusBuilder( - statusBuilder: (context, status) { - String statusString = ''; - bool showStatus = true; - - switch (status) { - case ConnectionStatus.connected: - statusString = 'Connected'; - showStatus = false; - break; - case ConnectionStatus.connecting: - statusString = 'Reconnecting...'; - break; - case ConnectionStatus.disconnected: - statusString = 'Disconnected'; - break; - } - return InfoTile( - showMessage: showStatus, - tileAnchor: Alignment.topCenter, - childAnchor: Alignment.topCenter, - message: statusString, - child: Column( - children: [ - Container( - width: double.maxFinite, - decoration: BoxDecoration( - gradient: - StreamChatTheme.of(context).colorTheme.bgGradient, - ), - child: Padding( - padding: const EdgeInsets.symmetric( - vertical: 8, - horizontal: 8, - ), - child: Text( - '$_totalUsers ${_totalUsers > 1 ? 'Members' : 'Member'}', - style: TextStyle( - color: StreamChatTheme.of(context).colorTheme.grey, - ), - ), - ), - ), - Expanded( - child: GestureDetector( - behavior: HitTestBehavior.opaque, - onPanDown: (_) => FocusScope.of(context).unfocus(), - child: ListView.separated( - itemCount: _selectedUsers.length + 1, - separatorBuilder: (_, __) => Container( - height: 1, - color: StreamChatTheme.of(context) - .colorTheme - .greyWhisper, - ), - itemBuilder: (_, index) { - if (index == _selectedUsers.length) { - return Container( - height: 1, - color: StreamChatTheme.of(context) - .colorTheme - .greyWhisper, - ); - } - final user = _selectedUsers[index]; - return ListTile( - key: ObjectKey(user), - leading: UserAvatar( - user: user, - constraints: BoxConstraints.tightFor( - width: 40, - height: 40, - ), - ), - title: Text( - user.name, - style: TextStyle(fontWeight: FontWeight.bold), - ), - contentPadding: const EdgeInsets.symmetric( - horizontal: 12, - vertical: 8, - ), - trailing: IconButton( - icon: Icon( - Icons.clear_rounded, - color: StreamChatTheme.of(context) - .colorTheme - .black, - ), - padding: const EdgeInsets.all(0), - splashRadius: 24, - onPressed: () { - setState(() { - _selectedUsers.remove(user); - }); - if (_selectedUsers.isEmpty) { - Navigator.pop(context, _selectedUsers); - } - }, - ), - ); - }, - ), - ), - ), - ], - ), - ); - }, - ), - ), - ); - } - - void _showErrorAlert() { - showModalBottomSheet( - backgroundColor: StreamChatTheme.of(context).colorTheme.white, - context: context, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.only( - topLeft: Radius.circular(16.0), - topRight: Radius.circular(16.0), - )), - builder: (context) { - return Column( - mainAxisSize: MainAxisSize.min, - children: [ - SizedBox( - height: 26.0, - ), - StreamSvgIcon.error( - color: StreamChatTheme.of(context).colorTheme.accentRed, - size: 24.0, - ), - SizedBox( - height: 26.0, - ), - Text( - 'Something went wrong', - style: StreamChatTheme.of(context).textTheme.headlineBold, - ), - SizedBox( - height: 7.0, - ), - Text('The operation couldn\'t be completed.'), - SizedBox( - height: 36.0, - ), - Container( - color: - StreamChatTheme.of(context).colorTheme.black.withOpacity(.08), - height: 1.0, - ), - Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - FlatButton( - child: Text( - 'OK', - style: StreamChatTheme.of(context) - .textTheme - .bodyBold - .copyWith( - color: StreamChatTheme.of(context) - .colorTheme - .accentBlue), - ), - onPressed: () { - Navigator.of(context).pop(); - }, - ), - ], - ), - ], - ); - }, - ); - } -} diff --git a/packages/stream_chat_flutter/example/lib/group_info_screen.dart b/packages/stream_chat_flutter/example/lib/group_info_screen.dart deleted file mode 100644 index d22b1ce4..00000000 --- a/packages/stream_chat_flutter/example/lib/group_info_screen.dart +++ /dev/null @@ -1,1023 +0,0 @@ -import 'dart:async'; - -import 'package:flutter/cupertino.dart'; -import 'package:flutter/material.dart'; -import 'package:jiffy/jiffy.dart'; -import 'package:stream_chat_flutter/src/option_list_tile.dart'; -import 'package:stream_chat_flutter/src/stream_svg_icon.dart'; -import 'package:stream_chat_flutter/stream_chat_flutter.dart'; - -import 'chat_info_screen.dart'; -import 'main.dart'; -import 'routes/routes.dart'; - -class GroupInfoScreen extends StatefulWidget { - @override - _GroupInfoScreenState createState() => _GroupInfoScreenState(); -} - -class _GroupInfoScreenState extends State { - TextEditingController _nameController; - - TextEditingController _searchController; - String _userNameQuery = ''; - - Timer _debounce; - Function modalSetStateCallback; - - final FocusNode _focusNode = FocusNode(); - - bool listExpanded = false; - - void _userNameListener() { - if (_searchController.text == _userNameQuery) { - return; - } - if (_debounce?.isActive ?? false) _debounce.cancel(); - _debounce = Timer(const Duration(milliseconds: 350), () { - if (mounted && modalSetStateCallback != null) { - modalSetStateCallback(() { - _userNameQuery = _searchController.text; - }); - } - }); - } - - @override - void initState() { - super.initState(); - var channel = StreamChannel.of(context); - _nameController = TextEditingController.fromValue( - TextEditingValue(text: channel.channel.extraData['name'] ?? '')); - _searchController = TextEditingController()..addListener(_userNameListener); - - _nameController.addListener(() { - setState(() {}); - }); - } - - @override - Widget build(BuildContext context) { - var channel = StreamChannel.of(context); - - return StreamBuilder>( - stream: channel.channel.state.membersStream, - builder: (context, snapshot) { - if (!snapshot.hasData) { - return Container( - color: StreamChatTheme.of(context).colorTheme.greyGainsboro, - child: Center(child: CircularProgressIndicator()), - ); - } - - var userMember = snapshot.data - .firstWhere((e) => e.user.id == StreamChat.of(context).user.id); - var isOwner = userMember.role == 'owner'; - - return Scaffold( - backgroundColor: StreamChatTheme.of(context).colorTheme.whiteSnow, - appBar: AppBar( - brightness: Theme.of(context).brightness, - elevation: 1.0, - toolbarHeight: 56.0, - backgroundColor: StreamChatTheme.of(context).colorTheme.white, - leading: InkWell( - onTap: () { - Navigator.pop(context); - }, - child: Padding( - padding: const EdgeInsets.only(left: 12.0), - child: StreamSvgIcon.left( - color: StreamChatTheme.of(context).colorTheme.black, - ), - ), - ), - leadingWidth: 36.0, - title: Column( - children: [ - StreamBuilder( - stream: channel.channelStateStream, - builder: (context, state) { - if (!state.hasData) { - return Text( - 'Loading...', - style: TextStyle( - color: - StreamChatTheme.of(context).colorTheme.black, - fontSize: 16, - ), - maxLines: 1, - overflow: TextOverflow.ellipsis, - ); - } - - return Text( - _getChannelName( - 2 * MediaQuery.of(context).size.width / 3, - members: snapshot.data, - extraData: state.data.channel.extraData, - maxFontSize: 16.0), - style: TextStyle( - color: StreamChatTheme.of(context).colorTheme.black, - fontSize: 16, - ), - maxLines: 1, - overflow: TextOverflow.ellipsis, - ); - }), - SizedBox( - height: 3.0, - ), - Text( - '${channel.channel.memberCount} Members, ${snapshot?.data?.where((e) => e.user.online)?.length ?? 0} Online', - style: TextStyle( - color: StreamChatTheme.of(context) - .colorTheme - .black - .withOpacity(0.5), - fontSize: 12.0, - ), - ), - ], - ), - centerTitle: true, - actions: [ - if (!channel.channel.isDistinct) - StreamNeumorphicButton( - child: InkWell( - onTap: () { - _buildAddUserModal(context); - }, - child: Padding( - padding: const EdgeInsets.all(8.0), - child: StreamSvgIcon.userAdd( - color: StreamChatTheme.of(context) - .colorTheme - .accentBlue), - ), - ), - ), - ], - ), - body: ListView( - children: [ - _buildMembers(snapshot.data), - Container( - height: 8.0, - color: StreamChatTheme.of(context).colorTheme.greyGainsboro, - ), - if (isOwner) _buildNameTile(), - _buildOptionListTiles(), - ], - ), - ); - }); - } - - Widget _buildMembers(List members) { - final groupMembers = members - ..sort((prev, curr) { - if (curr.role == 'owner') return 1; - return 0; - }); - - int groupMembersLength; - - if (listExpanded) { - groupMembersLength = groupMembers.length; - } else { - groupMembersLength = groupMembers.length > 6 ? 6 : groupMembers.length; - } - - return Column( - children: [ - ListView.builder( - shrinkWrap: true, - physics: NeverScrollableScrollPhysics(), - itemCount: groupMembersLength, - itemBuilder: (context, index) { - final member = groupMembers[index]; - return Material( - child: InkWell( - onTap: () { - var userMember = groupMembers.firstWhere( - (e) => e.user.id == StreamChat.of(context).user.id); - _showUserInfoModal(member.user, userMember.role == 'owner'); - }, - child: Container( - height: 65.0, - child: Column( - children: [ - Row( - children: [ - Padding( - padding: const EdgeInsets.symmetric( - horizontal: 8.0, vertical: 12.0), - child: UserAvatar( - user: member.user, - constraints: BoxConstraints( - maxHeight: 40.0, maxWidth: 40.0), - ), - ), - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text( - member.user.name, - style: TextStyle(fontWeight: FontWeight.bold), - ), - SizedBox( - height: 1.0, - ), - Text( - _getLastSeen(member.user), - style: TextStyle( - color: StreamChatTheme.of(context) - .colorTheme - .black - .withOpacity(0.5)), - ), - ], - ), - ), - Padding( - padding: const EdgeInsets.all(8.0), - child: Text( - member.role == 'owner' ? 'Owner' : '', - style: TextStyle( - color: StreamChatTheme.of(context) - .colorTheme - .black - .withOpacity(0.5)), - ), - ), - ], - ), - Container( - height: 1.0, - color: StreamChatTheme.of(context) - .colorTheme - .greyGainsboro, - ), - ], - ), - ), - ), - color: StreamChatTheme.of(context).colorTheme.whiteSnow, - ); - }, - ), - if (groupMembersLength != groupMembers.length) - InkWell( - onTap: () { - setState(() { - listExpanded = true; - }); - }, - child: Material( - color: StreamChatTheme.of(context).colorTheme.whiteSnow, - child: Container( - height: 65.0, - child: Column( - children: [ - Expanded( - child: Row( - children: [ - Padding( - padding: const EdgeInsets.symmetric( - horizontal: 21.0, vertical: 12.0), - child: StreamSvgIcon.down( - color: - StreamChatTheme.of(context).colorTheme.grey, - ), - ), - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text( - '${members.length - groupMembersLength} more', - style: TextStyle( - color: StreamChatTheme.of(context) - .colorTheme - .grey), - ), - ], - ), - ), - ], - ), - ), - Container( - height: 1.0, - color: - StreamChatTheme.of(context).colorTheme.greyGainsboro, - ), - ], - ), - ), - ), - ), - ], - ); - } - - Widget _buildNameTile() { - var channel = StreamChannel.of(context).channel; - var channelName = channel.extraData['name'] ?? ''; - - return Material( - color: StreamChatTheme.of(context).colorTheme.whiteSnow, - child: Container( - height: 56.0, - alignment: Alignment.center, - child: Row( - children: [ - Padding( - padding: const EdgeInsets.all(7.0), - child: Text( - 'NAME', - style: StreamChatTheme.of(context).textTheme.footnote.copyWith( - color: StreamChatTheme.of(context) - .colorTheme - .black - .withOpacity(0.5)), - ), - ), - SizedBox( - width: 7.0, - ), - Expanded( - child: TextField( - focusNode: _focusNode, - controller: _nameController, - cursorColor: StreamChatTheme.of(context).colorTheme.black, - decoration: InputDecoration.collapsed( - hintText: 'Add a group name', - hintStyle: StreamChatTheme.of(context) - .textTheme - .bodyBold - .copyWith( - color: StreamChatTheme.of(context) - .colorTheme - .black - .withOpacity(0.5))), - style: TextStyle( - fontWeight: FontWeight.bold, - height: 0.82, - ), - ), - ), - if ((channelName == null) || - (channelName != _nameController.text.trim())) - Row( - mainAxisSize: MainAxisSize.min, - children: [ - InkWell( - child: StreamSvgIcon.closeSmall(), - onTap: () { - setState(() { - _nameController.text = - _getChannelName(MediaQuery.of(context).size.width); - _focusNode.unfocus(); - }); - }, - ), - Padding( - padding: const EdgeInsets.only(right: 16.0, left: 8.0), - child: InkWell( - child: StreamSvgIcon.check( - color: - StreamChatTheme.of(context).colorTheme.accentBlue, - size: 24.0, - ), - onTap: () { - StreamChannel.of(context).channel.update({ - 'name': _nameController.text.trim(), - }).catchError((err) { - setState(() { - _nameController.text = channelName; - _focusNode.unfocus(); - }); - }); - }, - ), - ), - ], - ), - ], - ), - ), - ); - } - - Widget _buildOptionListTiles() { - var channel = StreamChannel.of(context); - - return Column( - children: [ - // OptionListTile( - // title: 'Notifications', - // leading: StreamSvgIcon.Icon_notification( - // size: 24.0, - // color: StreamChatTheme.of(context).colorTheme.black.withOpacity(0.5), - // ), - // trailing: CupertinoSwitch( - // value: true, - // onChanged: (val) {}, - // ), - // onTap: () {}, - // ), - StreamBuilder( - stream: StreamChannel.of(context).channel.isMutedStream, - builder: (context, snapshot) { - return OptionListTile( - tileColor: StreamChatTheme.of(context).colorTheme.whiteSnow, - separatorColor: - StreamChatTheme.of(context).colorTheme.greyGainsboro, - title: 'Mute group', - titleTextStyle: StreamChatTheme.of(context).textTheme.body, - leading: Padding( - padding: const EdgeInsets.symmetric(horizontal: 16.0), - child: StreamSvgIcon.mute( - size: 24.0, - color: StreamChatTheme.of(context) - .colorTheme - .black - .withOpacity(0.5), - ), - ), - trailing: snapshot.data == null - ? CircularProgressIndicator() - : CupertinoSwitch( - value: snapshot.data, - onChanged: (val) { - if (snapshot.data) { - channel.channel.unmute(); - } else { - channel.channel.mute(); - } - }, - ), - onTap: () {}, - ); - }), - OptionListTile( - tileColor: StreamChatTheme.of(context).colorTheme.whiteSnow, - separatorColor: StreamChatTheme.of(context).colorTheme.greyGainsboro, - title: 'Photos & Videos', - titleTextStyle: StreamChatTheme.of(context).textTheme.body, - leading: Padding( - padding: const EdgeInsets.symmetric(horizontal: 12.0), - child: StreamSvgIcon.pictures( - size: 32.0, - color: - StreamChatTheme.of(context).colorTheme.black.withOpacity(0.5), - ), - ), - trailing: StreamSvgIcon.right( - color: StreamChatTheme.of(context).colorTheme.grey, - ), - onTap: () { - var channel = StreamChannel.of(context).channel; - - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => StreamChannel( - channel: channel, - child: MessageSearchBloc( - child: ChannelMediaDisplayScreen( - sortOptions: [ - SortOption( - 'created_at', - direction: SortOption.ASC, - ), - ], - paginationParams: PaginationParams(limit: 20), - onShowMessage: (m, c) async { - final client = StreamChat.of(context).client; - final message = m; - final channel = client.channel( - c.type, - id: c.id, - ); - if (channel.state == null) { - await channel.watch(); - } - await Navigator.pushNamed( - context, - Routes.CHANNEL_PAGE, - arguments: ChannelPageArgs( - channel: channel, - initialMessage: message, - ), - ); - }, - ), - ), - ), - ), - ); - }, - ), - OptionListTile( - tileColor: StreamChatTheme.of(context).colorTheme.whiteSnow, - separatorColor: StreamChatTheme.of(context).colorTheme.greyGainsboro, - title: 'Files', - titleTextStyle: StreamChatTheme.of(context).textTheme.body, - leading: Padding( - padding: const EdgeInsets.symmetric(horizontal: 12.0), - child: StreamSvgIcon.files( - size: 32.0, - color: - StreamChatTheme.of(context).colorTheme.black.withOpacity(0.5), - ), - ), - trailing: StreamSvgIcon.right( - color: StreamChatTheme.of(context).colorTheme.grey, - ), - onTap: () { - var channel = StreamChannel.of(context).channel; - - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => StreamChannel( - channel: channel, - child: MessageSearchBloc( - child: ChannelFileDisplayScreen( - sortOptions: [ - SortOption( - 'created_at', - direction: SortOption.ASC, - ), - ], - paginationParams: PaginationParams(limit: 20), - ), - ), - ), - ), - ); - }, - ), - if (!channel.channel.isDistinct) - OptionListTile( - tileColor: StreamChatTheme.of(context).colorTheme.whiteSnow, - separatorColor: - StreamChatTheme.of(context).colorTheme.greyGainsboro, - title: 'Leave Group', - titleTextStyle: StreamChatTheme.of(context).textTheme.body, - leading: Padding( - padding: const EdgeInsets.symmetric(horizontal: 16.0), - child: StreamSvgIcon.userRemove( - size: 24.0, - color: StreamChatTheme.of(context) - .colorTheme - .black - .withOpacity(0.5), - ), - ), - trailing: Container( - height: 24.0, - width: 24.0, - ), - onTap: () async { - await channel.channel - .removeMembers([StreamChat.of(context).user.id]); - Navigator.pop(context); - Navigator.pop(context); - }, - ), - ], - ); - } - - void _buildAddUserModal(context) { - var channel = StreamChannel.of(context).channel; - - showDialog( - context: context, - barrierColor: StreamChatTheme.of(context).colorTheme.overlay, - builder: (context) { - return StatefulBuilder(builder: (context, modalSetState) { - modalSetStateCallback = modalSetState; - return Padding( - padding: EdgeInsets.only(top: 16.0, left: 8.0, right: 8.0), - child: Material( - borderRadius: BorderRadius.only( - topLeft: Radius.circular(16.0), - topRight: Radius.circular(16.0), - ), - clipBehavior: Clip.antiAlias, - child: Scaffold( - body: UsersBloc( - child: Column( - children: [ - Padding( - padding: const EdgeInsets.all(16), - child: _buildTextInputSection(modalSetState), - ), - Expanded( - child: UserListView( - selectedUsers: {}, - onUserTap: (user, _) async { - _searchController.clear(); - - await channel.addMembers([user.id]); - Navigator.pop(context); - setState(() {}); - }, - crossAxisCount: 4, - pagination: PaginationParams( - limit: 25, - ), - filter: { - if (_searchController.text.isNotEmpty) - 'name': { - r'$autocomplete': _userNameQuery, - }, - 'id': { - r'$nin': [ - StreamChat.of(context).user.id, - ...channel.state.members.map((e) => e.userId), - ], - }, - }, - sort: [ - SortOption( - 'name', - direction: 1, - ), - ], - emptyBuilder: (_) { - return LayoutBuilder( - builder: (context, viewportConstraints) { - return SingleChildScrollView( - physics: AlwaysScrollableScrollPhysics(), - child: ConstrainedBox( - constraints: BoxConstraints( - minHeight: viewportConstraints.maxHeight, - ), - child: Center( - child: Column( - children: [ - Padding( - padding: const EdgeInsets.all(24), - child: StreamSvgIcon.search( - size: 96, - color: StreamChatTheme.of(context) - .colorTheme - .grey, - ), - ), - Text( - 'No user matches these keywords...'), - ], - ), - ), - ), - ); - }, - ); - }, - ), - ), - ], - ), - ), - ), - ), - ); - }); - }, - ); - } - - Widget _buildTextInputSection(modalSetState) { - final theme = StreamChatTheme.of(context); - return Column( - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Expanded( - child: Container( - height: 36, - child: TextField( - controller: _searchController, - cursorColor: theme.colorTheme.black, - autofocus: true, - decoration: InputDecoration( - hintText: 'Search', - hintStyle: theme.textTheme.body.copyWith( - color: theme.colorTheme.grey, - ), - prefixIconConstraints: BoxConstraints.tight(Size(40, 24)), - prefixIcon: StreamSvgIcon.search( - color: theme.colorTheme.black, - size: 24, - ), - enabledBorder: OutlineInputBorder( - borderRadius: BorderRadius.circular(24.0), - borderSide: BorderSide( - color: theme.colorTheme.greyWhisper, - ), - ), - focusedBorder: OutlineInputBorder( - borderRadius: BorderRadius.circular(24.0), - borderSide: BorderSide( - color: theme.colorTheme.greyWhisper, - )), - contentPadding: const EdgeInsets.all(0), - ), - ), - ), - ), - SizedBox(width: 16.0), - IconButton( - icon: StreamSvgIcon.closeSmall( - color: theme.colorTheme.grey, - ), - constraints: BoxConstraints.tightFor( - height: 24, - width: 24, - ), - padding: EdgeInsets.zero, - splashRadius: 24, - onPressed: () => Navigator.pop(context), - ) - ], - ), - ], - ); - } - - void _showUserInfoModal(User user, bool isUserAdmin) { - var channel = StreamChannel.of(context).channel; - - showModalBottomSheet( - context: context, - clipBehavior: Clip.antiAlias, - isScrollControlled: true, - builder: (context) { - return StreamChannel( - channel: channel, - child: Material( - color: StreamChatTheme.of(context).colorTheme.white, - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - SizedBox( - height: 24.0, - ), - Center( - child: Text( - user.name, - style: TextStyle( - fontSize: 16.0, - fontWeight: FontWeight.bold, - ), - ), - ), - SizedBox( - height: 5.0, - ), - _buildConnectedTitleState(user), - Center( - child: Padding( - padding: const EdgeInsets.all(16.0), - child: UserAvatar( - user: user, - constraints: BoxConstraints( - maxHeight: 64.0, - minHeight: 64.0, - ), - borderRadius: BorderRadius.circular(32.0), - ), - ), - ), - if (StreamChat.of(context).user.id != user.id) - _buildModalListTile( - context, - StreamSvgIcon.user( - color: StreamChatTheme.of(context).colorTheme.grey, - size: 24.0, - ), - 'View info', - () async { - var client = StreamChat.of(context).client; - - var c = client.channel('messaging', extraData: { - 'members': [ - user.id, - StreamChat.of(context).user.id, - ], - }); - - await c.watch(); - - await Navigator.push( - context, - MaterialPageRoute( - builder: (context) => StreamChannel( - channel: c, - child: ChatInfoScreen( - user: user, - ), - ), - ), - ); - }, - ), - if (StreamChat.of(context).user.id != user.id) - _buildModalListTile( - context, - StreamSvgIcon.message( - color: StreamChatTheme.of(context).colorTheme.grey, - size: 24.0, - ), - 'Message', - () async { - var client = StreamChat.of(context).client; - - var c = client.channel('messaging', extraData: { - 'members': [ - user.id, - StreamChat.of(context).user.id, - ], - }); - - await c.watch(); - - await Navigator.push( - context, - MaterialPageRoute( - builder: (context) => StreamChannel( - channel: c, - child: ChannelPage(), - ), - ), - ); - }, - ), - if (!channel.isDistinct && - StreamChat.of(context).user.id != user.id && - isUserAdmin) - _buildModalListTile( - context, - StreamSvgIcon.iconUserSettings( - color: StreamChatTheme.of(context).colorTheme.grey, - size: 24.0, - ), - 'Make Owner', () { - // TODO: Add make owner implementation (Remaining from backend) - }), - if (!channel.isDistinct && - StreamChat.of(context).user.id != user.id && - isUserAdmin) - _buildModalListTile( - context, - StreamSvgIcon.userRemove( - color: StreamChatTheme.of(context).colorTheme.accentRed, - size: 24.0, - ), - 'Remove From Group', () async { - await channel.removeMembers([user.id]); - Navigator.pop(context); - }, color: StreamChatTheme.of(context).colorTheme.accentRed), - _buildModalListTile( - context, - StreamSvgIcon.closeSmall( - color: StreamChatTheme.of(context).colorTheme.grey, - size: 24.0, - ), - 'Cancel', () { - Navigator.pop(context); - }), - ], - ), - ), - ); - }, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.only( - topLeft: Radius.circular(16.0), - topRight: Radius.circular(16.0), - ), - ), - ); - } - - Widget _buildConnectedTitleState(User user) { - var alternativeWidget; - - final otherMember = user; - - if (otherMember != null) { - if (otherMember.online) { - alternativeWidget = Text( - 'Online', - style: TextStyle( - color: StreamChatTheme.of(context) - .colorTheme - .black - .withOpacity(0.5)), - ); - } else { - alternativeWidget = Text( - 'Last seen ${Jiffy(otherMember.lastActive).fromNow()}', - style: TextStyle( - color: StreamChatTheme.of(context) - .colorTheme - .black - .withOpacity(0.5)), - ); - } - } - - return alternativeWidget; - } - - Widget _buildModalListTile( - BuildContext context, Widget leading, String title, VoidCallback onTap, - {Color color}) { - color ??= StreamChatTheme.of(context).colorTheme.black; - - return Material( - color: StreamChatTheme.of(context).colorTheme.white, - child: InkWell( - onTap: onTap, - child: Column( - children: [ - Container( - height: 1.0, - color: StreamChatTheme.of(context).colorTheme.greyGainsboro, - ), - Container( - height: 64.0, - child: Row( - children: [ - Padding( - padding: const EdgeInsets.all(16.0), - child: leading, - ), - Expanded( - child: Text( - title, - style: - TextStyle(color: color, fontWeight: FontWeight.bold), - ), - ) - ], - ), - ), - ], - ), - ), - ); - } - - String _getChannelName(double width, - {List members, Map extraData, double maxFontSize}) { - String title; - var client = StreamChat.of(context); - if (extraData['name'] == null) { - final otherMembers = - members.where((member) => member.user.id != client.user.id); - if (otherMembers.isNotEmpty) { - final maxWidth = width; - final maxChars = maxWidth / maxFontSize; - var currentChars = 0; - final currentMembers = []; - otherMembers.forEach((element) { - final newLength = currentChars + element.user.name.length; - if (newLength < maxChars) { - currentChars = newLength; - currentMembers.add(element); - } - }); - - final exceedingMembers = otherMembers.length - currentMembers.length; - title = - '${currentMembers.map((e) => e.user.name).join(', ')} ${exceedingMembers > 0 ? '+ $exceedingMembers' : ''}'; - } else { - title = 'No title'; - } - } else { - title = extraData['name']; - } - return title; - } - - String _getLastSeen(User user) { - if (user.online) { - return 'Online'; - } else { - return 'Last seen ${Jiffy(user.lastActive).fromNow()}'; - } - } -} diff --git a/packages/stream_chat_flutter/example/lib/main.dart b/packages/stream_chat_flutter/example/lib/main.dart index 45f86f07..d2d691e9 100644 --- a/packages/stream_chat_flutter/example/lib/main.dart +++ b/packages/stream_chat_flutter/example/lib/main.dart @@ -1,832 +1,63 @@ -import 'dart:async'; - -import 'package:example/chat_info_screen.dart'; -import 'package:example/choose_user_page.dart'; -import 'package:example/group_info_screen.dart'; -import 'package:flutter/cupertino.dart'; -import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; -import 'package:flutter_secure_storage/flutter_secure_storage.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; -import 'package:stream_chat_persistence/stream_chat_persistence.dart'; -import 'package:streaming_shared_preferences/streaming_shared_preferences.dart'; - -import 'notifications_service.dart'; -import 'routes/app_routes.dart'; -import 'routes/routes.dart'; -import 'search_text_field.dart'; - -final chatPersistentClient = StreamChatPersistenceClient( - logLevel: Level.INFO, - connectionMode: ConnectionMode.background, -); void main() async { - WidgetsFlutterBinding.ensureInitialized(); - final secureStorage = FlutterSecureStorage(); - - final apiKey = await secureStorage.read(key: kStreamApiKey); - final userId = await secureStorage.read(key: kStreamUserId); - final client = StreamChatClient( - apiKey ?? kDefaultStreamApiKey, + 's2dxdhpxd94g', logLevel: Level.INFO, - )..chatPersistenceClient = chatPersistentClient; + ); - if (userId != null) { - final token = await secureStorage.read(key: kStreamToken); - await client.setUser( - User(id: userId), - token, - ); - } + await client.setUser( + User(id: 'super-band-9'), + 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoic3VwZXItYmFuZC05In0.0L6lGoeLwkz0aZRUcpZKsvaXtNEDHBcezVTZ0oPq40A', + ); - runApp(MyApp(client)); + final channel = client.channel('messaging', id: 'godevs'); + + // ignore: unawaited_futures + channel.watch(); + + runApp(MyApp(client, channel)); } class MyApp extends StatelessWidget { final StreamChatClient client; + final Channel channel; - MyApp(this.client); + MyApp(this.client, this.channel); @override Widget build(BuildContext context) { - return FutureBuilder( - future: StreamingSharedPreferences.instance, - builder: (context, snapshot) { - if (!snapshot.hasData) { - return SizedBox(); - } - return PreferenceBuilder( - preference: snapshot.data.getInt( - 'theme', - defaultValue: 0, - ), - builder: (context, snapshot) => MaterialApp( - builder: (context, child) { - return StreamChat( - client: client, - onBackgroundEventReceived: showLocalNotification, - child: Builder( - builder: (context) => AnnotatedRegion( - child: child, - value: SystemUiOverlayStyle( - systemNavigationBarColor: - StreamChatTheme.of(context).colorTheme.white, - systemNavigationBarIconBrightness: - Theme.of(context).brightness == Brightness.dark - ? Brightness.light - : Brightness.dark, - ), - ), - ), - ); - }, - debugShowCheckedModeBanner: false, - theme: ThemeData.light(), - darkTheme: ThemeData.dark(), - themeMode: { - -1: ThemeMode.dark, - 0: ThemeMode.system, - 1: ThemeMode.light, - }[snapshot], - onGenerateRoute: AppRoutes.generateRoute, - initialRoute: - client.state.user == null ? Routes.CHOOSE_USER : Routes.HOME, - ), + return MaterialApp( + builder: (context, widget) { + return StreamChat( + child: widget, + client: client, ); }, - ); - } -} - -class HomePage extends StatefulWidget { - @override - _HomePageState createState() => _HomePageState(); -} - -class _HomePageState extends State { - int _currentIndex = 0; - - bool _isSelected(int index) => _currentIndex == index; - - List get _navBarItems { - return [ - BottomNavigationBarItem( - icon: Stack( - clipBehavior: Clip.none, - children: [ - StreamSvgIcon.message( - color: _isSelected(0) - ? StreamChatTheme.of(context).colorTheme.black - : Colors.grey, - ), - Positioned( - top: -3, - right: -16, - child: UnreadIndicator(), - ), - ], - ), - label: 'Chats', - ), - BottomNavigationBarItem( - icon: Stack( - clipBehavior: Clip.none, - children: [ - StreamSvgIcon.mentions( - color: _isSelected(1) - ? StreamChatTheme.of(context).colorTheme.black - : Colors.grey, - ), - ], - ), - label: 'Mentions', - ), - ]; - } - - @override - Widget build(BuildContext context) { - final user = StreamChat.of(context).user; - return Scaffold( - backgroundColor: StreamChatTheme.of(context).colorTheme.whiteSnow, - appBar: ChannelListHeader( - onNewChatButtonTap: () { - Navigator.pushNamed(context, Routes.NEW_CHAT); - }, - preNavigationCallback: () { - FocusScope.of(context).requestFocus(FocusNode()); - }, - ), - drawer: _buildDrawer(context, user), - drawerEdgeDragWidth: 50, - bottomNavigationBar: BottomNavigationBar( - backgroundColor: StreamChatTheme.of(context).colorTheme.white, - currentIndex: _currentIndex, - items: _navBarItems, - selectedLabelStyle: StreamChatTheme.of(context).textTheme.footnoteBold, - unselectedLabelStyle: - StreamChatTheme.of(context).textTheme.footnoteBold, - type: BottomNavigationBarType.fixed, - selectedItemColor: StreamChatTheme.of(context).colorTheme.black, - unselectedItemColor: Colors.grey, - onTap: (index) { - setState(() => _currentIndex = index); - }, - ), - body: IndexedStack( - index: _currentIndex, - children: [ - ChannelListPage(), - UserMentionPage(), - ], - ), - ); - } - - 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, - ), - ), - ), - ], - ), - ), - 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, - ), - ), - trailing: IconButton( - icon: StreamSvgIcon.iconMoon( - size: 24, - ), - color: StreamChatTheme.of(context).colorTheme.grey, - onPressed: () async { - final sp = await StreamingSharedPreferences.instance; - sp.setInt( - 'theme', - Theme.of(context).brightness == Brightness.dark - ? 1 - : -1, - ); - }, - ), - ), - ), - ), - ], - ), - ), - ), + home: StreamChannel( + channel: channel, + child: ChannelPage(), ), ); } } -class UserMentionPage extends StatelessWidget { - @override - Widget build(BuildContext context) { - final user = StreamChat.of(context).user; - return MessageSearchBloc( - child: MessageSearchListView( - filters: { - 'members': { - r'$in': [user.id], - }, - }, - messageFilters: { - 'mentioned_users.id': { - r'$contains': user.id, - }, - }, - sortOptions: [ - SortOption( - 'created_at', - direction: SortOption.ASC, - ), - ], - paginationParams: PaginationParams(limit: 20), - showResultCount: false, - emptyBuilder: (_, __) { - return LayoutBuilder( - builder: (context, viewportConstraints) { - return SingleChildScrollView( - physics: AlwaysScrollableScrollPhysics(), - child: ConstrainedBox( - constraints: BoxConstraints( - minHeight: viewportConstraints.maxHeight, - ), - child: Center( - child: Column( - children: [ - Padding( - padding: const EdgeInsets.all(24), - child: StreamSvgIcon.mentions( - size: 96, - color: StreamChatTheme.of(context) - .colorTheme - .greyGainsboro, - ), - ), - Text( - 'No mentions exist yet...', - style: StreamChatTheme.of(context) - .textTheme - .body - .copyWith( - color: - StreamChatTheme.of(context).colorTheme.grey, - ), - ), - ], - ), - ), - ), - ); - }, - ); - }, - onItemTap: (messageResponse) async { - final client = StreamChat.of(context).client; - final message = messageResponse.message; - final channel = client.channel( - messageResponse.channel.type, - id: messageResponse.channel.id, - ); - if (channel.state == null) { - await channel.watch(); - } - Navigator.pushNamed( - context, - Routes.CHANNEL_PAGE, - arguments: ChannelPageArgs( - channel: channel, - initialMessage: message, - ), - ); - }, - ), - ); - } -} - -class ChannelListPage extends StatefulWidget { - @override - _ChannelListPageState createState() => _ChannelListPageState(); -} - -class _ChannelListPageState extends State { - TextEditingController _controller; - - String _channelQuery = ''; - - bool _isSearchActive = false; - - Timer _debounce; - - void _channelQueryListener() { - if (_debounce?.isActive ?? false) _debounce.cancel(); - _debounce = Timer(const Duration(milliseconds: 350), () { - if (mounted) { - setState(() { - _channelQuery = _controller.text; - _isSearchActive = _channelQuery.isNotEmpty; - }); - } - }); - } - - @override - void initState() { - super.initState(); - _controller = TextEditingController()..addListener(_channelQueryListener); - } - - @override - void dispose() { - _controller?.removeListener(_channelQueryListener); - _controller?.dispose(); - super.dispose(); - } - - @override - Widget build(BuildContext context) { - final user = StreamChat.of(context).user; - return WillPopScope( - onWillPop: () async { - if (_isSearchActive) { - _controller.clear(); - setState(() => _isSearchActive = false); - return false; - } - return true; - }, - child: ChannelsBloc( - child: MessageSearchBloc( - child: NestedScrollView( - floatHeaderSlivers: true, - headerSliverBuilder: (_, __) => [ - SliverToBoxAdapter( - child: SearchTextField( - controller: _controller, - showCloseButton: _isSearchActive, - ), - ), - ], - body: AnimatedSwitcher( - duration: const Duration(milliseconds: 350), - child: GestureDetector( - behavior: HitTestBehavior.opaque, - onPanDown: (_) => FocusScope.of(context).unfocus(), - child: _isSearchActive - ? MessageSearchListView( - messageQuery: _channelQuery, - filters: { - 'members': { - r'$in': [user.id] - } - }, - sortOptions: [ - SortOption( - 'created_at', - direction: SortOption.ASC, - ), - ], - pullToRefresh: false, - paginationParams: PaginationParams(limit: 20), - emptyBuilder: (_, query) { - return LayoutBuilder( - builder: (context, viewportConstraints) { - return SingleChildScrollView( - physics: AlwaysScrollableScrollPhysics(), - child: ConstrainedBox( - constraints: BoxConstraints( - minHeight: viewportConstraints.maxHeight, - ), - child: Center( - child: Column( - children: [ - Padding( - padding: const EdgeInsets.all(24), - child: StreamSvgIcon.search( - size: 96, - color: Colors.grey, - ), - ), - Text( - 'No results for \"$query\"...', - ), - ], - ), - ), - ), - ); - }, - ); - }, - onItemTap: (messageResponse) async { - FocusScope.of(context).requestFocus(FocusNode()); - final client = StreamChat.of(context).client; - final message = messageResponse.message; - final channel = client.channel( - messageResponse.channel.type, - id: messageResponse.channel.id, - ); - if (channel.state == null) { - await channel.watch(); - } - Navigator.pushNamed( - context, - Routes.CHANNEL_PAGE, - arguments: ChannelPageArgs( - channel: channel, - initialMessage: message, - ), - ); - }, - ) - : ChannelListView( - onStartChatPressed: () { - Navigator.pushNamed(context, Routes.NEW_CHAT); - }, - swipeToAction: true, - filter: { - 'members': { - r'$in': [user.id], - }, - }, - options: { - 'presence': true, - }, - pagination: PaginationParams( - limit: 20, - ), - channelWidget: ChannelPage(), - onViewInfoTap: (channel) { - if (channel.memberCount == 2 && channel.isDistinct) { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => StreamChannel( - channel: channel, - child: ChatInfoScreen( - user: channel.state.members.first.user, - ), - ), - ), - ); - } else { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => StreamChannel( - channel: channel, - child: GroupInfoScreen(), - ), - ), - ); - } - }, - ), - ), - ), - ), - ), - ), - ); - } -} - -class ChannelPageArgs { - final Channel channel; - final Message initialMessage; - - const ChannelPageArgs({ - this.channel, - this.initialMessage, - }); -} - -class ChannelPage extends StatefulWidget { - final int initialScrollIndex; - final double initialAlignment; - final bool highlightInitialMessage; - +class ChannelPage extends StatelessWidget { const ChannelPage({ Key key, - this.initialScrollIndex, - this.initialAlignment, - this.highlightInitialMessage = false, }) : super(key: key); - @override - _ChannelPageState createState() => _ChannelPageState(); -} - -class _ChannelPageState extends State { - Message _quotedMessage; - FocusNode _focusNode; - - @override - void initState() { - _focusNode = FocusNode(); - super.initState(); - } - - @override - void dispose() { - _focusNode.dispose(); - super.dispose(); - } - - void _reply(Message message) { - setState(() => _quotedMessage = message); - WidgetsBinding.instance.addPostFrameCallback((timeStamp) { - _focusNode.requestFocus(); - }); - } - @override Widget build(BuildContext context) { return Scaffold( - backgroundColor: StreamChatTheme.of(context).colorTheme.whiteSnow, - appBar: ChannelHeader( - showTypingIndicator: false, - onImageTap: () async { - var channel = StreamChannel.of(context).channel; - - if (channel.memberCount == 2 && channel.isDistinct) { - final currentUser = StreamChat.of(context).user; - final otherUser = channel.state.members.firstWhere( - (element) => element.user.id != currentUser.id, - orElse: () => null, - ); - if (otherUser != null) { - final pop = await Navigator.push( - context, - MaterialPageRoute( - builder: (context) => StreamChannel( - child: ChatInfoScreen( - user: otherUser.user, - ), - channel: channel, - ), - ), - ); - - if (pop == true) { - Navigator.pop(context); - } - } - } else { - await Navigator.push( - context, - MaterialPageRoute( - builder: (context) => StreamChannel( - child: GroupInfoScreen(), - channel: channel, - ), - ), - ); - } - }, - ), + appBar: ChannelHeader(), body: Column( children: [ Expanded( - child: Stack( - children: [ - MessageListView( - initialScrollIndex: widget.initialScrollIndex, - initialAlignment: widget.initialAlignment, - highlightInitialMessage: widget.highlightInitialMessage, - onMessageSwiped: _reply, - onReplyTap: _reply, - threadBuilder: (_, parentMessage) { - return ThreadPage( - parent: parentMessage, - ); - }, - onShowMessage: (m, c) async { - final client = StreamChat.of(context).client; - final message = m; - final channel = client.channel( - c.type, - id: c.id, - ); - if (channel.state == null) { - await channel.watch(); - } - Navigator.pushReplacementNamed( - context, - Routes.CHANNEL_PAGE, - arguments: ChannelPageArgs( - channel: channel, - initialMessage: message, - ), - ); - }, - ), - Positioned( - bottom: 0, - left: 0, - right: 0, - child: Container( - alignment: Alignment.centerLeft, - color: StreamChatTheme.of(context) - .colorTheme - .whiteSnow - .withOpacity(.9), - child: TypingIndicator( - alignment: Alignment.centerLeft, - padding: const EdgeInsets.symmetric( - horizontal: 8, - vertical: 4, - ), - style: StreamChatTheme.of(context) - .textTheme - .footnote - .copyWith( - color: - StreamChatTheme.of(context).colorTheme.grey), - ), - ), - ), - ], - ), - ), - MessageInput( - focusNode: _focusNode, - quotedMessage: _quotedMessage, - onQuotedMessageCleared: () { - setState(() => _quotedMessage = null); - _focusNode.unfocus(); - }, + child: MessageListView(), ), - ], - ), - ); - } -} - -class ThreadPage extends StatefulWidget { - final Message parent; - final int initialScrollIndex; - final double initialAlignment; - - ThreadPage({ - Key key, - this.parent, - this.initialScrollIndex, - this.initialAlignment, - }) : super(key: key); - - @override - _ThreadPageState createState() => _ThreadPageState(); -} - -class _ThreadPageState extends State { - Message _quotedMessage; - FocusNode _focusNode = FocusNode(); - - @override - void dispose() { - _focusNode.dispose(); - super.dispose(); - } - - void _reply(Message message) { - setState(() => _quotedMessage = message); - WidgetsBinding.instance.addPostFrameCallback((timeStamp) { - _focusNode.requestFocus(); - }); - } - - @override - Widget build(BuildContext context) { - return Scaffold( - backgroundColor: StreamChatTheme.of(context).colorTheme.whiteSnow, - appBar: ThreadHeader( - parent: widget.parent, - ), - body: Column( - children: [ - Expanded( - child: MessageListView( - parentMessage: widget.parent, - initialScrollIndex: widget.initialScrollIndex, - initialAlignment: widget.initialAlignment, - onMessageSwiped: _reply, - onReplyTap: _reply, - ), - ), - if (widget.parent.type != 'deleted') - MessageInput( - parentMessage: widget.parent, - focusNode: _focusNode, - quotedMessage: _quotedMessage, - onQuotedMessageCleared: () { - setState(() => _quotedMessage = null); - _focusNode.unfocus(); - }, - ), + MessageInput(), ], ), ); diff --git a/packages/stream_chat_flutter/example/lib/new_chat_screen.dart b/packages/stream_chat_flutter/example/lib/new_chat_screen.dart deleted file mode 100644 index 7f47e871..00000000 --- a/packages/stream_chat_flutter/example/lib/new_chat_screen.dart +++ /dev/null @@ -1,417 +0,0 @@ -import 'dart:async'; - -import 'package:flutter/material.dart'; -import 'package:stream_chat_flutter/stream_chat_flutter.dart'; - -import 'chips_input_text_field.dart'; -import 'main.dart'; -import 'routes/routes.dart'; - -class NewChatScreen extends StatefulWidget { - @override - _NewChatScreenState createState() => _NewChatScreenState(); -} - -class _NewChatScreenState extends State { - final _chipInputTextFieldStateKey = - GlobalKey>(); - - TextEditingController _controller; - - ChipInputTextFieldState get _chipInputTextFieldState => - _chipInputTextFieldStateKey.currentState; - - String _userNameQuery = ''; - - final _selectedUsers = {}; - - final _searchFocusNode = FocusNode(); - final _messageInputFocusNode = FocusNode(); - - bool _isSearchActive = false; - - Channel channel; - - Timer _debounce; - - bool _showUserList = true; - - void _userNameListener() { - if (_debounce?.isActive ?? false) _debounce.cancel(); - _debounce = Timer(const Duration(milliseconds: 350), () { - if (mounted) - setState(() { - _userNameQuery = _controller.text; - _isSearchActive = _userNameQuery.isNotEmpty; - }); - }); - } - - @override - void initState() { - super.initState(); - channel = StreamChat.of(context).client.channel('messaging'); - _controller = TextEditingController()..addListener(_userNameListener); - - _searchFocusNode.addListener(() async { - if (_searchFocusNode.hasFocus && !_showUserList) { - setState(() { - _showUserList = true; - }); - } - }); - - _messageInputFocusNode.addListener(() async { - if (_messageInputFocusNode.hasFocus && _selectedUsers.isNotEmpty) { - final chatState = StreamChat.of(context); - - final res = await chatState.client.queryChannels( - options: { - 'state': false, - 'watch': false, - }, - filter: { - 'members': [ - ..._selectedUsers.map((e) => e.id), - chatState.user.id, - ], - 'distinct': true, - }, - messageLimit: 0, - paginationParams: PaginationParams( - limit: 1, - ), - ); - - final _channelExisted = res.length == 1; - if (_channelExisted) { - channel = res.first; - await channel.watch(); - } else { - channel = chatState.client.channel( - 'messaging', - extraData: { - 'members': [ - ..._selectedUsers.map((e) => e.id), - chatState.user.id, - ], - }, - ); - } - - setState(() { - _showUserList = false; - }); - } - }); - } - - @override - void dispose() { - _searchFocusNode.dispose(); - _messageInputFocusNode.dispose(); - _controller?.clear(); - _controller?.removeListener(_userNameListener); - _controller?.dispose(); - super.dispose(); - } - - @override - Widget build(BuildContext context) { - return Scaffold( - backgroundColor: StreamChatTheme.of(context).colorTheme.whiteSnow, - appBar: AppBar( - brightness: Theme.of(context).brightness, - elevation: 0, - backgroundColor: StreamChatTheme.of(context).colorTheme.white, - leading: const StreamBackButton(), - title: Text( - 'New Chat', - style: StreamChatTheme.of(context) - .textTheme - .headlineBold - .copyWith(color: StreamChatTheme.of(context).colorTheme.black), - ), - centerTitle: true, - ), - body: ConnectionStatusBuilder( - statusBuilder: (context, status) { - String statusString = ''; - bool showStatus = true; - - switch (status) { - case ConnectionStatus.connected: - statusString = 'Connected'; - showStatus = false; - break; - case ConnectionStatus.connecting: - statusString = 'Reconnecting...'; - break; - case ConnectionStatus.disconnected: - statusString = 'Disconnected'; - break; - } - return InfoTile( - showMessage: showStatus, - tileAnchor: Alignment.topCenter, - childAnchor: Alignment.topCenter, - message: statusString, - child: StreamChannel( - showLoading: false, - channel: channel, - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - ChipsInputTextField( - key: _chipInputTextFieldStateKey, - controller: _controller, - focusNode: _searchFocusNode, - chipBuilder: (context, user) { - return GestureDetector( - onTap: () { - _chipInputTextFieldState.removeItem(user); - _searchFocusNode.requestFocus(); - }, - child: Stack( - alignment: AlignmentDirectional.centerStart, - children: [ - Container( - decoration: BoxDecoration( - color: StreamChatTheme.of(context) - .colorTheme - .greyGainsboro, - borderRadius: BorderRadius.circular(12), - ), - padding: const EdgeInsets.only(left: 24), - child: Padding( - padding: const EdgeInsets.fromLTRB(8, 4, 12, 4), - child: Text( - user.name, - maxLines: 1, - style: TextStyle( - color: StreamChatTheme.of(context) - .colorTheme - .black, - ), - ), - ), - ), - Container( - foregroundDecoration: BoxDecoration( - color: StreamChatTheme.of(context) - .colorTheme - .overlay, - shape: BoxShape.circle, - ), - child: UserAvatar( - showOnlineStatus: false, - user: user, - constraints: BoxConstraints.tightFor( - height: 24, - width: 24, - ), - ), - ), - StreamSvgIcon.close(), - ], - ), - ); - }, - onChipAdded: (user) { - setState(() => _selectedUsers.add(user)); - }, - onChipRemoved: (user) { - setState(() => _selectedUsers.remove(user)); - }, - ), - if (!_isSearchActive && !_selectedUsers.isNotEmpty) - Container( - child: InkWell( - onTap: () { - Navigator.pushNamed( - context, - Routes.NEW_GROUP_CHAT, - ); - }, - child: Padding( - padding: const EdgeInsets.symmetric(vertical: 8), - child: Row( - children: [ - StreamNeumorphicButton( - child: Center( - child: StreamSvgIcon.contacts( - color: StreamChatTheme.of(context) - .colorTheme - .accentBlue, - size: 24, - ), - ), - ), - SizedBox(width: 8), - Text( - 'Create a Group', - style: StreamChatTheme.of(context) - .textTheme - .bodyBold, - ), - ], - ), - ), - ), - ), - if (_showUserList) - Container( - width: double.maxFinite, - decoration: BoxDecoration( - gradient: - StreamChatTheme.of(context).colorTheme.bgGradient, - ), - child: Padding( - padding: const EdgeInsets.symmetric( - vertical: 8, - horizontal: 8, - ), - child: Text( - _isSearchActive - ? "Matches for \"$_userNameQuery\"" - : 'On the platform', - style: StreamChatTheme.of(context) - .textTheme - .footnote - .copyWith( - color: StreamChatTheme.of(context) - .colorTheme - .black - .withOpacity(.5))), - ), - ), - Expanded( - child: _showUserList - ? GestureDetector( - behavior: HitTestBehavior.opaque, - onPanDown: (_) => FocusScope.of(context).unfocus(), - child: UsersBloc( - child: UserListView( - selectedUsers: _selectedUsers, - groupAlphabetically: - _isSearchActive ? false : true, - onUserTap: (user, _) { - _controller.clear(); - if (!_selectedUsers.contains(user)) { - _chipInputTextFieldState - ..addItem(user) - ..pauseItemAddition(); - } else { - _chipInputTextFieldState.removeItem(user); - } - }, - pagination: PaginationParams( - limit: 25, - ), - filter: { - if (_userNameQuery.isNotEmpty) - 'name': { - r'$autocomplete': _userNameQuery, - }, - 'id': { - r'$ne': StreamChat.of(context).user.id, - }, - }, - sort: [ - SortOption( - 'name', - direction: 1, - ), - ], - emptyBuilder: (_) { - return LayoutBuilder( - builder: (context, viewportConstraints) { - return SingleChildScrollView( - physics: - AlwaysScrollableScrollPhysics(), - child: ConstrainedBox( - constraints: BoxConstraints( - minHeight: - viewportConstraints.maxHeight, - ), - child: Center( - child: Column( - children: [ - Padding( - padding: - const EdgeInsets.all(24), - child: StreamSvgIcon.search( - size: 96, - color: Colors.grey, - ), - ), - Text( - 'No user matches these keywords...', - style: StreamChatTheme.of( - context) - .textTheme - .footnote - .copyWith( - color: StreamChatTheme - .of(context) - .colorTheme - .black - .withOpacity(.5)), - ), - ], - ), - ), - ), - ); - }, - ); - }, - ), - ), - ) - : FutureBuilder( - future: channel.initialized, - builder: (context, snapshot) { - if (snapshot.data == true) { - return MessageListView(); - } - - return Center( - child: Text( - 'No chats here yet...', - style: TextStyle( - fontSize: 12, - color: StreamChatTheme.of(context) - .colorTheme - .black - .withOpacity(.5), - ), - ), - ); - }, - ), - ), - MessageInput( - focusNode: _messageInputFocusNode, - preMessageSending: (message) async { - await channel.watch(); - return message; - }, - onMessageSent: (m) { - Navigator.pushNamedAndRemoveUntil( - context, - Routes.CHANNEL_PAGE, - ModalRoute.withName(Routes.HOME), - arguments: ChannelPageArgs(channel: channel), - ); - }, - ), - ], - ), - ), - ); - }, - ), - ); - } -} diff --git a/packages/stream_chat_flutter/example/lib/new_group_chat_screen.dart b/packages/stream_chat_flutter/example/lib/new_group_chat_screen.dart deleted file mode 100644 index 209d3729..00000000 --- a/packages/stream_chat_flutter/example/lib/new_group_chat_screen.dart +++ /dev/null @@ -1,339 +0,0 @@ -import 'dart:async'; - -import 'package:flutter/material.dart'; -import 'package:stream_chat_flutter/stream_chat_flutter.dart'; - -import 'routes/routes.dart'; -import 'search_text_field.dart'; - -class NewGroupChatScreen extends StatefulWidget { - @override - _NewGroupChatScreenState createState() => _NewGroupChatScreenState(); -} - -class _NewGroupChatScreenState extends State { - TextEditingController _controller; - - String _userNameQuery = ''; - - final _selectedUsers = {}; - - bool _isSearchActive = false; - - Timer _debounce; - - void _userNameListener() { - if (_debounce?.isActive ?? false) _debounce.cancel(); - _debounce = Timer(const Duration(milliseconds: 350), () { - if (mounted) { - setState(() { - _userNameQuery = _controller.text; - _isSearchActive = _userNameQuery.isNotEmpty; - }); - } - }); - } - - @override - void initState() { - super.initState(); - _controller = TextEditingController()..addListener(_userNameListener); - } - - @override - void dispose() { - _controller?.clear(); - _controller?.removeListener(_userNameListener); - _controller?.dispose(); - super.dispose(); - } - - @override - Widget build(BuildContext context) { - return Scaffold( - backgroundColor: StreamChatTheme.of(context).colorTheme.whiteSnow, - appBar: AppBar( - elevation: 1, - backgroundColor: StreamChatTheme.of(context).colorTheme.white, - leading: const StreamBackButton(), - title: Text( - 'Add Group Members', - style: TextStyle( - color: StreamChatTheme.of(context).colorTheme.black, - fontSize: 16, - ), - ), - centerTitle: true, - actions: [ - if (_selectedUsers.isNotEmpty) - IconButton( - icon: StreamSvgIcon.arrowRight( - color: StreamChatTheme.of(context).colorTheme.accentBlue, - ), - onPressed: () async { - final updatedList = await Navigator.pushNamed( - context, - Routes.NEW_GROUP_CHAT_DETAILS, - arguments: _selectedUsers.toList(growable: false), - ); - if (updatedList != null) { - setState(() { - _selectedUsers - ..clear() - ..addAll(updatedList); - }); - } - }, - ) - ], - ), - body: ConnectionStatusBuilder( - statusBuilder: (context, status) { - String statusString = ''; - bool showStatus = true; - - switch (status) { - case ConnectionStatus.connected: - statusString = 'Connected'; - showStatus = false; - break; - case ConnectionStatus.connecting: - statusString = 'Reconnecting...'; - break; - case ConnectionStatus.disconnected: - statusString = 'Disconnected'; - break; - } - return InfoTile( - showMessage: showStatus, - tileAnchor: Alignment.topCenter, - childAnchor: Alignment.topCenter, - message: statusString, - child: NestedScrollView( - floatHeaderSlivers: true, - headerSliverBuilder: - (BuildContext context, bool innerBoxIsScrolled) { - return [ - SliverToBoxAdapter( - child: SearchTextField( - controller: _controller, - ), - ), - if (_selectedUsers.isNotEmpty) - SliverToBoxAdapter( - child: Container( - height: 104, - child: ListView.separated( - scrollDirection: Axis.horizontal, - itemCount: _selectedUsers.length, - padding: const EdgeInsets.all(8), - separatorBuilder: (_, __) => SizedBox(width: 16), - itemBuilder: (_, index) { - final user = _selectedUsers.elementAt(index); - return Column( - children: [ - Stack( - children: [ - UserAvatar( - onlineIndicatorAlignment: - Alignment(0.9, 0.9), - user: user, - showOnlineStatus: true, - borderRadius: BorderRadius.circular(32), - constraints: BoxConstraints.tightFor( - height: 64, - width: 64, - ), - ), - Positioned( - top: -4, - right: -4, - child: GestureDetector( - onTap: () { - if (_selectedUsers.contains(user)) { - setState(() => - _selectedUsers.remove(user)); - } - }, - child: Container( - decoration: BoxDecoration( - color: StreamChatTheme.of(context) - .colorTheme - .white, - shape: BoxShape.circle, - border: Border.all( - color: StreamChatTheme.of(context) - .colorTheme - .whiteSnow, - ), - ), - child: StreamSvgIcon.close( - color: StreamChatTheme.of(context) - .colorTheme - .black, - size: 24, - ), - ), - ), - ) - ], - ), - SizedBox(height: 4), - Text( - user.name.split(' ')[0], - style: TextStyle( - fontWeight: FontWeight.bold, - fontSize: 12, - ), - ), - ], - ); - }, - ), - ), - ), - SliverPersistentHeader( - pinned: true, - delegate: _HeaderDelegate( - height: 30, - child: Container( - width: double.maxFinite, - decoration: BoxDecoration( - gradient: - StreamChatTheme.of(context).colorTheme.bgGradient, - ), - child: Padding( - padding: const EdgeInsets.symmetric( - vertical: 8, - horizontal: 8, - ), - child: Text( - _isSearchActive - ? 'Matches for \"$_userNameQuery\"' - : 'On the platform', - style: TextStyle( - color: - StreamChatTheme.of(context).colorTheme.grey, - ), - ), - ), - ), - ), - ), - ]; - }, - body: GestureDetector( - behavior: HitTestBehavior.opaque, - onPanDown: (_) => FocusScope.of(context).unfocus(), - child: UsersBloc( - child: UserListView( - selectedUsers: _selectedUsers, - pullToRefresh: false, - groupAlphabetically: _isSearchActive ? false : true, - onUserTap: (user, _) { - if (!_selectedUsers.contains(user)) { - setState(() { - _selectedUsers.add(user); - }); - } else { - setState(() { - _selectedUsers.remove(user); - }); - } - }, - pagination: PaginationParams( - limit: 25, - ), - filter: { - if (_userNameQuery.isNotEmpty) - 'name': { - r'$autocomplete': _userNameQuery, - }, - 'id': { - r'$ne': StreamChat.of(context).user.id, - } - }, - sort: [ - SortOption( - 'name', - direction: 1, - ), - ], - emptyBuilder: (_) { - return LayoutBuilder( - builder: (context, viewportConstraints) { - return SingleChildScrollView( - physics: AlwaysScrollableScrollPhysics(), - child: ConstrainedBox( - constraints: BoxConstraints( - minHeight: viewportConstraints.maxHeight, - ), - child: Center( - child: Column( - children: [ - Padding( - padding: const EdgeInsets.all(24), - child: StreamSvgIcon.search( - size: 96, - color: StreamChatTheme.of(context) - .colorTheme - .grey, - ), - ), - Text( - 'No user matches these keywords...', - style: StreamChatTheme.of(context) - .textTheme - .footnote - .copyWith( - color: StreamChatTheme.of(context) - .colorTheme - .grey, - ), - ), - ], - ), - ), - ), - ); - }, - ); - }, - ), - ), - ), - ), - ); - }, - ), - ); - } -} - -class _HeaderDelegate extends SliverPersistentHeaderDelegate { - final Widget child; - final double height; - - const _HeaderDelegate({ - @required this.child, - @required this.height, - }); - - @override - Widget build( - BuildContext context, double shrinkOffset, bool overlapsContent) { - return Container( - color: StreamChatTheme.of(context).colorTheme.white, - child: child, - ); - } - - @override - double get maxExtent => height; - - @override - double get minExtent => height; - - @override - bool shouldRebuild(_HeaderDelegate oldDelegate) => true; -} diff --git a/packages/stream_chat_flutter/example/lib/notifications_service.dart b/packages/stream_chat_flutter/example/lib/notifications_service.dart deleted file mode 100644 index 246923df..00000000 --- a/packages/stream_chat_flutter/example/lib/notifications_service.dart +++ /dev/null @@ -1,31 +0,0 @@ -import 'package:flutter_local_notifications/flutter_local_notifications.dart' - hide Message; -import 'package:stream_chat_flutter/stream_chat_flutter.dart'; - -void showLocalNotification(Event event) async { - if (event.message == null) return; - final flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin(); - final initializationSettingsAndroid = - AndroidInitializationSettings('launch_background'); - final initializationSettingsIOS = IOSInitializationSettings(); - final initializationSettings = InitializationSettings( - android: initializationSettingsAndroid, - iOS: initializationSettingsIOS, - ); - await flutterLocalNotificationsPlugin.initialize(initializationSettings); - await flutterLocalNotificationsPlugin.show( - event.message.id.hashCode, - event.message.user.name, - event.message.text, - NotificationDetails( - android: AndroidNotificationDetails( - 'message channel', - 'Message channel', - 'Channel used for showing messages', - priority: Priority.high, - importance: Importance.high, - ), - iOS: IOSNotificationDetails(), - ), - ); -} diff --git a/packages/stream_chat_flutter/example/lib/routes/app_routes.dart b/packages/stream_chat_flutter/example/lib/routes/app_routes.dart deleted file mode 100644 index e7c7e318..00000000 --- a/packages/stream_chat_flutter/example/lib/routes/app_routes.dart +++ /dev/null @@ -1,93 +0,0 @@ -import 'routes.dart'; -import 'package:flutter/material.dart'; -import '../choose_user_page.dart'; -import '../advanced_options_page.dart'; -import 'package:stream_chat_flutter/stream_chat_flutter.dart'; -import '../main.dart'; -import '../group_chat_details_screen.dart'; -import '../new_group_chat_screen.dart'; -import '../new_chat_screen.dart'; -import '../chat_info_screen.dart'; -import '../group_info_screen.dart'; - -class AppRoutes { - /// Add entry for new route here - static Route generateRoute(RouteSettings settings) { - final args = settings.arguments; - switch (settings.name) { - case Routes.APP: - return MaterialPageRoute( - settings: const RouteSettings(name: Routes.APP), - builder: (_) { - return MyApp(args); - }); - case Routes.HOME: - return MaterialPageRoute( - settings: const RouteSettings(name: Routes.HOME), - builder: (_) { - return HomePage(); - }); - case Routes.CHOOSE_USER: - return MaterialPageRoute( - settings: const RouteSettings(name: Routes.CHOOSE_USER), - builder: (_) { - return ChooseUserPage(); - }); - case Routes.ADVANCED_OPTIONS: - return MaterialPageRoute( - settings: const RouteSettings(name: Routes.ADVANCED_OPTIONS), - builder: (_) => AdvancedOptionsPage(), - ); - case Routes.CHANNEL_PAGE: - return MaterialPageRoute( - settings: const RouteSettings(name: Routes.CHANNEL_PAGE), - builder: (_) { - final arg = args as ChannelPageArgs; - return StreamChannel( - channel: arg.channel, - initialMessageId: arg.initialMessage?.id, - child: ChannelPage( - highlightInitialMessage: arg.initialMessage != null, - ), - ); - }); - case Routes.NEW_CHAT: - return MaterialPageRoute( - settings: const RouteSettings(name: Routes.NEW_CHAT), - builder: (_) { - return NewChatScreen(); - }); - case Routes.NEW_GROUP_CHAT: - return MaterialPageRoute( - settings: const RouteSettings(name: Routes.NEW_GROUP_CHAT), - builder: (_) { - return NewGroupChatScreen(); - }); - case Routes.NEW_GROUP_CHAT_DETAILS: - return MaterialPageRoute( - settings: const RouteSettings(name: Routes.NEW_GROUP_CHAT_DETAILS), - builder: (_) { - return GroupChatDetailsScreen( - selectedUsers: args, - ); - }); - case Routes.CHAT_INFO_SCREEN: - return MaterialPageRoute( - settings: const RouteSettings(name: Routes.CHAT_INFO_SCREEN), - builder: (_) { - return ChatInfoScreen( - user: args, - ); - }); - case Routes.GROUP_INFO_SCREEN: - return MaterialPageRoute( - settings: const RouteSettings(name: Routes.GROUP_INFO_SCREEN), - builder: (_) { - return GroupInfoScreen(); - }); - // Default case, should not reach here. - default: - return null; - } - } -} diff --git a/packages/stream_chat_flutter/example/lib/routes/routes.dart b/packages/stream_chat_flutter/example/lib/routes/routes.dart deleted file mode 100644 index 2280ca30..00000000 --- a/packages/stream_chat_flutter/example/lib/routes/routes.dart +++ /dev/null @@ -1,13 +0,0 @@ -/// Define all the route names here -class Routes { - static const String APP = '/app'; - static const String HOME = '/home'; - static const String CHOOSE_USER = '/choose_user'; - static const String ADVANCED_OPTIONS = '/advance_options'; - static const String CHANNEL_PAGE = '/channel_page'; - static const String NEW_CHAT = '/new_chat'; - static const String NEW_GROUP_CHAT = '/new_group_chat'; - static const String NEW_GROUP_CHAT_DETAILS = '/new_group_chat_details'; - static const String CHAT_INFO_SCREEN = '/chat_info_screen'; - static const String GROUP_INFO_SCREEN = '/group_info_screen'; -} diff --git a/packages/stream_chat_flutter/example/lib/search_text_field.dart b/packages/stream_chat_flutter/example/lib/search_text_field.dart deleted file mode 100644 index 9628ddba..00000000 --- a/packages/stream_chat_flutter/example/lib/search_text_field.dart +++ /dev/null @@ -1,94 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:stream_chat_flutter/stream_chat_flutter.dart'; - -class SearchTextField extends StatelessWidget { - final TextEditingController controller; - final ValueChanged onChanged; - final String hintText; - final VoidCallback onTap; - final bool showCloseButton; - - const SearchTextField({ - Key key, - @required this.controller, - this.onChanged, - this.onTap, - this.hintText = 'Search', - this.showCloseButton = true, - }) : super(key: key); - - @override - Widget build(BuildContext context) { - return Container( - height: 36, - decoration: BoxDecoration( - color: StreamChatTheme.of(context).colorTheme.white, - border: Border.all( - color: StreamChatTheme.of(context).colorTheme.greyWhisper, - ), - borderRadius: BorderRadius.circular(24), - ), - margin: const EdgeInsets.symmetric( - vertical: 8, - horizontal: 8, - ), - child: Row( - children: [ - Expanded( - child: TextField( - onTap: onTap, - controller: controller, - onChanged: onChanged, - decoration: InputDecoration( - prefixText: ' ', - prefixIconConstraints: BoxConstraints.tight(Size(40, 24)), - prefixIcon: Padding( - padding: const EdgeInsets.only( - left: 8, - right: 8, - ), - child: StreamSvgIcon.search( - color: StreamChatTheme.of(context).colorTheme.black, - size: 24, - ), - ), - hintText: hintText, - hintStyle: StreamChatTheme.of(context).textTheme.body.copyWith( - color: StreamChatTheme.of(context) - .colorTheme - .black - .withOpacity(.5)), - contentPadding: const EdgeInsets.all(0), - border: OutlineInputBorder( - borderSide: BorderSide.none, - borderRadius: BorderRadius.circular(24), - ), - ), - ), - ), - if (showCloseButton) - Material( - color: Colors.transparent, - child: IconButton( - padding: const EdgeInsets.all(0), - icon: StreamSvgIcon.closeSmall( - color: Colors.grey, - ), - splashRadius: 24, - onPressed: () { - if (controller.text.isNotEmpty) { - Future.microtask( - () => [ - controller.clear(), - if (onChanged != null) onChanged(''), - ], - ); - } - }, - ), - ), - ], - ), - ); - } -} diff --git a/packages/stream_chat_flutter/example/lib/stream_version.dart b/packages/stream_chat_flutter/example/lib/stream_version.dart deleted file mode 100644 index b3f926be..00000000 --- a/packages/stream_chat_flutter/example/lib/stream_version.dart +++ /dev/null @@ -1,39 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; -import 'package:yaml/yaml.dart'; -import 'package:stream_chat_flutter/stream_chat_flutter.dart'; - -class StreamVersion extends StatelessWidget { - const StreamVersion({ - Key key, - }) : super(key: key); - - @override - Widget build(BuildContext context) { - return Container( - padding: const EdgeInsets.symmetric(vertical: 16), - alignment: Alignment.bottomCenter, - child: FutureBuilder( - future: rootBundle.loadString('pubspec.lock'), - builder: (context, snapshot) { - if (!snapshot.hasData) { - return SizedBox(); - } - - final pubspec = snapshot.data; - final yaml = loadYaml(pubspec); - final streamChatDep = - yaml['packages']['stream_chat_flutter']['version']; - - return Text( - 'Stream SDK v ${streamChatDep}', - style: TextStyle( - fontSize: 14, - color: StreamChatTheme.of(context).colorTheme.greyGainsboro, - ), - ); - }, - ), - ); - } -} diff --git a/packages/stream_chat_flutter/example/pubspec.yaml b/packages/stream_chat_flutter/example/pubspec.yaml index 9b387e39..7a1863b0 100644 --- a/packages/stream_chat_flutter/example/pubspec.yaml +++ b/packages/stream_chat_flutter/example/pubspec.yaml @@ -1,10 +1,24 @@ name: example description: A new Flutter project. -publish_to: 'none' -version: 1.2.0+1 + +# The following line prevents the package from being accidentally published to +# pub.dev using `pub publish`. This is preferred for private packages. +publish_to: 'none' # Remove this line if you wish to publish to pub.dev + +# The following defines the version and build number for your application. +# A version number is three numbers separated by dots, like 1.2.43 +# followed by an optional build number separated by a +. +# Both the version and the builder number may be overridden in flutter +# build by specifying --build-name and --build-number, respectively. +# In Android, build-name is used as versionName while build-number used as versionCode. +# Read more about Android versioning at https://developer.android.com/studio/publish/versioning +# In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. +# Read more about iOS versioning at +# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html +version: 1.0.0+1 environment: - sdk: ">=2.2.2 <3.0.0" + sdk: ">=2.7.0 <3.0.0" dependencies: flutter: @@ -13,30 +27,53 @@ dependencies: path: ../ stream_chat_persistence: path: ../../stream_chat_persistence - flutter_apns: ^1.4.1 - flutter_local_notifications: ^2.0.2 - flutter_svg: ^0.19.1 - flutter_secure_storage: ^3.3.5 - yaml: ^2.2.1 - uuid: ^2.2.2 - streaming_shared_preferences: ^1.0.2 + + # The following adds the Cupertino Icons font to your application. + # Use with the CupertinoIcons class for iOS style icons. + cupertino_icons: ^1.0.0 dev_dependencies: flutter_test: sdk: flutter - flutter_driver: - sdk: flutter - flutter_launcher_icons: ^0.8.1 - test: any +# For information on the generic Dart part of this file, see the +# following page: https://dart.dev/tools/pub/pubspec + +# The following section is specific to Flutter. flutter: - assets: - - assets/ - - pubspec.lock + + # The following line ensures that the Material Icons font is + # included with your application, so that you can use the icons in + # the material Icons class. uses-material-design: true -flutter_icons: - android: true - ios: true - image_path_android: "assets/android_icon.png" - image_path_ios: "assets/ios_icon.png" + # To add assets to your application, add an assets section, like this: + # assets: + # - images/a_dot_burr.jpeg + # - images/a_dot_ham.jpeg + + # An image asset can refer to one or more resolution-specific "variants", see + # https://flutter.dev/assets-and-images/#resolution-aware. + + # For details regarding adding assets from package dependencies, see + # https://flutter.dev/assets-and-images/#from-packages + + # To add custom fonts to your application, add a fonts section here, + # in this "flutter" section. Each entry in this list should have a + # "family" key with the font family name, and a "fonts" key with a + # list giving the asset and other descriptors for the font. For + # example: + # fonts: + # - family: Schyler + # fonts: + # - asset: fonts/Schyler-Regular.ttf + # - asset: fonts/Schyler-Italic.ttf + # style: italic + # - family: Trajan Pro + # fonts: + # - asset: fonts/TrajanPro.ttf + # - asset: fonts/TrajanPro_Bold.ttf + # weight: 700 + # + # For details regarding fonts from package dependencies, + # see https://flutter.dev/custom-fonts/#from-packages diff --git a/packages/stream_chat_flutter/example/test/widget_test.dart b/packages/stream_chat_flutter/example/test/widget_test.dart new file mode 100644 index 00000000..747db1da --- /dev/null +++ b/packages/stream_chat_flutter/example/test/widget_test.dart @@ -0,0 +1,30 @@ +// This is a basic Flutter widget test. +// +// To perform an interaction with a widget in your test, use the WidgetTester +// utility that Flutter provides. For example, you can send tap and scroll +// gestures. You can also use WidgetTester to find child widgets in the widget +// tree, read text, and verify that the values of widget properties are correct. + +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; + +import 'package:example/main.dart'; + +void main() { + testWidgets('Counter increments smoke test', (WidgetTester tester) async { + // Build our app and trigger a frame. + await tester.pumpWidget(MyApp()); + + // Verify that our counter starts at 0. + expect(find.text('0'), findsOneWidget); + expect(find.text('1'), findsNothing); + + // Tap the '+' icon and trigger a frame. + await tester.tap(find.byIcon(Icons.add)); + await tester.pump(); + + // Verify that our counter has incremented. + expect(find.text('0'), findsNothing); + expect(find.text('1'), findsOneWidget); + }); +} diff --git a/packages/stream_chat_flutter/example/test_driver/single_conversation.dart b/packages/stream_chat_flutter/example/test_driver/single_conversation.dart deleted file mode 100644 index 28ec8e56..00000000 --- a/packages/stream_chat_flutter/example/test_driver/single_conversation.dart +++ /dev/null @@ -1,9 +0,0 @@ -import 'package:flutter_driver/driver_extension.dart'; - -import '../lib/single_conversation.dart' as app; - -void main() async { - enableFlutterDriverExtension(); - - await app.main(); -} diff --git a/packages/stream_chat_flutter/example/test_driver/single_conversation_test.dart b/packages/stream_chat_flutter/example/test_driver/single_conversation_test.dart deleted file mode 100644 index c4f7b991..00000000 --- a/packages/stream_chat_flutter/example/test_driver/single_conversation_test.dart +++ /dev/null @@ -1,46 +0,0 @@ -import 'dart:io'; - -import 'package:flutter_driver/flutter_driver.dart'; -import 'package:test/test.dart'; - -void main() { - test('Single conversation', () async { - final inputFinder = find.byValueKey('messageInputText'); - final sendButtonFinder = find.byValueKey('sendButton'); - final messageListViewFinder = find.byValueKey('messageListView'); - - FlutterDriver driver = await FlutterDriver.connect(); - // Connect to the Flutter driver before running any tests. - - sleep(Duration(seconds: 5)); - - await driver.waitFor(inputFinder); - - await driver.tap(inputFinder); - - sleep(Duration(seconds: 1)); - - await driver.enterText('hey'); - - sleep(Duration(seconds: 1)); - - await driver.tap(sendButtonFinder); - - sleep(Duration(seconds: 1)); - - await driver.scroll( - messageListViewFinder, - 0, - 2000, - Duration(seconds: 1), - ); - - sleep(Duration(seconds: 1)); - - // Close the connection to the driver after the tests have completed. - sleep(Duration(seconds: 5)); - if (driver != null) { - await driver.close(); - } - }); -} diff --git a/packages/stream_chat_flutter/example/web/favicon.png b/packages/stream_chat_flutter/example/web/favicon.png deleted file mode 100644 index 8aaa46ac1ae21512746f852a42ba87e4165dfdd1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 917 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|I14-?iy0X7 zltGxWVyS%@P(fs7NJL45ua8x7ey(0(N`6wRUPW#JP&EUCO@$SZnVVXYs8ErclUHn2 zVXFjIVFhG^g!Ppaz)DK8ZIvQ?0~DO|i&7O#^-S~(l1AfjnEK zjFOT9D}DX)@^Za$W4-*MbbUihOG|wNBYh(yU7!lx;>x^|#0uTKVr7USFmqf|i<65o z3raHc^AtelCMM;Vme?vOfh>Xph&xL%(-1c06+^uR^q@XSM&D4+Kp$>4P^%3{)XKjo zGZknv$b36P8?Z_gF{nK@`XI}Z90TzwSQO}0J1!f2c(B=V`5aP@1P1a|PZ!4!3&Gl8 zTYqUsf!gYFyJnXpu0!n&N*SYAX-%d(5gVjrHJWqXQshj@!Zm{!01WsQrH~9=kTxW#6SvuapgMqt>$=j#%eyGrQzr zP{L-3gsMA^$I1&gsBAEL+vxi1*Igl=8#8`5?A-T5=z-sk46WA1IUT)AIZHx1rdUrf zVJrJn<74DDw`j)Ki#gt}mIT-Q`XRa2-jQXQoI%w`nb|XblvzK${ZzlV)m-XcwC(od z71_OEC5Bt9GEXosOXaPTYOia#R4ID2TiU~`zVMl08TV_C%DnU4^+HE>9(CE4D6?Fz oujB08i7adh9xk7*FX66dWH6F5TM;?E2b5PlUHx3vIVCg!0Dx9vYXATM diff --git a/packages/stream_chat_flutter/example/web/icons/Icon-192.png b/packages/stream_chat_flutter/example/web/icons/Icon-192.png deleted file mode 100644 index b749bfef07473333cf1dd31e9eed89862a5d52aa..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5292 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 diff --git a/packages/stream_chat_flutter/example/web/icons/Icon-512.png b/packages/stream_chat_flutter/example/web/icons/Icon-512.png deleted file mode 100644 index 88cfd48dff1169879ba46840804b412fe02fefd6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8252 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 diff --git a/packages/stream_chat_flutter/example/web/index.html b/packages/stream_chat_flutter/example/web/index.html deleted file mode 100644 index c9fb7275..00000000 --- a/packages/stream_chat_flutter/example/web/index.html +++ /dev/null @@ -1,34 +0,0 @@ - - - - - - - - - - - - - - - - - example - - - - - - - - - diff --git a/packages/stream_chat_flutter/example/web/manifest.json b/packages/stream_chat_flutter/example/web/manifest.json deleted file mode 100644 index 8c012917..00000000 --- a/packages/stream_chat_flutter/example/web/manifest.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "name": "example", - "short_name": "example", - "start_url": ".", - "display": "standalone", - "background_color": "#0175C2", - "theme_color": "#0175C2", - "description": "A new Flutter project.", - "orientation": "portrait-primary", - "prefer_related_applications": false, - "icons": [ - { - "src": "icons/Icon-192.png", - "sizes": "192x192", - "type": "image/png" - }, - { - "src": "icons/Icon-512.png", - "sizes": "512x512", - "type": "image/png" - } - ] -} diff --git a/packages/stream_chat_flutter/example/web/sql-wasm.js b/packages/stream_chat_flutter/example/web/sql-wasm.js deleted file mode 100644 index 9ef1837d..00000000 --- a/packages/stream_chat_flutter/example/web/sql-wasm.js +++ /dev/null @@ -1,207 +0,0 @@ -// We are modularizing this manually because the current modularize setting in Emscripten has some issues: -// https://github.com/kripken/emscripten/issues/5820 -// In addition, When you use emcc's modularization, it still expects to export a global object called `Module`, -// which is able to be used/called before the WASM is loaded. -// The modularization below exports a promise that loads and resolves to the actual sql.js module. -// That way, this module can't be used before the WASM is finished loading. - -// We are going to define a function that a user will call to start loading initializing our Sql.js library -// However, that function might be called multiple times, and on subsequent calls, we don't actually want it to instantiate a new instance of the Module -// Instead, we want to return the previously loaded module - -// TODO: Make this not declare a global if used in the browser -var initSqlJsPromise = undefined; - -var initSqlJs = function (moduleConfig) { - -if (initSqlJsPromise){ -return initSqlJsPromise; -} -// If we're here, we've never called this function before -initSqlJsPromise = new Promise((resolveModule, reject) => { - -// We are modularizing this manually because the current modularize setting in Emscripten has some issues: -// https://github.com/kripken/emscripten/issues/5820 - -// The way to affect the loading of emcc compiled modules is to create a variable called `Module` and add -// properties to it, like `preRun`, `postRun`, etc -// We are using that to get notified when the WASM has finished loading. -// Only then will we return our promise - -// If they passed in a moduleConfig object, use that -// Otherwise, initialize Module to the empty object -var Module = typeof moduleConfig !== 'undefined' ? moduleConfig : {}; - -// EMCC only allows for a single onAbort function (not an array of functions) -// So if the user defined their own onAbort function, we remember it and call it -var originalOnAbortFunction = Module['onAbort']; -Module['onAbort'] = function (errorThatCausedAbort) { -reject(new Error(errorThatCausedAbort)); -if (originalOnAbortFunction){ -originalOnAbortFunction(errorThatCausedAbort); -} -}; - -Module['postRun'] = Module['postRun'] || []; -Module['postRun'].push(function () { -// When Emscripted calls postRun, this promise resolves with the built Module -resolveModule(Module); -}); - -// There is a section of code in the emcc-generated code below that looks like this: -// (Note that this is lowercase `module`) -// if (typeof module !== 'undefined') { -// module['exports'] = Module; -// } -// When that runs, it's going to overwrite our own modularization export efforts in shell-post.js! -// The only way to tell emcc not to emit it is to pass the MODULARIZE=1 or MODULARIZE_INSTANCE=1 flags, -// but that carries with it additional unnecessary baggage/bugs we don't want either. -// So, we have three options: -// 1) We undefine `module` -// 2) We remember what `module['exports']` was at the beginning of this function and we restore it later -// 3) We write a script to remove those lines of code as part of the Make process. -// -// Since those are the only lines of code that care about module, we will undefine it. It's the most straightforward -// of the options, and has the side effect of reducing emcc's efforts to modify the module if its output were to change in the future. -// That's a nice side effect since we're handling the modularization efforts ourselves -module = undefined; - -// The emcc-generated code and shell-post.js code goes below, -// meaning that all of it runs inside of this promise. If anything throws an exception, our promise will abort -var aa;var f;f||(f=typeof Module !== 'undefined' ? Module : {}); -var va=function(){var a;var b=h(4);var c={};var d=function(){function a(a,b){this.fb=a;this.db=b;this.nb=1;this.Eb=[]}a.prototype.bind=function(a){if(!this.fb)throw"Statement closed";this.reset();return Array.isArray(a)?this.lc(a):this.mc(a)};a.prototype.step=function(){var a;if(!this.fb)throw"Statement closed";this.nb=1;switch(a=Tb(this.fb)){case c.hc:return!0;case c.DONE:return!1;default:return this.db.handleError(a)}};a.prototype.sc=function(a){null==a&&(a=this.nb++);return Ub(this.fb,a)};a.prototype.tc= -function(a){null==a&&(a=this.nb++);return Vb(this.fb,a)};a.prototype.getBlob=function(a){var b;null==a&&(a=this.nb++);var c=Wb(this.fb,a);var d=Xb(this.fb,a);var e=new Uint8Array(c);for(a=b=0;0<=c?bc;a=0<=c?++b:--b)e[a]=l[d+a];return e};a.prototype.get=function(a){var b,d;null!=a&&this.bind(a)&&this.step();var e=[];a=b=0;for(d=ib(this.fb);0<=d?bd;a=0<=d?++b:--b)switch(Yb(this.fb,a)){case c.fc:case c.FLOAT:e.push(this.sc(a));break;case c.ic:e.push(this.tc(a));break;case c.Zb:e.push(this.getBlob(a)); -break;default:e.push(null)}return e};a.prototype.getColumnNames=function(){var a,b;var c=[];var d=a=0;for(b=ib(this.fb);0<=b?ab;d=0<=b?++a:--a)c.push(Zb(this.fb,d));return c};a.prototype.getAsObject=function(a){var b,c;var d=this.get(a);var e=this.getColumnNames();var g={};a=b=0;for(c=e.length;b>>0);if(null!=a){var c=this.filename,d=c?n("/",c):"/";c=ia(!0,!0);d=ja(d,(void 0!==c?c:438)&4095|32768,0);if(a){if("string"===typeof a){for(var e=Array(a.length),k=0,m=a.length;kc;e=0<=c?++g:--g){var m=q(d+4*e,"i32");var z=jc(m);e=function(){switch(!1){case 1!==z:return kc; -case 2!==z:return lc;case 3!==z:return mc;case 4!==z:return function(a){var b,c;var d=nc(a);var e=oc(a);a=new Uint8Array(d);for(b=c=0;0<=d?cd;b=0<=d?++c:--c)a[b]=l[e+b];return a};default:return function(){return null}}}();e=e(m);k.push(e)}if(c=b.apply(null,k))switch(typeof c){case "number":return pc(a,c);case "string":return qc(a,c,-1,-1)}else return rc(a)});this.handleError(sc(this.db,a,b.length,c.jc,0,d,0,0,0));return this};return a}();var g=f.cwrap("sqlite3_open","number",["string","number"]); -var k=f.cwrap("sqlite3_close_v2","number",["number"]);var m=f.cwrap("sqlite3_exec","number",["number","string","number","number","number"]);f.cwrap("sqlite3_free","",["number"]);var y=f.cwrap("sqlite3_changes","number",["number"]);var z=f.cwrap("sqlite3_prepare_v2","number",["number","string","number","number","number"]);var fa=f.cwrap("sqlite3_prepare_v2","number",["number","number","number","number","number"]);var ca=f.cwrap("sqlite3_bind_text","number",["number","number","number","number","number"]); -var Ia=f.cwrap("sqlite3_bind_blob","number",["number","number","number","number","number"]);var ac=f.cwrap("sqlite3_bind_double","number",["number","number","number"]);var $b=f.cwrap("sqlite3_bind_int","number",["number","number","number"]);var bc=f.cwrap("sqlite3_bind_parameter_index","number",["number","string"]);var Tb=f.cwrap("sqlite3_step","number",["number"]);var hc=f.cwrap("sqlite3_errmsg","string",["number"]);var ib=f.cwrap("sqlite3_data_count","number",["number"]);var Ub=f.cwrap("sqlite3_column_double", -"number",["number","number"]);var Vb=f.cwrap("sqlite3_column_text","string",["number","number"]);var Xb=f.cwrap("sqlite3_column_blob","number",["number","number"]);var Wb=f.cwrap("sqlite3_column_bytes","number",["number","number"]);var Yb=f.cwrap("sqlite3_column_type","number",["number","number"]);var Zb=f.cwrap("sqlite3_column_name","string",["number","number"]);var dc=f.cwrap("sqlite3_reset","number",["number"]);var cc=f.cwrap("sqlite3_clear_bindings","number",["number"]);var ec=f.cwrap("sqlite3_finalize", -"number",["number"]);var sc=f.cwrap("sqlite3_create_function_v2","number","number string number number number number number number number".split(" "));var jc=f.cwrap("sqlite3_value_type","number",["number"]);var nc=f.cwrap("sqlite3_value_bytes","number",["number"]);var mc=f.cwrap("sqlite3_value_text","string",["number"]);var kc=f.cwrap("sqlite3_value_int","number",["number"]);var oc=f.cwrap("sqlite3_value_blob","number",["number"]);var lc=f.cwrap("sqlite3_value_double","number",["number"]);var pc= -f.cwrap("sqlite3_result_double","",["number","number"]);var rc=f.cwrap("sqlite3_result_null","",["number"]);var qc=f.cwrap("sqlite3_result_text","",["number","string","number","number"]);var fc=f.cwrap("RegisterExtensionFunctions","number",["number"]);this.SQL={Database:e};for(a in this.SQL)f[a]=this.SQL[a];var da=0;c.xb=0;c.we=1;c.Pe=2;c.Ze=3;c.Cc=4;c.Ec=5;c.Se=6;c.NOMEM=7;c.bf=8;c.Qe=9;c.Re=10;c.Hc=11;c.NOTFOUND=12;c.Oe=13;c.Fc=14;c.$e=15;c.EMPTY=16;c.cf=17;c.df=18;c.Gc=19;c.Te=20;c.Ue=21;c.Ve= -22;c.Dc=23;c.Ne=24;c.af=25;c.We=26;c.Xe=27;c.ef=28;c.hc=100;c.DONE=101;c.fc=1;c.FLOAT=2;c.ic=3;c.Zb=4;c.Ye=5;c.jc=1}.bind(this);f.preRun=f.preRun||[];f.preRun.push(va);var wa={},u;for(u in f)f.hasOwnProperty(u)&&(wa[u]=f[u]);f.arguments=[];f.thisProgram="./this.program";f.quit=function(a,b){throw b;};f.preRun=[];f.postRun=[];var v=!1,w=!1,x=!1,xa=!1;v="object"===typeof window;w="function"===typeof importScripts;x="object"===typeof process&&"function"===typeof require&&!v&&!w;xa=!v&&!x&&!w;var A=""; -if(x){A=__dirname+"/";var ya,za;f.read=function(a,b){ya||(ya=require("fs"));za||(za=require("path"));a=za.normalize(a);a=ya.readFileSync(a);return b?a:a.toString()};f.readBinary=function(a){a=f.read(a,!0);a.buffer||(a=new Uint8Array(a));assert(a.buffer);return a};1>2];a=b+a+15&-16;if(a<=Da())D[Ca>>2]=a;else if(!Ea(a))return 0;return b} -var Fa={"f64-rem":function(a,b){return a%b},"debugger":function(){debugger}},Ga=1,E=Array(64);function ua(a){for(var b=0;64>b;b++)if(!E[b])return E[b]=a,Ga+b;throw"Finished up all reserved function pointers. Use a higher value for RESERVED_FUNCTION_POINTERS.";}"object"!==typeof WebAssembly&&C("no native wasm support detected"); -function q(a,b){b=b||"i8";"*"===b.charAt(b.length-1)&&(b="i32");switch(b){case "i1":return l[a>>0];case "i8":return l[a>>0];case "i16":return Ha[a>>1];case "i32":return D[a>>2];case "i64":return D[a>>2];case "float":return Ja[a>>2];case "double":return Ka[a>>3];default:B("invalid type for getValue: "+b)}return null}var La,Ma=!1;function assert(a,b){a||B("Assertion failed: "+b)}function Na(a){var b=f["_"+a];assert(b,"Cannot call unknown function "+a+", make sure it is exported");return b} -function Oa(a,b,c,d){var e={string:function(a){var b=0;if(null!==a&&void 0!==a&&0!==a){var c=(a.length<<2)+1;b=h(c);r(a,F,b,c)}return b},array:function(a){var b=h(a.length);l.set(a,b);return b}},g=Na(a),k=[];a=0;if(d)for(var m=0;m>0]=0;break;case "i8":l[a>>0]=0;break;case "i16":Ha[a>>1]=0;break;case "i32":D[a>>2]=0;break;case "i64":aa=[0,1<=+Pa(0)?~~+Qa(0)>>>0:0];D[a>>2]=aa[0];D[a+4>>2]=aa[1];break;case "float":Ja[a>>2]=0;break;case "double":Ka[a>>3]=0;break;default:B("invalid type for setValue: "+b)}}var Ra=0,Sa=3; -function ea(a){var b=Ra;if("number"===typeof a){var c=!0;var d=a}else c=!1,d=a.length;b=b==Sa?e:[Ta,h,Ba][b](Math.max(d,1));if(c){var e=b;assert(0==(b&3));for(a=b+(d&-4);e>2]=0;for(a=b+d;e>0]=0;return b}a.subarray||a.slice?F.set(a,b):F.set(new Uint8Array(a),b);return b}var Ua="undefined"!==typeof TextDecoder?new TextDecoder("utf8"):void 0; -function t(a,b,c){var d=b+c;for(c=b;a[c]&&!(c>=d);)++c;if(16e?d+=String.fromCharCode(e):(e-=65536,d+=String.fromCharCode(55296|e>>10,56320|e&1023))}}else d+=String.fromCharCode(e)}return d}function G(a){return a?t(F,a,void 0):""} -function r(a,b,c,d){if(!(0=k){var m=a.charCodeAt(++g);k=65536+((k&1023)<<10)|m&1023}if(127>=k){if(c>=d)break;b[c++]=k}else{if(2047>=k){if(c+1>=d)break;b[c++]=192|k>>6}else{if(65535>=k){if(c+2>=d)break;b[c++]=224|k>>12}else{if(c+3>=d)break;b[c++]=240|k>>18;b[c++]=128|k>>12&63}b[c++]=128|k>>6&63}b[c++]=128|k&63}}b[c]=0;return c-e} -function oa(a){for(var b=0,c=0;c=d&&(d=65536+((d&1023)<<10)|a.charCodeAt(++c)&1023);127>=d?++b:b=2047>=d?b+2:65535>=d?b+3:b+4}return b}"undefined"!==typeof TextDecoder&&new TextDecoder("utf-16le");function Va(a){return a.replace(/__Z[\w\d_]+/g,function(a){return a===a?a:a+" ["+a+"]"})}function Wa(a){0Ya&&C("TOTAL_MEMORY should be larger than TOTAL_STACK, was "+Ya+"! (TOTAL_STACK=5242880)"); -f.buffer?buffer=f.buffer:"object"===typeof WebAssembly&&"function"===typeof WebAssembly.Memory?(La=new WebAssembly.Memory({initial:Ya/65536}),buffer=La.buffer):buffer=new ArrayBuffer(Ya);Xa();D[Ca>>2]=5303264;function Za(a){for(;0>2];var c=D[b>>2]}else ob.rb=!0,J.USER=J.LOGNAME="web_user",J.PATH="/",J.PWD="/",J.HOME="/home/web_user",J.LANG="C.UTF-8",J._=f.thisProgram,c=db?Ta(1024):Ba(1024),b=db?Ta(256):Ba(256),D[b>>2]=c,D[a>>2]=b;a=[];var d=0,e;for(e in J)if("string"===typeof J[e]){var g=e+"="+J[e];a.push(g);d+=g.length}if(1024>0]=d.charCodeAt(m);l[k>>0]=0;D[b+ -4*e>>2]=c;c+=g.length+1}D[b+4*a.length>>2]=0}function pb(a){f.___errno_location&&(D[f.___errno_location()>>2]=a);return a}function qb(a,b){for(var c=0,d=a.length-1;0<=d;d--){var e=a[d];"."===e?a.splice(d,1):".."===e?(a.splice(d,1),c++):c&&(a.splice(d,1),c--)}if(b)for(;c;c--)a.unshift("..");return a}function rb(a){var b="/"===a.charAt(0),c="/"===a.substr(-1);(a=qb(a.split("/").filter(function(a){return!!a}),!b).join("/"))||b||(a=".");a&&c&&(a+="/");return(b?"/":"")+a} -function sb(a){var b=/^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/.exec(a).slice(1);a=b[0];b=b[1];if(!a&&!b)return".";b&&(b=b.substr(0,b.length-1));return a+b}function tb(a){if("/"===a)return"/";var b=a.lastIndexOf("/");return-1===b?a:a.substr(b+1)}function ub(){var a=Array.prototype.slice.call(arguments,0);return rb(a.join("/"))}function n(a,b){return rb(a+"/"+b)} -function vb(){for(var a="",b=!1,c=arguments.length-1;-1<=c&&!b;c--){b=0<=c?arguments[c]:"/";if("string"!==typeof b)throw new TypeError("Arguments to path.resolve must be strings");if(!b)return"";a=b+"/"+a;b="/"===b.charAt(0)}a=qb(a.split("/").filter(function(a){return!!a}),!b).join("/");return(b?"/":"")+a||"."}var wb=[];function xb(a,b){wb[a]={input:[],output:[],ub:b};yb(a,zb)} -var zb={open:function(a){var b=wb[a.node.rdev];if(!b)throw new K(L.Cb);a.tty=b;a.seekable=!1},close:function(a){a.tty.ub.flush(a.tty)},flush:function(a){a.tty.ub.flush(a.tty)},read:function(a,b,c,d){if(!a.tty||!a.tty.ub.Xb)throw new K(L.Ob);for(var e=0,g=0;g=b||(b=Math.max(b,c*(1048576>c?2:1.125)|0),0!=c&&(b=Math.max(b,256)),c=a.bb,a.bb=new Uint8Array(b),0b)a.bb.length=b;else for(;a.bb.length=a.node.gb)return 0;a=Math.min(a.node.gb-e,d);if(8b)throw new K(L.ib);return b},Pb:function(a,b,c){M.Tb(a.node,b+c);a.node.gb=Math.max(a.node.gb,b+c)},zb:function(a,b,c,d,e,g,k){if(32768!== -(a.node.mode&61440))throw new K(L.Cb);c=a.node.bb;if(k&2||c.buffer!==b&&c.buffer!==b.buffer){if(0>2)}catch(c){if(!c.code)throw c; -throw new K(L[c.code]);}return b.mode},kb:function(a){for(var b=[];a.parent!==a;)b.push(a.name),a=a.parent;b.push(a.jb.Hb.root);b.reverse();return ub.apply(null,b)},qc:function(a){a&=-2656257;var b=0,c;for(c in P.Ub)a&c&&(b|=P.Ub[c],a^=c);if(a)throw new K(L.ib);return b},ab:{lb:function(a){a=P.kb(a);try{var b=fs.lstatSync(a)}catch(c){if(!c.code)throw c;throw new K(L[c.code]);}P.yb&&!b.pb&&(b.pb=4096);P.yb&&!b.blocks&&(b.blocks=(b.size+b.pb-1)/b.pb|0);return{dev:b.dev,ino:b.ino,mode:b.mode,nlink:b.nlink, -uid:b.uid,gid:b.gid,rdev:b.rdev,size:b.size,atime:b.atime,mtime:b.mtime,ctime:b.ctime,pb:b.pb,blocks:b.blocks}},hb:function(a,b){var c=P.kb(a);try{void 0!==b.mode&&(fs.chmodSync(c,b.mode),a.mode=b.mode),void 0!==b.size&&fs.truncateSync(c,b.size)}catch(d){if(!d.code)throw d;throw new K(L[d.code]);}},lookup:function(a,b){var c=n(P.kb(a),b);c=P.Wb(c);return P.createNode(a,b,c)},vb:function(a,b,c,d){a=P.createNode(a,b,c,d);b=P.kb(a);try{N(a.mode)?fs.mkdirSync(b,a.mode):fs.writeFileSync(b,"",{mode:a.mode})}catch(e){if(!e.code)throw e; -throw new K(L[e.code]);}return a},rename:function(a,b,c){a=P.kb(a);b=n(P.kb(b),c);try{fs.renameSync(a,b)}catch(d){if(!d.code)throw d;throw new K(L[d.code]);}},unlink:function(a,b){a=n(P.kb(a),b);try{fs.unlinkSync(a)}catch(c){if(!c.code)throw c;throw new K(L[c.code]);}},rmdir:function(a,b){a=n(P.kb(a),b);try{fs.rmdirSync(a)}catch(c){if(!c.code)throw c;throw new K(L[c.code]);}},readdir:function(a){a=P.kb(a);try{return fs.readdirSync(a)}catch(b){if(!b.code)throw b;throw new K(L[b.code]);}},symlink:function(a, -b,c){a=n(P.kb(a),b);try{fs.symlinkSync(c,a)}catch(d){if(!d.code)throw d;throw new K(L[d.code]);}},readlink:function(a){var b=P.kb(a);try{return b=fs.readlinkSync(b),b=Fb.relative(Fb.resolve(a.jb.Hb.root),b)}catch(c){if(!c.code)throw c;throw new K(L[c.code]);}}},cb:{open:function(a){var b=P.kb(a.node);try{32768===(a.node.mode&61440)&&(a.wb=fs.openSync(b,P.qc(a.flags)))}catch(c){if(!c.code)throw c;throw new K(L[c.code]);}},close:function(a){try{32768===(a.node.mode&61440)&&a.wb&&fs.closeSync(a.wb)}catch(b){if(!b.code)throw b; -throw new K(L[b.code]);}},read:function(a,b,c,d,e){if(0===d)return 0;try{return fs.readSync(a.wb,P.Rb(b.buffer),c,d,e)}catch(g){throw new K(L[g.code]);}},write:function(a,b,c,d,e){try{return fs.writeSync(a.wb,P.Rb(b.buffer),c,d,e)}catch(g){throw new K(L[g.code]);}},ob:function(a,b,c){if(1===c)b+=a.position;else if(2===c&&32768===(a.node.mode&61440))try{b+=fs.fstatSync(a.wb).size}catch(d){throw new K(L[d.code]);}if(0>b)throw new K(L.ib);return b}}},Gb=null,Hb={},Q=[],Ib=1,R=null,Jb=!0,S={},K=null, -Eb={};function T(a,b){a=vb("/",a);b=b||{};if(!a)return{path:"",node:null};var c={Vb:!0,Jb:0},d;for(d in c)void 0===b[d]&&(b[d]=c[d]);if(8>>0)%R.length}function Nb(a){var b=Mb(a.parent.id,a.name);a.tb=R[b];R[b]=a}function Ob(a){var b=Mb(a.parent.id,a.name);if(R[b]===a)R[b]=a.tb;else for(b=R[b];b;){if(b.tb===a){b.tb=a.tb;break}b=b.tb}} -function O(a,b){var c;if(c=(c=Pb(a,"x"))?c:a.ab.lookup?0:13)throw new K(c,a);for(c=R[Mb(a.id,b)];c;c=c.tb){var d=c.name;if(c.parent.id===a.id&&d===b)return c}return a.ab.lookup(a,b)} -function Db(a,b,c,d){Qb||(Qb=function(a,b,c,d){a||(a=this);this.parent=a;this.jb=a.jb;this.sb=null;this.id=Ib++;this.name=b;this.mode=c;this.ab={};this.cb={};this.rdev=d},Qb.prototype={},Object.defineProperties(Qb.prototype,{read:{get:function(){return 365===(this.mode&365)},set:function(a){a?this.mode|=365:this.mode&=-366}},write:{get:function(){return 146===(this.mode&146)},set:function(a){a?this.mode|=146:this.mode&=-147}}}));a=new Qb(a,b,c,d);Nb(a);return a} -function N(a){return 16384===(a&61440)}var Rb={r:0,rs:1052672,"r+":2,w:577,wx:705,xw:705,"w+":578,"wx+":706,"xw+":706,a:1089,ax:1217,xa:1217,"a+":1090,"ax+":1218,"xa+":1218};function ic(a){var b=["r","w","rw"][a&3];a&512&&(b+="w");return b}function Pb(a,b){if(Jb)return 0;if(-1===b.indexOf("r")||a.mode&292){if(-1!==b.indexOf("w")&&!(a.mode&146)||-1!==b.indexOf("x")&&!(a.mode&73))return 13}else return 13;return 0}function tc(a,b){try{return O(a,b),17}catch(c){}return Pb(a,"wx")} -function uc(a,b,c){try{var d=O(a,b)}catch(e){return e.eb}if(a=Pb(a,"wx"))return a;if(c){if(!N(d.mode))return 20;if(d===d.parent||"/"===Lb(d))return 16}else if(N(d.mode))return 21;return 0}function vc(a){var b=4096;for(a=a||0;a<=b;a++)if(!Q[a])return a;throw new K(24);} -function wc(a,b){xc||(xc=function(){},xc.prototype={},Object.defineProperties(xc.prototype,{object:{get:function(){return this.node},set:function(a){this.node=a}}}));var c=new xc,d;for(d in a)c[d]=a[d];a=c;b=vc(b);a.fd=b;return Q[b]=a}var Cb={open:function(a){a.cb=Hb[a.node.rdev].cb;a.cb.open&&a.cb.open(a)},ob:function(){throw new K(29);}};function yb(a,b){Hb[a]={cb:b}} -function yc(a,b){var c="/"===b,d=!b;if(c&&Gb)throw new K(16);if(!c&&!d){var e=T(b,{Vb:!1});b=e.path;e=e.node;if(e.sb)throw new K(16);if(!N(e.mode))throw new K(20);}b={type:a,Hb:{},Yb:b,wc:[]};a=a.jb(b);a.jb=b;b.root=a;c?Gb=a:e&&(e.sb=b,e.jb&&e.jb.wc.push(b))}function ja(a,b,c){var d=T(a,{parent:!0}).node;a=tb(a);if(!a||"."===a||".."===a)throw new K(22);var e=tc(d,a);if(e)throw new K(e);if(!d.ab.vb)throw new K(1);return d.ab.vb(d,a,b,c)}function U(a,b){ja(a,(void 0!==b?b:511)&1023|16384,0)} -function zc(a,b,c){"undefined"===typeof c&&(c=b,b=438);ja(a,b|8192,c)}function Ac(a,b){if(!vb(a))throw new K(2);var c=T(b,{parent:!0}).node;if(!c)throw new K(2);b=tb(b);var d=tc(c,b);if(d)throw new K(d);if(!c.ab.symlink)throw new K(1);c.ab.symlink(c,b,a)} -function ta(a){var b=T(a,{parent:!0}).node,c=tb(a),d=O(b,c),e=uc(b,c,!1);if(e)throw new K(e);if(!b.ab.unlink)throw new K(1);if(d.sb)throw new K(16);try{S.willDeletePath&&S.willDeletePath(a)}catch(g){console.log("FS.trackingDelegate['willDeletePath']('"+a+"') threw an exception: "+g.message)}b.ab.unlink(b,c);Ob(d);try{if(S.onDeletePath)S.onDeletePath(a)}catch(g){console.log("FS.trackingDelegate['onDeletePath']('"+a+"') threw an exception: "+g.message)}} -function Kb(a){a=T(a).node;if(!a)throw new K(2);if(!a.ab.readlink)throw new K(22);return vb(Lb(a.parent),a.ab.readlink(a))}function ra(a,b){a=T(a,{qb:!b}).node;if(!a)throw new K(2);if(!a.ab.lb)throw new K(1);return a.ab.lb(a)}function Bc(a){return ra(a,!0)}function ka(a,b){var c;"string"===typeof a?c=T(a,{qb:!0}).node:c=a;if(!c.ab.hb)throw new K(1);c.ab.hb(c,{mode:b&4095|c.mode&-4096,timestamp:Date.now()})} -function Cc(a){var b;"string"===typeof a?b=T(a,{qb:!0}).node:b=a;if(!b.ab.hb)throw new K(1);b.ab.hb(b,{timestamp:Date.now()})}function Dc(a,b){if(0>b)throw new K(22);var c;"string"===typeof a?c=T(a,{qb:!0}).node:c=a;if(!c.ab.hb)throw new K(1);if(N(c.mode))throw new K(21);if(32768!==(c.mode&61440))throw new K(22);if(a=Pb(c,"w"))throw new K(a);c.ab.hb(c,{size:b,timestamp:Date.now()})} -function p(a,b,c,d){if(""===a)throw new K(2);if("string"===typeof b){var e=Rb[b];if("undefined"===typeof e)throw Error("Unknown file open mode: "+b);b=e}c=b&64?("undefined"===typeof c?438:c)&4095|32768:0;if("object"===typeof a)var g=a;else{a=rb(a);try{g=T(a,{qb:!(b&131072)}).node}catch(k){}}e=!1;if(b&64)if(g){if(b&128)throw new K(17);}else g=ja(a,c,0),e=!0;if(!g)throw new K(2);8192===(g.mode&61440)&&(b&=-513);if(b&65536&&!N(g.mode))throw new K(20);if(!e&&(c=g?40960===(g.mode&61440)?40:N(g.mode)&& -("r"!==ic(b)||b&512)?21:Pb(g,ic(b)):2))throw new K(c);b&512&&Dc(g,0);b&=-641;d=wc({node:g,path:Lb(g),flags:b,seekable:!0,position:0,cb:g.cb,Bc:[],error:!1},d);d.cb.open&&d.cb.open(d);!f.logReadFiles||b&1||(Ec||(Ec={}),a in Ec||(Ec[a]=1,console.log("FS.trackingDelegate error on read file: "+a)));try{S.onOpenFile&&(g=0,1!==(b&2097155)&&(g|=1),0!==(b&2097155)&&(g|=2),S.onOpenFile(a,g))}catch(k){console.log("FS.trackingDelegate['onOpenFile']('"+a+"', flags) threw an exception: "+k.message)}return d} -function ma(a){if(null===a.fd)throw new K(9);a.Gb&&(a.Gb=null);try{a.cb.close&&a.cb.close(a)}catch(b){throw b;}finally{Q[a.fd]=null}a.fd=null}function Fc(a,b,c){if(null===a.fd)throw new K(9);if(!a.seekable||!a.cb.ob)throw new K(29);if(0!=c&&1!=c&&2!=c)throw new K(22);a.position=a.cb.ob(a,b,c);a.Bc=[]} -function sa(a,b,c,d,e){if(0>d||0>e)throw new K(22);if(null===a.fd)throw new K(9);if(1===(a.flags&2097155))throw new K(9);if(N(a.node.mode))throw new K(21);if(!a.cb.read)throw new K(22);var g="undefined"!==typeof e;if(!g)e=a.position;else if(!a.seekable)throw new K(29);b=a.cb.read(a,b,c,d,e);g||(a.position+=b);return b} -function la(a,b,c,d,e,g){if(0>d||0>e)throw new K(22);if(null===a.fd)throw new K(9);if(0===(a.flags&2097155))throw new K(9);if(N(a.node.mode))throw new K(21);if(!a.cb.write)throw new K(22);a.flags&1024&&Fc(a,0,2);var k="undefined"!==typeof e;if(!k)e=a.position;else if(!a.seekable)throw new K(29);b=a.cb.write(a,b,c,d,e,g);k||(a.position+=b);try{if(a.path&&S.onWriteToFile)S.onWriteToFile(a.path)}catch(m){console.log("FS.trackingDelegate['onWriteToFile']('"+a.path+"') threw an exception: "+m.message)}return b} -function Gc(){K||(K=function(a,b){this.node=b;this.zc=function(a){this.eb=a};this.zc(a);this.message="FS error";this.stack&&Object.defineProperty(this,"stack",{value:Error().stack,writable:!0})},K.prototype=Error(),K.prototype.constructor=K,[2].forEach(function(a){Eb[a]=new K(a);Eb[a].stack=""}))}var Hc;function ia(a,b){var c=0;a&&(c|=365);b&&(c|=146);return c} -function Ic(a,b,c){a=n("/dev",a);var d=ia(!!b,!!c);Jc||(Jc=64);var e=Jc++<<8|0;yb(e,{open:function(a){a.seekable=!1},close:function(){c&&c.buffer&&c.buffer.length&&c(10)},read:function(a,c,d,e){for(var g=0,k=0;k>2]=d.dev;D[c+4>>2]=0;D[c+8>>2]=d.ino;D[c+12>>2]=d.mode;D[c+16>>2]=d.nlink;D[c+20>>2]=d.uid;D[c+24>>2]=d.gid;D[c+28>>2]=d.rdev;D[c+32>>2]=0;D[c+36>>2]=d.size;D[c+40>>2]=4096;D[c+44>>2]=d.blocks;D[c+48>>2]=d.atime.getTime()/1E3|0;D[c+52>>2]=0;D[c+56>>2]=d.mtime.getTime()/1E3|0;D[c+60>>2]=0;D[c+64>>2]=d.ctime.getTime()/1E3|0;D[c+68>>2]=0;D[c+72>>2]=d.ino;return 0}var W=0; -function X(){W+=4;return D[W-4>>2]}function Y(){return G(X())}function Z(){var a=Q[X()];if(!a)throw new K(L.Kb);return a}function Da(){return l.length}function Ea(a){if(2147418112=b?b=Wa(2*b):b=Math.min(Wa((3*b+2147483648)/4),2147418112);a=Wa(b);var c=buffer.byteLength;try{var d=-1!==La.grow((a-c)/65536)?buffer=La.buffer:null}catch(e){d=null}if(!d||d.byteLength!=b)return!1;Xa();return!0} -function Mc(a){if(0===a)return 0;a=G(a);if(!J.hasOwnProperty(a))return 0;Mc.rb&&ha(Mc.rb);a=J[a];var b=oa(a)+1,c=Ta(b);c&&r(a,l,c,b);Mc.rb=c;return Mc.rb}r("GMT",F,60272,4); -function Nc(){function a(a){return(a=a.toTimeString().match(/\(([A-Za-z ]+)\)$/))?a[1]:"GMT"}if(!Oc){Oc=!0;D[Pc()>>2]=60*(new Date).getTimezoneOffset();var b=new Date(2E3,0,1),c=new Date(2E3,6,1);D[Qc()>>2]=Number(b.getTimezoneOffset()!=c.getTimezoneOffset());var d=a(b),e=a(c);d=ea(ba(d));e=ea(ba(e));c.getTimezoneOffset()>2]=d,D[Rc()+4>>2]=e):(D[Rc()>>2]=e,D[Rc()+4>>2]=d)}}var Oc; -function Sc(a){a/=1E3;if((v||w)&&self.performance&&self.performance.now)for(var b=self.performance.now();self.performance.now()-b>2]=c.position;c.Gb&&0===d&&0===g&&(c.Gb=null);return 0}catch(k){return"undefined"!==typeof V&&k instanceof K||B(k),-k.eb}},ca:function(a,b){W=b;try{var c=Y(),d=X();ka(c,d);return 0}catch(e){return"undefined"!==typeof V&&e instanceof K||B(e),-e.eb}},ba:function(a,b){W=b;try{var c=X(),d=X();if(0===d)return-L.ib;if(dd?-L.ib:p(c.path,c.flags,0,d).fd;case 1:case 2:return 0; -case 3:return c.flags;case 4:return d=X(),c.flags|=d,0;case 12:return d=X(),Ha[d+0>>1]=2,0;case 13:case 14:return 0;case 16:case 8:return-L.ib;case 9:return pb(L.ib),-1;default:return-L.ib}}catch(e){return"undefined"!==typeof V&&e instanceof K||B(e),-e.eb}},U:function(a,b){W=b;try{var c=Z(),d=X(),e=X();return sa(c,l,d,e)}catch(g){return"undefined"!==typeof V&&g instanceof K||B(g),-g.eb}},T:function(a,b){W=b;try{var c=Y();var d=X();if(d&-8)var e=-L.ib;else{var g=T(c,{qb:!0}).node;a="";d&4&&(a+="r"); -d&2&&(a+="w");d&1&&(a+="x");e=a&&Pb(g,a)?-L.$b:0}return e}catch(k){return"undefined"!==typeof V&&k instanceof K||B(k),-k.eb}},S:function(a,b){W=b;try{var c=Y(),d=X();a=c;a=rb(a);"/"===a[a.length-1]&&(a=a.substr(0,a.length-1));U(a,d);return 0}catch(e){return"undefined"!==typeof V&&e instanceof K||B(e),-e.eb}},R:function(a,b){W=b;try{var c=Z(),d=X(),e=X();return la(c,l,d,e)}catch(g){return"undefined"!==typeof V&&g instanceof K||B(g),-g.eb}},Q:function(a,b){W=b;try{var c=Y(),d=T(c,{parent:!0}).node, -e=tb(c),g=O(d,e),k=uc(d,e,!0);if(k)throw new K(k);if(!d.ab.rmdir)throw new K(1);if(g.sb)throw new K(16);try{S.willDeletePath&&S.willDeletePath(c)}catch(m){console.log("FS.trackingDelegate['willDeletePath']('"+c+"') threw an exception: "+m.message)}d.ab.rmdir(d,e);Ob(g);try{if(S.onDeletePath)S.onDeletePath(c)}catch(m){console.log("FS.trackingDelegate['onDeletePath']('"+c+"') threw an exception: "+m.message)}return 0}catch(m){return"undefined"!==typeof V&&m instanceof K||B(m),-m.eb}},P:function(a,b){W= -b;try{var c=Y(),d=X(),e=X();return p(c,d,e).fd}catch(g){return"undefined"!==typeof V&&g instanceof K||B(g),-g.eb}},s:function(a,b){W=b;try{var c=Z();ma(c);return 0}catch(d){return"undefined"!==typeof V&&d instanceof K||B(d),-d.eb}},O:function(a,b){W=b;try{var c=Y(),d=X();var e=X();if(0>=e)var g=-L.ib;else{var k=Kb(c),m=Math.min(e,oa(k)),y=l[d+m];r(k,F,d,e+1);l[d+m]=y;g=m}return g}catch(z){return"undefined"!==typeof V&&z instanceof K||B(z),-z.eb}},N:function(a,b){W=b;try{var c=X(),d=X(),e=Kc[c];if(!e)return 0; -if(d===e.uc){var g=Q[e.fd],k=e.flags,m=new Uint8Array(F.subarray(c,c+d));g&&g.cb.Ab&&g.cb.Ab(g,m,0,d,k);Kc[c]=null;e.Db&&ha(e.vc)}return 0}catch(y){return"undefined"!==typeof V&&y instanceof K||B(y),-y.eb}},M:function(a,b){W=b;try{var c=X(),d=X(),e=Q[c];if(!e)throw new K(9);ka(e.node,d);return 0}catch(g){return"undefined"!==typeof V&&g instanceof K||B(g),-g.eb}},L:Da,K:function(a,b,c){F.set(F.subarray(b,b+c),a)},J:Ea,r:Mc,q:function(a){var b=Date.now();D[a>>2]=b/1E3|0;D[a+4>>2]=b%1E3*1E3|0;return 0}, -I:function(a){return Math.log(a)/Math.LN10},p:function(){B("trap!")},H:function(a){Nc();a=new Date(1E3*D[a>>2]);D[15056]=a.getSeconds();D[15057]=a.getMinutes();D[15058]=a.getHours();D[15059]=a.getDate();D[15060]=a.getMonth();D[15061]=a.getFullYear()-1900;D[15062]=a.getDay();var b=new Date(a.getFullYear(),0,1);D[15063]=(a.getTime()-b.getTime())/864E5|0;D[15065]=-(60*a.getTimezoneOffset());var c=(new Date(2E3,6,1)).getTimezoneOffset();b=b.getTimezoneOffset();a=(c!=b&&a.getTimezoneOffset()==Math.min(b, -c))|0;D[15064]=a;a=D[Rc()+(a?4:0)>>2];D[15066]=a;return 60224},G:function(a,b){var c=D[a>>2];a=D[a+4>>2];0!==b&&(D[b>>2]=0,D[b+4>>2]=0);return Sc(1E6*c+a/1E3)},F:function(a){switch(a){case 30:return 16384;case 85:return 131068;case 132:case 133:case 12:case 137:case 138:case 15:case 235:case 16:case 17:case 18:case 19:case 20:case 149:case 13:case 10:case 236:case 153:case 9:case 21:case 22:case 159:case 154:case 14:case 77:case 78:case 139:case 80:case 81:case 82:case 68:case 67:case 164:case 11:case 29:case 47:case 48:case 95:case 52:case 51:case 46:return 200809; -case 79:return 0;case 27:case 246:case 127:case 128:case 23:case 24:case 160:case 161:case 181:case 182:case 242:case 183:case 184:case 243:case 244:case 245:case 165:case 178:case 179:case 49:case 50:case 168:case 169:case 175:case 170:case 171:case 172:case 97:case 76:case 32:case 173:case 35:return-1;case 176:case 177:case 7:case 155:case 8:case 157:case 125:case 126:case 92:case 93:case 129:case 130:case 131:case 94:case 91:return 1;case 74:case 60:case 69:case 70:case 4:return 1024;case 31:case 42:case 72:return 32; -case 87:case 26:case 33:return 2147483647;case 34:case 1:return 47839;case 38:case 36:return 99;case 43:case 37:return 2048;case 0:return 2097152;case 3:return 65536;case 28:return 32768;case 44:return 32767;case 75:return 16384;case 39:return 1E3;case 89:return 700;case 71:return 256;case 40:return 255;case 2:return 100;case 180:return 64;case 25:return 20;case 5:return 16;case 6:return 6;case 73:return 4;case 84:return"object"===typeof navigator?navigator.hardwareConcurrency||1:1}pb(22);return-1}, -E:function(a){var b=Date.now()/1E3|0;a&&(D[a>>2]=b);return b},D:function(a,b){if(b){var c=1E3*D[b+8>>2];c+=D[b+12>>2]/1E3}else c=Date.now();a=G(a);try{b=c;var d=T(a,{qb:!0}).node;d.ab.hb(d,{timestamp:Math.max(b,c)});return 0}catch(e){a=e;if(!(a instanceof K)){a+=" : ";a:{d=Error();if(!d.stack){try{throw Error(0);}catch(g){d=g}if(!d.stack){d="(no stack trace available)";break a}}d=d.stack.toString()}f.extraStackTrace&&(d+="\n"+f.extraStackTrace());d=Va(d);throw a+d;}pb(a.eb);return-1}},C:function(){B("OOM")}, -a:Ca},buffer);f.asm=Vc;f._RegisterExtensionFunctions=function(){return f.asm.ha.apply(null,arguments)};var nb=f.___emscripten_environ_constructor=function(){return f.asm.ia.apply(null,arguments)};f.___errno_location=function(){return f.asm.ja.apply(null,arguments)}; -var Qc=f.__get_daylight=function(){return f.asm.ka.apply(null,arguments)},Pc=f.__get_timezone=function(){return f.asm.la.apply(null,arguments)},Rc=f.__get_tzname=function(){return f.asm.ma.apply(null,arguments)},ha=f._free=function(){return f.asm.na.apply(null,arguments)},Ta=f._malloc=function(){return f.asm.oa.apply(null,arguments)},Tc=f._memalign=function(){return f.asm.pa.apply(null,arguments)},Uc=f._memset=function(){return f.asm.qa.apply(null,arguments)}; -f._sqlite3_bind_blob=function(){return f.asm.ra.apply(null,arguments)};f._sqlite3_bind_double=function(){return f.asm.sa.apply(null,arguments)};f._sqlite3_bind_int=function(){return f.asm.ta.apply(null,arguments)};f._sqlite3_bind_parameter_index=function(){return f.asm.ua.apply(null,arguments)};f._sqlite3_bind_text=function(){return f.asm.va.apply(null,arguments)};f._sqlite3_changes=function(){return f.asm.wa.apply(null,arguments)};f._sqlite3_clear_bindings=function(){return f.asm.xa.apply(null,arguments)}; -f._sqlite3_close_v2=function(){return f.asm.ya.apply(null,arguments)};f._sqlite3_column_blob=function(){return f.asm.za.apply(null,arguments)};f._sqlite3_column_bytes=function(){return f.asm.Aa.apply(null,arguments)};f._sqlite3_column_double=function(){return f.asm.Ba.apply(null,arguments)};f._sqlite3_column_name=function(){return f.asm.Ca.apply(null,arguments)};f._sqlite3_column_text=function(){return f.asm.Da.apply(null,arguments)};f._sqlite3_column_type=function(){return f.asm.Ea.apply(null,arguments)}; -f._sqlite3_create_function_v2=function(){return f.asm.Fa.apply(null,arguments)};f._sqlite3_data_count=function(){return f.asm.Ga.apply(null,arguments)};f._sqlite3_errmsg=function(){return f.asm.Ha.apply(null,arguments)};f._sqlite3_exec=function(){return f.asm.Ia.apply(null,arguments)};f._sqlite3_finalize=function(){return f.asm.Ja.apply(null,arguments)};f._sqlite3_free=function(){return f.asm.Ka.apply(null,arguments)};f._sqlite3_open=function(){return f.asm.La.apply(null,arguments)}; -f._sqlite3_prepare_v2=function(){return f.asm.Ma.apply(null,arguments)};f._sqlite3_reset=function(){return f.asm.Na.apply(null,arguments)};f._sqlite3_result_double=function(){return f.asm.Oa.apply(null,arguments)};f._sqlite3_result_null=function(){return f.asm.Pa.apply(null,arguments)};f._sqlite3_result_text=function(){return f.asm.Qa.apply(null,arguments)};f._sqlite3_step=function(){return f.asm.Ra.apply(null,arguments)};f._sqlite3_value_blob=function(){return f.asm.Sa.apply(null,arguments)}; -f._sqlite3_value_bytes=function(){return f.asm.Ta.apply(null,arguments)};f._sqlite3_value_double=function(){return f.asm.Ua.apply(null,arguments)};f._sqlite3_value_int=function(){return f.asm.Va.apply(null,arguments)};f._sqlite3_value_text=function(){return f.asm.Wa.apply(null,arguments)};f._sqlite3_value_type=function(){return f.asm.Xa.apply(null,arguments)}; -var h=f.stackAlloc=function(){return f.asm.Za.apply(null,arguments)},qa=f.stackRestore=function(){return f.asm._a.apply(null,arguments)},na=f.stackSave=function(){return f.asm.$a.apply(null,arguments)};f.dynCall_vi=function(){return f.asm.Ya.apply(null,arguments)};f.asm=Vc;f.cwrap=function(a,b,c,d){c=c||[];var e=c.every(function(a){return"number"===a});return"string"!==b&&e&&!d?Na(a):function(){return Oa(a,b,c,arguments)}};f.stackSave=na;f.stackRestore=qa;f.stackAlloc=h; -function Wc(a){this.name="ExitStatus";this.message="Program terminated with exit("+a+")";this.status=a}Wc.prototype=Error();Wc.prototype.constructor=Wc;gb=function Xc(){f.calledRun||Yc();f.calledRun||(gb=Xc)}; -function Yc(){function a(){if(!f.calledRun&&(f.calledRun=!0,!Ma)){db||(db=!0,f.noFSInit||Hc||(Hc=!0,Gc(),f.stdin=f.stdin,f.stdout=f.stdout,f.stderr=f.stderr,f.stdin?Ic("stdin",f.stdin):Ac("/dev/tty","/dev/stdin"),f.stdout?Ic("stdout",null,f.stdout):Ac("/dev/tty","/dev/stdout"),f.stderr?Ic("stderr",null,f.stderr):Ac("/dev/tty1","/dev/stderr"),p("/dev/stdin","r"),p("/dev/stdout","w"),p("/dev/stderr","w")),Za(ab));Jb=!1;Za(bb);if(f.onRuntimeInitialized)f.onRuntimeInitialized();if(f.postRun)for("function"== -typeof f.postRun&&(f.postRun=[f.postRun]);f.postRun.length;){var a=f.postRun.shift();cb.unshift(a)}Za(cb)}}if(!(02&huzyoEav; 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

    IbsY-~g+Osb8%J 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Ǵ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ޯ`x#}oImq(?5WM^RtVA1>l-1+U`%UE2Rl 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

    Nj(Ca$cWF^KE1KeRyqzuxLjq*u0Bub+i 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

    00thGJox890Ufbl-<|d;d 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[@sF%ydm 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 PHh^;|(lM Date: Tue, 2 Feb 2021 13:07:49 +0100 Subject: [PATCH 1136/1140] rename tutorial steps --- .../example/lib/customize_message_widget.dart | 135 ------------------ ...conversation.dart => tutorial-part-1.dart} | 0 ...conversation.dart => tutorial-part-2.dart} | 0 ...nnel_preview.dart => tutorial-part-3.dart} | 0 .../{threads.dart => tutorial-part-4.dart} | 0 ...stom_message.dart => tutorial-part-5.dart} | 0 ...custom_theme.dart => tutorial-part-6.dart} | 0 7 files changed, 135 deletions(-) delete mode 100644 packages/stream_chat_flutter/example/lib/customize_message_widget.dart rename packages/stream_chat_flutter/example/lib/{single_conversation.dart => tutorial-part-1.dart} (100%) rename packages/stream_chat_flutter/example/lib/{multiple_conversation.dart => tutorial-part-2.dart} (100%) rename packages/stream_chat_flutter/example/lib/{customize_channel_preview.dart => tutorial-part-3.dart} (100%) rename packages/stream_chat_flutter/example/lib/{threads.dart => tutorial-part-4.dart} (100%) rename packages/stream_chat_flutter/example/lib/{custom_message.dart => tutorial-part-5.dart} (100%) rename packages/stream_chat_flutter/example/lib/{custom_theme.dart => tutorial-part-6.dart} (100%) diff --git a/packages/stream_chat_flutter/example/lib/customize_message_widget.dart b/packages/stream_chat_flutter/example/lib/customize_message_widget.dart deleted file mode 100644 index d19d6023..00000000 --- a/packages/stream_chat_flutter/example/lib/customize_message_widget.dart +++ /dev/null @@ -1,135 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:stream_chat_flutter/stream_chat_flutter.dart'; - -/// Fifth step of the [tutorial](https://getstream.io/chat/flutter/tutorial/) -/// -/// Customizing how messages are rendered is another very common use-case that the SDK supports easily. -/// -/// Replace the built-in message component with your own is done by passing it as a builder function to the [MessageListView] widget. -/// -/// The message builder function will get the usual [BuildContext] argument as well as the [Message] object and its position inside the list. -/// -/// If you look at the code you can see that we use [StreamChat.of] to retrieve the current user so that we can style messages own messages in a different way. -/// -/// Since custom widgets and builders are always children of [StreamChat] or part of a [Channel], -/// you can use [StreamChat.of], [StreamChannel.of] and [StreamChatTheme.of] to use the API client directly -/// or to retrieve outer scope needed such as messages from the [Channel.state]. -void main() async { - final client = StreamChatClient( - 's2dxdhpxd94g', - logLevel: Level.INFO, - ); - - await client.setUser( - User(id: 'super-band-9'), - 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoic3VwZXItYmFuZC05In0.0L6lGoeLwkz0aZRUcpZKsvaXtNEDHBcezVTZ0oPq40A', - ); - - runApp(MyApp(client)); -} - -class MyApp extends StatelessWidget { - final StreamChatClient client; - - MyApp(this.client); - - @override - Widget build(BuildContext context) { - return MaterialApp( - builder: (context, child) => StreamChat( - child: child, - client: client, - ), - home: Container( - child: ChannelListPage(), - ), - ); - } -} - -class ChannelListPage extends StatelessWidget { - @override - Widget build(BuildContext context) { - return Scaffold( - body: ChannelsBloc( - child: ChannelListView( - filter: { - 'members': { - '\$in': [StreamChat.of(context).user.id], - } - }, - sort: [SortOption('last_message_at')], - pagination: PaginationParams( - limit: 20, - ), - channelWidget: ChannelPage(), - ), - ), - ); - } -} - -class ChannelPage extends StatelessWidget { - const ChannelPage({ - Key key, - }) : super(key: key); - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: ChannelHeader(), - body: Column( - children: [ - Expanded( - child: MessageListView( - messageBuilder: _messageBuilder, - ), - ), - MessageInput(), - ], - ), - ); - } - - Widget _messageBuilder( - BuildContext context, - MessageDetails details, - List messages, - ) { - final message = details.message; - final color = details.isMyMessage ? Colors.red : Colors.blue; - if (message.isSystem) { - return SizedBox(); - } - return MessageWidget( - message: message, - messageTheme: details.isMyMessage - ? StreamChatTheme.of(context).ownMessageTheme - : StreamChatTheme.of(context).otherMessageTheme, - borderSide: BorderSide( - color: color, - width: 2, - ), - padding: const EdgeInsets.symmetric( - vertical: 2, - horizontal: 4, - ), - attachmentBorderSide: BorderSide( - color: color, - width: 2, - ), - attachmentPadding: EdgeInsets.all(8), - borderRadiusGeometry: BorderRadius.vertical( - top: !details.isLastUser ? Radius.circular(16) : Radius.zero, - bottom: !details.isNextUser ? Radius.circular(16) : Radius.zero, - ), - showSendingIndicator: false, - reverse: false, - showUserAvatar: - details.isNextUser ? DisplayWidget.hide : DisplayWidget.show, - showTimestamp: !details.isNextUser, - showUsername: !details.isNextUser, - showReactions: false, - ); - } -} diff --git a/packages/stream_chat_flutter/example/lib/single_conversation.dart b/packages/stream_chat_flutter/example/lib/tutorial-part-1.dart similarity index 100% rename from packages/stream_chat_flutter/example/lib/single_conversation.dart rename to packages/stream_chat_flutter/example/lib/tutorial-part-1.dart diff --git a/packages/stream_chat_flutter/example/lib/multiple_conversation.dart b/packages/stream_chat_flutter/example/lib/tutorial-part-2.dart similarity index 100% rename from packages/stream_chat_flutter/example/lib/multiple_conversation.dart rename to packages/stream_chat_flutter/example/lib/tutorial-part-2.dart diff --git a/packages/stream_chat_flutter/example/lib/customize_channel_preview.dart b/packages/stream_chat_flutter/example/lib/tutorial-part-3.dart similarity index 100% rename from packages/stream_chat_flutter/example/lib/customize_channel_preview.dart rename to packages/stream_chat_flutter/example/lib/tutorial-part-3.dart diff --git a/packages/stream_chat_flutter/example/lib/threads.dart b/packages/stream_chat_flutter/example/lib/tutorial-part-4.dart similarity index 100% rename from packages/stream_chat_flutter/example/lib/threads.dart rename to packages/stream_chat_flutter/example/lib/tutorial-part-4.dart diff --git a/packages/stream_chat_flutter/example/lib/custom_message.dart b/packages/stream_chat_flutter/example/lib/tutorial-part-5.dart similarity index 100% rename from packages/stream_chat_flutter/example/lib/custom_message.dart rename to packages/stream_chat_flutter/example/lib/tutorial-part-5.dart diff --git a/packages/stream_chat_flutter/example/lib/custom_theme.dart b/packages/stream_chat_flutter/example/lib/tutorial-part-6.dart similarity index 100% rename from packages/stream_chat_flutter/example/lib/custom_theme.dart rename to packages/stream_chat_flutter/example/lib/tutorial-part-6.dart From c165f16183304a2b817684b5b4e7bc87b130b6a7 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Tue, 2 Feb 2021 14:09:31 +0100 Subject: [PATCH 1137/1140] update tutorials --- .../stream_chat_flutter/analysis_options.yaml | 2 +- .../stream_chat_flutter/example/lib/main.dart | 25 ++++++++++++++++ .../example/lib/split_view.dart | 1 + .../example/lib/tutorial-part-1.dart | 1 + .../example/lib/tutorial-part-2.dart | 1 + .../example/lib/tutorial-part-3.dart | 3 +- .../example/lib/tutorial-part-4.dart | 1 + .../example/lib/tutorial-part-5.dart | 1 + .../example/lib/tutorial-part-6.dart | 1 + .../example/test/widget_test.dart | 30 ------------------- 10 files changed, 34 insertions(+), 32 deletions(-) delete mode 100644 packages/stream_chat_flutter/example/test/widget_test.dart diff --git a/packages/stream_chat_flutter/analysis_options.yaml b/packages/stream_chat_flutter/analysis_options.yaml index 8d6f9064..36d1fbb7 100644 --- a/packages/stream_chat_flutter/analysis_options.yaml +++ b/packages/stream_chat_flutter/analysis_options.yaml @@ -46,7 +46,7 @@ linter: - package_prefixed_library_names - prefer_is_not_empty # - prefer_mixin # https://github.com/dart-lang/language/issues/32 - - public_member_api_docs + # - public_member_api_docs - slash_for_doc_comments # - sort_constructors_first # - sort_unnamed_constructors_first diff --git a/packages/stream_chat_flutter/example/lib/main.dart b/packages/stream_chat_flutter/example/lib/main.dart index d2d691e9..31ed8711 100644 --- a/packages/stream_chat_flutter/example/lib/main.dart +++ b/packages/stream_chat_flutter/example/lib/main.dart @@ -2,11 +2,17 @@ import 'package:flutter/material.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; void main() async { + /// Create a new instance of [StreamChatClient] passing the apikey obtained from your + /// project dashboard. final client = StreamChatClient( 's2dxdhpxd94g', logLevel: Level.INFO, ); + /// Set the current user. In a production scenario, this should be done using + /// a backend to generate a user token using our server SDK. + /// Please see the following for more information: + /// https://getstream.io/chat/docs/ios_user_setup_and_tokens/ await client.setUser( User(id: 'super-band-9'), 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoic3VwZXItYmFuZC05In0.0L6lGoeLwkz0aZRUcpZKsvaXtNEDHBcezVTZ0oPq40A', @@ -20,10 +26,24 @@ void main() async { runApp(MyApp(client, channel)); } +/// Example application using Stream Chat Flutter widgets. +/// Stream Chat Flutter is a set of Flutter widgets which provide full chat functionalities +/// for building Flutter applications using Stream. +/// If you'd prefer using minimal wrapper widgets for your app, please see our other +/// package, `stream_chat_flutter_core`. class MyApp extends StatelessWidget { + /// Instance of Stream Client. + /// Stream's [StreamChatClient] can be used to connect to our servers and set the default + /// user for the application. Performing these actions trigger a websocket connection + /// allowing for real-time updates. final StreamChatClient client; + + /// Instance of the Channel final Channel channel; + /// Example using Stream's Flutter package. + /// If you'd prefer using minimal wrapper widgets for your app, please see our other + /// package, `stream_chat_flutter_core`. MyApp(this.client, this.channel); @override @@ -43,7 +63,12 @@ class MyApp extends StatelessWidget { } } +/// A list of messages sent in the current channel. +/// +/// This is implemented using [MessageListView], a widget that provides query functionalities +/// fetching the messages from the api and showing them in a listView class ChannelPage extends StatelessWidget { + /// Creates the page that shows the list of messages const ChannelPage({ Key key, }) : super(key: key); diff --git a/packages/stream_chat_flutter/example/lib/split_view.dart b/packages/stream_chat_flutter/example/lib/split_view.dart index 08324759..dbece419 100644 --- a/packages/stream_chat_flutter/example/lib/split_view.dart +++ b/packages/stream_chat_flutter/example/lib/split_view.dart @@ -1,3 +1,4 @@ +// ignore_for_file: public_member_api_docs import 'package:flutter/material.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; diff --git a/packages/stream_chat_flutter/example/lib/tutorial-part-1.dart b/packages/stream_chat_flutter/example/lib/tutorial-part-1.dart index 66a1091c..8fda6029 100644 --- a/packages/stream_chat_flutter/example/lib/tutorial-part-1.dart +++ b/packages/stream_chat_flutter/example/lib/tutorial-part-1.dart @@ -1,3 +1,4 @@ +// ignore_for_file: public_member_api_docs import 'package:flutter/material.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; diff --git a/packages/stream_chat_flutter/example/lib/tutorial-part-2.dart b/packages/stream_chat_flutter/example/lib/tutorial-part-2.dart index f810231c..411b9475 100644 --- a/packages/stream_chat_flutter/example/lib/tutorial-part-2.dart +++ b/packages/stream_chat_flutter/example/lib/tutorial-part-2.dart @@ -1,3 +1,4 @@ +// ignore_for_file: public_member_api_docs import 'package:flutter/material.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; diff --git a/packages/stream_chat_flutter/example/lib/tutorial-part-3.dart b/packages/stream_chat_flutter/example/lib/tutorial-part-3.dart index 2f28fa80..5c309d48 100644 --- a/packages/stream_chat_flutter/example/lib/tutorial-part-3.dart +++ b/packages/stream_chat_flutter/example/lib/tutorial-part-3.dart @@ -1,3 +1,4 @@ +// ignore_for_file: public_member_api_docs import 'package:flutter/material.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; @@ -76,7 +77,7 @@ class ChannelListPage extends StatelessWidget { final lastMessage = channel.state.messages.reversed .firstWhere((message) => !message.isDeleted); - final subtitle = (lastMessage == null ? "nothing yet" : lastMessage.text); + final subtitle = (lastMessage == null ? 'nothing yet' : lastMessage.text); final opacity = channel.state.unreadCount > .0 ? 1.0 : 0.5; return ListTile( diff --git a/packages/stream_chat_flutter/example/lib/tutorial-part-4.dart b/packages/stream_chat_flutter/example/lib/tutorial-part-4.dart index 6a3c7766..2b46d46b 100644 --- a/packages/stream_chat_flutter/example/lib/tutorial-part-4.dart +++ b/packages/stream_chat_flutter/example/lib/tutorial-part-4.dart @@ -1,3 +1,4 @@ +// ignore_for_file: public_member_api_docs import 'package:flutter/material.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; diff --git a/packages/stream_chat_flutter/example/lib/tutorial-part-5.dart b/packages/stream_chat_flutter/example/lib/tutorial-part-5.dart index e2756430..4d9133ee 100644 --- a/packages/stream_chat_flutter/example/lib/tutorial-part-5.dart +++ b/packages/stream_chat_flutter/example/lib/tutorial-part-5.dart @@ -1,3 +1,4 @@ +// ignore_for_file: public_member_api_docs import 'package:flutter/material.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; diff --git a/packages/stream_chat_flutter/example/lib/tutorial-part-6.dart b/packages/stream_chat_flutter/example/lib/tutorial-part-6.dart index a7ad5ba0..69e0f26a 100644 --- a/packages/stream_chat_flutter/example/lib/tutorial-part-6.dart +++ b/packages/stream_chat_flutter/example/lib/tutorial-part-6.dart @@ -1,3 +1,4 @@ +// ignore_for_file: public_member_api_docs import 'package:flutter/material.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; diff --git a/packages/stream_chat_flutter/example/test/widget_test.dart b/packages/stream_chat_flutter/example/test/widget_test.dart deleted file mode 100644 index 747db1da..00000000 --- a/packages/stream_chat_flutter/example/test/widget_test.dart +++ /dev/null @@ -1,30 +0,0 @@ -// This is a basic Flutter widget test. -// -// To perform an interaction with a widget in your test, use the WidgetTester -// utility that Flutter provides. For example, you can send tap and scroll -// gestures. You can also use WidgetTester to find child widgets in the widget -// tree, read text, and verify that the values of widget properties are correct. - -import 'package:flutter/material.dart'; -import 'package:flutter_test/flutter_test.dart'; - -import 'package:example/main.dart'; - -void main() { - testWidgets('Counter increments smoke test', (WidgetTester tester) async { - // Build our app and trigger a frame. - await tester.pumpWidget(MyApp()); - - // Verify that our counter starts at 0. - expect(find.text('0'), findsOneWidget); - expect(find.text('1'), findsNothing); - - // Tap the '+' icon and trigger a frame. - await tester.tap(find.byIcon(Icons.add)); - await tester.pump(); - - // Verify that our counter has incremented. - expect(find.text('0'), findsNothing); - expect(find.text('1'), findsOneWidget); - }); -} From be63b845b56e7403a0c1bd6df7ea139f925cd2d2 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Tue, 2 Feb 2021 15:12:12 +0100 Subject: [PATCH 1138/1140] update changelog --- packages/stream_chat_flutter/CHANGELOG.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/stream_chat_flutter/CHANGELOG.md b/packages/stream_chat_flutter/CHANGELOG.md index b840a2bb..143751e3 100644 --- a/packages/stream_chat_flutter/CHANGELOG.md +++ b/packages/stream_chat_flutter/CHANGELOG.md @@ -1,6 +1,10 @@ ## 1.0.0-beta -- Integrated new-ui, split package functionality, +- **Refreshed widgets design** +- Improved api documentation +- Updated `stream_chat` dependency to `^1.0.0-beta` +- Extracted sample app into dedicated [repo](https://github.com/GetStream/flutter-samples) +- Reimplemented existing widgets using [stream_chat_flutter_core](https://pub.dev/packages/stream_chat_flutter_core) ## 0.2.20+2 From d810eb59c26115f4888215b5578519e267d25491 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Tue, 2 Feb 2021 15:12:41 +0100 Subject: [PATCH 1139/1140] remove build.yml --- .github/workflows/build.yml | 71 ------------------------------------- 1 file changed, 71 deletions(-) delete mode 100644 .github/workflows/build.yml diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml deleted file mode 100644 index 6a0bbcb9..00000000 --- a/.github/workflows/build.yml +++ /dev/null @@ -1,71 +0,0 @@ -name: Build - -on: - push: - branches: - - master - - feature/new-ui - release: - types: - - created -defaults: - run: - working-directory: packages/stream_chat_flutter - -jobs: - build_and_deploy_ios: - runs-on: [macos-latest] - steps: - - uses: actions/checkout@v2 - - name: Install RubyGems - run: | - cd example/ios - bundle install - - uses: subosito/flutter-action@v1.4.0 - with: - channel: 'stable' - - name: Install firebase-tools - run: npm install -g firebase-tools - - name: Flutter setup - run: | - cd example - flutter pub get - - name: Build and release - env: - MATCH_PASSWORD: ${{ secrets.MATCH_PASSWORD }} - MATCH_GIT_BASIC_AUTHORIZATION: ${{ secrets.MATCH_GIT_BASIC_AUTHORIZATION }} - FIREBASE_TOKEN: ${{ secrets.FIREBASE_TOKEN }} - run: | - cd example - flutter build ios --release --no-codesign - cd ios - bundle exec fastlane deploy_to_firebase - build_and_deploy_android: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - uses: actions/setup-java@v1 - with: - java-version: '12.x' - - uses: subosito/flutter-action@v1.4.0 - with: - channel: 'stable' - - run: | - cd example - flutter pub get - - name: Decode google-services.json - env: - ANDROID_GOOGLE_SERVICES: ${{ secrets.ANDROID_GOOGLE_SERVICES }} - run: echo $ANDROID_GOOGLE_SERVICES > ./example/android/app/google-services.json - - name: Build - run: | - cd example - flutter build apk - - name: Deploy - uses: wzieba/Firebase-Distribution-Github-Action@v1.3.2 - with: - appId: ${{secrets.FIREBASE_ANDROID_APPID}} - token: ${{secrets.FIREBASE_TOKEN}} - groups: stream-testers - debug: true - file: packages/stream_chat_flutter/example/build/app/outputs/apk/release/app-release.apk \ No newline at end of file From 0b57f1b5ad9352cc28d22d1a715725fb6585ef1f Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Tue, 2 Feb 2021 15:27:02 +0100 Subject: [PATCH 1140/1140] update actions --- .github/workflows/flutter-analyze.yml | 24 ------------------- .github/workflows/stream_flutter_workflow.yml | 3 +-- 2 files changed, 1 insertion(+), 26 deletions(-) delete mode 100644 .github/workflows/flutter-analyze.yml diff --git a/.github/workflows/flutter-analyze.yml b/.github/workflows/flutter-analyze.yml deleted file mode 100644 index 312a65ba..00000000 --- a/.github/workflows/flutter-analyze.yml +++ /dev/null @@ -1,24 +0,0 @@ -name: Flutter Analyze -on: - push: - branches: - - master - - pull_request: - branches: - - '*' - -jobs: - build: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - uses: subosito/flutter-action@v1 - with: - channel: 'beta' - - run: flutter pub get - - - name: 'Flutter Format Check' - run: flutter format --set-exit-if-changed --dry-run . - - - run: flutter analyze diff --git a/.github/workflows/stream_flutter_workflow.yml b/.github/workflows/stream_flutter_workflow.yml index fa2a5e69..4c8882d7 100644 --- a/.github/workflows/stream_flutter_workflow.yml +++ b/.github/workflows/stream_flutter_workflow.yml @@ -7,8 +7,7 @@ on: pull_request: push: branches: - - main - - feature/new-ui + - master paths-ignore: - 'docs/**'

    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 diff --git a/packages/flutter_widgets/screenshots/message_widget.png b/packages/flutter_widgets/screenshots/message_widget.png index d333c03adecdb42d2da34af09ce3869413e12883..3d99f0568a162be5735710404b8c4603f8c88be7 100644 GIT binary patch literal 347568 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

  2. hdUY{=;rffmIw}~@ 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
    rQkH!$&cDes3Pq!&G#z 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

    vAw}o8igL{9LK#wzJQ= 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 diff --git a/packages/flutter_widgets/screenshots/channel_list_view_paint.png b/packages/flutter_widgets/screenshots/channel_list_view_paint.png index c1d49780badef07847f72c321203fedd4801b9be..9fb72e65630648b2053701a9ebebade5dd2d5ebd 100644 GIT binary patch literal 398294 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