From 7c24e7b202d00d6b7c74b8d2f05f61f22decfa5d Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Thu, 17 Dec 2020 19:42:07 +0530 Subject: [PATCH] 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