From 4978d457630fc98c42223ef456b042f2ce8d3b2e Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Fri, 28 May 2021 20:17:59 +0530 Subject: [PATCH 1/6] feat: Added pinned message screen. TODO: Add new logo --- .../stream_chat_v1/lib/chat_info_screen.dart | 60 +++++ .../stream_chat_v1/lib/group_info_screen.dart | 60 +++++ .../lib/pinned_messages_screen.dart | 232 ++++++++++++++++++ 3 files changed, 352 insertions(+) create mode 100644 packages/stream_chat_v1/lib/pinned_messages_screen.dart diff --git a/packages/stream_chat_v1/lib/chat_info_screen.dart b/packages/stream_chat_v1/lib/chat_info_screen.dart index 2ba2839..1974e94 100644 --- a/packages/stream_chat_v1/lib/chat_info_screen.dart +++ b/packages/stream_chat_v1/lib/chat_info_screen.dart @@ -6,6 +6,7 @@ import 'package:stream_chat_flutter/stream_chat_flutter.dart'; import 'channel_file_display_screen.dart'; import 'channel_media_display_screen.dart'; +import 'pinned_messages_screen.dart'; import 'main.dart'; import 'routes/routes.dart'; @@ -199,6 +200,65 @@ class _ChatInfoScreenState extends State { // ), // onTap: () {}, // ), + OptionListTile( + title: 'Pinned Messages', + 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: PinnedMessagesScreen( + messageTheme: widget.messageTheme, + 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: 'Photos & Videos', tileColor: StreamChatTheme.of(context).colorTheme.whiteSnow, diff --git a/packages/stream_chat_v1/lib/group_info_screen.dart b/packages/stream_chat_v1/lib/group_info_screen.dart index 3e964b2..18db05b 100644 --- a/packages/stream_chat_v1/lib/group_info_screen.dart +++ b/packages/stream_chat_v1/lib/group_info_screen.dart @@ -10,6 +10,7 @@ import 'package:stream_chat_flutter/stream_chat_flutter.dart'; import 'channel_file_display_screen.dart'; import 'channel_media_display_screen.dart'; +import 'pinned_messages_screen.dart'; import 'chat_info_screen.dart'; import 'main.dart'; import 'routes/routes.dart'; @@ -482,6 +483,65 @@ class _GroupInfoScreenState extends State { onTap: () {}, ); }), + OptionListTile( + title: 'Pinned Messages', + 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( + 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: PinnedMessagesScreen( + messageTheme: widget.messageTheme, + 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( tileColor: StreamChatTheme.of(context).colorTheme.whiteSnow, separatorColor: StreamChatTheme.of(context).colorTheme.greyGainsboro, diff --git a/packages/stream_chat_v1/lib/pinned_messages_screen.dart b/packages/stream_chat_v1/lib/pinned_messages_screen.dart new file mode 100644 index 0000000..5f8174b --- /dev/null +++ b/packages/stream_chat_v1/lib/pinned_messages_screen.dart @@ -0,0 +1,232 @@ +import 'package:flutter/material.dart'; +import 'package:stream_chat_flutter/stream_chat_flutter.dart'; +import 'package:video_player/video_player.dart'; + +class PinnedMessagesScreen 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; + + /// The builder used when the file list is empty. + final WidgetBuilder? emptyBuilder; + + final ShowMessageCallback? onShowMessage; + + final MessageTheme messageTheme; + + const PinnedMessagesScreen({ + required this.messageTheme, + this.sortOptions, + this.paginationParams, + this.emptyBuilder, + this.onShowMessage, + }); + + @override + _PinnedMessagesScreenState createState() => _PinnedMessagesScreenState(); +} + +class _PinnedMessagesScreenState extends State { + Map controllerCache = {}; + + @override + void initState() { + super.initState(); + final messageSearchBloc = MessageSearchBloc.of(context); + messageSearchBloc.search( + filter: Filter.in_( + 'cid', + [StreamChannel.of(context).channel.cid!], + ), + messageFilter: Filter.equal( + 'pinned', + true, + ), + sort: widget.sortOptions, + pagination: widget.paginationParams, + ); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: StreamChatTheme.of(context).colorTheme.white, + appBar: AppBar( + brightness: Theme.of(context).brightness, + elevation: 1, + centerTitle: true, + title: Text( + 'Pinned Messages', + style: TextStyle( + color: StreamChatTheme.of(context).colorTheme.black, + fontSize: 16.0, + ), + ), + leading: Center( + child: InkWell( + onTap: () { + Navigator.of(context).pop(); + }, + child: Container( + width: 24.0, + height: 24.0, + child: StreamSvgIcon.left( + color: StreamChatTheme.of(context).colorTheme.black, + size: 24.0, + ), + ), + ), + ), + backgroundColor: StreamChatTheme.of(context).colorTheme.white, + ), + body: _buildMediaGrid(), + ); + } + + Widget _buildMediaGrid() { + final messageSearchBloc = MessageSearchBloc.of(context); + + return StreamBuilder>( + builder: (context, snapshot) { + if (snapshot.data == null) { + return Center( + child: const CircularProgressIndicator(), + ); + } + + if (snapshot.data!.isEmpty) { + if (widget.emptyBuilder != null) { + return widget.emptyBuilder!(context); + } + 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 pinned items', + style: TextStyle( + fontSize: 17.0, + color: StreamChatTheme.of(context).colorTheme.black, + fontWeight: FontWeight.bold, + ), + ), + SizedBox(height: 8.0), + RichText( + textAlign: TextAlign.center, + text: TextSpan(children: [ + TextSpan( + text: 'Long-press an important message and\nchoose ', + style: TextStyle( + fontSize: 14.0, + color: StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(0.5), + ), + ), + TextSpan( + text: 'Pin to conversation', + style: TextStyle( + fontSize: 14.0, + fontWeight: FontWeight.bold, + color: StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(0.5), + ), + ), + ]), + ), + ], + ), + ); + } + + var data = snapshot.data ?? []; + + return LazyLoadScrollView( + onEndOfPage: () => messageSearchBloc.search( + filter: Filter.in_( + 'cid', + [StreamChannel.of(context).channel.cid!], + ), + messageFilter: Filter.equal( + 'pinned', + true, + ), + sort: widget.sortOptions, + pagination: widget.paginationParams!.copyWith( + offset: messageSearchBloc.messageResponses?.length ?? 0, + ), + ), + child: ListView.builder( + itemBuilder: (context, position) { + var user = data[position].message.user!; + var attachments = data[position].message.attachments; + var text = data[position].message.text ?? ''; + + return ListTile( + leading: UserAvatar( + user: user, + constraints: BoxConstraints( + maxWidth: 56.0, + minHeight: 56.0, + ), + borderRadius: BorderRadius.circular(28), + ), + title: Text( + user.name, + style: TextStyle( + color: StreamChatTheme.of(context).colorTheme.black, + fontWeight: FontWeight.bold), + ), + subtitle: Text( + text != '' + ? text + : (attachments.isNotEmpty + ? '${attachments.length} attachment${attachments.length > 1 ? 's' : ''}' + : ''), + ), + onTap: () { + widget.onShowMessage?.call(data[position].message, + StreamChannel.of(context).channel); + }, + ); + }, + itemCount: snapshot.data!.length, + ), + ); + }, + stream: messageSearchBloc.messagesStream, + ); + } + + @override + void dispose() { + super.dispose(); + for (var c in controllerCache.values) { + c!.dispose(); + } + } +} + +class _AssetPackage { + Attachment attachment; + Message message; + VideoPlayerController? videoPlayer; + + _AssetPackage(this.attachment, this.message, this.videoPlayer); +} From 44ee8c9ca283e157bf37166a42682c35dea9ea84 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Fri, 28 May 2021 20:20:12 +0530 Subject: [PATCH 2/6] rfac: remove asset package --- .../stream_chat_v1/lib/pinned_messages_screen.dart | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/packages/stream_chat_v1/lib/pinned_messages_screen.dart b/packages/stream_chat_v1/lib/pinned_messages_screen.dart index 5f8174b..c6ef9a2 100644 --- a/packages/stream_chat_v1/lib/pinned_messages_screen.dart +++ b/packages/stream_chat_v1/lib/pinned_messages_screen.dart @@ -221,12 +221,4 @@ class _PinnedMessagesScreenState extends State { c!.dispose(); } } -} - -class _AssetPackage { - Attachment attachment; - Message message; - VideoPlayerController? videoPlayer; - - _AssetPackage(this.attachment, this.message, this.videoPlayer); -} +} \ No newline at end of file From d7a0d8cad9d5e94642b08de1dcf964592987ee14 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Fri, 11 Jun 2021 13:49:08 +0530 Subject: [PATCH 3/6] fix: changed pin logo --- packages/stream_chat_v1/lib/pinned_messages_screen.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/stream_chat_v1/lib/pinned_messages_screen.dart b/packages/stream_chat_v1/lib/pinned_messages_screen.dart index c6ef9a2..acfdb2d 100644 --- a/packages/stream_chat_v1/lib/pinned_messages_screen.dart +++ b/packages/stream_chat_v1/lib/pinned_messages_screen.dart @@ -110,7 +110,7 @@ class _PinnedMessagesScreenState extends State { child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ - StreamSvgIcon.message( + StreamSvgIcon.pin( size: 136.0, color: StreamChatTheme.of(context).colorTheme.greyGainsboro, ), From 807e9126f0b1caeb5c675edf9a20456c74618ed6 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Fri, 11 Jun 2021 13:52:36 +0530 Subject: [PATCH 4/6] fix: changed pin logo --- packages/stream_chat_v1/lib/chat_info_screen.dart | 2 +- packages/stream_chat_v1/lib/group_info_screen.dart | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/stream_chat_v1/lib/chat_info_screen.dart b/packages/stream_chat_v1/lib/chat_info_screen.dart index 1974e94..b0d18d9 100644 --- a/packages/stream_chat_v1/lib/chat_info_screen.dart +++ b/packages/stream_chat_v1/lib/chat_info_screen.dart @@ -206,7 +206,7 @@ class _ChatInfoScreenState extends State { titleTextStyle: StreamChatTheme.of(context).textTheme.body, leading: Padding( padding: const EdgeInsets.symmetric(horizontal: 16.0), - child: StreamSvgIcon.pictures( + child: StreamSvgIcon.pin( size: 36.0, color: StreamChatTheme.of(context).colorTheme.black.withOpacity(0.5), diff --git a/packages/stream_chat_v1/lib/group_info_screen.dart b/packages/stream_chat_v1/lib/group_info_screen.dart index 18db05b..dda7eb8 100644 --- a/packages/stream_chat_v1/lib/group_info_screen.dart +++ b/packages/stream_chat_v1/lib/group_info_screen.dart @@ -489,7 +489,7 @@ class _GroupInfoScreenState extends State { titleTextStyle: StreamChatTheme.of(context).textTheme.body, leading: Padding( padding: const EdgeInsets.symmetric(horizontal: 12.0), - child: StreamSvgIcon.pictures( + child: StreamSvgIcon.pin( size: 32.0, color: StreamChatTheme.of(context).colorTheme.black.withOpacity(0.5), From 52b97e4ad26d1f38f900d4ab09318406dda4c96d Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Fri, 11 Jun 2021 16:24:50 +0530 Subject: [PATCH 5/6] fix: icon sizes --- packages/stream_chat_v1/lib/chat_info_screen.dart | 4 ++-- packages/stream_chat_v1/lib/group_info_screen.dart | 4 ++-- packages/stream_chat_v1/lib/pinned_messages_screen.dart | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/stream_chat_v1/lib/chat_info_screen.dart b/packages/stream_chat_v1/lib/chat_info_screen.dart index b0d18d9..eca16bb 100644 --- a/packages/stream_chat_v1/lib/chat_info_screen.dart +++ b/packages/stream_chat_v1/lib/chat_info_screen.dart @@ -205,9 +205,9 @@ 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.pin( - size: 36.0, + size: 24.0, color: StreamChatTheme.of(context).colorTheme.black.withOpacity(0.5), ), diff --git a/packages/stream_chat_v1/lib/group_info_screen.dart b/packages/stream_chat_v1/lib/group_info_screen.dart index dda7eb8..6c45757 100644 --- a/packages/stream_chat_v1/lib/group_info_screen.dart +++ b/packages/stream_chat_v1/lib/group_info_screen.dart @@ -488,9 +488,9 @@ class _GroupInfoScreenState 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.pin( - size: 32.0, + size: 24.0, color: StreamChatTheme.of(context).colorTheme.black.withOpacity(0.5), ), diff --git a/packages/stream_chat_v1/lib/pinned_messages_screen.dart b/packages/stream_chat_v1/lib/pinned_messages_screen.dart index acfdb2d..82dd532 100644 --- a/packages/stream_chat_v1/lib/pinned_messages_screen.dart +++ b/packages/stream_chat_v1/lib/pinned_messages_screen.dart @@ -182,8 +182,8 @@ class _PinnedMessagesScreenState extends State { leading: UserAvatar( user: user, constraints: BoxConstraints( - maxWidth: 56.0, - minHeight: 56.0, + maxWidth: 40.0, + minHeight: 40.0, ), borderRadius: BorderRadius.circular(28), ), @@ -221,4 +221,4 @@ class _PinnedMessagesScreenState extends State { c!.dispose(); } } -} \ No newline at end of file +} From cd04652649580d1d033acc69ffe79fc0c7ed4b2a Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Fri, 11 Jun 2021 16:29:43 +0530 Subject: [PATCH 6/6] fix: Added pin permissions --- packages/stream_chat_v1/lib/main.dart | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/stream_chat_v1/lib/main.dart b/packages/stream_chat_v1/lib/main.dart index ecd9957..c4d16b1 100644 --- a/packages/stream_chat_v1/lib/main.dart +++ b/packages/stream_chat_v1/lib/main.dart @@ -898,6 +898,7 @@ class _ChannelPageState extends State { ), ); }, + pinPermissions: ['owner', 'admin', 'member'], ), Positioned( bottom: 0, @@ -990,6 +991,7 @@ class _ThreadPageState extends State { initialAlignment: widget.initialAlignment, onMessageSwiped: _reply, onReplyTap: _reply, + pinPermissions: ['owner', 'admin', 'member'], ), ), if (widget.parent!.type != 'deleted')